From 6f0593e31fe31a535eb66e89dbe322ad4ce37f66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juraj=20=C4=8Eurech?= Date: Thu, 16 Jan 2025 14:33:47 +0100 Subject: [PATCH 01/10] Core: Remove support for recovery codes Fix #650 Fix #640 --- include/PowerAuth/OtpUtil.h | 24 --- include/PowerAuth/PublicTypes.h | 31 ---- include/PowerAuth/Session.h | 21 --- src/Android.mk | 1 - src/PowerAuth/OtpUtil.cpp | 45 ------ src/PowerAuth/PublicTypes.cpp | 10 -- src/PowerAuth/Session.cpp | 47 +----- src/PowerAuth/jni/ActivationCodeUtilJNI.cpp | 35 ---- src/PowerAuth/jni/SessionJNI.cpp | 54 ------- src/PowerAuth/protocol/PrivateTypes.cpp | 78 +-------- src/PowerAuth/protocol/PrivateTypes.h | 31 ---- src/PowerAuth/utils/DataReader.cpp | 9 ++ src/PowerAuth/utils/DataReader.h | 5 + src/PowerAuthTests/PowerAuthTestsList.cpp | 1 - src/PowerAuthTests/pa2OtpUtilTests.cpp | 171 -------------------- src/PowerAuthTests/pa2RecoveryCodeTests.cpp | 89 ---------- src/PowerAuthTests/pa2SessionTests.cpp | 78 +++++---- 17 files changed, 66 insertions(+), 664 deletions(-) delete mode 100644 src/PowerAuthTests/pa2RecoveryCodeTests.cpp diff --git a/include/PowerAuth/OtpUtil.h b/include/PowerAuth/OtpUtil.h index f07ae093..ae654926 100644 --- a/include/PowerAuth/OtpUtil.h +++ b/include/PowerAuth/OtpUtil.h @@ -74,16 +74,6 @@ namespace powerAuth */ static bool parseActivationCode(const std::string & activation_code, OtpComponents & out_components); - /** - Parses an input |recovery_code| (which may or may not contain an optional "R:" prefix) and stores - the result into the |out_components| structure. The method doesn't perform an autocorrection, - so the provided code must be valid. - - Returns true if the code is valid and |out_components| contains a valid data. - */ - static bool parseRecoveryCode(const std::string & recovery_code, OtpComponents & out_components); - - // Validations /** @@ -114,20 +104,6 @@ namespace powerAuth Returns true if |signature| contains a valid Base64 string. */ static bool validateSignature(const std::string & signature); - - /** - Returns true if |recovery_code| is a valid recovery code. You can use this method to validate - a whole user-typed recovery code at once. The input code may contain "R:" prefix, if code is - scanned from QR code and |allow_r_prefix| is true. - */ - static bool validateRecoveryCode(const std::string & recovery_code, bool allow_r_prefix = true); - - /** - Returns true if |recovery_puk| appears to be valid. You can use this method to validate - a whole user-typed recovery PUK at once. In current version, only 10 digits long string is considered - as a valid PUK. - */ - static bool validateRecoveryPuk(const std::string & recovery_puk); }; } // io::getlime::powerAuth diff --git a/include/PowerAuth/PublicTypes.h b/include/PowerAuth/PublicTypes.h index 529e7f02..694f816a 100644 --- a/include/PowerAuth/PublicTypes.h +++ b/include/PowerAuth/PublicTypes.h @@ -452,32 +452,6 @@ namespace powerAuth }; - // - // MARK: - Recovery Codes - - // - - /** - RecoveryData structure contains information about recovery code and PUK, created - during the activation process. - */ - struct RecoveryData - { - /** - Contains recovery code. - */ - std::string recoveryCode; - /** - Contains PUK, valid with recovery code. - */ - std::string puk; - - /** - Returns true if structure is empty (e.g. contains no recovery data) - */ - bool isEmpty() const; - }; - - // // MARK: - Session activation steps - // @@ -527,11 +501,6 @@ namespace powerAuth Initial value for hash-based counter. */ std::string ctrData; - /** - Data for activation recovery. May contain empty strings, in case - that there's no recovery available. - */ - RecoveryData activationRecovery; }; /** diff --git a/include/PowerAuth/Session.h b/include/PowerAuth/Session.h index 05969c9e..2d415025 100644 --- a/include/PowerAuth/Session.h +++ b/include/PowerAuth/Session.h @@ -629,27 +629,6 @@ namespace powerAuth if upgrade was not completed properly. */ ErrorCode finishProtocolUpgrade(); - - public: - - // MARK: - Recovery code - - - /** - Returns true, if session contains an activation recovery data. - */ - bool hasActivationRecoveryData() const; - - /** - Gets an activation recovery data. You have to provide encrypted vault key |c_vault_key| and - |keys| structure where the valid possessionUnlockKey is set. - - Returns EC_Ok, if operation succeeded - EC_Encryption, if general encryption error occurs - EC_WrongState, if the session has no valid activation, or - if no activation recovery data is available. - EC_WrongParam, if some required parameter is missing - */ - ErrorCode getActivationRecoveryData(const std::string & c_vault_key, const SignatureUnlockKeys & keys, RecoveryData & out_recovery_data); public: diff --git a/src/Android.mk b/src/Android.mk index 01306fac..2369e9cb 100644 --- a/src/Android.mk +++ b/src/Android.mk @@ -98,7 +98,6 @@ LOCAL_SRC_FILES := \ PowerAuthTests/pa2MasterSecretKeyComputation.cpp \ PowerAuthTests/pa2PasswordTests.cpp \ PowerAuthTests/pa2ProtocolUtilsTests.cpp \ - PowerAuthTests/pa2RecoveryCodeTests.cpp \ PowerAuthTests/pa2SessionTests.cpp \ PowerAuthTests/pa2SessionSetupTests.cpp \ PowerAuthTests/pa2SignatureCalculationTests.cpp \ diff --git a/src/PowerAuth/OtpUtil.cpp b/src/PowerAuth/OtpUtil.cpp index 23f315e7..196bd740 100644 --- a/src/PowerAuth/OtpUtil.cpp +++ b/src/PowerAuth/OtpUtil.cpp @@ -60,27 +60,6 @@ namespace powerAuth return validateActivationCode(out_components.activationCode); } - static const std::string RECOVERY_QR_MARKER("R:"); - - bool OtpUtil::parseRecoveryCode(const std::string &recovery_code, OtpComponents &out_components) - { - std::string code_to_test; - auto recovery_marker_pos = recovery_code.find(RECOVERY_QR_MARKER); - if (recovery_marker_pos != std::string::npos) { - if (recovery_marker_pos != 0) { - return false; // "R:" is not at the beginning of string - } - code_to_test = recovery_code.substr(2); - } else { - code_to_test = recovery_code; - } - if (!parseActivationCode(code_to_test, out_components)) { - return false; - } - return out_components.hasSignature() == false; - } - - // Validations bool OtpUtil::validateTypedCharacter(cc7::U32 uc) @@ -146,30 +125,6 @@ namespace powerAuth return false; } - - bool OtpUtil::validateRecoveryCode(const std::string &recovery_code, bool allow_r_prefix) - { - if (recovery_code.find(RECOVERY_QR_MARKER) == std::string::npos) { - return validateActivationCode(recovery_code); - } - return allow_r_prefix && validateActivationCode(recovery_code.substr(2)); - } - - - bool OtpUtil::validateRecoveryPuk(const std::string &recovery_puk) - { - if (recovery_puk.length() != 10) { - return false; - } - for (size_t i = 0; i < recovery_puk.length(); i++) { - auto c = recovery_puk[i]; - if (c < '0' || c > '9') { - return false; - } - } - return true; - } - } // io::getlime::powerAuth } // io::getlime } // io diff --git a/src/PowerAuth/PublicTypes.cpp b/src/PowerAuth/PublicTypes.cpp index d7062432..caea0fc6 100644 --- a/src/PowerAuth/PublicTypes.cpp +++ b/src/PowerAuth/PublicTypes.cpp @@ -173,16 +173,6 @@ namespace powerAuth } - // - // MARK: - RecoveryData - - // - - bool RecoveryData::isEmpty() const - { - return recoveryCode.empty() && puk.empty(); - } - - // // MARK: - ActivationStatus - // diff --git a/src/PowerAuth/Session.cpp b/src/PowerAuth/Session.cpp index 6ae250fe..37a75bae 100644 --- a/src/PowerAuth/Session.cpp +++ b/src/PowerAuth/Session.cpp @@ -330,11 +330,6 @@ namespace powerAuth auto error_code = EC_Encryption; do { - // Validate (optional) recovery data - if (!protocol::ValidateRecoveryData(param.activationRecovery)) { - CC7_LOG("Session %p: Step 2: Invalid recovery data.", this); - return EC_WrongParam; - } // Validate CTR_DATA if (!_ad->ctrData.readFromBase64String(param.ctrData) || _ad->ctrData.size() != protocol::SIGNATURE_KEY_SIZE) { // Note that we treat all B64 decode failures as an encryption error. @@ -365,7 +360,6 @@ namespace powerAuth // Everything is OK, keep other data for later _ad->activationId = param.activationId; - _ad->recoveryData = param.activationRecovery; error_code = EC_Ok; @@ -433,12 +427,7 @@ namespace powerAuth if (pd->cDevicePrivateKey.empty()) { CC7_LOG("Session %p: Step 3: Unable to encrypt device private key.", this); break; - } - if (!protocol::SerializeRecoveryData(_ad->recoveryData, vault_key, pd->cRecoveryData)) { - CC7_LOG("Session %p: Step 3: Unable to encrypt recovery data.", this); - break; - } - + } // Final step is PD validation. If this step fails, then there's an internal problem. if (!protocol::ValidatePersistentData(*pd)) { CC7_LOG("Session %p: Step 3: Persistent data is invalid.", this); @@ -1310,39 +1299,7 @@ namespace powerAuth } return EC_WrongState; } - - - // MARK: - Recovery code - - - bool Session::hasActivationRecoveryData() const - { - LOCK_GUARD(); - return hasValidActivation() && !_pd->cRecoveryData.empty(); - } - - - ErrorCode Session::getActivationRecoveryData(const std::string & c_vault_key, const SignatureUnlockKeys & keys, RecoveryData & out_recovery_data) - { - LOCK_GUARD(); - if (!hasValidActivation()) { - CC7_LOG("Session %p: RecoveryData: Session has no valid activation.", this); - return EC_WrongState; - } - if (_pd->cRecoveryData.empty()) { - CC7_LOG("Session %p: RecoveryData: Session has no recovery data available.", this); - return EC_WrongState; - } - cc7::ByteArray vault_key; - auto ec = decryptVaultKey(c_vault_key, keys, vault_key); - if (ec == EC_Ok) { - if (!protocol::DeserializeRecoveryData(_pd->cRecoveryData, vault_key, out_recovery_data)) { - CC7_LOG("Session %p: RecoveryData: Cannot decrypt or deserialize recovery data.", this); - ec = EC_Encryption; - } - } - return ec; - } - + // MARK: - Private methods - /* diff --git a/src/PowerAuth/jni/ActivationCodeUtilJNI.cpp b/src/PowerAuth/jni/ActivationCodeUtilJNI.cpp index 18d8c249..20534b34 100644 --- a/src/PowerAuth/jni/ActivationCodeUtilJNI.cpp +++ b/src/PowerAuth/jni/ActivationCodeUtilJNI.cpp @@ -53,23 +53,6 @@ CC7_JNI_METHOD_PARAMS(jobject, parseFromActivationCode, jstring activationCode) return resultObject; } -// -// public native static ActivationCode parseFromRecoveryCode(String recoveryCode) -// -CC7_JNI_METHOD_PARAMS(jobject, parseFromRecoveryCode, jstring activationCode) -{ - std::string cppActivationCode = cc7::jni::CopyFromJavaString(env, activationCode); - OtpComponents cppComponents; - if (false == OtpUtil::parseRecoveryCode(cppActivationCode, cppComponents)) { - return NULL; - } - // Copy cppResult into java result object - jclass resultClazz = CC7_JNI_MODULE_FIND_CLASS("ActivationCode"); - jobject resultObject = cc7::jni::CreateJavaObject(env, CC7_JNI_MODULE_CLASS_PATH("ActivationCode"), "()V"); - CC7_JNI_SET_FIELD_STRING(resultObject, resultClazz, "activationCode", cc7::jni::CopyToJavaString(env, cppComponents.activationCode)); - return resultObject; -} - // ---------------------------------------------------------------------------- // Validations // ---------------------------------------------------------------------------- @@ -99,22 +82,4 @@ CC7_JNI_METHOD_PARAMS(jboolean, validateActivationCode, jstring activationCode) return (jboolean) OtpUtil::validateActivationCode(cppActivationCode); } -// -// public native static boolean validateRecoveryCode(String recoveryCode) -// -CC7_JNI_METHOD_PARAMS(jboolean, validateRecoveryCode, jstring recoveryCode) -{ - std::string cppRecoveryCode = cc7::jni::CopyFromJavaString(env, recoveryCode); - return (jboolean) OtpUtil::validateRecoveryCode(cppRecoveryCode); -} - -// -// public native static boolean validateRecoveryPuk(String recoveryPuk) -// -CC7_JNI_METHOD_PARAMS(jboolean, validateRecoveryPuk, jstring recoveryPuk) -{ - std::string cppRecoveryPuk = cc7::jni::CopyFromJavaString(env, recoveryPuk); - return (jboolean) OtpUtil::validateRecoveryPuk(cppRecoveryPuk); -} - } // extern "C" diff --git a/src/PowerAuth/jni/SessionJNI.cpp b/src/PowerAuth/jni/SessionJNI.cpp index 407e1620..c483205a 100644 --- a/src/PowerAuth/jni/SessionJNI.cpp +++ b/src/PowerAuth/jni/SessionJNI.cpp @@ -275,13 +275,6 @@ CC7_JNI_METHOD_PARAMS(jobject, validateActivationResponse, jobject param) cppParam.activationId = cc7::jni::CopyFromJavaString(env, CC7_JNI_GET_FIELD_STRING(param, paramClazz, "activationId")); cppParam.serverPublicKey = cc7::jni::CopyFromJavaString(env, CC7_JNI_GET_FIELD_STRING(param, paramClazz, "serverPublicKey")); cppParam.ctrData = cc7::jni::CopyFromJavaString(env, CC7_JNI_GET_FIELD_STRING(param, paramClazz, "ctrData")); - // Copy optional recovery data - jobject recoveryData = CC7_JNI_GET_FIELD_OBJECT(param, paramClazz, "activationRecovery", CC7_JNI_MODULE_CLASS_SIGNATURE("RecoveryData")); - if (recoveryData != NULL) { - jclass recoveryDataClazz = CC7_JNI_MODULE_FIND_CLASS("RecoveryData"); - cppParam.activationRecovery.recoveryCode = cc7::jni::CopyFromJavaString(env, CC7_JNI_GET_FIELD_STRING(recoveryData, recoveryDataClazz, "recoveryCode")); - cppParam.activationRecovery.puk = cc7::jni::CopyFromJavaString(env, CC7_JNI_GET_FIELD_STRING(recoveryData, recoveryDataClazz, "puk")); - } // Call C++ session ActivationStep2Result cppResult; ErrorCode code = session->validateActivationResponse(cppParam, cppResult); @@ -932,51 +925,4 @@ CC7_JNI_METHOD_PARAMS(jstring, getMaxSupportedHttpProtocolVersion, jint protocol return cc7::jni::CopyToJavaString(env, Version_GetMaxSupportedHttpProtocolVersion((Version)protocolVersionValue)); } -// ---------------------------------------------------------------------------- -// Recovery codes -// ---------------------------------------------------------------------------- - -// -// public native boolean hasActivationRecoveryData() -// -CC7_JNI_METHOD(jboolean, hasActivationRecoveryData) -{ - auto session = CC7_THIS_OBJ(); - if (!session) { - CC7_ASSERT(false, "Missing internal handle."); - return false; - } - return (jboolean) session->hasActivationRecoveryData(); -} - -// -// public native RecoveryData getActivationRecoveryData(String cVaultKey, SignatureUnlockKeys unlockKeys) -// -CC7_JNI_METHOD_PARAMS(jobject , getActivationRecoveryData, jstring cVaultKey, jobject unlockKeys) -{ - auto session = CC7_THIS_OBJ(); - if (!session) { - CC7_ASSERT(false, "Missing internal handle."); - return NULL; - } - // Load parameters into C++ objects - std::string cppCVaultKey = cc7::jni::CopyFromJavaString(env, cVaultKey); - SignatureUnlockKeys cppUnlockKeys; - if (false == LoadSignatureUnlockKeys(cppUnlockKeys, env, unlockKeys)) { - return NULL; - } - RecoveryData cppRecoveryData; - auto result = session->getActivationRecoveryData(cppCVaultKey, cppUnlockKeys, cppRecoveryData); - if (EC_Ok != result) { - CC7_ASSERT(false, "getActivationRecoveryData failed with error %d", result); - return NULL; - } - // Copy cppResult into java result object - jclass resultClazz = CC7_JNI_MODULE_FIND_CLASS("RecoveryData"); - jobject resultObject = cc7::jni::CreateJavaObject(env, CC7_JNI_MODULE_CLASS_PATH("RecoveryData"), "()V"); - CC7_JNI_SET_FIELD_STRING(resultObject, resultClazz, "recoveryCode", cc7::jni::CopyToJavaString(env, cppRecoveryData.recoveryCode)); - CC7_JNI_SET_FIELD_STRING(resultObject, resultClazz, "puk", cc7::jni::CopyToJavaString(env, cppRecoveryData.puk)); - return resultObject; -} - CC7_JNI_MODULE_CLASS_END() diff --git a/src/PowerAuth/protocol/PrivateTypes.cpp b/src/PowerAuth/protocol/PrivateTypes.cpp index 545282a8..1ac9eea6 100644 --- a/src/PowerAuth/protocol/PrivateTypes.cpp +++ b/src/PowerAuth/protocol/PrivateTypes.cpp @@ -196,8 +196,9 @@ namespace protocol // flags writer.writeU32 (pd.flagsU32); - // encrypted recovery data (PD v4) - writer.writeData (pd.cRecoveryData); + // encrypted recovery data (PD v4), for compatibility reason, we store + // zero count only (e.g. no recovery data is available) + writer.writeCount(0); // Counter byte (PD v5) writer.writeByte (pd.signatureCounterByte); @@ -238,11 +239,9 @@ namespace protocol // Copy external key flag to the SignatureKeys structure pd.sk.usesExternalKey = pd.flags.usesExternalKey; - // encrypted recovery data (PD v4) + // encrypted recovery data (PD v4). For a compatibility reasons, we just skip possible stored bytes. if (reader.currentVersion() >= PD_VERSION_V4) { - result = result && reader.readData (pd.cRecoveryData); - } else { - pd.cRecoveryData.clear(); + result = result && reader.skipDataOrString(); } // signature counter byte (PD v5) @@ -259,73 +258,6 @@ namespace protocol return result; } - - - // - // MARK: - Recovery codes - - // - - const cc7::byte RD_TAG = 'R'; - const cc7::byte RD_VERSION_V1 = '1'; // recovery data version - - bool ValidateRecoveryData(const RecoveryData & data) - { - if (data.isEmpty()) { - return true; - } - // Validate recovery code and PUK. Recovery code should not contain "R:" prefix. - return OtpUtil::validateRecoveryCode(data.recoveryCode, false) && - OtpUtil::validateRecoveryPuk(data.puk); - } - - bool SerializeRecoveryData(const RecoveryData & data, const cc7::ByteRange vault_key, cc7::ByteArray & out_data) - { - CC7_ASSERT(ValidateRecoveryData(data), "Invalid recovery data"); - - if (data.isEmpty()) { - out_data.clear(); - return true; - } - // Serialize structure to sequence of bytes - utils::DataWriter writer; - writer.openVersion(RD_TAG, RD_VERSION_V1); - writer.writeString(data.recoveryCode); - writer.writeString(data.puk); - writer.closeVersion(); - - // Encrypt sequence of bytes - out_data = crypto::AES_CBC_Encrypt_Padding(vault_key, ZERO_IV, writer.serializedData()); - return !out_data.empty(); - } - - bool DeserializeRecoveryData(const cc7::ByteRange & serialized, const cc7::ByteRange vault_key, RecoveryData & out_data) - { - // Should not be called with an empty data. Unlike in serialization routine, we consider this as an error. - if (serialized.empty()) { - CC7_ASSERT(false, "Should not be called when recovery data is not available"); - return false; - } - - // Decrypt serialized sequence of bytes. - bool error = false; - auto decrypted = crypto::AES_CBC_Decrypt_Padding(vault_key, ZERO_IV, serialized, &error); - if (error) { - return false; - } - - utils::DataReader reader(decrypted); - - // Open version with V1, which automatically allows deserialization of future variants. - bool result = reader.openVersion(RD_TAG, RD_VERSION_V1); - result = result && reader.readString(out_data.recoveryCode); - result = result && reader.readString(out_data.puk); - result = result && reader.closeVersion(); - - result = result && ValidateRecoveryData(out_data); - - return result; - } - // // MARK: - Session Data - diff --git a/src/PowerAuth/protocol/PrivateTypes.h b/src/PowerAuth/protocol/PrivateTypes.h index 51229892..ca4322f0 100644 --- a/src/PowerAuth/protocol/PrivateTypes.h +++ b/src/PowerAuth/protocol/PrivateTypes.h @@ -85,7 +85,6 @@ namespace protocol cc7::ByteArray masterSharedSecret; // The result of ECDH. This value is VERY sensitive! cc7::ByteArray ctrData; // Initial value for hash-based counter - RecoveryData recoveryData; // Received recovery data // Construction, destruction @@ -173,10 +172,6 @@ namespace protocol Encrypted device's private key. */ cc7::ByteArray cDevicePrivateKey; - /** - Encrypted recovery data. - */ - cc7::ByteArray cRecoveryData; struct _Flags { /** @@ -318,32 +313,6 @@ namespace protocol */ bool DeserializePersistentData(PersistentData & pd, utils::DataReader & reader); - - // - // MARK: - Recovery codes - - // - - /** - Validates |data| in provided structure and returns true if structure contains valid data. The true is returned also - in case that RecoveryData structure is empty. - */ - bool ValidateRecoveryData(const RecoveryData & data); - - /** - Serializes provided |data| structure into sequence of bytes and then encrypts that sequence with using |vaultKey|. - The resulted sequence of bytes is stored to the |out_data| array. If |data| structure is empty, then result is - an empty sequence of bytes. - - Returns false in case of encryption failure. - */ - bool SerializeRecoveryData(const RecoveryData & data, const cc7::ByteRange vault_key, cc7::ByteArray & out_data); - - /** - Decrypts provided |serialized| data with using vault key and then deserializes decrypted sequence into |out_data| - structure. Returns true in case that both steps succeeded. - */ - bool DeserializeRecoveryData(const cc7::ByteRange & serialized, const cc7::ByteRange vault_key, RecoveryData & out_data); - // // MARK: - Session Data - // diff --git a/src/PowerAuth/utils/DataReader.cpp b/src/PowerAuth/utils/DataReader.cpp index bf051658..adfd7645 100644 --- a/src/PowerAuth/utils/DataReader.cpp +++ b/src/PowerAuth/utils/DataReader.cpp @@ -88,6 +88,15 @@ namespace utils _offset += size; return true; } + + bool DataReader::skipDataOrString() + { + size_t count; + if (!readCount(count)) { + return false; + } + return skipBytes(count); + } bool DataReader::readData(ByteArray & out_data, size_t expected_size) { diff --git a/src/PowerAuth/utils/DataReader.h b/src/PowerAuth/utils/DataReader.h index 40ef8e26..0d5f1d57 100644 --- a/src/PowerAuth/utils/DataReader.h +++ b/src/PowerAuth/utils/DataReader.h @@ -94,6 +94,11 @@ namespace utils */ bool skipBytes(size_t size); + /** + Skips sequence of bytes serialized as Data or String. + */ + bool skipDataOrString(); + /** Reads data object into |out_data|. You can specify exact |expected_size| or 0 for any size. diff --git a/src/PowerAuthTests/PowerAuthTestsList.cpp b/src/PowerAuthTests/PowerAuthTestsList.cpp index d17b99ca..5934a360 100644 --- a/src/PowerAuthTests/PowerAuthTestsList.cpp +++ b/src/PowerAuthTests/PowerAuthTestsList.cpp @@ -45,7 +45,6 @@ namespace powerAuthTests // Protocol tests CC7_ADD_UNIT_TEST(pa2ProtocolUtilsTests, list); - CC7_ADD_UNIT_TEST(pa2RecoveryCodeTests, list); CC7_ADD_UNIT_TEST(pa2URLEncodingTests, list); CC7_ADD_UNIT_TEST(pa2SignatureKeysDerivationTest, list); CC7_ADD_UNIT_TEST(pa2MasterSecretKeyComputation, list); diff --git a/src/PowerAuthTests/pa2OtpUtilTests.cpp b/src/PowerAuthTests/pa2OtpUtilTests.cpp index 23ef5fd0..e51e5836 100644 --- a/src/PowerAuthTests/pa2OtpUtilTests.cpp +++ b/src/PowerAuthTests/pa2OtpUtilTests.cpp @@ -42,9 +42,6 @@ namespace powerAuthTests CC7_REGISTER_TEST_METHOD(testCharValidation) CC7_REGISTER_TEST_METHOD(testCharAutocorrection) CC7_REGISTER_TEST_METHOD(testActivationCodeParser) - CC7_REGISTER_TEST_METHOD(testRecoveryCodeValidation) - CC7_REGISTER_TEST_METHOD(testRecoveryPukValidation) - CC7_REGISTER_TEST_METHOD(testRecoveryCodeParser) CC7_REGISTER_TEST_METHOD(niceCodeGenerator) } @@ -210,174 +207,6 @@ namespace powerAuthTests ccstAssertFalse(result); } - - void testRecoveryCodeValidation() - { - const char * valid_codes[] = { - // nice codes - "AAAAA-AAAAA-AAAAA-AAAAA", - "MMMMM-MMMMM-MMMMM-MUTOA", - "VVVVV-VVVVV-VVVVV-VTFVA", - "55555-55555-55555-55YMA", - // random codes - "W65WE-3T7VI-7FBS2-A4OYA", - "DD7P5-SY4RW-XHSNB-GO52A", - "X3TS3-TI35Z-JZDNT-TRPFA", - "HCPJX-U4QC4-7UISL-NJYMA", - "XHGSM-KYQDT-URE34-UZGWQ", - "45AWJ-BVACS-SBWHS-ABANA", - - // With R: prefix - "R:AAAAA-AAAAA-AAAAA-AAAAA", - "R:MMMMM-MMMMM-MMMMM-MUTOA", - "R:VVVVV-VVVVV-VVVVV-VTFVA", - "R:55555-55555-55555-55YMA", - "R:BUSES-ETYN2-5HTFE-NOV2Q", - "R:ATQAZ-WJ7ZG-FWA7J-QFAJQ", - "R:MXSYF-LLQJ7-PS6LF-E2FMQ", - "R:ZKMVN-4IMFK-FLSYX-ARRGA", - "R:NQHGX-LNM2S-EQ4NT-G3NAA", - NULL - }; - const char ** p = valid_codes; - while (const char * code = *p++) { - bool result = OtpUtil::validateRecoveryCode(std::string(code)); - ccstAssertTrue(result, "Code '%s' should pass the test", code); - } - - const char * invalid_codes[] = { - "", - " ", - "R", - "R:", - "X:AAAAA-AAAAA-AAAAA-AAAAA", - "KLMNO-PQRST", - "R:KLMNO-PQRST", - "KLMNO-PQRST-UVWXY-Z234", - "KLMNO-PQRST-UVWXY-Z2345 ", - "R:KLMNO-PQRST-UVWXY-Z2345 ", - "KLMNO-PQRST-UVWXY-Z2345#", - "NQHGX-LNM2S-EQ4NT-G3NAA#aGVsbG8td29ybGQ=", - "R:NQHGX-LNM2S-EQ4NT-G3NAA#aGVsbG8td29ybGQ=", - "67AAA-B0BCC-DDEEF-GGHHI", - "67AAA-BB1CC-DDEEF-GGHHI", - "67AAA-BBBC8-DDEEF-GGHHI", - "67AAA-BBBCC-DDEEF-GGHH9", - "67aAA-BBBCC-DDEEF-GGHHI", - "6-AAA-BB1CC-DDEEF-GGHHI", - "67AA#-BB1CC-DDEEF-GGHHI", - "67AABCBB1CC-DDEEF-GGHHI", - "67AAB-BB1CCEDDEEF-GGHHI", - "67AAA-BBBCC-DDEEFZGGHHI", - NULL - }; - p = invalid_codes; - while (const char * code = *p++) { - bool result = OtpUtil::validateRecoveryCode(std::string(code)); - ccstAssertFalse(result, "Code '%s' should not pass the test", code); - } - - ccstAssertTrue(OtpUtil::validateRecoveryCode("NQHGX-LNM2S-EQ4NT-G3NAA", false)); - ccstAssertFalse(OtpUtil::validateRecoveryCode("R:NQHGX-LNM2S-EQ4NT-G3NAA", false)); - } - - void testRecoveryPukValidation() - { - const char * valid_puks[] = { - "0000000000", - "9999999999", - "0123456789", - "9876543210", - "1111111111", - "3487628763", - NULL - }; - const char ** p = valid_puks; - while (const char * puk = *p++) { - bool result = OtpUtil::validateRecoveryPuk(std::string(puk)); - ccstAssertTrue(result, "PUK '%s' should pass the test", puk); - } - - const char * invalid_puks[] = { - "", - " ", - "11111111111", - "111111111", - "0", - "999999999A", - "99999999b9", - "9999999c99", - "999999d999", - "99999e9999", - "9999f99999", - "999g999999", - "99h9999999", - "9i99999999", - "A999999999", - "999999999 ", - "99999999 9", - "9999999 99", - "999999 999", - "99999 9999", - "9999 99999", - "999 999999", - "99 9999999", - "9 99999999", - " 999999999", - NULL - }; - p = invalid_puks; - while (const char * puk = *p++) { - bool result = OtpUtil::validateRecoveryPuk(std::string(puk)); - ccstAssertFalse(result, "PUK '%s' should not pass the test", puk); - } - } - - void testRecoveryCodeParser() - { - OtpComponents components; - bool result; - - // valid sequences - result = OtpUtil::parseRecoveryCode("BBBBB-BBBBB-BBBBB-BTA6Q", components); - ccstAssertTrue(result); - ccstAssertEqual(components.activationCode, "BBBBB-BBBBB-BBBBB-BTA6Q"); - - result = OtpUtil::parseRecoveryCode("R:BBBBB-BBBBB-BBBBB-BTA6Q", components); - ccstAssertTrue(result); - ccstAssertEqual(components.activationCode, "BBBBB-BBBBB-BBBBB-BTA6Q"); - - // invalid sequences - result = OtpUtil::parseRecoveryCode("", components); - ccstAssertFalse(result); - result = OtpUtil::parseRecoveryCode("#", components); - ccstAssertFalse(result); - result = OtpUtil::parseRecoveryCode("#AB==", components); - ccstAssertFalse(result); - result = OtpUtil::parseRecoveryCode("KLMNO-PQRST", components); - ccstAssertFalse(result); - result = OtpUtil::parseRecoveryCode("EEEEE-EEEEE-EEEEE-E2OXA#", components); - ccstAssertFalse(result); - result = OtpUtil::parseRecoveryCode("OOOOO-OOOOO-OOOOO-OZH2Q#", components); - ccstAssertFalse(result); - result = OtpUtil::parseRecoveryCode("SSSSS-SSSSS-SSSSS-SX7IA#AB", components); - ccstAssertFalse(result); - result = OtpUtil::parseRecoveryCode("UUUUU-UUUUU-UUUUU-UAFLQ#AB#", components); - ccstAssertFalse(result); - result = OtpUtil::parseRecoveryCode("WWWWW-WWWWW-WWWWW-WNR7A#ABA=#", components); - ccstAssertFalse(result); - result = OtpUtil::parseRecoveryCode("XXXXX-XXXXX-XXXXX-X6RBQ#ABA-=", components); - ccstAssertFalse(result); - result = OtpUtil::parseRecoveryCode("DDDDD-DDDDD-DDDDD-D6UKA#ABC=", components); - ccstAssertFalse(result); - result = OtpUtil::parseRecoveryCode("EEEEE-EEEEE-EEEEE-E2OXA#AB==", components); - ccstAssertFalse(result); - result = OtpUtil::parseRecoveryCode("R:DDDDD-DDDDD-DDDDD-D6UKA#ABC=", components); - ccstAssertFalse(result); - result = OtpUtil::parseRecoveryCode("R:EEEEE-EEEEE-EEEEE-E2OXA#AB==", components); - ccstAssertFalse(result); - } - ////// void niceCodeGenerator() diff --git a/src/PowerAuthTests/pa2RecoveryCodeTests.cpp b/src/PowerAuthTests/pa2RecoveryCodeTests.cpp deleted file mode 100644 index ff903980..00000000 --- a/src/PowerAuthTests/pa2RecoveryCodeTests.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2021 Wultra s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "protocol/ProtocolUtils.h" -#include "protocol/Constants.h" -#include "protocol/PrivateTypes.h" -#include "crypto/CryptoUtils.h" - -using namespace cc7; -using namespace cc7::tests; -using namespace io::getlime::powerAuth; - -namespace io -{ -namespace getlime -{ -namespace powerAuthTests -{ - class pa2RecoveryCodeTests : public UnitTest - { - public: - - pa2RecoveryCodeTests() - { - CC7_REGISTER_TEST_METHOD(testGoodRecoveryData) - CC7_REGISTER_TEST_METHOD(testBadRecoveryData) - } - - // unit tests - - void testGoodRecoveryData() - { - RecoveryData rd; - - ccstAssertTrue(protocol::ValidateRecoveryData(rd)); - - rd.recoveryCode = "VVVVV-VVVVV-VVVVV-VTFVA"; - rd.puk = "1111122222"; - - ccstAssertTrue(protocol::ValidateRecoveryData(rd)); - } - - void testBadRecoveryData() - { - static struct TestData { - const char * recovery_code; - const char * puk; - } bad_data[] = { - { "VVVVV-VVVVV-VVVVV-VTFVA", "" }, - { "", "111112222" }, - { "VVVVV-VVVVV-VVVVV-VTFVA", "111112222" }, - { "VVVVV-VVVVV-VVVVV-VTFVA", "11111222233" }, - { "VVVVV-VVVVV-VVVVV-VTFVA", "11111A2223" }, - { "VVVVV-VVVVV-VVVVV-VTFVA", "11111 2223" }, - { "VAVVV-VVVVV-VVVVV-VTFVA", "1111122222" }, - { nullptr, nullptr } - }; - - const TestData * td = bad_data; - while (td->recovery_code && td->puk) { - RecoveryData rd; - rd.recoveryCode = td->recovery_code; - rd.puk = td->puk; - ccstAssertFalse(protocol::ValidateRecoveryData(rd)); - td++; - } - } - - }; - - CC7_CREATE_UNIT_TEST(pa2RecoveryCodeTests, "pa2") - -} // io::getlime::powerAuthTests -} // io::getlime -} // io diff --git a/src/PowerAuthTests/pa2SessionTests.cpp b/src/PowerAuthTests/pa2SessionTests.cpp index 7af61ade..d8f3c440 100644 --- a/src/PowerAuthTests/pa2SessionTests.cpp +++ b/src/PowerAuthTests/pa2SessionTests.cpp @@ -72,6 +72,7 @@ namespace powerAuthTests CC7_REGISTER_TEST_METHOD(testPersistentDataUpgradeFromV2ToV5); CC7_REGISTER_TEST_METHOD(testPersistentDataUpgradeFromV3ToV5); CC7_REGISTER_TEST_METHOD(testPersistentDataUpgradeFromV4ToV5); + CC7_REGISTER_TEST_METHOD(testSkipRecoveryDataInV5) } ECKeyPair _masterServerPrivateKey; @@ -246,7 +247,6 @@ namespace powerAuthTests ccstMessage("%s || Let's don't break the activation", eek_msg); } - const bool USE_RECOVERY_CODE = break_in_step == 4; const bool TEST_ECIES_RESET = break_in_step == 4; EC_KEY * serverPrivateKey = nullptr; @@ -322,11 +322,6 @@ namespace powerAuthTests param2.activationId = _activation_id; param2.ctrData = CTR_DATA.base64String(); param2.serverPublicKey = serverPublicKey.base64String(); - if (USE_RECOVERY_CODE) { - // Store recovery code - param2.activationRecovery.recoveryCode = _recovery_code; - param2.activationRecovery.puk = _recovery_puk; - } // calculate hkKEY_DEVICE_PUBLIC on dummy server's side auto fingerprint_data = crypto::ECC_ExportPublicKeyToNormalizedForm(devicePublicKey); @@ -459,8 +454,6 @@ namespace powerAuthTests ccstAssertTrue(s1.hasValidActivation()); // Compare whether the fingerprint is still correct ccstAssertEqual(s1.activationFingerprint(), ACTIVATION_FINGERPRINT); - // Validate existence of recovery data - ccstAssertTrue(s1.hasActivationRecoveryData() == USE_RECOVERY_CODE); } // Signature test #1 { @@ -956,26 +949,6 @@ namespace powerAuthTests ccstAssertEqual(ec, EC_Ok); ccstAssertEqual(request_data, cc7::MakeRange("Plan9!")); } - // Recovery codes - if (USE_RECOVERY_CODE) { - // Recovery data is available - SignatureUnlockKeys keys; - keys.possessionUnlockKey = possessionUnlock; - RecoveryData recovery_data; - ec = s1.getActivationRecoveryData(cVaultKey, keys, recovery_data); - ccstAssertEqual(ec, EC_Ok); - ccstAssertFalse(recovery_data.isEmpty()); - ccstAssertEqual(recovery_data.recoveryCode, _recovery_code); - ccstAssertEqual(recovery_data.puk, _recovery_puk); - } else { - // Recovery data is not available - SignatureUnlockKeys keys; - keys.possessionUnlockKey = possessionUnlock; - RecoveryData recovery_data; - ec = s1.getActivationRecoveryData(cVaultKey, keys, recovery_data); - ccstAssertEqual(ec, EC_WrongState); - ccstAssertTrue(recovery_data.isEmpty()); - } if (TEST_ECIES_RESET) { // Test Reset session ccstAssertTrue(s1.hasPublicKeyForEciesScope(ECIES_ApplicationScope)); @@ -1122,7 +1095,6 @@ namespace powerAuthTests ccstAssertFalse(s1.hasExternalEncryptionKey()); ccstAssertEqual(s1.activationIdentifier(), "FULL-BUT-FAKE-ACTIVATION-ID"); ccstAssertEqual(Version_NA, s1.pendingProtocolUpgradeVersion()); - ccstAssertFalse(s1.hasActivationRecoveryData()); ec = s1.startProtocolUpgrade(); ccstAssertEqual(ec, EC_Ok); @@ -1189,7 +1161,6 @@ namespace powerAuthTests ccstAssertFalse(s1.hasExternalEncryptionKey()); ccstAssertEqual(s1.activationIdentifier(), "FULL-BUT-FAKE-ACTIVATION-ID"); ccstAssertEqual(Version_NA, s1.pendingProtocolUpgradeVersion()); - ccstAssertFalse(s1.hasActivationRecoveryData()); auto v5_data = s1.saveSessionState(); s1.resetSession(); @@ -1203,7 +1174,6 @@ namespace powerAuthTests ccstAssertFalse(s1.hasExternalEncryptionKey()); ccstAssertEqual(s1.activationIdentifier(), "FULL-BUT-FAKE-ACTIVATION-ID"); ccstAssertEqual(Version_NA, s1.pendingProtocolUpgradeVersion()); - ccstAssertFalse(s1.hasActivationRecoveryData()); // Try low level function. The ctr_byte must not be available. protocol::PersistentData pd; @@ -1243,7 +1213,6 @@ namespace powerAuthTests ccstAssertFalse(s1.hasExternalEncryptionKey()); ccstAssertEqual(s1.activationIdentifier(), "FULL-BUT-FAKE-ACTIVATION-ID"); ccstAssertEqual(Version_NA, s1.pendingProtocolUpgradeVersion()); - ccstAssertFalse(s1.hasActivationRecoveryData()); auto v5_data = s1.saveSessionState(); s1.resetSession(); @@ -1257,7 +1226,6 @@ namespace powerAuthTests ccstAssertFalse(s1.hasExternalEncryptionKey()); ccstAssertEqual(s1.activationIdentifier(), "FULL-BUT-FAKE-ACTIVATION-ID"); ccstAssertEqual(Version_NA, s1.pendingProtocolUpgradeVersion()); - ccstAssertFalse(s1.hasActivationRecoveryData()); // Try low level function. The ctr_byte must not be available. protocol::PersistentData pd; @@ -1270,6 +1238,50 @@ namespace powerAuthTests ccstAssertEqual(pd.flags.hasSignatureCounterByte, 0); } + void testSkipRecoveryDataInV5() + { + // constants + SessionSetup setup; + setup.applicationKey = "MDEyMzQ1Njc4OUFCQ0RFRg=="; + setup.applicationSecret = "QUJDREVGMDEyMzQ1Njc4OQ=="; + setup.masterServerPublicKey = "AuCDGp3fAHL695yWxCP6d+jZEzwZleOdmCU+qFIImjBs"; + + Session s1(setup); + const auto activationId = std::string("6c536561-cf7a-4ad2-ac40-e9c62493f9a3"); + const auto activationFingerprint = std::string("58727422"); + // The following sequence of data contains V5 persistent data with encrypted recovery code and PUK. The new loader in SDK 1.10 should properly skip this payload. + auto v5_data = cc7::FromBase64String("UEECUDYQEBdQCpAMPu3ezKccRLMr3yQ2YzUzNjU2MS1jZjdhLTRhZDItYWM0MC1lOWM2MjQ5M2Y5YTMAACcQEPyBOyTBrp+zdEwm+XO" + "9ziIQ26hRbh2VQM9MHX9Agy/guxDJ+nJUxSToxG2tumhGyCqLABAbZ5S0cwJ9JmFdyUAS0Oc4QQQ3x+wVZm1xTlS+UQAtK9xZ+3JG6k" + "UY/gyHOVgf6nREtM39BmrsGImS4ICdY5g/gm5vJtRfL5X07rdsmxbPQ5R8IQIz/Y8sTT8qXBl+bVjn/mUtCcNH2KdEhx+GFhr6B6khE" + "zAixbkEYlhLh0LC+qzb5L+hdIWwg1/xon93T7SCZ0w/fnWKw51yEWvU0GFJTrx5+W4AAAQAMC+xmCKOL0gmhTRbBzwNMWvSl8BLyUTh" + "W0tdk38pUu9R/ybdoErBwrtGBzm0MLmZIAA="); + auto ec = s1.loadSessionState(v5_data); + ccstAssertTrue(ec == EC_Ok); + ccstAssertEqual(s1.protocolVersion(), Version_V3); + ccstAssertFalse(s1.canStartActivation()); + ccstAssertTrue(s1.hasValidActivation()); + ccstAssertFalse(s1.hasPendingActivation()); + ccstAssertFalse(s1.hasExternalEncryptionKey()); + ccstAssertEqual(activationId, s1.activationIdentifier()); + ccstAssertEqual(activationFingerprint, s1.activationFingerprint()); + ccstAssertEqual(Version_NA, s1.pendingProtocolUpgradeVersion()); + + // If session's state is serialized in SDK 1.10, then the RC part is no longer present in the serialized data. + auto v5_data_2 = s1.saveSessionState(); + ccstAssertNotEqual(v5_data, v5_data_2); + + // Now try to reload data without RC + ec = s1.loadSessionState(v5_data); + ccstAssertTrue(ec == EC_Ok); + ccstAssertFalse(s1.canStartActivation()); + ccstAssertTrue(s1.hasValidActivation()); + ccstAssertFalse(s1.hasPendingActivation()); + ccstAssertFalse(s1.hasExternalEncryptionKey()); + ccstAssertEqual(activationId, s1.activationIdentifier()); + ccstAssertEqual(activationFingerprint, s1.activationFingerprint()); + ccstAssertEqual(Version_NA, s1.pendingProtocolUpgradeVersion()); + } + // Helper methods From 4a6f7642ce5f78803cb7002da614cd7624741e57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juraj=20=C4=8Eurech?= Date: Thu, 16 Jan 2025 14:34:55 +0100 Subject: [PATCH 02/10] iOS: Remove recovery codes support --- docs/PowerAuth-SDK-for-iOS.md | 155 +----------------- .../PowerAuth2.xcodeproj/project.pbxproj | 24 --- proj-xcode/PowerAuth2/PowerAuthActivation.h | 29 ---- proj-xcode/PowerAuth2/PowerAuthActivation.m | 32 ---- .../PowerAuth2/PowerAuthActivationCode.h | 22 --- .../PowerAuth2/PowerAuthActivationCode.m | 15 -- .../PowerAuthActivationRecoveryData.h | 35 ---- .../PowerAuthActivationRecoveryData.m | 54 ------ .../PowerAuth2/PowerAuthActivationResult.h | 7 - .../PowerAuth2/PowerAuthActivationResult.m | 3 +- proj-xcode/PowerAuth2/PowerAuthSDK.h | 62 ------- proj-xcode/PowerAuth2/PowerAuthSDK.m | 104 ------------ .../private/PA2ConfirmRecoveryCodeRequest.h | 1 + .../private/PA2ConfirmRecoveryCodeRequest.m | 1 + .../private/PA2ConfirmRecoveryCodeResponse.h | 1 + .../private/PA2ConfirmRecoveryCodeResponse.m | 1 + .../private/PA2CreateActivationRecoveryData.h | 24 --- .../private/PA2CreateActivationRecoveryData.m | 32 ---- .../private/PA2CreateActivationResponseData.h | 2 - .../private/PA2CreateActivationResponseData.m | 5 - .../PowerAuth2/private/PA2RestApiEndpoint.h | 2 - .../PowerAuth2/private/PA2RestApiEndpoint.m | 9 - .../PowerAuth2/private/PA2RestApiObjects.h | 1 - .../PowerAuth2/private/PowerAuthSDK+Private.h | 5 - .../PowerAuthSDKDefaultTests.m | 109 ------------ .../PowerAuthServer/PowerAuthTestServerAPI.h | 7 - .../PowerAuthServer/PowerAuthTestServerAPI.m | 8 +- .../PowerAuthTestServerConfig.h | 1 + .../PowerAuthTestServerConfig.m | 3 +- .../PowerAuthServer/RestHelper.m | 2 +- .../PowerAuthActivationTests.m | 68 +------- .../PowerAuthCore.xcodeproj/project.pbxproj | 6 - .../PowerAuthCore/PowerAuthCoreOtpUtil.h | 22 --- .../PowerAuthCore/PowerAuthCoreOtpUtil.mm | 20 --- .../PowerAuthCore/PowerAuthCorePrivateImpl.h | 9 - .../PowerAuthCore/PowerAuthCoreSession.h | 17 -- .../PowerAuthCore/PowerAuthCoreSession.mm | 24 --- proj-xcode/PowerAuthCore/PowerAuthCoreTypes.h | 23 --- .../PowerAuthCore/PowerAuthCoreTypes.mm | 22 --- 39 files changed, 14 insertions(+), 953 deletions(-) delete mode 100644 proj-xcode/PowerAuth2/PowerAuthActivationRecoveryData.h delete mode 100644 proj-xcode/PowerAuth2/PowerAuthActivationRecoveryData.m delete mode 100644 proj-xcode/PowerAuth2/private/PA2CreateActivationRecoveryData.h delete mode 100644 proj-xcode/PowerAuth2/private/PA2CreateActivationRecoveryData.m diff --git a/docs/PowerAuth-SDK-for-iOS.md b/docs/PowerAuth-SDK-for-iOS.md index 1009c93c..5fd7996c 100644 --- a/docs/PowerAuth-SDK-for-iOS.md +++ b/docs/PowerAuth-SDK-for-iOS.md @@ -15,7 +15,6 @@ - [Activation via Activation Code](#activation-via-activation-code) - [Activation via OpenID Connect](#activation-via-openid-connect) - [Activation via Custom Credentials](#activation-via-custom-credentials) - - [Activation via Recovery Code](#activation-via-recovery-code) - [Customize Activation](#customize-activation) - [Persisting Activation Data](#persisting-activation-data) - [Validating User Inputs](#validating-user-inputs) @@ -33,9 +32,6 @@ - [Device Activation Removal](#activation-removal) - [End-To-End Encryption](#end-to-end-encryption) - [Secure Vault](#secure-vault) -- [Recovery Codes](#recovery-codes) - - [Getting Recovery Data](#getting-recovery-data) - - [Confirm Recovery Postcard](#confirm-recovery-postcard) - [Token-Based Authentication](#token-based-authentication) - [Apple Watch Support](#apple-watch-support) - [Prepare Watch Connectivity](#prepare-watch-connectivity) @@ -235,15 +231,12 @@ powerAuthSDK.createActivation(activation) { (result, error) in if error == nil { // No error occurred, proceed to credentials entry (PIN prompt, Enable Touch ID switch, ...) and persist // The 'result' contains the 'activationFingerprint' property, representing the device public key - it may be used as visual confirmation - // If the server supports recovery codes for activations, then the `activationRecovery` property contains an object with information about activation recovery. } else { // Error occurred, report it to the user } } ``` -If the received activation result also contains recovery data, then you should display those values to the user. To do that, please read the [Getting Recovery Data](#getting-recovery-data) section of this document, which describes how to treat that sensitive information. This is relevant for all types of activation you use. - Note that if you use `UIDevice.current.name` for a device’s name, your application must include an [appropriate entitlement](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_developer_device-information_user-assigned-device-name); otherwise, the operating system will provide a generic `iPhone` string. @@ -317,7 +310,6 @@ powerAuthSDK.createActivation(activation) { (result, error) in if error == nil { // No error occurred, proceed to credentials entry (PIN prompt, Enable Touch ID switch, ...) and persist // The 'result' contains 'activationFingerprint' property, representing the device public key - it may be used as visual confirmation - // If the server supports recovery codes for activations, then the `activationRecovery` property contains an object with information about activation recovery. } else { // Error occurred, report it to the user } @@ -332,46 +324,6 @@ Note that by using weak identity attributes to create an activation, the resulti Note that if you use `UIDevice.current.name` for a device’s name, your application must include an [appropriate entitlement](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_developer_device-information_user-assigned-device-name); otherwise, the operating system will provide a generic `iPhone` string. -### Activation via Recovery Code - -If the PowerAuth Server is configured to support [Recovery Codes](https://github.com/wultra/powerauth-crypto/blob/develop/docs/Activation-Recovery.md), then also you can create an activation via the recovery code and PUK. - -Use the following code to create an activation using the recovery code: - -```swift -let deviceName = "John Tramonta" // or UIDevice.current.name (see warning below) -let recoveryCode = "55555-55555-55555-55YMA" // User's input -let puk = "0123456789" // User's input. You should validate RC & PUK with using PowerAuthActivationCodeUtil - -// Create activation object with recovery code and PUK -guard let activation = try? PowerAuthActivation(recoveryCode: recoveryCode, recoveryPuk: puk, name: deviceName) else { - // Recovery code or PUK is not valid. -} - -// Create a new activation with just created activation object -powerAuthSDK.createActivation(activation) { (result, error) in - if let error = error { - // Error occurred, report it to the user - // On top of regular error processing, you should handle a special situation, when the server gives an additional information - // about which PUK must be used for the recovery. The information is valid only when a recovery code from a postcard is applied. - if let responseError = (error.userInfo[PowerAuthErrorDomain] as? PowerAuthRestApiErrorResponse)?.responseObject { - let currentRecoveryPukIndex = responseError.currentRecoveryPukIndex - if currentRecoveryPukIndex > 0 { - // The PUK index is known, you should inform the user that it has to rewrite PUK from a specific position. - } - } - } else { - // No error occurred, proceed to credentials entry (PIN prompt, Enable Touch ID switch, ...) and persist - // The 'result' contains the 'activationFingerprint' property, representing the device public key - it may be used as visual confirmation - // If the server supports recovery codes for activations, then the `activationRecovery` property contains an object with information about activation recovery. - } -} -``` - - -Note that if you use `UIDevice.current.name` for a device’s name, your application must include an [appropriate entitlement](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_developer_device-information_user-assigned-device-name); otherwise, the operating system will provide a generic `iPhone` string. - - ### Customize Activation You can set additional properties to the `PowerAuthActivation` object before any type of activation is created. For example: @@ -434,7 +386,6 @@ The mobile SDK provides a couple of functions in the `PowerAuthActivationCodeUti - Parse activation code when it's scanned from QR code - Validate a whole code at once -- Validate recovery code or PUK - Auto-correct characters typed on the fly #### Validating Scanned QR Code @@ -475,24 +426,9 @@ let isInvalid = PowerAuthActivationCodeUtil.validateActivationCode("VVVVV-VVVVV- If your application is using your own validation, then you should switch to functions provided by SDK. The reason for that is that since SDK `1.0.0`, all activation codes contain a checksum, so it's possible to detect mistyped characters before you start the activation. Check our [Activation Code](https://github.com/wultra/powerauth-crypto/blob/develop/docs/Activation-Code.md) documentation for more details. -#### Validating Recovery Code and PUK - -To validate a recovery code at once, you can call the `PowerAuthActivationCodeUtil.validateRecoveryCode()` function. You can provide the whole code, which may or may not contain `"R:"` prefix. So, you can validate manually entered codes, but also codes scanned from QR. For example: - -```swift -let isValid1 = PowerAuthActivationCodeUtil.validateRecoveryCode("VVVVV-VVVVV-VVVVV-VTFVA") -let isValid2 = PowerAuthActivationCodeUtil.validateRecoveryCode("R:VVVVV-VVVVV-VVVVV-VTFVA") -``` - -To validate PUK at once, you can call the `PowerAuthActivationCodeUtil.validateRecoveryPuk()` function: - -```swift -let isValid = PowerAuthActivationCodeUtil.validateRecoveryPuk("0123456789") -``` - #### Auto-Correcting Typed Characters -You can implement auto-correcting of typed characters by using the `PowerAuthActivationCodeUtil.validateAndCorrectTypedCharacter()` function on screens, where the user is supposed to enter an activation or recovery code. This technique is possible because Base32 is constructed so that it doesn't contain visually confusing characters. For example, `1` (number one) and `I` (capital I) are confusing, so only `I` is allowed. The benefit is that the provided function can correct typed `1` and translate it to `I`. +You can implement auto-correcting of typed characters by using the `PowerAuthActivationCodeUtil.validateAndCorrectTypedCharacter()` function on screens, where the user is supposed to enter an activation code. This technique is possible because Base32 is constructed so that it doesn't contain visually confusing characters. For example, `1` (number one) and `I` (capital I) are confusing, so only `I` is allowed. The benefit is that the provided function can correct typed `1` and translate it to `I`. Here's an example of how to iterate over the string and validate it character by character: @@ -1450,93 +1386,6 @@ powerAuthSDK.fetchEncryptionKey(auth, index: index) { (encryptionKey, error) in } ``` -## Recovery Codes - -The recovery codes allow your users to recover their activation in case their device is lost or stolen. Before you start, please read the [Activation Recovery](https://github.com/wultra/powerauth-crypto/blob/develop/docs/Activation-Recovery.md) document, available in our [powerauth-crypto](https://github.com/wultra/powerauth-crypto) repository. - -To recover an activation, the user has to re-type two separate values: - -1. Recovery Code itself, which is very similar to an activation code. So you can detect typing errors before you submit such code to the server. -1. PUK, which is an additional numeric value and acts as a one-time password in the scheme. - -PowerAuth currently supports two basic types of recovery codes: - -1. Recovery Code bound to a previous PowerAuth activation. - - This type of code can be obtained only in an already-activated application. - - This type of code has only one PUK available, so only one recovery operation is possible. - - The activation associated with the code is removed once the recovery operation succeeds. - -2. Recovery Code delivered via OOB channel, typically in the form of a securely printed postcard, delivered by the post service. - - This type of code has typically more than one PUK associated with the code, so it can be used multiple times. - - The user has to keep that postcard in a safe and secure place, and mark already used PUKs. - - The code delivery must be confirmed by the user before the code can be used for a recovery operation. - -The feature is not automatically available. It must be enabled and configured on the PowerAuth Server. If it's so, then your mobile application can use several methods related to this feature. - -### Getting Recovery Data - -If the recovery data was received during the activation process, then you can later display that information to the user. To check the existence of recovery data and get that information, use the following code: - -```swift -guard powerAuthSdk.hasActivationRecoveryData() else { - // Recovery information is not available - return -} - -// 2FA signature - uses device-related key and user PIN code -let auth = PowerAuthAuthentication.possessionWithPassword(password: "1234") - -powerAuthSdk.activationRecoveryData(auth) { recoveryData, error in - if let recoveryData = recoveryData { - let recoveryCode = recoveryData.recoveryCode - let puk = recoveryData.puk - // Show values on the screen - } else { - // Show an error - } -} -``` - -The obtained information is very sensitive, so you should be very careful how your application manipulates the received values: - -- You should never store `recoveryCode` or `puk` on the device. -- You should never print the values to the debug log. -- You should never send the values over the network. -- You should never copy the values to the clipboard. -- You should require a PIN code every time to display the values on the screen. -- You should warn the user that taking a screenshot of the values is not recommended. -- Do not cache the values in RAM. - -You should inform the user that: - -- Making a screenshot when values are displayed on the screen is dangerous. -- The user should write down those values on paper and keep it as safe as possible for future use. - - -### Confirm Recovery Postcard - -The recovery postcard can contain the recovery code and multiple PUK values on one printed card. Due to security reasons, this kind of recovery code cannot be used for the recovery operation before the user confirms its physical delivery. To confirm such recovery code, use the following code: - -```swift -// 2FA signature with possession factor is required -let auth = PowerAuthAuthentication.possessionWithPassword(password: "1234") - -let recoveryCode = "VVVVV-VVVVV-VVVVV-VTFVA" // You can also use code scanned from QR -powerAuthSDK.confirmRecoveryCode(recoveryCode, authentication: auth) { alreadyConfirmed, error in - if let error = error { - // Process error - } else { - if alreadyConfirmed { - print("Recovery code has been already confirmed. This is not an error, just information.") - } else { - print("Recovery code has been successfully confirmed.") - } - } -} -``` - -The `alreadyConfirmed` boolean indicates that the code was already confirmed in the past. You can choose a different "success" screen, describing that the user has already confirmed such code. Also, note that codes bound to the activations are already confirmed. - ## Token-Based Authentication @@ -2016,7 +1865,7 @@ if error == nil { print("Error code for error that occurs when activation state is invalid") case .invalidActivationCode: - print("Error code for error that occurs when activation or recovery code is invalid") + print("Error code for error that occurs when activation code is invalid") case .invalidActivationData: print("Error code for error that occurs when activation data is invalid") diff --git a/proj-xcode/PowerAuth2.xcodeproj/project.pbxproj b/proj-xcode/PowerAuth2.xcodeproj/project.pbxproj index 434d07ab..69178f14 100644 --- a/proj-xcode/PowerAuth2.xcodeproj/project.pbxproj +++ b/proj-xcode/PowerAuth2.xcodeproj/project.pbxproj @@ -19,10 +19,6 @@ BF08254B2631607C00B34E24 /* PowerAuthActivationStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = BF0825482631607C00B34E24 /* PowerAuthActivationStatus.h */; settings = {ATTRIBUTES = (Public, ); }; }; BF08254C2631607C00B34E24 /* PowerAuthActivationStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = BF0825492631607C00B34E24 /* PowerAuthActivationStatus.m */; }; BF08254D2631607C00B34E24 /* PowerAuthActivationStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = BF0825492631607C00B34E24 /* PowerAuthActivationStatus.m */; }; - BF08255E263164F100B34E24 /* PowerAuthActivationRecoveryData.h in Headers */ = {isa = PBXBuildFile; fileRef = BF08255C263164F100B34E24 /* PowerAuthActivationRecoveryData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - BF08255F263164F100B34E24 /* PowerAuthActivationRecoveryData.h in Headers */ = {isa = PBXBuildFile; fileRef = BF08255C263164F100B34E24 /* PowerAuthActivationRecoveryData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - BF082560263164F100B34E24 /* PowerAuthActivationRecoveryData.m in Sources */ = {isa = PBXBuildFile; fileRef = BF08255D263164F100B34E24 /* PowerAuthActivationRecoveryData.m */; }; - BF082561263164F100B34E24 /* PowerAuthActivationRecoveryData.m in Sources */ = {isa = PBXBuildFile; fileRef = BF08255D263164F100B34E24 /* PowerAuthActivationRecoveryData.m */; }; BF08256C2631670D00B34E24 /* PowerAuthActivationResult.h in Headers */ = {isa = PBXBuildFile; fileRef = BF08256A2631670D00B34E24 /* PowerAuthActivationResult.h */; settings = {ATTRIBUTES = (Public, ); }; }; BF08256D2631670D00B34E24 /* PowerAuthActivationResult.h in Headers */ = {isa = PBXBuildFile; fileRef = BF08256A2631670D00B34E24 /* PowerAuthActivationResult.h */; settings = {ATTRIBUTES = (Public, ); }; }; BF08256E2631670D00B34E24 /* PowerAuthActivationResult.m in Sources */ = {isa = PBXBuildFile; fileRef = BF08256B2631670D00B34E24 /* PowerAuthActivationResult.m */; }; @@ -37,8 +33,6 @@ BF0899E32A97408500AF29E5 /* PowerAuthTimeSynchronizationService.h in Headers */ = {isa = PBXBuildFile; fileRef = BF0899E02A97408500AF29E5 /* PowerAuthTimeSynchronizationService.h */; settings = {ATTRIBUTES = (Public, ); }; }; BF15E1E82C6B990A003CCABB /* PA2ObjectSerializationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BF15E1E12C6B990A003CCABB /* PA2ObjectSerializationTests.m */; }; BF15E1E92C6B990A003CCABB /* PA2ObjectSerializationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BF15E1E12C6B990A003CCABB /* PA2ObjectSerializationTests.m */; }; - BF1EC6CF223BD3BB00883236 /* PA2CreateActivationRecoveryData.h in Headers */ = {isa = PBXBuildFile; fileRef = BF1EC6CD223BD3BB00883236 /* PA2CreateActivationRecoveryData.h */; }; - BF1EC6D0223BD3BB00883236 /* PA2CreateActivationRecoveryData.m in Sources */ = {isa = PBXBuildFile; fileRef = BF1EC6CE223BD3BB00883236 /* PA2CreateActivationRecoveryData.m */; }; BF1EC6D7223BDF5500883236 /* PA2ConfirmRecoveryCodeRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = BF1EC6D5223BDF5500883236 /* PA2ConfirmRecoveryCodeRequest.h */; }; BF1EC6D8223BDF5500883236 /* PA2ConfirmRecoveryCodeRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = BF1EC6D6223BDF5500883236 /* PA2ConfirmRecoveryCodeRequest.m */; }; BF1ED06E283CEB2700D6B380 /* PowerAuthKeychainAuthentication.h in Headers */ = {isa = PBXBuildFile; fileRef = BF1ED06C283CEB2700D6B380 /* PowerAuthKeychainAuthentication.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -177,7 +171,6 @@ BF5EB4D524C85FE200F9DDB2 /* PA2VaultUnlockRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = BF30DB5B206CEAE900430C12 /* PA2VaultUnlockRequest.m */; }; BF5EB4D624C85FE200F9DDB2 /* PowerAuthLog.m in Sources */ = {isa = PBXBuildFile; fileRef = BFDFED9720BEEFAC0094138A /* PowerAuthLog.m */; }; BF5EB4D924C85FE200F9DDB2 /* PowerAuthActivation.m in Sources */ = {isa = PBXBuildFile; fileRef = BFF6716A243376B0009279CA /* PowerAuthActivation.m */; }; - BF5EB4DA24C85FE200F9DDB2 /* PA2CreateActivationRecoveryData.m in Sources */ = {isa = PBXBuildFile; fileRef = BF1EC6CE223BD3BB00883236 /* PA2CreateActivationRecoveryData.m */; }; BF5EB4DB24C85FE200F9DDB2 /* PowerAuthAuthorizationHttpHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B5D5A061D91D77D000995A7 /* PowerAuthAuthorizationHttpHeader.m */; }; BF5EB4DC24C85FE200F9DDB2 /* PowerAuthAuthentication.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B0A239F1D6C714100D24167 /* PowerAuthAuthentication.m */; }; BF5EB4E124C85FE200F9DDB2 /* PA2EncryptedResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = BF77510A1FC4876B008455A6 /* PA2EncryptedResponse.h */; }; @@ -224,7 +217,6 @@ BF5EB52224C85FE200F9DDB2 /* PowerAuthKeychainConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = BF5A236C1FE0030A00B78DE2 /* PowerAuthKeychainConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; }; BF5EB52324C85FE200F9DDB2 /* PowerAuthActivation.h in Headers */ = {isa = PBXBuildFile; fileRef = BFF67169243376B0009279CA /* PowerAuthActivation.h */; settings = {ATTRIBUTES = (Public, ); }; }; BF5EB52424C85FE200F9DDB2 /* PA2WeakArray.h in Headers */ = {isa = PBXBuildFile; fileRef = BFA0E2D4200FB33B0011F0A6 /* PA2WeakArray.h */; }; - BF5EB52624C85FE200F9DDB2 /* PA2CreateActivationRecoveryData.h in Headers */ = {isa = PBXBuildFile; fileRef = BF1EC6CD223BD3BB00883236 /* PA2CreateActivationRecoveryData.h */; }; BF5EB52724C85FE200F9DDB2 /* PA2Error+Decodable.h in Headers */ = {isa = PBXBuildFile; fileRef = BF5344662163D0BF003C201C /* PA2Error+Decodable.h */; }; BF5EB52824C85FE200F9DDB2 /* PowerAuthOperationTask.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B9AD2BE1DA5B2F200CF52C9 /* PowerAuthOperationTask.h */; settings = {ATTRIBUTES = (Public, ); }; }; BF5EB52924C85FE200F9DDB2 /* PA2HttpRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = BF8BFBE2215B8760001D6852 /* PA2HttpRequest.h */; }; @@ -639,8 +631,6 @@ BF0825182630514D00B34E24 /* PowerAuthErrorConstants.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PowerAuthErrorConstants.m; sourceTree = ""; }; BF0825482631607C00B34E24 /* PowerAuthActivationStatus.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PowerAuthActivationStatus.h; sourceTree = ""; }; BF0825492631607C00B34E24 /* PowerAuthActivationStatus.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PowerAuthActivationStatus.m; sourceTree = ""; }; - BF08255C263164F100B34E24 /* PowerAuthActivationRecoveryData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PowerAuthActivationRecoveryData.h; sourceTree = ""; }; - BF08255D263164F100B34E24 /* PowerAuthActivationRecoveryData.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PowerAuthActivationRecoveryData.m; sourceTree = ""; }; BF08256A2631670D00B34E24 /* PowerAuthActivationResult.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PowerAuthActivationResult.h; sourceTree = ""; }; BF08256B2631670D00B34E24 /* PowerAuthActivationResult.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PowerAuthActivationResult.m; sourceTree = ""; }; BF08257C2632E0E400B34E24 /* PowerAuthActivationStatus+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PowerAuthActivationStatus+Private.h"; sourceTree = ""; }; @@ -648,8 +638,6 @@ BF0825A72632E64600B34E24 /* PowerAuthActivationCode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PowerAuthActivationCode.m; sourceTree = ""; }; BF0899E02A97408500AF29E5 /* PowerAuthTimeSynchronizationService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PowerAuthTimeSynchronizationService.h; sourceTree = ""; }; BF15E1E12C6B990A003CCABB /* PA2ObjectSerializationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PA2ObjectSerializationTests.m; sourceTree = ""; }; - BF1EC6CD223BD3BB00883236 /* PA2CreateActivationRecoveryData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PA2CreateActivationRecoveryData.h; sourceTree = ""; }; - BF1EC6CE223BD3BB00883236 /* PA2CreateActivationRecoveryData.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PA2CreateActivationRecoveryData.m; sourceTree = ""; }; BF1EC6D5223BDF5500883236 /* PA2ConfirmRecoveryCodeRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PA2ConfirmRecoveryCodeRequest.h; sourceTree = ""; }; BF1EC6D6223BDF5500883236 /* PA2ConfirmRecoveryCodeRequest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PA2ConfirmRecoveryCodeRequest.m; sourceTree = ""; }; BF1ED06C283CEB2700D6B380 /* PowerAuthKeychainAuthentication.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PowerAuthKeychainAuthentication.h; sourceTree = ""; }; @@ -958,8 +946,6 @@ 1B2EEF641D662C960039D92A /* PA2CreateActivationResponse.m */, BFFB0B9F2167A9B4004A06E2 /* PA2CreateActivationResponseData.h */, BFFB0BA02167A9B4004A06E2 /* PA2CreateActivationResponseData.m */, - BF1EC6CD223BD3BB00883236 /* PA2CreateActivationRecoveryData.h */, - BF1EC6CE223BD3BB00883236 /* PA2CreateActivationRecoveryData.m */, 1B2EEF611D662C960039D92A /* PA2GetActivationStatusResponse.h */, 1B2EEF621D662C960039D92A /* PA2GetActivationStatusResponse.m */, BFD389722C62647C0087F96D /* PA2GetTemporaryKeyResponse.h */, @@ -1047,8 +1033,6 @@ BF0825492631607C00B34E24 /* PowerAuthActivationStatus.m */, BF08256A2631670D00B34E24 /* PowerAuthActivationResult.h */, BF08256B2631670D00B34E24 /* PowerAuthActivationResult.m */, - BF08255C263164F100B34E24 /* PowerAuthActivationRecoveryData.h */, - BF08255D263164F100B34E24 /* PowerAuthActivationRecoveryData.m */, 1B0A239E1D6C714100D24167 /* PowerAuthAuthentication.h */, 1B0A239F1D6C714100D24167 /* PowerAuthAuthentication.m */, 1B5D5A051D91D77D000995A7 /* PowerAuthAuthorizationHttpHeader.h */, @@ -1489,9 +1473,7 @@ BF5EB52324C85FE200F9DDB2 /* PowerAuthActivation.h in Headers */, BFFECED3263844AC001DA7A9 /* PA2PrivateConstants.h in Headers */, BF5EB52424C85FE200F9DDB2 /* PA2WeakArray.h in Headers */, - BF5EB52624C85FE200F9DDB2 /* PA2CreateActivationRecoveryData.h in Headers */, BF5EB52724C85FE200F9DDB2 /* PA2Error+Decodable.h in Headers */, - BF08255F263164F100B34E24 /* PowerAuthActivationRecoveryData.h in Headers */, BF5EB52824C85FE200F9DDB2 /* PowerAuthOperationTask.h in Headers */, BFD389772C62647C0087F96D /* PA2GetTemporaryKeyResponse.h in Headers */, BF5EB52924C85FE200F9DDB2 /* PA2HttpRequest.h in Headers */, @@ -1604,7 +1586,6 @@ BF8CF5022032EB41002A6B6E /* PA2WeakArray.h in Headers */, BF6B39EB27F312D100BDF579 /* PA2SharedMemory.h in Headers */, BF8CF5032032EB41002A6B6E /* PowerAuthWCSessionManager+Private.h in Headers */, - BF1EC6CF223BD3BB00883236 /* PA2CreateActivationRecoveryData.h in Headers */, BF28C1A829815D6900E2CD8E /* PowerAuthUserInfo.h in Headers */, BF1ED06E283CEB2700D6B380 /* PowerAuthKeychainAuthentication.h in Headers */, BFC192A127FC8C3F001455C1 /* PA2SessionInterface.h in Headers */, @@ -1615,7 +1596,6 @@ BF8BFBE4215B8760001D6852 /* PA2HttpRequest.h in Headers */, BF8CF5062032EB41002A6B6E /* PA2PrivateRemoteTokenProvider.h in Headers */, BF8BFBEE215BBA7B001D6852 /* PowerAuthClientConfiguration.h in Headers */, - BF08255E263164F100B34E24 /* PowerAuthActivationRecoveryData.h in Headers */, BF8CF5072032EB41002A6B6E /* PA2WCSessionPacket_Constants.h in Headers */, BF30DB5C206CEAE900430C12 /* PA2VaultUnlockRequest.h in Headers */, BFCEE09C216E280600B41201 /* PA2GetActivationStatusTask.h in Headers */, @@ -2011,7 +1991,6 @@ buildActionMask = 2147483647; files = ( BF4BED362AA08D2D00A8A2D0 /* PA2CompositeTask.m in Sources */, - BF082561263164F100B34E24 /* PowerAuthActivationRecoveryData.m in Sources */, BF5EB4A424C85FE200F9DDB2 /* PA2HttpRequest.m in Sources */, BFFECEC426383E48001DA7A9 /* PowerAuthDeprecated.m in Sources */, BF5EB4A524C85FE200F9DDB2 /* PA2PrivateTokenKeychainStore.m in Sources */, @@ -2083,7 +2062,6 @@ BF38903C2A97861100D7A18E /* PA2TimeSynchronizationService.m in Sources */, BF5EB4D924C85FE200F9DDB2 /* PowerAuthActivation.m in Sources */, BFBD68772C5A838D007AE16F /* PA2JwtObject.m in Sources */, - BF5EB4DA24C85FE200F9DDB2 /* PA2CreateActivationRecoveryData.m in Sources */, BF1ED0BA2844D3D200D6B380 /* PA2GroupedTask.m in Sources */, BF5EB4DB24C85FE200F9DDB2 /* PowerAuthAuthorizationHttpHeader.m in Sources */, BFF711E5265D500300DB696A /* PowerAuthSDK+WatchSupport.m in Sources */, @@ -2168,7 +2146,6 @@ BF585FD8215D3C4E00DE49C3 /* PowerAuthSDK+Private.m in Sources */, BF4017F22636CBCB00C1E65C /* PA2WeakArray.m in Sources */, BF8CF4842032EB41002A6B6E /* PowerAuthSystem.m in Sources */, - BF082560263164F100B34E24 /* PowerAuthActivationRecoveryData.m in Sources */, BF8CF4852032EB41002A6B6E /* PowerAuthSDK+WatchSupport.m in Sources */, BF1ED0B92844D3D200D6B380 /* PA2GroupedTask.m in Sources */, BFDA50382A9799BD0091A2E2 /* PowerAuthServerStatus.m in Sources */, @@ -2239,7 +2216,6 @@ BF08251B2630514D00B34E24 /* PowerAuthErrorConstants.m in Sources */, BF28AA1927EB1EDE00FBFCEB /* PA2SessionDataProvider.m in Sources */, BF4BED352AA08D2D00A8A2D0 /* PA2CompositeTask.m in Sources */, - BF1EC6D0223BD3BB00883236 /* PA2CreateActivationRecoveryData.m in Sources */, BF28AA1327EA0A1900FBFCEB /* PA2DefaultSessionInterface.m in Sources */, BF8CF4C62032EB41002A6B6E /* PowerAuthAuthorizationHttpHeader.m in Sources */, BF8CF4C92032EB41002A6B6E /* PowerAuthAuthentication.m in Sources */, diff --git a/proj-xcode/PowerAuth2/PowerAuthActivation.h b/proj-xcode/PowerAuth2/PowerAuthActivation.h index 2b402aa3..3ce902b9 100644 --- a/proj-xcode/PowerAuth2/PowerAuthActivation.h +++ b/proj-xcode/PowerAuth2/PowerAuthActivation.h @@ -48,18 +48,6 @@ + (nullable instancetype) activationWithIdentityAttributes:(nonnull NSDictionary*)identityAttributes error:(NSError * _Nullable * _Nullable)error; -/** - Creates an instance of `PowerAuthActivation` with a recovery activation code and PUK. - - @param recoveryCode Recovery code, obtained either via QR code scanning or by manual entry. - @param recoveryPuk PUK obtained by manual entry. - @param error Error reference in case some error occurs. - @return New instance of `PowerAuthActivation` or `nil` in case that recovery code, or recovery PUK is invalid. - */ -+ (nullable instancetype) activationWithRecoveryCode:(nonnull NSString*)recoveryCode - recoveryPuk:(nonnull NSString*)recoveryPuk - error:(NSError * _Nullable * _Nullable)error; - /** Creates an instance of `PowerAuthActivation` with OpenID connect credentials. @@ -78,23 +66,6 @@ #pragma mark - Obsolete methods (will be deprecated in future version) -/** - Creates an instance of `PowerAuthActivation` with a recovery activation code and PUK. - - The activation's `name` parameter is optional, but recommended to set. You can use the value obtained from - `UIDevice.current.name` or let the user set the name. The name of activation will be associated with - an activation record on PowerAuth Server. - - @param recoveryCode Recovery code, obtained either via QR code scanning or by manual entry. - @param recoveryPuk PUK obtained by manual entry. - @param name Activation name to be used for the activation. - @param error Error reference in case some error occurs. - @return New instance of `PowerAuthActivation` or `nil` in case that recovery code, or recovery PUK is invalid. - */ -+ (nullable instancetype) activationWithRecoveryCode:(nonnull NSString*)recoveryCode - recoveryPuk:(nonnull NSString*)recoveryPuk - name:(nullable NSString*)name - error:(NSError * _Nullable * _Nullable)error; /** Create an instance of `PowerAuthActivation` configured with the activation code. The activation code may contain an optional signature part, in case that it is scanned from QR code. diff --git a/proj-xcode/PowerAuth2/PowerAuthActivation.m b/proj-xcode/PowerAuth2/PowerAuthActivation.m index 8fd49158..ce4d993f 100644 --- a/proj-xcode/PowerAuth2/PowerAuthActivation.m +++ b/proj-xcode/PowerAuth2/PowerAuthActivation.m @@ -106,38 +106,6 @@ + (instancetype) activationWithIdentityAttributes:(NSDictionary - -/** - `PowerAuthActivationRecoveryData` object contains information about recovery code and PUK, created - during the activation process. - */ -@interface PowerAuthActivationRecoveryData : NSObject - -/** - Contains recovery code. - */ -@property (nonatomic, readonly, strong, nonnull) NSString * recoveryCode; - -/** - Contains PUK, valid with recovery code. - */ -@property (nonatomic, readonly, strong, nonnull) NSString * puk; - -@end diff --git a/proj-xcode/PowerAuth2/PowerAuthActivationRecoveryData.m b/proj-xcode/PowerAuth2/PowerAuthActivationRecoveryData.m deleted file mode 100644 index 2b791f63..00000000 --- a/proj-xcode/PowerAuth2/PowerAuthActivationRecoveryData.m +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2021 Wultra s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#import - -@import PowerAuthCore; - -@implementation PowerAuthActivationRecoveryData -{ - PowerAuthCoreRecoveryData * _recoveryData; -} - -- (instancetype) initWithRecoveryData:(PowerAuthCoreRecoveryData*)recoveryData -{ - self = [super init]; - if (self) { - _recoveryData = recoveryData; - } - return self; -} - -- (NSString*) recoveryCode -{ - return _recoveryData.recoveryCode; -} - -- (NSString*) puk -{ - return _recoveryData.puk; -} - -#ifdef DEBUG -- (NSString*) description -{ - NSString * rc = _recoveryData.recoveryCode ? _recoveryData.recoveryCode : @""; - NSString * puk = _recoveryData.puk ? _recoveryData.puk : @""; - return [NSString stringWithFormat:@"", rc, puk]; -} -#endif - -@end diff --git a/proj-xcode/PowerAuth2/PowerAuthActivationResult.h b/proj-xcode/PowerAuth2/PowerAuthActivationResult.h index 4cca0418..6beccf94 100644 --- a/proj-xcode/PowerAuth2/PowerAuthActivationResult.h +++ b/proj-xcode/PowerAuth2/PowerAuthActivationResult.h @@ -14,7 +14,6 @@ * limitations under the License. */ -#import #import /** @@ -26,12 +25,6 @@ Decimalized fingerprint calculated from device's public key. */ @property (nonatomic, strong, nonnull) NSString * activationFingerprint; -/** - If supported and enabled on the server, then the object contains "Recovery Code" and PUK, - created for this particular activation. Your application should display that values to the user - and forget the values immediately. You should NEVER store values from the object persistently on the device. - */ -@property (nonatomic, strong, nullable) PowerAuthActivationRecoveryData * activationRecovery; /** Custom attributes received from the server. The value may be nil in case that there are no custom attributes available. diff --git a/proj-xcode/PowerAuth2/PowerAuthActivationResult.m b/proj-xcode/PowerAuth2/PowerAuthActivationResult.m index 8c34557b..a0ce6568 100644 --- a/proj-xcode/PowerAuth2/PowerAuthActivationResult.m +++ b/proj-xcode/PowerAuth2/PowerAuthActivationResult.m @@ -22,9 +22,8 @@ @implementation PowerAuthActivationResult - (NSString*) description { NSString * fingerprint = _activationFingerprint ? _activationFingerprint : @""; - NSString * rc = _activationRecovery ? [@", recovery=" stringByAppendingString:[_activationRecovery description]] : @""; NSString * attrs = _customAttributes ? [@", attributes=" stringByAppendingString:[_customAttributes description]] : @""; - return [NSString stringWithFormat:@"", fingerprint, rc,attrs]; + return [NSString stringWithFormat:@"", fingerprint, attrs]; } #endif diff --git a/proj-xcode/PowerAuth2/PowerAuthSDK.h b/proj-xcode/PowerAuth2/PowerAuthSDK.h index 9e509c28..77979842 100644 --- a/proj-xcode/PowerAuth2/PowerAuthSDK.h +++ b/proj-xcode/PowerAuth2/PowerAuthSDK.h @@ -17,7 +17,6 @@ #import #import #import -#import #import #import #import @@ -191,23 +190,6 @@ extras:(nullable NSString*)extras callback:(nonnull void(^)(PowerAuthActivationResult * _Nullable result, NSError * _Nullable error))callback; -/** - Create a new recovery activation with given name, recovery code, puk and additional extras information. - - @param name Activation name, for example "John's iPhone". - @param recoveryCode Recovery code, obtained either via QR code scanning or by manual entry. - @param puk PUK obtained by manual entry. - @param extras Extra attributes of the activation, used for application specific purposes (for example, info about the client device or system). - @param callback A callback called when the process finishes - it contains an activation fingerprint in case of success and error in case of failure. - @return PowerAuthOperationTask associated with the running request. - @exception NSException thrown in case configuration is not present. - */ -- (nullable id) createActivationWithName:(nullable NSString*)name - recoveryCode:(nonnull NSString*)recoveryCode - puk:(nonnull NSString*)puk - extras:(nullable NSString*)extras - callback:(nonnull void(^)(PowerAuthActivationResult * _Nullable result, NSError * _Nullable error))callback; - /** Persist activation that was created and store related data using provided authentication instance. @@ -667,50 +649,6 @@ @end - -#pragma mark - Recovery code - -@interface PowerAuthSDK (RecoveryCode) - -/** - Returns YES if underlying session contains an activation recovery data. - */ -- (BOOL) hasActivationRecoveryData; - -/** - Get an activation recovery data. - - This method calls PowerAuth Standard RESTful API endpoint '/pa/vault/unlock' to obtain the vault encryption key used for private recovery data decryption. - - @param authentication Authentication used for vault unlocking call. - @param callback The callback method with an activation recovery information. - @return PowerAuthOperationTask associated with the running request. - */ -- (nullable id) activationRecoveryData:(nonnull PowerAuthAuthentication*)authentication - callback:(nonnull void(^)(PowerAuthActivationRecoveryData * _Nullable recoveryData, NSError * _Nullable error))callback; - -/** - Confirm given recovery code on the server. - - The method is useful for situations when user receives a recovery information via OOB channel (for example via postcard). Such - recovery codes cannot be used without a proper confirmation on the server. To confirm codes, user has to authenticate himself - with a knowledge factor. - - Note that the provided recovery code can contain a `"R:"` prefix, if it's scanned from QR code. - - @param recoveryCode Recovery code to confirm - @param authentication Authentication used for recovery code confirmation - @param callback The callback method with activation recovery information. - @return PowerAuthOperationTask associated with the running request. - */ -- (nullable id) confirmRecoveryCode:(nonnull NSString*)recoveryCode - authentication:(nonnull PowerAuthAuthentication*)authentication - callback:(nonnull void(^)(BOOL alreadyConfirmed, NSError * _Nullable error))callback; - -@end - - - #pragma mark - Activation data sharing @interface PowerAuthSDK (ActivationDataSharing) diff --git a/proj-xcode/PowerAuth2/PowerAuthSDK.m b/proj-xcode/PowerAuth2/PowerAuthSDK.m index 3b24f910..7e7ab7fa 100644 --- a/proj-xcode/PowerAuth2/PowerAuthSDK.m +++ b/proj-xcode/PowerAuth2/PowerAuthSDK.m @@ -702,22 +702,6 @@ - (void) cancelAllPendingTasks return [self createActivation:activation callback:callback]; } -- (nullable id) createActivationWithName:(nullable NSString*)name - recoveryCode:(nonnull NSString*)recoveryCode - puk:(nonnull NSString*)puk - extras:(nullable NSString*)extras - callback:(nonnull void(^)(PowerAuthActivationResult * result, NSError * error))callback -{ - NSError * error = nil; - PowerAuthActivation * activation = [[PowerAuthActivation activationWithRecoveryCode:recoveryCode recoveryPuk:puk name:name error:&error] withExtras:extras]; - if (!activation && callback) { - // Wrong recovery code or PUK - callback(nil, error ? error : PA2MakeError(PowerAuthErrorCode_InvalidActivationData, nil)); - return nil; - } - return [self createActivation:activation callback:callback]; -} - #pragma mark Commit - (BOOL) persistActivationWithPassword:(NSString*)password @@ -855,21 +839,12 @@ - (NSError*) prepareActivation:(PowerAuthActivation*)activation paramStep2.activationId = responseData.activationId; paramStep2.serverPublicKey = responseData.serverPublicKey; paramStep2.ctrData = responseData.ctrData; - PowerAuthActivationRecoveryData * activationRecoveryData = nil; - if (responseData.activationRecovery) { - PowerAuthCoreRecoveryData * recoveryData = [[PowerAuthCoreRecoveryData alloc] init]; - recoveryData.recoveryCode = responseData.activationRecovery.recoveryCode; - recoveryData.puk = responseData.activationRecovery.puk; - paramStep2.activationRecovery = recoveryData; - activationRecoveryData = [[PowerAuthActivationRecoveryData alloc] initWithRecoveryData:recoveryData]; - } PowerAuthCoreActivationStep2Result * resultStep2 = [session validateActivationResponse:paramStep2]; if (resultStep2) { // Everything looks OK, we can construct result object. PowerAuthActivationResult * result = [[PowerAuthActivationResult alloc] init]; result.activationFingerprint = resultStep2.activationFingerprint; result.customAttributes = response.customAttributes; - result.activationRecovery = activationRecoveryData; result.userInfo = [[PowerAuthUserInfo alloc] initWithDictionary:response.userInfo]; [self setLastFetchedUserInfo:result.userInfo]; return [PA2Result success:result]; @@ -1604,85 +1579,6 @@ - (BOOL) executeOperationOnSerialQueue:(nonnull NSOperation *)operation @end - - -#pragma mark - Recovery codes - -@implementation PowerAuthSDK (RecoveryCode) - -- (BOOL) hasActivationRecoveryData -{ - return [_sessionInterface readBoolTaskWithSession:^BOOL(PowerAuthCoreSession * session) { - return session.hasActivationRecoveryData; - }]; -} - -- (nullable id) activationRecoveryData:(nonnull PowerAuthAuthentication*)authentication - callback:(nonnull void(^)(PowerAuthActivationRecoveryData * _Nullable recoveryData, NSError * _Nullable error))callback -{ - if (![self hasActivationRecoveryData]) { - callback(nil, PA2MakeError(PowerAuthErrorCode_InvalidActivationState, @"Session has no recovery data available.")); - return nil; - } - return [self fetchEncryptedVaultUnlockKey:authentication reason:PA2VaultUnlockReason_RECOVERY_CODE callback:^(NSString *encryptedEncryptionKey, NSError *error) { - PowerAuthActivationRecoveryData * activationRecovery = nil; - if (!error) { - // Let's extract the data - PowerAuthCoreSignatureUnlockKeys *keys = [[PowerAuthCoreSignatureUnlockKeys alloc] init]; - keys.possessionUnlockKey = [self deviceRelatedKey]; - PowerAuthCoreRecoveryData * recoveryData = [_sessionInterface readTaskWithSession:^id _Nullable(PowerAuthCoreSession * _Nonnull session) { - return [session activationRecoveryData:encryptedEncryptionKey keys:keys]; - }]; - // Propagate error - if (recoveryData) { - activationRecovery = [[PowerAuthActivationRecoveryData alloc] initWithRecoveryData:recoveryData]; - } else { - error = PA2MakeError(PowerAuthErrorCode_Encryption, nil); - } - } - // Call back to application - callback(activationRecovery, error); - }]; -} - -- (nullable id) confirmRecoveryCode:(nonnull NSString*)recoveryCode - authentication:(nonnull PowerAuthAuthentication*)authentication - callback:(nonnull void(^)(BOOL alreadyConfirmed, NSError * _Nullable error))callback -{ - [self checkForValidSetup]; - - // Check if there is an activation present - if (![self hasValidActivation]) { - callback(NO, PA2MakeError(PowerAuthErrorCode_MissingActivation, nil)); - return nil; - } - - // Validate recovery code - PowerAuthActivationCode * otp = [PowerAuthActivationCodeUtil parseFromRecoveryCode:recoveryCode]; - if (!otp) { - callback(NO, PA2MakeError(PowerAuthErrorCode_WrongParameter, @"Invalid recovery code.")); - return nil; - } - - // Construct and post request - PA2ConfirmRecoveryCodeRequest * request = [[PA2ConfirmRecoveryCodeRequest alloc] init]; - request.recoveryCode = otp.activationCode; - return [_client postObject:request - to:[PA2RestApiEndpoint confirmRecoveryCode] - auth:authentication - completion:^(PowerAuthRestApiResponseStatus status, id response, NSError *error) { - BOOL alreadyConfirmed; - if (status == PowerAuthRestApiResponseStatus_OK) { - alreadyConfirmed = ((PA2ConfirmRecoveryCodeResponse*)response).alreadyConfirmed; - } else { - alreadyConfirmed = NO; - } - callback(alreadyConfirmed, error); - }]; -} - -@end - #pragma mark - Activation data sharing @implementation PowerAuthSDK (ActivationDataSharing) diff --git a/proj-xcode/PowerAuth2/private/PA2ConfirmRecoveryCodeRequest.h b/proj-xcode/PowerAuth2/private/PA2ConfirmRecoveryCodeRequest.h index 014738d8..fb6e6402 100644 --- a/proj-xcode/PowerAuth2/private/PA2ConfirmRecoveryCodeRequest.h +++ b/proj-xcode/PowerAuth2/private/PA2ConfirmRecoveryCodeRequest.h @@ -16,6 +16,7 @@ #import "PA2Codable.h" +// PA2_DEPRECATED(1.10.0) @interface PA2ConfirmRecoveryCodeRequest : NSObject @property (nonnull, nonatomic, strong) NSString * recoveryCode; diff --git a/proj-xcode/PowerAuth2/private/PA2ConfirmRecoveryCodeRequest.m b/proj-xcode/PowerAuth2/private/PA2ConfirmRecoveryCodeRequest.m index 77602547..5ab3306b 100644 --- a/proj-xcode/PowerAuth2/private/PA2ConfirmRecoveryCodeRequest.m +++ b/proj-xcode/PowerAuth2/private/PA2ConfirmRecoveryCodeRequest.m @@ -16,6 +16,7 @@ #import "PA2ConfirmRecoveryCodeRequest.h" +// PA2_DEPRECATED(1.10.0) @implementation PA2ConfirmRecoveryCodeRequest - (NSDictionary*) toDictionary diff --git a/proj-xcode/PowerAuth2/private/PA2ConfirmRecoveryCodeResponse.h b/proj-xcode/PowerAuth2/private/PA2ConfirmRecoveryCodeResponse.h index 386804c7..63a019f8 100644 --- a/proj-xcode/PowerAuth2/private/PA2ConfirmRecoveryCodeResponse.h +++ b/proj-xcode/PowerAuth2/private/PA2ConfirmRecoveryCodeResponse.h @@ -16,6 +16,7 @@ #import "PA2Codable.h" +// PA2_DEPRECATED(1.10.0) @interface PA2ConfirmRecoveryCodeResponse : NSObject @property (nonatomic, assign) BOOL alreadyConfirmed; diff --git a/proj-xcode/PowerAuth2/private/PA2ConfirmRecoveryCodeResponse.m b/proj-xcode/PowerAuth2/private/PA2ConfirmRecoveryCodeResponse.m index 9b7e724d..f93d0b45 100644 --- a/proj-xcode/PowerAuth2/private/PA2ConfirmRecoveryCodeResponse.m +++ b/proj-xcode/PowerAuth2/private/PA2ConfirmRecoveryCodeResponse.m @@ -18,6 +18,7 @@ #import "PA2ConfirmRecoveryCodeResponse.h" #import "PA2PrivateMacros.h" +// PA2_DEPRECATED(1.10.0) @implementation PA2ConfirmRecoveryCodeResponse - (instancetype) initWithDictionary:(NSDictionary *)dictionary diff --git a/proj-xcode/PowerAuth2/private/PA2CreateActivationRecoveryData.h b/proj-xcode/PowerAuth2/private/PA2CreateActivationRecoveryData.h deleted file mode 100644 index 2a0ff891..00000000 --- a/proj-xcode/PowerAuth2/private/PA2CreateActivationRecoveryData.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright 2021 Wultra s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#import "PA2Codable.h" - -@interface PA2CreateActivationRecoveryData : NSObject - -@property (nonatomic, strong) NSString * recoveryCode; -@property (nonatomic, strong) NSString * puk; - -@end diff --git a/proj-xcode/PowerAuth2/private/PA2CreateActivationRecoveryData.m b/proj-xcode/PowerAuth2/private/PA2CreateActivationRecoveryData.m deleted file mode 100644 index 9585010b..00000000 --- a/proj-xcode/PowerAuth2/private/PA2CreateActivationRecoveryData.m +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright 2021 Wultra s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#import "PA2CreateActivationRecoveryData.h" -#import "PA2PrivateMacros.h" - -@implementation PA2CreateActivationRecoveryData - -- (instancetype) initWithDictionary:(NSDictionary *)dictionary -{ - self = [super init]; - if (self) { - _recoveryCode = PA2ObjectAs(dictionary[@"recoveryCode"], NSString); - _puk = PA2ObjectAs(dictionary[@"puk"], NSString); - } - return self; -} - -@end diff --git a/proj-xcode/PowerAuth2/private/PA2CreateActivationResponseData.h b/proj-xcode/PowerAuth2/private/PA2CreateActivationResponseData.h index a4642037..9ff27fcd 100644 --- a/proj-xcode/PowerAuth2/private/PA2CreateActivationResponseData.h +++ b/proj-xcode/PowerAuth2/private/PA2CreateActivationResponseData.h @@ -24,6 +24,4 @@ @property (nonatomic, strong) NSString * serverPublicKey; @property (nonatomic, strong) NSString * ctrData; -@property (nonatomic, strong) PA2CreateActivationRecoveryData * activationRecovery; - @end diff --git a/proj-xcode/PowerAuth2/private/PA2CreateActivationResponseData.m b/proj-xcode/PowerAuth2/private/PA2CreateActivationResponseData.m index ea1bb902..e27be4ab 100644 --- a/proj-xcode/PowerAuth2/private/PA2CreateActivationResponseData.m +++ b/proj-xcode/PowerAuth2/private/PA2CreateActivationResponseData.m @@ -15,7 +15,6 @@ */ #import "PA2CreateActivationResponseData.h" -#import "PA2CreateActivationRecoveryData.h" #import "PA2PrivateMacros.h" @implementation PA2CreateActivationResponseData @@ -27,10 +26,6 @@ - (instancetype) initWithDictionary:(NSDictionary *)dicti _activationId = PA2ObjectAs(dictionary[@"activationId"], NSString); _serverPublicKey = PA2ObjectAs(dictionary[@"serverPublicKey"], NSString); _ctrData = PA2ObjectAs(dictionary[@"ctrData"], NSString); - NSDictionary * arDictionary = PA2ObjectAs(dictionary[@"activationRecovery"], NSDictionary); - if (arDictionary) { - _activationRecovery = [[PA2CreateActivationRecoveryData alloc] initWithDictionary:arDictionary]; - } } return self; } diff --git a/proj-xcode/PowerAuth2/private/PA2RestApiEndpoint.h b/proj-xcode/PowerAuth2/private/PA2RestApiEndpoint.h index bd8b96ca..781085d1 100644 --- a/proj-xcode/PowerAuth2/private/PA2RestApiEndpoint.h +++ b/proj-xcode/PowerAuth2/private/PA2RestApiEndpoint.h @@ -83,8 +83,6 @@ + (instancetype) getToken; + (instancetype) removeToken; -+ (instancetype) confirmRecoveryCode; - + (instancetype) getUserInfo; + (instancetype) getSystemStatus; diff --git a/proj-xcode/PowerAuth2/private/PA2RestApiEndpoint.m b/proj-xcode/PowerAuth2/private/PA2RestApiEndpoint.m index 4bf93b08..636b9e39 100644 --- a/proj-xcode/PowerAuth2/private/PA2RestApiEndpoint.m +++ b/proj-xcode/PowerAuth2/private/PA2RestApiEndpoint.m @@ -129,15 +129,6 @@ + (instancetype) vaultUnlock; authUriId:@"/pa/vault/unlock"]; } -+ (instancetype) confirmRecoveryCode -{ - return [[PA2RestApiEndpoint alloc] initWithPath:@"/pa/v3/recovery/confirm" - request:[PA2ConfirmRecoveryCodeRequest class] - response:[PA2ConfirmRecoveryCodeResponse class] - encryptor:PA2EncryptorId_ConfirmRecoveryCode - authUriId:@"/pa/recovery/confirm"]; -} - + (instancetype) getUserInfo { return [[PA2RestApiEndpoint alloc] initWithPath:@"/pa/v3/user/info" diff --git a/proj-xcode/PowerAuth2/private/PA2RestApiObjects.h b/proj-xcode/PowerAuth2/private/PA2RestApiObjects.h index bd6714a7..b773cc13 100644 --- a/proj-xcode/PowerAuth2/private/PA2RestApiObjects.h +++ b/proj-xcode/PowerAuth2/private/PA2RestApiObjects.h @@ -30,7 +30,6 @@ #import "PA2GetServerStatusResponse.h" #import "PA2CreateActivationResponse.h" #import "PA2CreateActivationResponseData.h" -#import "PA2CreateActivationRecoveryData.h" #import "PA2GetActivationStatusResponse.h" #import "PA2VaultUnlockResponse.h" #import "PA2GetTokenResponse.h" diff --git a/proj-xcode/PowerAuth2/private/PowerAuthSDK+Private.h b/proj-xcode/PowerAuth2/private/PowerAuthSDK+Private.h index 5beb8097..4159c7dd 100644 --- a/proj-xcode/PowerAuth2/private/PowerAuthSDK+Private.h +++ b/proj-xcode/PowerAuth2/private/PowerAuthSDK+Private.h @@ -74,11 +74,6 @@ #endif // defined(PA2_WATCH_SUPPORT) // ----------------------------------------------------------------------- -// Reveal private init in PowerAuthActivationRecoveryData object -@interface PowerAuthActivationRecoveryData (Private) -- (instancetype) initWithRecoveryData:(PowerAuthCoreRecoveryData*)recoveryData; -@end - // Reveal private readonly property that helps distinguish between "current" or "any set" biometric access. @interface PowerAuthKeychainConfiguration (BiometricAccess) @property (nonatomic, readonly) PowerAuthKeychainItemAccess biometricItemAccess; diff --git a/proj-xcode/PowerAuth2IntegrationTests/PowerAuthSDKDefaultTests.m b/proj-xcode/PowerAuth2IntegrationTests/PowerAuthSDKDefaultTests.m index aa4b0bbd..f0555390 100644 --- a/proj-xcode/PowerAuth2IntegrationTests/PowerAuthSDKDefaultTests.m +++ b/proj-xcode/PowerAuth2IntegrationTests/PowerAuthSDKDefaultTests.m @@ -715,115 +715,6 @@ - (void) testCounterSync_ServerIsAhead XCTAssertEqual(status.state, PowerAuthActivationState_Deadlock); } -- (void) testRecoveryCodes -{ - CHECK_TEST_CONFIG() - - // - // This test validates whether the recovery code received in activation can be confirmed. - // If server supports recovery codes, then such code can be confirmed, but it's already confirmed. - // Also we can create a new activation with using recovery code and PUK. That operation must remove - // original activation. - // - - BOOL result; - NSError * operationError = nil; - PowerAuthSdkActivation * activation = [_helper createActivation:YES]; - if (!activation) { - return; - } - PowerAuthAuthentication * auth = activation.credentials; - PATSInitActivationResponse * activationData = activation.activationData; - PowerAuthActivationResult * activationResult = activation.activationResult; - PowerAuthActivationRecoveryData * recoveryData = activationResult.activationRecovery; - - if (!recoveryData) { - NSLog(@"WARNING: Server doesn't support recovery codes."); - XCTAssertFalse([_sdk hasActivationRecoveryData]); - return; - } - - // 1. now try to confirm received recovery code - - XCTAssertTrue([_sdk hasActivationRecoveryData]); - - __block BOOL isAlreadyConfirmed = NO; - __block NSError * resultError = nil; - result = [[AsyncHelper synchronizeAsynchronousBlock:^(AsyncHelper *waiting) { - id task = [_sdk confirmRecoveryCode:recoveryData.recoveryCode authentication:auth callback:^(BOOL alreadyConfirmed, NSError * _Nullable error) { - isAlreadyConfirmed = alreadyConfirmed; - resultError = error; - [waiting reportCompletion:@(error == nil)]; - }]; - // Returned task should be valid - XCTAssertNotNil(task); - }] boolValue]; - - XCTAssertTrue(result); - XCTAssertTrue(isAlreadyConfirmed); - - // 2. Get recovery codes - - __block PowerAuthActivationRecoveryData * decryptedRecoveryData = nil; - result = [[AsyncHelper synchronizeAsynchronousBlock:^(AsyncHelper *waiting) { - id task = [_sdk activationRecoveryData:auth callback:^(PowerAuthActivationRecoveryData * _Nullable recoveryData, NSError * _Nullable error) { - decryptedRecoveryData = recoveryData; - resultError = error; - [waiting reportCompletion:@(error == nil)]; - }]; - XCTAssertNotNil(task); - }] boolValue]; - - XCTAssertTrue(result); - XCTAssertTrue([recoveryData.recoveryCode isEqualToString:decryptedRecoveryData.recoveryCode]); - XCTAssertTrue([recoveryData.puk isEqualToString:decryptedRecoveryData.puk]); - - // 3. Now remove a local activation. This simulates that user loose the device. - - [_sdk removeActivationLocal]; - - // 4. Try to create a new activation with recovery code and PUK. - - __block PowerAuthActivationResult * newActivation = nil; - __block NSError * newActivationError = nil; - - result = [[AsyncHelper synchronizeAsynchronousBlock:^(AsyncHelper *waiting) { - NSString * activationName = _helper.testServerConfig.userActivationName; - id task = [_sdk createActivationWithName:activationName recoveryCode:recoveryData.recoveryCode puk:recoveryData.puk extras:nil callback:^(PowerAuthActivationResult * _Nullable result, NSError * _Nullable error) { - newActivation = result; - newActivationError = error; - [waiting reportCompletion:@(error == nil)]; - }]; - // Returned task should be valid - XCTAssertNotNil(task); - }] boolValue]; - - XCTAssertTrue(result); - - // 5. At this point, old activation should be in "REMOVED" state - - PATSActivationStatus * serverOldActivationStatus = [_helper.testServerApi getActivationStatus:activationData.activationId challenge:nil]; - XCTAssertNotNil(serverOldActivationStatus); - XCTAssertTrue([serverOldActivationStatus.activationStatus isEqualToString:@"REMOVED"]); - - - // 6. Create a new authentication and persist it in the SDK. - - auth = [_helper createAuthentication]; - result = [_sdk persistActivationWithAuthentication:auth error:&operationError]; - XCTAssertTrue(result); - - // 7. Cleanup - remove activation on the server. - result = [[AsyncHelper synchronizeAsynchronousBlock:^(AsyncHelper *waiting) { - id task = [_sdk removeActivationWithAuthentication:auth callback:^(NSError * _Nullable error) { - [waiting reportCompletion:@(error == nil)]; - }]; - // Returned task should be valid - XCTAssertNotNil(task); - }] boolValue]; - - XCTAssertTrue(result); -} /* In negative scenarios we're testing situations, when some configurations are invalid. diff --git a/proj-xcode/PowerAuth2IntegrationTests/PowerAuthServer/PowerAuthTestServerAPI.h b/proj-xcode/PowerAuth2IntegrationTests/PowerAuthServer/PowerAuthTestServerAPI.h index 2cc67555..eb837726 100644 --- a/proj-xcode/PowerAuth2IntegrationTests/PowerAuthServer/PowerAuthTestServerAPI.h +++ b/proj-xcode/PowerAuth2IntegrationTests/PowerAuthServer/PowerAuthTestServerAPI.h @@ -150,13 +150,6 @@ */ - (BOOL) removeActivation:(NSString*)activationId; -/** - Removes an existing activation and revokes all associated recovery codes. - Returns YES if activation was successfully removed. Note that you can still check status - of removed activation. -*/ -- (BOOL) removeActivation:(NSString*)activationId revokeRecoveryCodes:(BOOL)revokeRecoveryCodes; - #pragma mark - SOAP Signatures /** diff --git a/proj-xcode/PowerAuth2IntegrationTests/PowerAuthServer/PowerAuthTestServerAPI.m b/proj-xcode/PowerAuth2IntegrationTests/PowerAuthServer/PowerAuthTestServerAPI.m index 2f2ca424..90ab845a 100644 --- a/proj-xcode/PowerAuth2IntegrationTests/PowerAuthServer/PowerAuthTestServerAPI.m +++ b/proj-xcode/PowerAuth2IntegrationTests/PowerAuthServer/PowerAuthTestServerAPI.m @@ -214,19 +214,15 @@ - (PATSInitActivationResponse*) initializeActivation:(NSString *)userId } - (BOOL) removeActivation:(NSString *)activationId -{ - return [self removeActivation:activationId revokeRecoveryCodes:NO]; -} - -- (BOOL) removeActivation:(NSString*)activationId revokeRecoveryCodes:(BOOL)revokeRecoveryCodes { [self checkForValidConnection]; - NSDictionary * response = [_rest request:@"ActivationRemove" params:@[activationId, @(revokeRecoveryCodes)]]; + NSDictionary * response = [_rest request:@"ActivationRemove" params:@[activationId, @YES]]; if (![response[@"removed"] boolValue]) { NSLog(@"The requested activation '%@' was not removed.", activationId); return NO; } return YES; + } static PATSActivationStatusEnum _String_to_ActivationStatusEnum(NSString * str) diff --git a/proj-xcode/PowerAuth2IntegrationTests/PowerAuthServer/PowerAuthTestServerConfig.h b/proj-xcode/PowerAuth2IntegrationTests/PowerAuthServer/PowerAuthTestServerConfig.h index 1e2d990e..90d76774 100644 --- a/proj-xcode/PowerAuth2IntegrationTests/PowerAuthServer/PowerAuthTestServerConfig.h +++ b/proj-xcode/PowerAuth2IntegrationTests/PowerAuthServer/PowerAuthTestServerConfig.h @@ -32,6 +32,7 @@ typedef NS_ENUM(int, PowerAuthTestServerVersion) { PATS_V1_7 = 10700, // V3.2 crypto + Activation OTP, applicationId as String, userInfo PATS_V1_8 = 10800, // V3.2 crypto + Activation OTP, applicationId as String, userInfo PATS_V1_9 = 10900, // V3.3 crypto + Activation OTP, applicationId as String, userInfo, temporary keys + PATS_V1_10 = 11000, // V3.3 crypto + Activation OTP, applicationId as String, userInfo, temporary keys }; /** diff --git a/proj-xcode/PowerAuth2IntegrationTests/PowerAuthServer/PowerAuthTestServerConfig.m b/proj-xcode/PowerAuth2IntegrationTests/PowerAuthServer/PowerAuthTestServerConfig.m index 87bcaa6c..0f1e224a 100644 --- a/proj-xcode/PowerAuth2IntegrationTests/PowerAuthServer/PowerAuthTestServerConfig.m +++ b/proj-xcode/PowerAuth2IntegrationTests/PowerAuthServer/PowerAuthTestServerConfig.m @@ -63,7 +63,8 @@ PowerAuthProtocolVersion PATSProtoVer(PowerAuthTestServerVersion serverVer) } static int s_KnownVersions[] = { - PATS_V1_0, PATS_V1_1, PATS_V1_2, PATS_V1_2_5, PATS_V1_3, PATS_V1_4, PATS_V1_5, PATS_V1_6, PATS_V1_7, PATS_V1_8, PATS_V1_9, + PATS_V1_0, PATS_V1_1, PATS_V1_2, PATS_V1_2_5, PATS_V1_3, PATS_V1_4, PATS_V1_5, PATS_V1_6, PATS_V1_7, PATS_V1_8, PATS_V1_9, PATS_V1_10 + , 0 }; diff --git a/proj-xcode/PowerAuth2IntegrationTests/PowerAuthServer/RestHelper.m b/proj-xcode/PowerAuth2IntegrationTests/PowerAuthServer/RestHelper.m index 2951ed23..a096cb10 100644 --- a/proj-xcode/PowerAuth2IntegrationTests/PowerAuthServer/RestHelper.m +++ b/proj-xcode/PowerAuth2IntegrationTests/PowerAuthServer/RestHelper.m @@ -183,7 +183,7 @@ - (NSDictionary*) loadEndpointMapping:(NSString*)serverVersion } __block NSString * mappingKey = nil; [versions enumerateKeysAndObjectsUsingBlock:^(NSString * key, NSString * value, BOOL * stop) { - if ([serverVersion isEqualToString:key] || [serverVersion hasPrefix:key] || [serverVersion hasPrefix:[key stringByAppendingString:@"."]]) { + if ([serverVersion isEqualToString:key] || [serverVersion hasPrefix:[key stringByAppendingString:@"."]]) { mappingKey = value; *stop = YES; } diff --git a/proj-xcode/PowerAuth2Tests/PowerAuthActivationTests.m b/proj-xcode/PowerAuth2Tests/PowerAuthActivationTests.m index 9d1d5cb5..03d116a5 100644 --- a/proj-xcode/PowerAuth2Tests/PowerAuthActivationTests.m +++ b/proj-xcode/PowerAuth2Tests/PowerAuthActivationTests.m @@ -76,54 +76,6 @@ - (void) testRegularActivationInvalid XCTAssertEqual(PowerAuthErrorCode_InvalidActivationCode, error.code); } - -#pragma mark - Recovery - -- (void) testRecoveryActivation -{ - id act1Identity = @{@"recoveryCode" : @"VVVVV-VVVVV-VVVVV-VTFVA" , @"puk" : @"0123456789"}; - NSError * error = nil; - PowerAuthActivation * act1 = [PowerAuthActivation activationWithRecoveryCode:@"VVVVV-VVVVV-VVVVV-VTFVA" recoveryPuk:@"0123456789" name:nil error:&error]; - XCTAssertNotNil(act1); - XCTAssertNil(error); - XCTAssertEqualObjects(@"RECOVERY", act1.activationType); - XCTAssertEqualObjects(act1Identity, act1.identityAttributes); - XCTAssertNil(act1.activationCode); - XCTAssertNil(act1.name); - XCTAssertNil(act1.extras); - XCTAssertNil(act1.customAttributes); - XCTAssertTrue([act1 validate]); - - id act2Identity = @{@"recoveryCode" : @"3PZ2Z-DOXSL-PSSQI-I5VBA" , @"puk" : @"0123456789"}; - PowerAuthActivation * act2 = [PowerAuthActivation activationWithRecoveryCode:@"R:3PZ2Z-DOXSL-PSSQI-I5VBA" recoveryPuk:@"0123456789" name:@"John Tramonta" error:nil]; - XCTAssertNotNil(act2); - XCTAssertNil(error); - XCTAssertEqualObjects(@"RECOVERY", act2.activationType); - XCTAssertEqualObjects(act2Identity, act2.identityAttributes); - XCTAssertNil(act2.activationCode); - XCTAssertEqualObjects(@"John Tramonta", act2.name); - XCTAssertTrue([act2 validate]); -} - -- (void) testRecoveryActivationInvalid -{ - NSError * error = nil; - PowerAuthActivation * act1 = [PowerAuthActivation activationWithRecoveryCode:@"12345" recoveryPuk:@"0123456789" name:nil error:&error]; - XCTAssertNil(act1); - XCTAssertTrue([PowerAuthErrorDomain isEqualToString:error.domain]); - XCTAssertEqual(PowerAuthErrorCode_InvalidActivationCode, error.code); - PowerAuthActivation * act2 = [PowerAuthActivation activationWithRecoveryCode:@"3PZ2Z-DOXSL-PSSQI-I5VBA" recoveryPuk:@"1234" name:nil error:&error]; - XCTAssertNil(act2); - XCTAssertTrue([PowerAuthErrorDomain isEqualToString:error.domain]); - XCTAssertEqual(PowerAuthErrorCode_InvalidActivationCode, error.code); - PowerAuthActivation * act3 = [[PowerAuthActivation activationWithRecoveryCode:@"VVVVV-VVVVV-VVVVV-VTFVA" recoveryPuk:@"0123456789" name:nil error:&error] withAdditionalActivationOtp:@"1234"]; - XCTAssertNotNil(act3); - error = [act3 validateAndGetError]; - XCTAssertNotNil(error); - XCTAssertTrue([PowerAuthErrorDomain isEqualToString:error.domain]); - XCTAssertEqual(PowerAuthErrorCode_InvalidActivationData, error.code); -} - #pragma mark - OIDC - (void) testOidcActivation @@ -224,25 +176,7 @@ - (void) testObjectCustomization XCTAssertEqualObjects(expectedExtras, act1.extras); XCTAssertEqualObjects(expectedCustomAttrs, act1.customAttributes); XCTAssertTrue([act1 validate]); - - // Recovery - id act2Identity = @{@"recoveryCode" : @"3PZ2Z-DOXSL-PSSQI-I5VBA" , @"puk" : @"0123456789"}; - PowerAuthActivation * act2 = [[[PowerAuthActivation activationWithRecoveryCode:@"R:3PZ2Z-DOXSL-PSSQI-I5VBA" - recoveryPuk:@"0123456789" - name:@"John Tramonta" - error:&error] - withExtras:@"FL:123"] - withCustomAttributes:@{@"isPrimary":@(NO)}]; - XCTAssertNotNil(act2); - XCTAssertNil(error); - XCTAssertEqualObjects(@"RECOVERY", act2.activationType); - XCTAssertEqualObjects(act2Identity, act2.identityAttributes); - XCTAssertNil(act2.activationCode); - XCTAssertEqualObjects(@"John Tramonta", act2.name); - XCTAssertEqualObjects(expectedExtras, act2.extras); - XCTAssertEqualObjects(expectedCustomAttrs, act2.customAttributes); - XCTAssertTrue([act2 validate]); - + // Custom id act3Identity = @{ @"username" : @"elvis", @"password" : @"lives" }; id act3IdentityExp = @{ @"username" : @"elvis", @"password" : @"lives" }; diff --git a/proj-xcode/PowerAuthCore.xcodeproj/project.pbxproj b/proj-xcode/PowerAuthCore.xcodeproj/project.pbxproj index da8def87..46b5c320 100644 --- a/proj-xcode/PowerAuthCore.xcodeproj/project.pbxproj +++ b/proj-xcode/PowerAuthCore.xcodeproj/project.pbxproj @@ -8,7 +8,6 @@ /* Begin PBXBuildFile section */ BF1B33F52334C062009BA222 /* pa2ActivationStatusBlobTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF1B33F42334C062009BA222 /* pa2ActivationStatusBlobTests.cpp */; }; - BF1EC6CA223A936A00883236 /* pa2RecoveryCodeTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF1EC6C9223A936A00883236 /* pa2RecoveryCodeTests.cpp */; }; BF2040C42A6FF0D700EEA36E /* PowerAuthCoreEciesEncryptorTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = BF2040C32A6FF0D700EEA36E /* PowerAuthCoreEciesEncryptorTest.mm */; }; BF2040C52A6FF0D700EEA36E /* PowerAuthCoreEciesEncryptorTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = BF2040C32A6FF0D700EEA36E /* PowerAuthCoreEciesEncryptorTest.mm */; }; BF28A1D82A6AC56600E50F76 /* PowerAuthCoreTimeService.h in Headers */ = {isa = PBXBuildFile; fileRef = BF28A1D62A6AC56600E50F76 /* PowerAuthCoreTimeService.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -48,7 +47,6 @@ BF6ADD7E24C84C0C001B3E5E /* DataReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF99D8E72073E00D00735ED2 /* DataReader.cpp */; }; BF6ADD7F24C84C0C001B3E5E /* ProtocolUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF99D8EE2073E00D00735ED2 /* ProtocolUtils.cpp */; }; BF6ADD8724C84C28001B3E5E /* libPowerAuthCoreLib-tvos.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BF6ADD8624C84C0C001B3E5E /* libPowerAuthCoreLib-tvos.a */; }; - BF6ADD9424C84FE0001B3E5E /* pa2RecoveryCodeTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF1EC6C9223A936A00883236 /* pa2RecoveryCodeTests.cpp */; }; BF6ADD9524C84FE0001B3E5E /* pa2CryptoAESTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF99D8C22073E00D00735ED2 /* pa2CryptoAESTests.cpp */; }; BF6ADD9624C84FE0001B3E5E /* g_pa2Files.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF99D8BB2073E00D00735ED2 /* g_pa2Files.cpp */; }; BF6ADD9724C84FE0001B3E5E /* pa2CryptoECDHKDFTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF99D8C82073E00D00735ED2 /* pa2CryptoECDHKDFTests.cpp */; }; @@ -366,7 +364,6 @@ BF1B33F02334C042009BA222 /* signatures-v31.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "signatures-v31.json"; sourceTree = ""; }; BF1B33F32334C042009BA222 /* activation-status-blob-iv.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "activation-status-blob-iv.json"; sourceTree = ""; }; BF1B33F42334C062009BA222 /* pa2ActivationStatusBlobTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pa2ActivationStatusBlobTests.cpp; sourceTree = ""; }; - BF1EC6C9223A936A00883236 /* pa2RecoveryCodeTests.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = pa2RecoveryCodeTests.cpp; sourceTree = ""; }; BF2040C32A6FF0D700EEA36E /* PowerAuthCoreEciesEncryptorTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PowerAuthCoreEciesEncryptorTest.mm; sourceTree = ""; }; BF28A1D62A6AC56600E50F76 /* PowerAuthCoreTimeService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PowerAuthCoreTimeService.h; sourceTree = ""; }; BF28AA3A27EDE7DF00FBFCEB /* PowerAuthCoreDebugMonitor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PowerAuthCoreDebugMonitor.h; sourceTree = ""; }; @@ -639,7 +636,6 @@ children = ( BF1B33F42334C062009BA222 /* pa2ActivationStatusBlobTests.cpp */, BF99D8CC2073E00D00735ED2 /* pa2ProtocolUtilsTests.cpp */, - BF1EC6C9223A936A00883236 /* pa2RecoveryCodeTests.cpp */, BF99D8CB2073E00D00735ED2 /* pa2URLEncodingTests.cpp */, BF99D8C52073E00D00735ED2 /* pa2SignatureKeysDerivationTest.cpp */, BF99D8C12073E00D00735ED2 /* pa2MasterSecretKeyComputation.cpp */, @@ -1358,7 +1354,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - BF6ADD9424C84FE0001B3E5E /* pa2RecoveryCodeTests.cpp in Sources */, BFEEEBEC2A3B067B007C6737 /* pa2ByteUtilsTests.cpp in Sources */, BF6ADD9524C84FE0001B3E5E /* pa2CryptoAESTests.cpp in Sources */, BF6ADD9624C84FE0001B3E5E /* g_pa2Files.cpp in Sources */, @@ -1417,7 +1412,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - BF1EC6CA223A936A00883236 /* pa2RecoveryCodeTests.cpp in Sources */, BFEEEBEB2A3B067B007C6737 /* pa2ByteUtilsTests.cpp in Sources */, BFC92DF02073E3860087851C /* pa2CryptoAESTests.cpp in Sources */, BF99D91E2073E28900735ED2 /* g_pa2Files.cpp in Sources */, diff --git a/proj-xcode/PowerAuthCore/PowerAuthCoreOtpUtil.h b/proj-xcode/PowerAuthCore/PowerAuthCoreOtpUtil.h index c9d323ad..bff34553 100644 --- a/proj-xcode/PowerAuthCore/PowerAuthCoreOtpUtil.h +++ b/proj-xcode/PowerAuthCore/PowerAuthCoreOtpUtil.h @@ -89,20 +89,6 @@ */ + (BOOL) validateActivationCode:(nonnull NSString*)activationCode; -/** - Returns YES if |recoveryCode| is a valid recovery code. You can use this method to validate - a whole user-typed recovery code at once. The input code may contain "R:" prefix, if code is - scanned from QR code. - */ -+ (BOOL) validateRecoveryCode:(nonnull NSString*)recoveryCode; - -/** - Returns true if |recoveryPuk| appears to be valid. You can use this method to validate - a whole user-typed recovery PUK at once. In current version, only 10 digits long string is considered - as a valid PUK. - */ -+ (BOOL) validateRecoveryPuk:(nonnull NSString*)recoveryPuk; - #pragma mark - Parser /** @@ -113,12 +99,4 @@ */ + (nullable PowerAuthCoreOtp*) parseFromActivationCode:(nonnull NSString*)activationCode; -/** - Parses an input |recoveryCode| (which may or may not contain an optional "R:" prefix) and returns PowerAuthCoreOtp - object filled with valid data. The method doesn't perform an auto-correction, so the provided code must be valid. - - Returns PowerAuthCoreOtp object if code is valid, or nil. - */ -+ (nullable PowerAuthCoreOtp*) parseFromRecoveryCode:(nonnull NSString*)recoveryCode; - @end diff --git a/proj-xcode/PowerAuthCore/PowerAuthCoreOtpUtil.mm b/proj-xcode/PowerAuthCore/PowerAuthCoreOtpUtil.mm index 26ebbfd8..a67b3b69 100644 --- a/proj-xcode/PowerAuthCore/PowerAuthCoreOtpUtil.mm +++ b/proj-xcode/PowerAuthCore/PowerAuthCoreOtpUtil.mm @@ -66,16 +66,6 @@ + (BOOL) validateActivationCode:(NSString*)activationCode return OtpUtil::validateActivationCode(cc7::objc::CopyFromNSString(activationCode)); } -+ (BOOL) validateRecoveryCode:(nonnull NSString*)recoveryCode -{ - return OtpUtil::validateRecoveryCode(cc7::objc::CopyFromNSString(recoveryCode)); -} - -+ (BOOL) validateRecoveryPuk:(nonnull NSString*)recoveryPuk -{ - return OtpUtil::validateRecoveryPuk(cc7::objc::CopyFromNSString(recoveryPuk)); -} - + (PowerAuthCoreOtp*) parseFromActivationCode:(NSString*)activationCode { auto cppActivationCode = cc7::objc::CopyFromNSString(activationCode); @@ -86,14 +76,4 @@ + (PowerAuthCoreOtp*) parseFromActivationCode:(NSString*)activationCode return nil; } -+ (PowerAuthCoreOtp*) parseFromRecoveryCode:(NSString *)recoveryCode -{ - auto cppRecoveryCode = cc7::objc::CopyFromNSString(recoveryCode); - OtpComponents cppComponents; - if (OtpUtil::parseRecoveryCode(cppRecoveryCode, cppComponents)) { - return [[PowerAuthCoreOtp alloc] initWithOtpComponents:cppComponents]; - } - return nil; -} - @end diff --git a/proj-xcode/PowerAuthCore/PowerAuthCorePrivateImpl.h b/proj-xcode/PowerAuthCore/PowerAuthCorePrivateImpl.h index 8b0e5785..c2287b0a 100644 --- a/proj-xcode/PowerAuthCore/PowerAuthCorePrivateImpl.h +++ b/proj-xcode/PowerAuthCore/PowerAuthCorePrivateImpl.h @@ -101,15 +101,6 @@ CC7_EXTERN_C void PowerAuthCoreActivationStep2ParamToStruct(PowerAuthCoreActivat */ CC7_EXTERN_C PowerAuthCoreActivationStep2Result * PowerAuthCoreActivationStep2ResultToObject(const io::getlime::powerAuth::ActivationStep2Result& cpp_r2); -/** - Converts PowerAuthCoreRecoveryData object into RecoveryData C++ structure - */ -CC7_EXTERN_C void PowerAuthCoreRecoveryDataToStruct(PowerAuthCoreRecoveryData * rd, io::getlime::powerAuth::RecoveryData& cpp_rd); -/** - Returns new instance of PowerAuthCoreRecoveryData object, with content copied from RecoveryData C++ structure - */ -CC7_EXTERN_C PowerAuthCoreRecoveryData * PowerAuthCoreRecoveryDataToObject(const io::getlime::powerAuth::RecoveryData& cpp_rd); - #pragma mark - Debug functions #if defined(DEBUG) diff --git a/proj-xcode/PowerAuthCore/PowerAuthCoreSession.h b/proj-xcode/PowerAuthCore/PowerAuthCoreSession.h index 00a9d102..eb47c066 100644 --- a/proj-xcode/PowerAuthCore/PowerAuthCoreSession.h +++ b/proj-xcode/PowerAuthCore/PowerAuthCoreSession.h @@ -654,21 +654,4 @@ */ + (nonnull NSString*) maxSupportedHttpProtocolVersion:(PowerAuthCoreProtocolVersion)protocolVersion; - -#pragma mark - Recovery codes - -/** - Returns YES, if session contains an activation recovery data. - */ -@property (nonatomic, assign, readonly) BOOL hasActivationRecoveryData; - -/** - Returns an activation recovery data. You have to provide encrypted vault key |c_vault_key| and - |keys| structure where the valid possessionUnlockKey is set. - - This function access the session's state, so read access must be guaranteed. - */ -- (nullable PowerAuthCoreRecoveryData*) activationRecoveryData:(nonnull NSString*)cVaultKey - keys:(nonnull PowerAuthCoreSignatureUnlockKeys*)unlockKeys; - @end diff --git a/proj-xcode/PowerAuthCore/PowerAuthCoreSession.mm b/proj-xcode/PowerAuthCore/PowerAuthCoreSession.mm index a83097c2..ff8a0738 100644 --- a/proj-xcode/PowerAuthCore/PowerAuthCoreSession.mm +++ b/proj-xcode/PowerAuthCore/PowerAuthCoreSession.mm @@ -550,28 +550,4 @@ + (NSString*) maxSupportedHttpProtocolVersion:(PowerAuthCoreProtocolVersion)prot return cc7::objc::CopyToNSString(Version_GetMaxSupportedHttpProtocolVersion(static_cast(protocolVersion))); } -#pragma mark - Recovery codes - -- (BOOL) hasActivationRecoveryData -{ - REQUIRE_READ_ACCESS(); - return _session->hasActivationRecoveryData(); -} - -- (PowerAuthCoreRecoveryData*) activationRecoveryData:(NSString *)cVaultKey keys:(PowerAuthCoreSignatureUnlockKeys *)unlockKeys -{ - REQUIRE_READ_ACCESS(); - std::string cpp_c_vault_key = cc7::objc::CopyFromNSString(cVaultKey); - SignatureUnlockKeys cpp_keys; - PowerAuthCoreSignatureUnlockKeysToStruct(unlockKeys, cpp_keys); - - RecoveryData cpp_recovery_data; - ErrorCode error = _session->getActivationRecoveryData(cpp_c_vault_key, cpp_keys, cpp_recovery_data); - if (error != EC_Ok) { - REPORT_ERROR_CODE(@"ActivationRecoveryData", error); - return nil; - } - return PowerAuthCoreRecoveryDataToObject(cpp_recovery_data); -} - @end diff --git a/proj-xcode/PowerAuthCore/PowerAuthCoreTypes.h b/proj-xcode/PowerAuthCore/PowerAuthCoreTypes.h index 943a526e..042b4a5e 100644 --- a/proj-xcode/PowerAuthCore/PowerAuthCoreTypes.h +++ b/proj-xcode/PowerAuthCore/PowerAuthCoreTypes.h @@ -379,25 +379,6 @@ typedef NS_ENUM(int, PowerAuthCoreSignatureFormat) { @end -#pragma mark - Recovery codes - - -/** - RecoveryData object contains information about recovery code and PUK, created - during the activation process. - */ -@interface PowerAuthCoreRecoveryData : NSObject -/** - Contains recovery code. - */ -@property (nonatomic, strong, nonnull) NSString * recoveryCode; -/** - Contains PUK, valid with recovery code. - */ -@property (nonatomic, strong, nonnull) NSString * puk; - -@end - - #pragma mark - Activation steps - /** @@ -446,10 +427,6 @@ typedef NS_ENUM(int, PowerAuthCoreSignatureFormat) { Initial value for hash-based counter. */ @property (nonatomic, strong, nonnull) NSString * ctrData; -/** - If configured on the server, contains recovery data received from the server. - */ -@property (nonatomic, strong, nullable) PowerAuthCoreRecoveryData * activationRecovery; @end diff --git a/proj-xcode/PowerAuthCore/PowerAuthCoreTypes.mm b/proj-xcode/PowerAuthCore/PowerAuthCoreTypes.mm index e613cc1f..250afb5d 100644 --- a/proj-xcode/PowerAuthCore/PowerAuthCoreTypes.mm +++ b/proj-xcode/PowerAuthCore/PowerAuthCoreTypes.mm @@ -224,9 +224,6 @@ - (NSString*) description @implementation PowerAuthCoreSignatureUnlockKeys @end -@implementation PowerAuthCoreRecoveryData -@end - @implementation PowerAuthCoreActivationStep1Param @end @@ -383,7 +380,6 @@ void PowerAuthCoreActivationStep2ParamToStruct(PowerAuthCoreActivationStep2Param cpp_p2.activationId = cc7::objc::CopyFromNSString(p2.activationId); cpp_p2.serverPublicKey = cc7::objc::CopyFromNSString(p2.serverPublicKey); cpp_p2.ctrData = cc7::objc::CopyFromNSString(p2.ctrData); - PowerAuthCoreRecoveryDataToStruct(p2.activationRecovery, cpp_p2.activationRecovery); } PowerAuthCoreActivationStep2Result * PowerAuthCoreActivationStep2ResultToObject(const io::getlime::powerAuth::ActivationStep2Result& cpp_r2) @@ -392,21 +388,3 @@ void PowerAuthCoreActivationStep2ParamToStruct(PowerAuthCoreActivationStep2Param res.activationFingerprint = cc7::objc::CopyToNSString(cpp_r2.activationFingerprint); return res; } - -void PowerAuthCoreRecoveryDataToStruct(PowerAuthCoreRecoveryData * rd, io::getlime::powerAuth::RecoveryData& cpp_rd) -{ - cpp_rd.recoveryCode = cc7::objc::CopyFromNSString(rd.recoveryCode); - cpp_rd.puk = cc7::objc::CopyFromNSString(rd.puk); -} - -PowerAuthCoreRecoveryData * PowerAuthCoreRecoveryDataToObject(const io::getlime::powerAuth::RecoveryData& cpp_rd) -{ - if (cpp_rd.isEmpty()) { - CC7_ASSERT(false, "Empty structure should be handled before the conversion."); - return nil; - } - PowerAuthCoreRecoveryData * res = [[PowerAuthCoreRecoveryData alloc] init]; - res.recoveryCode = cc7::objc::CopyToNSString(cpp_rd.recoveryCode); - res.puk = cc7::objc::CopyToNSString(cpp_rd.puk); - return res; -} From e80bd7b3fa187193f4e50ef0d978468a0b4e8c19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juraj=20=C4=8Eurech?= Date: Thu, 16 Jan 2025 14:51:06 +0100 Subject: [PATCH 03/10] Android: Remove recovery codes support --- docs/PowerAuth-SDK-for-Android.md | 268 +----------------- .../support/PowerAuthServerApi.java | 22 +- .../support/model/RecoveryConfig.java | 78 ----- .../support/model/ServerVersion.java | 4 +- .../v10/PowerAuthClientV3_ServerV10.java | 23 +- .../endpoints/GetRecoveryConfigEndpoint.java | 60 ---- .../UpdateRecoveryConfigEndpoint.java | 72 ----- .../v13/PowerAuthClientV3_ServerV13.java | 26 +- .../endpoints/GetRecoveryConfigEndpoint.java | 59 ---- .../UpdateRecoveryConfigEndpoint.java | 71 ----- .../v15/PowerAuthClientV3_ServerV15.java | 25 +- .../endpoints/GetRecoveryConfigEndpoint.java | 59 ---- .../endpoints/RemoveActivationEndpoint.java | 9 - .../UpdateRecoveryConfigEndpoint.java | 71 ----- .../v19/PowerAuthClientV3_ServerV19.java | 26 +- .../endpoints/GetRecoveryConfigEndpoint.java | 59 ---- .../UpdateRecoveryConfigEndpoint.java | 71 ----- .../integration/tests/ActivationHelper.java | 9 +- .../tests/RecoveryActivationTest.java | 156 ---------- .../sdk/PowerAuthActivationBuilderTest.java | 85 ------ .../powerauth/core/ActivationCodeUtil.java | 40 +-- .../powerauth/core/ActivationStep1Result.java | 4 +- .../powerauth/core/ActivationStep2Param.java | 10 +- .../security/powerauth/core/RecoveryData.java | 53 ---- .../security/powerauth/core/Session.java | 20 -- .../powerauth/ecies/EciesEncryptorId.java | 6 - .../exception/PowerAuthErrorCodes.java | 2 +- .../ConfirmRecoveryCodeEndpoint.java | 52 ---- .../exceptions/ErrorResponseApiException.java | 20 -- .../model/entity/ActivationRecovery.java | 59 ---- .../model/entity/ActivationType.java | 3 +- .../ConfirmRecoveryRequestPayload.java | 43 --- .../response/ActivationLayer2Response.java | 20 -- .../ConfirmRecoveryResponsePayload.java | 43 --- .../response/CreateActivationResult.java | 28 -- .../IConfirmRecoveryCodeListener.java | 41 --- .../response/IGetRecoveryDataListener.java | 44 --- .../powerauth/sdk/PowerAuthActivation.java | 39 --- .../security/powerauth/sdk/PowerAuthSDK.java | 154 +--------- .../powerauth/sdk/impl/VaultUnlockReason.java | 6 +- 40 files changed, 30 insertions(+), 1910 deletions(-) delete mode 100644 proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/model/RecoveryConfig.java delete mode 100644 proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v10/endpoints/GetRecoveryConfigEndpoint.java delete mode 100644 proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v10/endpoints/UpdateRecoveryConfigEndpoint.java delete mode 100644 proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v13/endpoints/GetRecoveryConfigEndpoint.java delete mode 100644 proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v13/endpoints/UpdateRecoveryConfigEndpoint.java delete mode 100644 proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v15/endpoints/GetRecoveryConfigEndpoint.java delete mode 100644 proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v15/endpoints/UpdateRecoveryConfigEndpoint.java delete mode 100644 proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v19/endpoints/GetRecoveryConfigEndpoint.java delete mode 100644 proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v19/endpoints/UpdateRecoveryConfigEndpoint.java delete mode 100644 proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/tests/RecoveryActivationTest.java delete mode 100644 proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/RecoveryData.java delete mode 100644 proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/endpoints/ConfirmRecoveryCodeEndpoint.java delete mode 100644 proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/model/entity/ActivationRecovery.java delete mode 100644 proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/model/request/ConfirmRecoveryRequestPayload.java delete mode 100644 proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/model/response/ConfirmRecoveryResponsePayload.java delete mode 100644 proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/response/IConfirmRecoveryCodeListener.java delete mode 100644 proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/response/IGetRecoveryDataListener.java diff --git a/docs/PowerAuth-SDK-for-Android.md b/docs/PowerAuth-SDK-for-Android.md index a46c2d1e..a8b317ce 100644 --- a/docs/PowerAuth-SDK-for-Android.md +++ b/docs/PowerAuth-SDK-for-Android.md @@ -9,7 +9,6 @@ - [Activation via Activation Code](#activation-via-activation-code) - [Activation via OpenID Connect](#activation-via-openid-connect) - [Activation via Custom Credentials](#activation-via-custom-credentials) - - [Activation via Recovery Code](#activation-via-recovery-code) - [Customize Activation](#customize-activation) - [Persisting Activation Data](#persisting-activation-data) - [Validating User Inputs](#validating-user-inputs) @@ -26,9 +25,6 @@ - [Device Activation Removal](#activation-removal) - [End-To-End Encryption](#end-to-end-encryption) - [Secure Vault](#secure-vault) -- [Recovery Codes](#recovery-codes) - - [Getting Recovery Data](#getting-recovery-data) - - [Confirm Recovery Postcard](#confirm-recovery-postcard) - [Token-Based Authentication](#token-based-authentication) - [External Encryption Key](#external-encryption-key) - [Synchronized Time](#synchronized-time) @@ -289,10 +285,8 @@ try { powerAuthSDK.createActivation(activation, object: ICreateActivationListener { override fun onActivationCreateSucceed(result: CreateActivationResult) { val fingerprint = result.activationFingerprint - val activationRecovery = result.recoveryData // No error occurred, proceed to credentials entry (PIN prompt, Enable "Fingerprint Authentication" switch, ...) and persist // The 'fingerprint' value represents the combination of device and server public keys - it may be used as visual confirmation - // If the server supports recovery codes for activation, then `activationRecovery` contains object with information about activation recovery. } override fun onActivationCreateFailed(t: Throwable) { @@ -317,10 +311,8 @@ powerAuthSDK.createActivation(activation, new ICreateActivationListener() { @Override public void onActivationCreateSucceed(CreateActivationResult result) { final String fingerprint = result.getActivationFingerprint(); - final RecoveryData activationRecovery = result.getRecoveryData(); // No error occurred, proceed to credentials entry (PIN prompt, Enable "Fingerprint Authentication" switch, ...) and persist // The 'fingerprint' value represents the combination of device and server public keys - it may be used as visual confirmation - // If the server supports recovery codes for activation, then `activationRecovery` contains object with information about activation recovery. } @Override @@ -331,8 +323,6 @@ powerAuthSDK.createActivation(activation, new ICreateActivationListener() { ``` -If the received activation result also contains recovery data, then you should display those values to the user. To do that, please read the [Getting Recovery Data](#getting-recovery-data) section of this document, which describes how to treat that sensitive information. This is relevant for all types of activation you use. - #### Additional Activation OTP If an [additional activation OTP](https://github.com/wultra/powerauth-crypto/blob/develop/docs/Additional-Activation-OTP.md) is required to complete the activation, then use the following code to configure the `PowerAuthActivation` object: @@ -403,10 +393,8 @@ try { powerAuthSDK.createActivation(activation, object: ICreateActivationListener { override fun onActivationCreateSucceed(result: CreateActivationResult) { val fingerprint = result.activationFingerprint - val activationRecovery = result.recoveryData // No error occurred, proceed to credentials entry (PIN prompt, Enable "Biometric Authentication" switch, ...) and persist // The 'fingerprint' value represents the combination of device and server public keys - it may be used as visual confirmation - // If the server supports recovery codes for activation, then `activationRecovery` contains object with information about activation recovery. } override fun onActivationCreateFailed(t: Throwable) { @@ -439,10 +427,8 @@ try { powerAuthSDK.createActivation(activation, object: ICreateActivationListener { override fun onActivationCreateSucceed(result: CreateActivationResult) { val fingerprint = result.activationFingerprint - val activationRecovery = result.recoveryData // No error occurred, proceed to credentials entry (PIN prompt, Enable "Biometric Authentication" switch, ...) and persist // The 'fingerprint' value represents the combination of device and server public keys - it may be used as visual confirmation - // If the server supports recovery codes for activation, then `activationRecovery` contains object with information about activation recovery. } override fun onActivationCreateFailed(t: Throwable) { @@ -470,10 +456,8 @@ powerAuthSDK.createActivation(activation, new ICreateActivationListener() { @Override public void onActivationCreateSucceed(CreateActivationResult result) { final String fingerprint = result.getActivationFingerprint(); - final RecoveryData activationRecovery = result.getRecoveryData(); // No error occurred, proceed to credentials entry (PIN prompt, Enable "Biometric Authentication" switch, ...) and persist // The 'fingerprint' value represents the combination of device and server public keys - it may be used as visual confirmation - // If the server supports recovery codes for activation, then `activationRecovery` contains object with information about activation recovery. } @Override @@ -486,93 +470,6 @@ powerAuthSDK.createActivation(activation, new ICreateActivationListener() { Note that by using weak identity attributes to create an activation, the resulting activation confirms a "blurry identity". This may greatly limit the legal weight and usability of a signature. We recommend using a strong identity verification before activation can actually be created. - -### Activation via Recovery Code - -If the PowerAuth Server is configured to support [Recovery Codes](https://github.com/wultra/powerauth-crypto/blob/develop/docs/Activation-Recovery.md), then also you can create an activation via the recovery code and PUK. - -Use the following code to create an activation using the recovery code: - - -```kotlin -val deviceName = "John Tramonta" -val recoveryCode = "55555-55555-55555-55YMA" // User's input -val puk = "0123456789" // User's input. You should validate RC & PUK with using ActivationCodeUtil - -// Create an activation object with the given recovery code and PUK. -val activation: PowerAuthActivation -try { - activation = PowerAuthActivation.Builder.recoveryActivation(recoveryCode, puk, deviceName).build(); -} catch (e: PowerAuthErrorException) { - // Invalid recovery code or PUK -} - -// Create a new activation with the given activation object -powerAuthSDK.createActivation(activation, object: ICreateActivationListener { - override fun onActivationCreateSucceed(result: CreateActivationResult) { - val fingerprint = result.activationFingerprint - val activationRecovery = result.recoveryData - // No error occurred, proceed to credentials entry (PIN prompt, Enable "Biometric Authentication" switch, ...) and persist - // The 'fingerprint' value represents the combination of device and server public keys - it may be used as visual confirmation - // If the server supports recovery codes for activation, then `activationRecovery` contains object with information about activation recovery. - } - - override fun onActivationCreateFailed(t: Throwable) { - // Error occurred, report it to the user - // On top of regular error processing, you should handle a special situation, when the server gives additional information - // about which PUK must be used for the recovery. The information is valid only when recovery code from a postcard is applied. - if (t is ErrorResponseApiException) { - val errorResponse = t.errorResponse - val currentRecoveryPukIndex = t.currentRecoveryPukIndex - if (currentRecoveryPukIndex > 0) { - // The PUK index is known, you should inform the user that it has to rewrite PUK from a specific position. - } - } - } -}) -``` -```java -final String deviceName = "John Tramonta" -final String recoveryCode = "55555-55555-55555-55YMA" // User's input -final String puk = "0123456789" // User's input. You should validate RC & PUK with using ActivationCodeUtil - -// Create an activation object with the given recovery code and PUK. -final PowerAuthActivation activation; -try { - activation = PowerAuthActivation.Builder.recoveryActivation(recoveryCode, puk, deviceName).build(); -} catch (PowerAuthErrorException e) { - // Invalid recovery code or PUK -} - -// Create a new activation with the given activation object -powerAuthSDK.createActivation(activation, new ICreateActivationListener() { - @Override - public void onActivationCreateSucceed(CreateActivationResult result) { - final String fingerprint = result.getActivationFingerprint(); - final RecoveryData activationRecovery = result.getRecoveryData(); - // No error occurred, proceed to credentials entry (PIN prompt, Enable "Biometric Authentication" switch, ...) and persist - // The 'fingerprint' value represents the combination of device and server public keys - it may be used as visual confirmation - // If the server supports recovery codes for activation, then `activationRecovery` contains object with information about activation recovery. - } - - @Override - public void onActivationCreateFailed(Throwable t) { - // Error occurred, report it to the user - // On top of regular error processing, you should handle a special situation, when the server gives an additional information - // about which PUK must be used for the recovery. The information is valid only when a recovery code from a postcard is applied. - if (t instanceof ErrorResponseApiException) { - ErrorResponseApiException exception = (ErrorResponseApiException) t; - Error errorResponse = exception.getErrorResponse(); - int currentRecoveryPukIndex = exception.getCurrentRecoveryPukIndex(); - if (currentRecoveryPukIndex > 0) { - // The PUK index is known, you should inform the user that it has to rewrite PUK from a specific position. - } - } - } -}); -``` - - ### Customize Activation You can set additional properties to `PowerAuthActivation` object before any type of activation is created. For example: @@ -727,7 +624,6 @@ The mobile SDK provides a couple of functions in `ActivationCodeUtil` class, hel - Parse activation code when it's scanned from QR code - Validate a whole code at once -- Validate recovery code or PUK - Auto-correct characters typed on the fly #### Validating Scanned QR Code @@ -799,35 +695,9 @@ boolean isInvalid = ActivationCodeUtil.validateActivationCode("VVVVV-VVVVV-VVVVV If your application is using your own validation, then you should switch to functions provided by SDK. The reason for that is that since SDK `1.0.0`, all activation codes contain a checksum, so it's possible to detect mistyped characters before you start the activation. Check our [Activation Code](https://github.com/wultra/powerauth-crypto/blob/develop/docs/Activation-Code.md) documentation for more details. -#### Validating Recovery Code and PUK - -To validate a recovery code at once, you can call `ActivationCodeUtil.validateRecoveryCode()` function. You can provide the whole code, which may or may not contain `"R:"` prefix. So, you can validate manually entered codes, but also codes scanned from QR. For example: - - -```kotlin -val isValid1 = ActivationCodeUtil.validateRecoveryCode("VVVVV-VVVVV-VVVVV-VTFVA") -val isValid2 = ActivationCodeUtil.validateRecoveryCode("R:VVVVV-VVVVV-VVVVV-VTFVA") -``` -```java -boolean isValid1 = ActivationCodeUtil.validateRecoveryCode("VVVVV-VVVVV-VVVVV-VTFVA"); -boolean isValid2 = ActivationCodeUtil.validateRecoveryCode("R:VVVVV-VVVVV-VVVVV-VTFVA"); -``` - - -To validate PUK at once, you can call `ActivationCodeUtil.validateRecoveryPuk()` function: - - -```kotlin -val isValid = ActivationCodeUtil.validateRecoveryPuk("0123456789") -``` -```java -boolean isValid = ActivationCodeUtil.validateRecoveryPuk("0123456789"); -``` - - #### Auto-Correcting Typed Characters -You can implement auto-correcting of typed characters by using `ActivationCodeUtil.validateAndCorrectTypedCharacter()` function in screens, where the user is supposed to enter an activation or recovery code. This technique is possible due to the fact that Base32 is constructed so that it doesn't contain visually confusing characters. For example, `1` (number one) and `I` (capital I) are confusing, so only `I` is allowed. The benefit is that the provided function can correct typed `1` and translate it to `I`. +You can implement auto-correcting of typed characters by using `ActivationCodeUtil.validateAndCorrectTypedCharacter()` function in screens, where the user is supposed to enter an activation code. This technique is possible due to the fact that Base32 is constructed so that it doesn't contain visually confusing characters. For example, `1` (number one) and `I` (capital I) are confusing, so only `I` is allowed. The benefit is that the provided function can correct typed `1` and translate it to `I`. Here's an example how to iterate over the string and validate it character by character: @@ -2259,142 +2129,6 @@ powerAuthSDK.fetchEncryptionKey(context, authentication, index, new IFetchEncryp ``` -## Recovery Codes - -The recovery codes allow your users to recover their activation in case their device is lost or stolen. Before you start, please read the [Activation Recovery](https://github.com/wultra/powerauth-crypto/blob/develop/docs/Activation-Recovery.md) document, available in our [powerauth-crypto](https://github.com/wultra/powerauth-crypto) repository. - -To recover an activation, the user has to re-type two separate values: - -1. Recovery Code itself, which is very similar to an activation code. So you can detect typing errors before you submit such code to the server. -1. PUK, which is an additional numeric value and acts as a one-time password in the scheme. - -PowerAuth currently supports two basic types of recovery codes: - -1. Recovery Code bound to a previous PowerAuth activation. - - This type of code can be obtained only in an already-activated application. - - This type of code has only one PUK available, so only one recovery operation is possible. - - The activation associated with the code is removed once the recovery operation succeeds. - -2. Recovery Code delivered via OOB channel, typically in the form of a securely printed postcard, delivered by the post service. - - This type of code has typically more than one PUK associated with the code, so it can be used multiple times. - - The user has to keep that postcard in a safe and secure place, and mark already used PUKs. - - The code delivery must be confirmed by the user before the code can be used for a recovery operation. - -The feature is not automatically available. It must be enabled and configured on the PowerAuth Server. If it's so, then your mobile application can use several methods related to this feature. - -### Getting Recovery Data - -If the recovery data was received during the activation process, then you can later display that information to the user. To check the existence of recovery data and get that information, use the following code: - - -```kotlin -if (!powerAuthSDK.hasActivationRecoveryData()) { - // Recovery information is not available - return -} - -// 2FA signature - uses device-related key and user PIN code -val authentication = PowerAuthAuthentication.possessionWithPassword("1234") - -powerAuthSDK.getActivationRecoveryData(context, authentication, object: IGetRecoveryDataListener { - override fun onGetRecoveryDataSucceeded(recoveryData: RecoveryData) { - val recoveryCode = recoveryData.recoveryCode - val puk = recoveryData.puk - // Show values on the screen... - } - - override fun onGetRecoveryDataFailed(t: Throwable) { - // Report error - } -}) -``` -```java -if (!powerAuthSDK.hasActivationRecoveryData()) { - // Recovery information is not available - return; -} - -// 2FA signature - uses device-related key and user PIN code -PowerAuthAuthentication authentication = PowerAuthAuthentication.possessionWithPassword("1234"); - -powerAuthSDK.getActivationRecoveryData(context, authentication, new IGetRecoveryDataListener() { - @Override - public void onGetRecoveryDataSucceeded(RecoveryData recoveryData) { - final String recoveryCode = recoveryData.recoveryCode; - final String puk = recoveryData.puk; - // Show values on the screen... - } - - @Override - public void onGetRecoveryDataFailed(Throwable t) { - // Report error - } -}); -``` - - -The obtained information is very sensitive, so you should be very careful how your application manipulates the received values: - -- You should never store `recoveryCode` or `puk` on the device. -- You should never print the values to the debug log. -- You should never send the values over the network. -- You should never copy the values to the clipboard. -- You should require a PIN code every time to display the values on the screen. -- You should warn the user that taking a screenshot of the values is not recommended. -- Do not cache the values in RAM. - -You should inform the user that: - -- Making a screenshot when values are displayed on the screen is dangerous. -- The user should write down those values on paper and keep it as safe as possible for future use. - - -### Confirm Recovery Postcard - -The recovery postcard can contain the recovery code and multiple PUK values on one printed card. Due to security reasons, this kind of recovery code cannot be used for the recovery operation before the user confirms its physical delivery. To confirm such recovery code, use the following code: - - -```kotlin -// 2FA signature with possession factor is required -val authentication = PowerAuthAuthentication.possessionWithPassword("1234") -val recoveryCode = "VVVVV-VVVVV-VVVVV-VTFVA" // You can also use code scanned from QR -powerAuthSDK.confirmRecoveryCode(context, authentication, recoveryCode, object: IConfirmRecoveryCodeListener { - override fun onRecoveryCodeConfirmed(alreadyConfirmed: Boolean) { - if (alreadyConfirmed) { - android.util.Log.d(TAG, "Recovery code has been already confirmed. This is not an error, just information.") - } else { - android.util.Log.d(TAG, "Recovery code has been successfully confirmed.") - } - } - - override fun onRecoveryCodeConfirmFailed(t: Throwable) { - // Report error - } -}) -``` -```java -// 2FA signature with possession factor is required -final PowerAuthAuthentication authentication = PowerAuthAuthentication.possessionWithPassword("1234"); -final String recoveryCode = "VVVVV-VVVVV-VVVVV-VTFVA" // You can also use code scanned from QR -powerAuthSDK.confirmRecoveryCode(context, authentication, recoveryCode, new IConfirmRecoveryCodeListener{ - @Override - public void onRecoveryCodeConfirmed(boolean alreadyConfirmed) { - if (alreadyConfirmed) { - android.util.Log.d(TAG, "Recovery code has been already confirmed. This is not an error, just information."); - } else { - android.util.Log.d(TAG, "Recovery code has been successfully confirmed."); - } - } - - @Override - public void onRecoveryCodeConfirmFailed(Throwable t) { - // Report error - } -}); -``` - - -The `alreadyConfirmed` boolean indicates that the code was already confirmed in the past. You can choose a different "success" screen, describing that the user has already confirmed such code. Also, note that codes bound to the activations are already confirmed. ## Token-Based Authentication diff --git a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/PowerAuthServerApi.java b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/PowerAuthServerApi.java index 5d1dfdbd..a2ca7e42 100644 --- a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/PowerAuthServerApi.java +++ b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/PowerAuthServerApi.java @@ -28,7 +28,6 @@ import io.getlime.security.powerauth.integration.support.model.ApplicationDetail; import io.getlime.security.powerauth.integration.support.model.ApplicationVersion; import io.getlime.security.powerauth.integration.support.model.OfflineSignaturePayload; -import io.getlime.security.powerauth.integration.support.model.RecoveryConfig; import io.getlime.security.powerauth.integration.support.model.ServerVersion; import io.getlime.security.powerauth.integration.support.model.SignatureData; import io.getlime.security.powerauth.integration.support.model.SignatureInfo; @@ -114,24 +113,6 @@ public interface PowerAuthServerApi { */ void setApplicationVersionSupported(String applicationVersionId, boolean supported) throws Exception; - // Recovery config - - /** - * Get recovery config for application. - * - * @param applicationId Application identifier. - * @return {@link RecoveryConfig} object. - * @throws Exception In case of failure. - */ - @NonNull RecoveryConfig getRecoveryConfig(String applicationId) throws Exception; - - /** - * Update recovery config for application specified in {@link RecoveryConfig} object. - * @param recoveryConfig Config that specifies application and fields that should be updated. - * @throws Exception In case of failure. - */ - void updateRecoveryConfig(@NonNull RecoveryConfig recoveryConfig) throws Exception; - // Activation /** @@ -197,10 +178,9 @@ public interface PowerAuthServerApi { * * @param activationId Activation identifier. * @param externalUserId Optional external user identifier. - * @param revokeRecoveryCodes Also revoke recovery codes associated to this activation. * @throws Exception In case of failure. */ - void activationRemove(@NonNull String activationId, @Nullable String externalUserId, boolean revokeRecoveryCodes) throws Exception; + void activationRemove(@NonNull String activationId, @Nullable String externalUserId) throws Exception; /** * Remove activation on the server and also revoke any associated recovery code with it. diff --git a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/model/RecoveryConfig.java b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/model/RecoveryConfig.java deleted file mode 100644 index c360979c..00000000 --- a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/model/RecoveryConfig.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2020 Wultra s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.getlime.security.powerauth.integration.support.model; - -public class RecoveryConfig { - - // Always present values - private String applicationId; - private boolean activationRecoveryEnabled; - private boolean recoveryPostcardEnabled; - - // Optional values - private Boolean allowMultipleRecoveryCodes; - private String postcardPublicKey; // Should not be set in update - private String remotePostcardPublicKey; - - public String getApplicationId() { - return applicationId; - } - - public void setApplicationId(String applicationId) { - this.applicationId = applicationId; - } - - public boolean isActivationRecoveryEnabled() { - return activationRecoveryEnabled; - } - - public void setActivationRecoveryEnabled(boolean activationRecoveryEnabled) { - this.activationRecoveryEnabled = activationRecoveryEnabled; - } - - public boolean isRecoveryPostcardEnabled() { - return recoveryPostcardEnabled; - } - - public void setRecoveryPostcardEnabled(boolean recoveryPostcardEnabled) { - this.recoveryPostcardEnabled = recoveryPostcardEnabled; - } - - public Boolean getAllowMultipleRecoveryCodes() { - return allowMultipleRecoveryCodes; - } - - public void setAllowMultipleRecoveryCodes(Boolean allowMultipleRecoveryCodes) { - this.allowMultipleRecoveryCodes = allowMultipleRecoveryCodes; - } - - public String getPostcardPublicKey() { - return postcardPublicKey; - } - - public void setPostcardPublicKey(String postcardPublicKey) { - this.postcardPublicKey = postcardPublicKey; - } - - public String getRemotePostcardPublicKey() { - return remotePostcardPublicKey; - } - - public void setRemotePostcardPublicKey(String remotePostcardPublicKey) { - this.remotePostcardPublicKey = remotePostcardPublicKey; - } -} diff --git a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/model/ServerVersion.java b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/model/ServerVersion.java index 7de1b393..5256cb43 100644 --- a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/model/ServerVersion.java +++ b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/model/ServerVersion.java @@ -37,13 +37,13 @@ public enum ServerVersion { V1_7_0("1.7", 1007000, ProtocolVersion.V3_2), V1_8_0("1.8", 1008000, ProtocolVersion.V3_2), V1_9_0("1.9", 1009000, ProtocolVersion.V3_3), - + V1_10_0("1.10", 1010000, ProtocolVersion.V3_3), ; /** * Contains constant for the latest PowerAuth Server version. */ - public static final ServerVersion LATEST = V1_9_0; + public static final ServerVersion LATEST = V1_10_0; /** * Server version represented as string. diff --git a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v10/PowerAuthClientV3_ServerV10.java b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v10/PowerAuthClientV3_ServerV10.java index 3d95e9fe..cd140ad2 100644 --- a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v10/PowerAuthClientV3_ServerV10.java +++ b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v10/PowerAuthClientV3_ServerV10.java @@ -156,23 +156,6 @@ public void setApplicationVersionSupported(String applicationVersionId, boolean } } - @NonNull - @Override - public RecoveryConfig getRecoveryConfig(String applicationId) throws Exception { - final GetRecoveryConfigEndpoint.Request request = new GetRecoveryConfigEndpoint.Request(); - request.setApplicationId(Long.parseLong(applicationId)); - return restClient.send(request, new GetRecoveryConfigEndpoint()); - } - - @Override - public void updateRecoveryConfig(@NonNull RecoveryConfig recoveryConfig) throws Exception { - final UpdateRecoveryConfigEndpoint.Request request = new UpdateRecoveryConfigEndpoint.Request(recoveryConfig); - final UpdateRecoveryConfigEndpoint.Response response = restClient.send(request, new UpdateRecoveryConfigEndpoint()); - if (!response.isUpdated()) { - throw new Exception("Recovery config for application " + recoveryConfig.getApplicationId() + " is not updated after successful response."); - } - } - @NonNull @Override public Activation activationInit(@NonNull Application application, @NonNull String userId, @Nullable String otp, @Nullable ActivationOtpValidation otpValidation, @Nullable Long maxFailureCount) throws Exception { @@ -229,11 +212,11 @@ public void activationCommit(@NonNull Activation activation) throws Exception { } @Override - public void activationRemove(@NonNull String activationId, @Nullable String externalUserId, boolean revokeRecoveryCodes) throws Exception { + public void activationRemove(@NonNull String activationId, @Nullable String externalUserId) throws Exception { final RemoveActivationEndpoint.Request request = new RemoveActivationEndpoint.Request(); request.setActivationId(activationId); request.setExternalUserId(externalUserId); - request.setRevokeRecoveryCodes(revokeRecoveryCodes); + request.setRevokeRecoveryCodes(true); final RemoveActivationEndpoint.Response response = restClient.send(request, new RemoveActivationEndpoint()); if (!response.isRemoved()) { throw new Exception("Activation " + activationId + " is not removed after request success."); @@ -242,7 +225,7 @@ public void activationRemove(@NonNull String activationId, @Nullable String exte @Override public void activationRemove(@NonNull Activation activation) throws Exception { - activationRemove(activation.getActivationId(), ServerConstants.DEFAULT_EXTERNAL_USER_ID, true); + activationRemove(activation.getActivationId(), ServerConstants.DEFAULT_EXTERNAL_USER_ID); } @Override diff --git a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v10/endpoints/GetRecoveryConfigEndpoint.java b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v10/endpoints/GetRecoveryConfigEndpoint.java deleted file mode 100644 index 2273b046..00000000 --- a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v10/endpoints/GetRecoveryConfigEndpoint.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2020 Wultra s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.getlime.security.powerauth.integration.support.v10.endpoints; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.google.gson.reflect.TypeToken; - -import io.getlime.security.powerauth.integration.support.client.IServerApiEndpoint; -import io.getlime.security.powerauth.integration.support.model.RecoveryConfig; - -public class GetRecoveryConfigEndpoint implements IServerApiEndpoint { - - @NonNull - @Override - public String getRelativePath() { - return "/rest/v3/recovery/config/detail"; - } - - @Nullable - @Override - public TypeToken getResponseType() { - return TypeToken.get(Response.class); - } - - // Request - - public static class Request { - - private long applicationId; - - public long getApplicationId() { - return applicationId; - } - - public void setApplicationId(long applicationId) { - this.applicationId = applicationId; - } - } - - // Response - - public static class Response extends RecoveryConfig { - } -} diff --git a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v10/endpoints/UpdateRecoveryConfigEndpoint.java b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v10/endpoints/UpdateRecoveryConfigEndpoint.java deleted file mode 100644 index ceaaf793..00000000 --- a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v10/endpoints/UpdateRecoveryConfigEndpoint.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2020 Wultra s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.getlime.security.powerauth.integration.support.v10.endpoints; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.google.gson.reflect.TypeToken; - -import io.getlime.security.powerauth.integration.support.client.IServerApiEndpoint; -import io.getlime.security.powerauth.integration.support.model.RecoveryConfig; - -public class UpdateRecoveryConfigEndpoint implements IServerApiEndpoint { - - @NonNull - @Override - public String getRelativePath() { - return "/rest/v3/recovery/config/update"; - } - - @Nullable - @Override - public TypeToken getResponseType() { - return TypeToken.get(Response.class); - } - - // Request - - public static class Request extends RecoveryConfig { - - /** - * Create request from given recovery config. - * @param config Recovery config. - */ - public Request(@NonNull RecoveryConfig config) { - setApplicationId(config.getApplicationId()); - setActivationRecoveryEnabled(config.isActivationRecoveryEnabled()); - setRecoveryPostcardEnabled(config.isRecoveryPostcardEnabled()); - setAllowMultipleRecoveryCodes(config.getAllowMultipleRecoveryCodes()); - setRemotePostcardPublicKey(config.getRemotePostcardPublicKey()); - } - } - - // Response - - public static class Response { - - private boolean updated; - - public boolean isUpdated() { - return updated; - } - - public void setUpdated(boolean updated) { - this.updated = updated; - } - } -} diff --git a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v13/PowerAuthClientV3_ServerV13.java b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v13/PowerAuthClientV3_ServerV13.java index 1ae00013..75f81101 100644 --- a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v13/PowerAuthClientV3_ServerV13.java +++ b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v13/PowerAuthClientV3_ServerV13.java @@ -31,7 +31,6 @@ import io.getlime.security.powerauth.integration.support.model.ApplicationDetail; import io.getlime.security.powerauth.integration.support.model.ApplicationVersion; import io.getlime.security.powerauth.integration.support.model.OfflineSignaturePayload; -import io.getlime.security.powerauth.integration.support.model.RecoveryConfig; import io.getlime.security.powerauth.integration.support.model.ServerConstants; import io.getlime.security.powerauth.integration.support.model.ServerVersion; import io.getlime.security.powerauth.integration.support.model.SignatureData; @@ -46,14 +45,12 @@ import io.getlime.security.powerauth.integration.support.v13.endpoints.GetActivationStatusEndpoint; import io.getlime.security.powerauth.integration.support.v13.endpoints.GetApplicationDetailEndpoint; import io.getlime.security.powerauth.integration.support.v13.endpoints.GetApplicationListEndpoint; -import io.getlime.security.powerauth.integration.support.v13.endpoints.GetRecoveryConfigEndpoint; import io.getlime.security.powerauth.integration.support.v13.endpoints.GetSystemStatusEndpoint; import io.getlime.security.powerauth.integration.support.v13.endpoints.InitActivationEndpoint; import io.getlime.security.powerauth.integration.support.v13.endpoints.RemoveActivationEndpoint; import io.getlime.security.powerauth.integration.support.v13.endpoints.SetApplicationVersionSupportedEndpoint; import io.getlime.security.powerauth.integration.support.v13.endpoints.UnblockActivationEndpoint; import io.getlime.security.powerauth.integration.support.v13.endpoints.UpdateActivationOtpEndpoint; -import io.getlime.security.powerauth.integration.support.v13.endpoints.UpdateRecoveryConfigEndpoint; import io.getlime.security.powerauth.integration.support.v13.endpoints.ValidateTokenEndpoint; import io.getlime.security.powerauth.integration.support.v13.endpoints.VerifyEcdsaSignatureEndpoint; import io.getlime.security.powerauth.integration.support.v13.endpoints.VerifyOfflineSignatureEndpoint; @@ -189,23 +186,6 @@ public void setApplicationVersionSupported(String applicationVersionId, boolean } } - @NonNull - @Override - public RecoveryConfig getRecoveryConfig(String applicationId) throws Exception { - final GetRecoveryConfigEndpoint.Request request = new GetRecoveryConfigEndpoint.Request(); - request.setApplicationId(applicationId); - return restClient.send(request, new GetRecoveryConfigEndpoint()); - } - - @Override - public void updateRecoveryConfig(@NonNull RecoveryConfig recoveryConfig) throws Exception { - final UpdateRecoveryConfigEndpoint.Request request = new UpdateRecoveryConfigEndpoint.Request(recoveryConfig); - final UpdateRecoveryConfigEndpoint.Response response = restClient.send(request, new UpdateRecoveryConfigEndpoint()); - if (!response.isUpdated()) { - throw new Exception("Recovery config for application " + recoveryConfig.getApplicationId() + " is not updated after successful response."); - } - } - @NonNull @Override public Activation activationInit(@NonNull Application application, @NonNull String userId, @Nullable String otp, @Nullable ActivationOtpValidation otpValidation, @Nullable Long maxFailureCount) throws Exception { @@ -262,11 +242,11 @@ public void activationCommit(@NonNull Activation activation) throws Exception { } @Override - public void activationRemove(@NonNull String activationId, @Nullable String externalUserId, boolean revokeRecoveryCodes) throws Exception { + public void activationRemove(@NonNull String activationId, @Nullable String externalUserId) throws Exception { final RemoveActivationEndpoint.Request request = new RemoveActivationEndpoint.Request(); request.setActivationId(activationId); request.setExternalUserId(externalUserId); - request.setRevokeRecoveryCodes(revokeRecoveryCodes); + request.setRevokeRecoveryCodes(true); final RemoveActivationEndpoint.Response response = restClient.send(request, new RemoveActivationEndpoint()); if (!response.isRemoved()) { throw new Exception("Activation " + activationId + " is not removed after request success."); @@ -275,7 +255,7 @@ public void activationRemove(@NonNull String activationId, @Nullable String exte @Override public void activationRemove(@NonNull Activation activation) throws Exception { - activationRemove(activation.getActivationId(), ServerConstants.DEFAULT_EXTERNAL_USER_ID, true); + activationRemove(activation.getActivationId(), ServerConstants.DEFAULT_EXTERNAL_USER_ID); } @Override diff --git a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v13/endpoints/GetRecoveryConfigEndpoint.java b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v13/endpoints/GetRecoveryConfigEndpoint.java deleted file mode 100644 index 4227a20b..00000000 --- a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v13/endpoints/GetRecoveryConfigEndpoint.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2020 Wultra s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.getlime.security.powerauth.integration.support.v13.endpoints; - -import com.google.gson.reflect.TypeToken; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import io.getlime.security.powerauth.integration.support.client.IServerApiEndpoint; -import io.getlime.security.powerauth.integration.support.model.RecoveryConfig; - -public class GetRecoveryConfigEndpoint implements IServerApiEndpoint { - - @NonNull - @Override - public String getRelativePath() { - return "/rest/v3/recovery/config/detail"; - } - - @Nullable - @Override - public TypeToken getResponseType() { - return TypeToken.get(Response.class); - } - - // Request - - public static class Request { - - private String applicationId; - - public String getApplicationId() { - return applicationId; - } - - public void setApplicationId(String applicationId) { - this.applicationId = applicationId; - } - } - - // Response - - public static class Response extends RecoveryConfig { - } -} diff --git a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v13/endpoints/UpdateRecoveryConfigEndpoint.java b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v13/endpoints/UpdateRecoveryConfigEndpoint.java deleted file mode 100644 index 89158f12..00000000 --- a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v13/endpoints/UpdateRecoveryConfigEndpoint.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2020 Wultra s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.getlime.security.powerauth.integration.support.v13.endpoints; - -import com.google.gson.reflect.TypeToken; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import io.getlime.security.powerauth.integration.support.client.IServerApiEndpoint; -import io.getlime.security.powerauth.integration.support.model.RecoveryConfig; - -public class UpdateRecoveryConfigEndpoint implements IServerApiEndpoint { - - @NonNull - @Override - public String getRelativePath() { - return "/rest/v3/recovery/config/update"; - } - - @Nullable - @Override - public TypeToken getResponseType() { - return TypeToken.get(Response.class); - } - - // Request - - public static class Request extends RecoveryConfig { - - /** - * Create request from given recovery config. - * @param config Recovery config. - */ - public Request(@NonNull RecoveryConfig config) { - setApplicationId(config.getApplicationId()); - setActivationRecoveryEnabled(config.isActivationRecoveryEnabled()); - setRecoveryPostcardEnabled(config.isRecoveryPostcardEnabled()); - setAllowMultipleRecoveryCodes(config.getAllowMultipleRecoveryCodes()); - setRemotePostcardPublicKey(config.getRemotePostcardPublicKey()); - } - } - - // Response - - public static class Response { - - private boolean updated; - - public boolean isUpdated() { - return updated; - } - - public void setUpdated(boolean updated) { - this.updated = updated; - } - } -} diff --git a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v15/PowerAuthClientV3_ServerV15.java b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v15/PowerAuthClientV3_ServerV15.java index bb04c2f6..eb1545c3 100644 --- a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v15/PowerAuthClientV3_ServerV15.java +++ b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v15/PowerAuthClientV3_ServerV15.java @@ -31,7 +31,6 @@ import io.getlime.security.powerauth.integration.support.model.ApplicationDetail; import io.getlime.security.powerauth.integration.support.model.ApplicationVersion; import io.getlime.security.powerauth.integration.support.model.OfflineSignaturePayload; -import io.getlime.security.powerauth.integration.support.model.RecoveryConfig; import io.getlime.security.powerauth.integration.support.model.ServerConstants; import io.getlime.security.powerauth.integration.support.model.ServerVersion; import io.getlime.security.powerauth.integration.support.model.SignatureData; @@ -46,14 +45,12 @@ import io.getlime.security.powerauth.integration.support.v15.endpoints.GetActivationStatusEndpoint; import io.getlime.security.powerauth.integration.support.v15.endpoints.GetApplicationDetailEndpoint; import io.getlime.security.powerauth.integration.support.v15.endpoints.GetApplicationListEndpoint; -import io.getlime.security.powerauth.integration.support.v15.endpoints.GetRecoveryConfigEndpoint; import io.getlime.security.powerauth.integration.support.v15.endpoints.GetSystemStatusEndpoint; import io.getlime.security.powerauth.integration.support.v15.endpoints.InitActivationEndpoint; import io.getlime.security.powerauth.integration.support.v15.endpoints.RemoveActivationEndpoint; import io.getlime.security.powerauth.integration.support.v15.endpoints.SetApplicationVersionSupportedEndpoint; import io.getlime.security.powerauth.integration.support.v15.endpoints.UnblockActivationEndpoint; import io.getlime.security.powerauth.integration.support.v15.endpoints.UpdateActivationOtpEndpoint; -import io.getlime.security.powerauth.integration.support.v15.endpoints.UpdateRecoveryConfigEndpoint; import io.getlime.security.powerauth.integration.support.v15.endpoints.ValidateTokenEndpoint; import io.getlime.security.powerauth.integration.support.v15.endpoints.VerifyEcdsaSignatureEndpoint; import io.getlime.security.powerauth.integration.support.v15.endpoints.VerifyOfflineSignatureEndpoint; @@ -189,23 +186,6 @@ public void setApplicationVersionSupported(String applicationVersionId, boolean } } - @NonNull - @Override - public RecoveryConfig getRecoveryConfig(String applicationId) throws Exception { - final GetRecoveryConfigEndpoint.Request request = new GetRecoveryConfigEndpoint.Request(); - request.setApplicationId(applicationId); - return restClient.send(request, new GetRecoveryConfigEndpoint()); - } - - @Override - public void updateRecoveryConfig(@NonNull RecoveryConfig recoveryConfig) throws Exception { - final UpdateRecoveryConfigEndpoint.Request request = new UpdateRecoveryConfigEndpoint.Request(recoveryConfig); - final UpdateRecoveryConfigEndpoint.Response response = restClient.send(request, new UpdateRecoveryConfigEndpoint()); - if (!response.isUpdated()) { - throw new Exception("Recovery config for application " + recoveryConfig.getApplicationId() + " is not updated after successful response."); - } - } - @NonNull @Override public Activation activationInit(@NonNull Application application, @NonNull String userId, @Nullable String otp, @Nullable ActivationOtpValidation otpValidation, @Nullable Long maxFailureCount) throws Exception { @@ -262,11 +242,10 @@ public void activationCommit(@NonNull Activation activation) throws Exception { } @Override - public void activationRemove(@NonNull String activationId, @Nullable String externalUserId, boolean revokeRecoveryCodes) throws Exception { + public void activationRemove(@NonNull String activationId, @Nullable String externalUserId) throws Exception { final RemoveActivationEndpoint.Request request = new RemoveActivationEndpoint.Request(); request.setActivationId(activationId); request.setExternalUserId(externalUserId); - request.setRevokeRecoveryCodes(revokeRecoveryCodes); final RemoveActivationEndpoint.Response response = restClient.send(request, new RemoveActivationEndpoint()); if (!response.isRemoved()) { throw new Exception("Activation " + activationId + " is not removed after request success."); @@ -275,7 +254,7 @@ public void activationRemove(@NonNull String activationId, @Nullable String exte @Override public void activationRemove(@NonNull Activation activation) throws Exception { - activationRemove(activation.getActivationId(), ServerConstants.DEFAULT_EXTERNAL_USER_ID, true); + activationRemove(activation.getActivationId(), ServerConstants.DEFAULT_EXTERNAL_USER_ID); } @Override diff --git a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v15/endpoints/GetRecoveryConfigEndpoint.java b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v15/endpoints/GetRecoveryConfigEndpoint.java deleted file mode 100644 index f7cdb7cc..00000000 --- a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v15/endpoints/GetRecoveryConfigEndpoint.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2020 Wultra s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.getlime.security.powerauth.integration.support.v15.endpoints; - -import com.google.gson.reflect.TypeToken; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import io.getlime.security.powerauth.integration.support.client.IServerApiEndpoint; -import io.getlime.security.powerauth.integration.support.model.RecoveryConfig; - -public class GetRecoveryConfigEndpoint implements IServerApiEndpoint { - - @NonNull - @Override - public String getRelativePath() { - return "/rest/v3/recovery/config/detail"; - } - - @Nullable - @Override - public TypeToken getResponseType() { - return TypeToken.get(Response.class); - } - - // Request - - public static class Request { - - private String applicationId; - - public String getApplicationId() { - return applicationId; - } - - public void setApplicationId(String applicationId) { - this.applicationId = applicationId; - } - } - - // Response - - public static class Response extends RecoveryConfig { - } -} diff --git a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v15/endpoints/RemoveActivationEndpoint.java b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v15/endpoints/RemoveActivationEndpoint.java index f47fc028..3962ee8a 100644 --- a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v15/endpoints/RemoveActivationEndpoint.java +++ b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v15/endpoints/RemoveActivationEndpoint.java @@ -42,7 +42,6 @@ public static class Request { private String activationId; private String externalUserId; - private boolean revokeRecoveryCodes; public String getActivationId() { return activationId; @@ -59,14 +58,6 @@ public String getExternalUserId() { public void setExternalUserId(String externalUserId) { this.externalUserId = externalUserId; } - - public boolean isRevokeRecoveryCodes() { - return revokeRecoveryCodes; - } - - public void setRevokeRecoveryCodes(boolean revokeRecoveryCodes) { - this.revokeRecoveryCodes = revokeRecoveryCodes; - } } // Response diff --git a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v15/endpoints/UpdateRecoveryConfigEndpoint.java b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v15/endpoints/UpdateRecoveryConfigEndpoint.java deleted file mode 100644 index f39c2f29..00000000 --- a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v15/endpoints/UpdateRecoveryConfigEndpoint.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2020 Wultra s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.getlime.security.powerauth.integration.support.v15.endpoints; - -import com.google.gson.reflect.TypeToken; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import io.getlime.security.powerauth.integration.support.client.IServerApiEndpoint; -import io.getlime.security.powerauth.integration.support.model.RecoveryConfig; - -public class UpdateRecoveryConfigEndpoint implements IServerApiEndpoint { - - @NonNull - @Override - public String getRelativePath() { - return "/rest/v3/recovery/config/update"; - } - - @Nullable - @Override - public TypeToken getResponseType() { - return TypeToken.get(Response.class); - } - - // Request - - public static class Request extends RecoveryConfig { - - /** - * Create request from given recovery config. - * @param config Recovery config. - */ - public Request(@NonNull RecoveryConfig config) { - setApplicationId(config.getApplicationId()); - setActivationRecoveryEnabled(config.isActivationRecoveryEnabled()); - setRecoveryPostcardEnabled(config.isRecoveryPostcardEnabled()); - setAllowMultipleRecoveryCodes(config.getAllowMultipleRecoveryCodes()); - setRemotePostcardPublicKey(config.getRemotePostcardPublicKey()); - } - } - - // Response - - public static class Response { - - private boolean updated; - - public boolean isUpdated() { - return updated; - } - - public void setUpdated(boolean updated) { - this.updated = updated; - } - } -} diff --git a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v19/PowerAuthClientV3_ServerV19.java b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v19/PowerAuthClientV3_ServerV19.java index 3e4f88ee..60592ab7 100644 --- a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v19/PowerAuthClientV3_ServerV19.java +++ b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v19/PowerAuthClientV3_ServerV19.java @@ -31,7 +31,6 @@ import io.getlime.security.powerauth.integration.support.model.ApplicationDetail; import io.getlime.security.powerauth.integration.support.model.ApplicationVersion; import io.getlime.security.powerauth.integration.support.model.OfflineSignaturePayload; -import io.getlime.security.powerauth.integration.support.model.RecoveryConfig; import io.getlime.security.powerauth.integration.support.model.ServerConstants; import io.getlime.security.powerauth.integration.support.model.ServerVersion; import io.getlime.security.powerauth.integration.support.model.SignatureData; @@ -46,14 +45,12 @@ import io.getlime.security.powerauth.integration.support.v19.endpoints.GetActivationStatusEndpoint; import io.getlime.security.powerauth.integration.support.v19.endpoints.GetApplicationDetailEndpoint; import io.getlime.security.powerauth.integration.support.v19.endpoints.GetApplicationListEndpoint; -import io.getlime.security.powerauth.integration.support.v19.endpoints.GetRecoveryConfigEndpoint; import io.getlime.security.powerauth.integration.support.v19.endpoints.GetSystemStatusEndpoint; import io.getlime.security.powerauth.integration.support.v19.endpoints.InitActivationEndpoint; import io.getlime.security.powerauth.integration.support.v19.endpoints.RemoveActivationEndpoint; import io.getlime.security.powerauth.integration.support.v19.endpoints.SetApplicationVersionSupportedEndpoint; import io.getlime.security.powerauth.integration.support.v19.endpoints.UnblockActivationEndpoint; import io.getlime.security.powerauth.integration.support.v19.endpoints.UpdateActivationOtpEndpoint; -import io.getlime.security.powerauth.integration.support.v19.endpoints.UpdateRecoveryConfigEndpoint; import io.getlime.security.powerauth.integration.support.v19.endpoints.ValidateTokenEndpoint; import io.getlime.security.powerauth.integration.support.v19.endpoints.VerifyEcdsaSignatureEndpoint; import io.getlime.security.powerauth.integration.support.v19.endpoints.VerifyOfflineSignatureEndpoint; @@ -189,23 +186,6 @@ public void setApplicationVersionSupported(String applicationVersionId, boolean } } - @NonNull - @Override - public RecoveryConfig getRecoveryConfig(String applicationId) throws Exception { - final GetRecoveryConfigEndpoint.Request request = new GetRecoveryConfigEndpoint.Request(); - request.setApplicationId(applicationId); - return restClient.send(request, new GetRecoveryConfigEndpoint()); - } - - @Override - public void updateRecoveryConfig(@NonNull RecoveryConfig recoveryConfig) throws Exception { - final UpdateRecoveryConfigEndpoint.Request request = new UpdateRecoveryConfigEndpoint.Request(recoveryConfig); - final UpdateRecoveryConfigEndpoint.Response response = restClient.send(request, new UpdateRecoveryConfigEndpoint()); - if (!response.isUpdated()) { - throw new Exception("Recovery config for application " + recoveryConfig.getApplicationId() + " is not updated after successful response."); - } - } - @NonNull @Override public Activation activationInit(@NonNull Application application, @NonNull String userId, @Nullable String otp, @Nullable ActivationOtpValidation otpValidation, @Nullable Long maxFailureCount) throws Exception { @@ -262,11 +242,11 @@ public void activationCommit(@NonNull Activation activation) throws Exception { } @Override - public void activationRemove(@NonNull String activationId, @Nullable String externalUserId, boolean revokeRecoveryCodes) throws Exception { + public void activationRemove(@NonNull String activationId, @Nullable String externalUserId) throws Exception { final RemoveActivationEndpoint.Request request = new RemoveActivationEndpoint.Request(); request.setActivationId(activationId); request.setExternalUserId(externalUserId); - request.setRevokeRecoveryCodes(revokeRecoveryCodes); + request.setRevokeRecoveryCodes(true); final RemoveActivationEndpoint.Response response = restClient.send(request, new RemoveActivationEndpoint()); if (!response.isRemoved()) { throw new Exception("Activation " + activationId + " is not removed after request success."); @@ -275,7 +255,7 @@ public void activationRemove(@NonNull String activationId, @Nullable String exte @Override public void activationRemove(@NonNull Activation activation) throws Exception { - activationRemove(activation.getActivationId(), ServerConstants.DEFAULT_EXTERNAL_USER_ID, true); + activationRemove(activation.getActivationId(), ServerConstants.DEFAULT_EXTERNAL_USER_ID); } @Override diff --git a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v19/endpoints/GetRecoveryConfigEndpoint.java b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v19/endpoints/GetRecoveryConfigEndpoint.java deleted file mode 100644 index 9055c3bb..00000000 --- a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v19/endpoints/GetRecoveryConfigEndpoint.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2020 Wultra s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.getlime.security.powerauth.integration.support.v19.endpoints; - -import com.google.gson.reflect.TypeToken; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import io.getlime.security.powerauth.integration.support.client.IServerApiEndpoint; -import io.getlime.security.powerauth.integration.support.model.RecoveryConfig; - -public class GetRecoveryConfigEndpoint implements IServerApiEndpoint { - - @NonNull - @Override - public String getRelativePath() { - return "/rest/v3/recovery/config/detail"; - } - - @Nullable - @Override - public TypeToken getResponseType() { - return TypeToken.get(Response.class); - } - - // Request - - public static class Request { - - private String applicationId; - - public String getApplicationId() { - return applicationId; - } - - public void setApplicationId(String applicationId) { - this.applicationId = applicationId; - } - } - - // Response - - public static class Response extends RecoveryConfig { - } -} diff --git a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v19/endpoints/UpdateRecoveryConfigEndpoint.java b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v19/endpoints/UpdateRecoveryConfigEndpoint.java deleted file mode 100644 index 4a33cd8e..00000000 --- a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/v19/endpoints/UpdateRecoveryConfigEndpoint.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2020 Wultra s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.getlime.security.powerauth.integration.support.v19.endpoints; - -import com.google.gson.reflect.TypeToken; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import io.getlime.security.powerauth.integration.support.client.IServerApiEndpoint; -import io.getlime.security.powerauth.integration.support.model.RecoveryConfig; - -public class UpdateRecoveryConfigEndpoint implements IServerApiEndpoint { - - @NonNull - @Override - public String getRelativePath() { - return "/rest/v3/recovery/config/update"; - } - - @Nullable - @Override - public TypeToken getResponseType() { - return TypeToken.get(Response.class); - } - - // Request - - public static class Request extends RecoveryConfig { - - /** - * Create request from given recovery config. - * @param config Recovery config. - */ - public Request(@NonNull RecoveryConfig config) { - setApplicationId(config.getApplicationId()); - setActivationRecoveryEnabled(config.isActivationRecoveryEnabled()); - setRecoveryPostcardEnabled(config.isRecoveryPostcardEnabled()); - setAllowMultipleRecoveryCodes(config.getAllowMultipleRecoveryCodes()); - setRemotePostcardPublicKey(config.getRemotePostcardPublicKey()); - } - } - - // Response - - public static class Response { - - private boolean updated; - - public boolean isUpdated() { - return updated; - } - - public void setUpdated(boolean updated) { - this.updated = updated; - } - } -} diff --git a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/tests/ActivationHelper.java b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/tests/ActivationHelper.java index 72f3da8f..b757a904 100644 --- a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/tests/ActivationHelper.java +++ b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/tests/ActivationHelper.java @@ -177,12 +177,11 @@ public ActivationHelper(@NonNull PowerAuthTestHelper testHelper, @NonNull Applic /** * Remove activation on the server and locally, from PowerAuthSDK instance. - * @param revokeRecoveryCodes Set true to also revoke possible recovery codes associated with the activation. * @throws Exception In case of failure. */ - public void removeActivation(boolean revokeRecoveryCodes) throws Exception { + public void removeActivation() throws Exception { if (activation != null) { - testHelper.getServerApi().activationRemove(activation.getActivationId(), ServerConstants.DEFAULT_EXTERNAL_USER_ID, revokeRecoveryCodes); + testHelper.getServerApi().activationRemove(activation.getActivationId(), ServerConstants.DEFAULT_EXTERNAL_USER_ID); activation = null; validAuthentication = null; invalidAuthentication = null; @@ -465,12 +464,12 @@ public void onPasswordValidationFailed(@NonNull Throwable t) { } /** - * Function removes activation on the server and locally. Unlike {@link #removeActivation(boolean)}, this + * Function removes activation on the server and locally. Unlike {@link #removeActivation()}, this * method catch all possible errors and allows tests to continue. */ public void cleanupAfterTest() { try { - removeActivation(true); + removeActivation(); } catch (Exception ex) { Logger.e("ActivationHelper failed to remove activation: " + ex.getMessage()); } diff --git a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/tests/RecoveryActivationTest.java b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/tests/RecoveryActivationTest.java deleted file mode 100644 index 5cea9f30..00000000 --- a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/tests/RecoveryActivationTest.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2020 Wultra s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.getlime.security.powerauth.integration.tests; - -import androidx.annotation.NonNull; -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import io.getlime.security.powerauth.core.ActivationStatus; -import io.getlime.security.powerauth.core.RecoveryData; -import io.getlime.security.powerauth.integration.support.AsyncHelper; -import io.getlime.security.powerauth.integration.support.Logger; -import io.getlime.security.powerauth.integration.support.PowerAuthTestHelper; -import io.getlime.security.powerauth.integration.support.model.ActivationDetail; -import io.getlime.security.powerauth.integration.support.model.RecoveryConfig; -import io.getlime.security.powerauth.networking.response.CreateActivationResult; -import io.getlime.security.powerauth.networking.response.ICreateActivationListener; -import io.getlime.security.powerauth.sdk.PowerAuthActivation; -import io.getlime.security.powerauth.sdk.PowerAuthSDK; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -@RunWith(AndroidJUnit4.class) -public class RecoveryActivationTest { - - private PowerAuthTestHelper testHelper; - private ActivationHelper regularActivation; - private ActivationHelper recoveryActivation; - - @Before - public void setUp() throws Exception { - testHelper = new PowerAuthTestHelper.Builder().build(); - regularActivation = new ActivationHelper(testHelper); - final PowerAuthSDK recoverySdk = testHelper.createSdk("test.recoveryInstance", true); - recoveryActivation = new ActivationHelper(testHelper, testHelper.getSharedApplication(), testHelper.getUserId(), recoverySdk); - } - - @After - public void tearDown() { - if (regularActivation != null) { - regularActivation.cleanupAfterTest(); - } - if (recoveryActivation != null) { - recoveryActivation.cleanupAfterTest(); - } - } - - @Test - public void testCreateActivationWithNoRC() throws Exception { - // Disable recovery activations - enableRecoveryActivations(false); - regularActivation.createStandardActivation(true, null); - CreateActivationResult createActivationResult = regularActivation.getCreateActivationResult(); - assertNotNull(createActivationResult); - assertNull(createActivationResult.getRecoveryData()); - } - - @Test - public void testCreateRecoveryActivation() throws Exception { - - final String extras = "recovery,attributes"; - - // Enable recovery activations - enableRecoveryActivations(true); - - // Create activation to just acquire a recovery code - regularActivation.createStandardActivation(true, null); - CreateActivationResult createActivationResult = regularActivation.getCreateActivationResult(); - assertNotNull(createActivationResult); - RecoveryData recoveryData = createActivationResult.getRecoveryData(); - assertNotNull(recoveryData); - assertNotNull(recoveryData.recoveryCode); - assertNotNull(recoveryData.puk); - - // Now try to create a recovery activation - final PowerAuthActivation paActivation = PowerAuthActivation.Builder.recoveryActivation(recoveryData.recoveryCode, recoveryData.puk, testHelper.getDeviceInfo()) - .setExtras(extras) - .build(); - // Create a recovery activation - createActivationResult = AsyncHelper.await(new AsyncHelper.Execution() { - @Override - public void execute(@NonNull final AsyncHelper.ResultCatcher resultCatcher) throws Exception { - recoveryActivation.getPowerAuthSDK().createActivation(paActivation, new ICreateActivationListener() { - @Override - public void onActivationCreateSucceed(@NonNull CreateActivationResult result) { - resultCatcher.completeWithResult(result); - } - - @Override - public void onActivationCreateFailed(@NonNull Throwable t) { - resultCatcher.completeWithError(t); - } - }); - } - }); - // Commit new activation locally - ActivationDetail recoveryActivationDetail = recoveryActivation.assignCustomActivationAndCommitLocally(createActivationResult); - assertEquals(extras, recoveryActivationDetail.getExtras()); - - // Validate old activation state - ActivationStatus oldActivationStatus = regularActivation.fetchActivationStatus(); - assertEquals(ActivationStatus.State_Removed, oldActivationStatus.state); - - // Validate new activation state - ActivationStatus recoveryActivationStatus = recoveryActivation.fetchActivationStatus(); - assertEquals(ActivationStatus.State_Active, recoveryActivationStatus.state); - - // Validate valid and invalid password - boolean passwordValid = recoveryActivation.validateUserPassword(recoveryActivation.getValidPassword()); - assertTrue(passwordValid); - passwordValid = recoveryActivation.validateUserPassword(recoveryActivation.getInvalidPassword()); - assertFalse(passwordValid); - } - - /** - * Enable or disable recovery codes associated with activations. - * - * @param enable Enable or disable recovery activations. - * @throws Exception In case of failure. - */ - private void enableRecoveryActivations(boolean enable) throws Exception { - String applicationId = testHelper.getSharedApplication().getApplicationId(); - RecoveryConfig recoveryConfig = testHelper.getServerApi().getRecoveryConfig(applicationId); - if (recoveryConfig.isActivationRecoveryEnabled() == enable) { - String currentState = enable ? "enabled" : "disabled"; - Logger.d("Recovery activations are already " + currentState + " for application " + applicationId); - return; - } - Logger.d("Enabling recovery activations for application " + applicationId); - recoveryConfig.setActivationRecoveryEnabled(enable); - testHelper.getServerApi().updateRecoveryConfig(recoveryConfig); - } - -} diff --git a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/sdk/PowerAuthActivationBuilderTest.java b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/sdk/PowerAuthActivationBuilderTest.java index b0d33fb7..629a58f8 100644 --- a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/sdk/PowerAuthActivationBuilderTest.java +++ b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/sdk/PowerAuthActivationBuilderTest.java @@ -198,91 +198,6 @@ public void createOidcActivationWithName() throws Exception { assertEquals("OIDC Activation", activation.activationName); } - // Recovery activations - - @Test - public void createRecoveryActivation() throws Exception { - PowerAuthActivation activation = PowerAuthActivation.Builder.recoveryActivation("W65WE-3T7VI-7FBS2-A4OYA", "1234567890") - .build(); - - assertNotNull(activation); - assertEquals(ActivationType.RECOVERY, activation.activationType); - assertNotNull(activation.identityAttributes); - assertEquals("1234567890", activation.identityAttributes.get("puk")); - assertEquals("W65WE-3T7VI-7FBS2-A4OYA", activation.identityAttributes.get("recoveryCode")); - assertNull(activation.activationName); - } - - @Test - public void createRecoveryActivationFromQrCode() throws Exception { - PowerAuthActivation activation = PowerAuthActivation.Builder.recoveryActivation("R:W65WE-3T7VI-7FBS2-A4OYA", "1234567890") - .build(); - - assertNotNull(activation); - assertEquals(ActivationType.RECOVERY, activation.activationType); - assertNotNull(activation.identityAttributes); - assertEquals("1234567890", activation.identityAttributes.get("puk")); - assertEquals("W65WE-3T7VI-7FBS2-A4OYA", activation.identityAttributes.get("recoveryCode")); - assertNull(activation.activationName); - } - - @Test - public void createRecoveryActivationWithName() throws Exception { - PowerAuthActivation activation = PowerAuthActivation.Builder.recoveryActivation("W65WE-3T7VI-7FBS2-A4OYA", "1234567890") - .setActivationName("Recovery") - .build(); - - assertNotNull(activation); - assertEquals(ActivationType.RECOVERY, activation.activationType); - assertNotNull(activation.identityAttributes); - assertEquals("1234567890", activation.identityAttributes.get("puk")); - assertEquals("W65WE-3T7VI-7FBS2-A4OYA", activation.identityAttributes.get("recoveryCode")); - assertEquals("Recovery", activation.activationName); - } - - @Test - public void createRecoveryActivationWithExtras() throws Exception { - Map additionalAttributes = new HashMap<>(); - additionalAttributes.put("test", "value"); - additionalAttributes.put("zero", 0); - - PowerAuthActivation activation = PowerAuthActivation.Builder.recoveryActivation("W65WE-3T7VI-7FBS2-A4OYA", "1234567890", "Recovery") - .setExtras("extras") - .setCustomAttributes(additionalAttributes) - .build(); - - assertNotNull(activation); - assertEquals(ActivationType.RECOVERY, activation.activationType); - assertNotNull(activation.identityAttributes); - assertEquals("1234567890", activation.identityAttributes.get("puk")); - assertEquals("W65WE-3T7VI-7FBS2-A4OYA", activation.identityAttributes.get("recoveryCode")); - assertEquals("Recovery", activation.activationName); - assertEquals("extras", activation.extras); - assertNotNull(activation.customAttributes); - assertEquals(0, activation.customAttributes.get("zero")); - assertEquals("value", activation.customAttributes.get("test")); - } - - @Test(expected = PowerAuthErrorException.class) - public void createRecoveryActivationWithOtp() throws Exception { - PowerAuthActivation.Builder.recoveryActivation("W65WE-3T7VI-7FBS2-A4OYA", "1234567890") - .setActivationName("Recovery") - .setAdditionalActivationOtp("1234") - .build(); - } - - @Test(expected = PowerAuthErrorException.class) - public void createRecoveryActivationWithInvalidCode() throws Exception { - PowerAuthActivation.Builder.recoveryActivation("W65WE-3T7VI-7FBS2-A4OYB", "1234567890") - .build(); - } - - @Test(expected = PowerAuthErrorException.class) - public void createRecoveryActivationWithInvalidPuk() throws Exception { - PowerAuthActivation.Builder.recoveryActivation("W65WE-3T7VI-7FBS2-A4OYA", "123456789") - .build(); - } - // Custom activation @Test diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/ActivationCodeUtil.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/ActivationCodeUtil.java index 2ab38833..d179bad5 100644 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/ActivationCodeUtil.java +++ b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/ActivationCodeUtil.java @@ -21,17 +21,12 @@ /** * The {@code PowerAuthActivationCodeUtil} class provides various set of methods for parsing - * and validating activation or recovery codes. + * and validating activation codes. *

* Current format of code: *

  * code without signature:  CCCCC-CCCCC-CCCCC-CCCCC
  * code with signature:     CCCCC-CCCCC-CCCCC-CCCCC#BASE64_STRING_WITH_SIGNATURE
- *
- * recovery code:           CCCCC-CCCCC-CCCCC-CCCCC
- * recovery code from QR:   R:CCCCC-CCCCC-CCCCC-CCCCC
- *
- * recovery PUK:            DDDDDDDDDD
  * 
*
    *
  • @@ -62,18 +57,7 @@ public class ActivationCodeUtil { public native static ActivationCode parseFromActivationCode(@NonNull String activationCode); /** - * Parses an input recovery code (which may or may not contain an optional "R:" prefix) and - * returns {@link ActivationCode} object filled with valid data. The method doesn't perform an auto-correction, - * so the provided code must be valid. - * - * @param recoveryCode string with a recovery code. - * @return {@link ActivationCode} object if code is valid, or null - */ - @Nullable - public native static ActivationCode parseFromRecoveryCode(@NonNull String recoveryCode); - - /** - * Returns true if UTF codepoint is a valid character allowed in the activation or recovery code. + * Returns true if UTF codepoint is a valid character allowed in the activation code. * The method strictly checks whether the character is from [A-Z2-7] characters range. * * @param utfCodepoint unicode code point to be validated. @@ -110,24 +94,4 @@ public class ActivationCodeUtil { * @return true if code is valid */ public native static boolean validateActivationCode(@NonNull String activationCode); - - /** - * Returns true if provided string is a valid recovery code. You can use this method to validate - * a whole user-typed recovery code at once. The input code may contain "R:" prefix, if code is - * scanned from QR code. - * - * @param recoveryCode recovery code which may, or may not contain "R:" prefix. - * @return true if code is valid - */ - public native static boolean validateRecoveryCode(@NonNull String recoveryCode); - - /** - * Returns true if provided recovery PUK appears to be valid. You can use this method to validate - * a whole user-typed recovery PUK at once. In current version, only 10 digits long string is - * considered as a valid PUK. - * - * @param recoveryPuk recovery code which may, or may not contain "R:" prefix. - * @return true if PUK appears to be a valid - */ - public native static boolean validateRecoveryPuk(@NonNull String recoveryPuk); } diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/ActivationStep1Result.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/ActivationStep1Result.java index 05c80621..36ed473e 100644 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/ActivationStep1Result.java +++ b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/ActivationStep1Result.java @@ -34,7 +34,7 @@ public class ActivationStep1Result { public final String devicePublicKey; public ActivationStep1Result() { - this.errorCode = 0; + this.errorCode = ErrorCode.OK; this.devicePublicKey = null; } -} \ No newline at end of file +} diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/ActivationStep2Param.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/ActivationStep2Param.java index 45a00979..55d4b4c3 100644 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/ActivationStep2Param.java +++ b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/ActivationStep2Param.java @@ -33,16 +33,10 @@ public class ActivationStep2Param { * Initial value for hash-based counter. */ public final String ctrData; - /** - * Data for activation recovery. May contain null, in case - * that there's no recovery available. - */ - public final RecoveryData activationRecovery; - public ActivationStep2Param(String activationId, String serverPublicKey, String ctrData, RecoveryData activationRecovery) { + public ActivationStep2Param(String activationId, String serverPublicKey, String ctrData) { this.activationId = activationId; this.serverPublicKey = serverPublicKey; this.ctrData = ctrData; - this.activationRecovery = activationRecovery; } -} \ No newline at end of file +} diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/RecoveryData.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/RecoveryData.java deleted file mode 100644 index e85a639c..00000000 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/RecoveryData.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2019 Wultra s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.getlime.security.powerauth.core; - -import androidx.annotation.NonNull; - -/** - * The {@code RecoveryData} contains information about recovery code and PUK, created - * during the activation process. - */ -public class RecoveryData { - - /** - * Contains recovery code. - */ - public final String recoveryCode; - - /** - * Contains PUK, valid with recovery code. - */ - public final String puk; - - /** - * @param recoveryCode String with recovery code - * @param puk String with PUK (10 digits long string) - */ - public RecoveryData(@NonNull String recoveryCode, @NonNull String puk) { - this.recoveryCode = recoveryCode; - this.puk = puk; - } - - /** - * Constructor used from JNI code. - */ - public RecoveryData() { - this.recoveryCode = null; - this.puk = null; - } -} diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/Session.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/Session.java index 516d2d6d..e0ab2f36 100644 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/Session.java +++ b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/Session.java @@ -728,24 +728,4 @@ public static String getMaxSupportedHttpProtocolVersion(ProtocolVersion version) */ @NonNull private static native String getMaxSupportedHttpProtocolVersion(int protocolVersionValue); - - // - // Recovery codes - // - - /** - * @return true if session contains an activation recovery data. - */ - public native boolean hasActivationRecoveryData(); - - /** - * Get an activation recovery data. This method calls PowerAuth Standard RESTful API endpoint '/pa/vault/unlock' - * to obtain the vault encryption key used for private recovery data decryption. - * - * @param cVaultKey encrypted vault key - * @param unlockKeys unlock keys object with required possession factor - * @return {@link RecoveryData} object or null in case of error - */ - public native RecoveryData getActivationRecoveryData(String cVaultKey, SignatureUnlockKeys unlockKeys); - } diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/ecies/EciesEncryptorId.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/ecies/EciesEncryptorId.java index 01170fe5..8bd88b6f 100644 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/ecies/EciesEncryptorId.java +++ b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/ecies/EciesEncryptorId.java @@ -80,12 +80,6 @@ public enum EciesEncryptorId { */ TOKEN_CREATE(EciesEncryptorScope.ACTIVATION, "/pa/token/create"), - /** - * Constructs a new encryptor for the confirm recovery code request purposes. The content encrypted - * with this object can be decrypted only by the PowerAuth server. - */ - CONFIRM_RECOVERY_CODE(EciesEncryptorScope.ACTIVATION, "/pa/recovery/confirm") - ; /** diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/exception/PowerAuthErrorCodes.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/exception/PowerAuthErrorCodes.java index a34d28ec..161e5d17 100644 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/exception/PowerAuthErrorCodes.java +++ b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/exception/PowerAuthErrorCodes.java @@ -87,7 +87,7 @@ int OPERATION_CANCELED = 11; /** - * Error code for error that occurs when invalid activation or invalid recovery code is provided. + * Error code for error that occurs when invalid activation code is provided. */ int INVALID_ACTIVATION_CODE = 12; diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/endpoints/ConfirmRecoveryCodeEndpoint.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/endpoints/ConfirmRecoveryCodeEndpoint.java deleted file mode 100644 index 321d8ead..00000000 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/endpoints/ConfirmRecoveryCodeEndpoint.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2019 Wultra s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.getlime.security.powerauth.networking.endpoints; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.google.gson.reflect.TypeToken; - -import io.getlime.security.powerauth.ecies.EciesEncryptorId; -import io.getlime.security.powerauth.networking.interfaces.IEndpointDefinition; -import io.getlime.security.powerauth.networking.model.response.ConfirmRecoveryResponsePayload; - -public class ConfirmRecoveryCodeEndpoint implements IEndpointDefinition { - @NonNull - @Override - public String getRelativePath() { - return "/pa/v3/recovery/confirm"; - } - - @Nullable - @Override - public String getAuthorizationUriId() { - return "/pa/recovery/confirm"; - } - - @NonNull - @Override - public EciesEncryptorId getEncryptorId() { - return EciesEncryptorId.CONFIRM_RECOVERY_CODE; - } - - @Nullable - @Override - public TypeToken getResponseType() { - return TypeToken.get(ConfirmRecoveryResponsePayload.class); - } -} diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/exceptions/ErrorResponseApiException.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/exceptions/ErrorResponseApiException.java index 5c4f66a5..dec6a99f 100644 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/exceptions/ErrorResponseApiException.java +++ b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/exceptions/ErrorResponseApiException.java @@ -57,24 +57,4 @@ public ErrorResponseApiException(@NonNull Error errorResponse, int responseCode, public Error getErrorResponse() { return errorResponse; } - - - /** - * @return Index of valid PUK in case that recovery activation did fail and - * there's still some recovery PUK available. Returns -1 if the information is not - * available in the error response. - */ - public int getCurrentRecoveryPukIndex() { - final JsonObject errorResponse = getResponseObjectFromResponseJson(); - if (errorResponse != null) { - final JsonElement currentRecoveryPukIndex = errorResponse.get("currentRecoveryPukIndex"); - if (currentRecoveryPukIndex != null && currentRecoveryPukIndex.isJsonPrimitive()) { - final JsonPrimitive value = currentRecoveryPukIndex.getAsJsonPrimitive(); - if (value.isNumber()) { - return value.getAsInt(); - } - } - } - return -1; - } } diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/model/entity/ActivationRecovery.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/model/entity/ActivationRecovery.java deleted file mode 100644 index 7f35c8a3..00000000 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/model/entity/ActivationRecovery.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2019 Wultra s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.getlime.security.powerauth.networking.model.entity; - -/** - * Activation recovery model class for recovery code and PUK. - * - * @author Roman Strobl, roman.strobl@wultra.com - */ -public class ActivationRecovery { - - private String recoveryCode; - private String puk; - - /** - * Get recovery code. - * @return Recovery code. - */ - public String getRecoveryCode() { - return recoveryCode; - } - - /** - * Set recovery code. - * @param recoveryCode Recovery code. - */ - public void setRecoveryCode(String recoveryCode) { - this.recoveryCode = recoveryCode; - } - - /** - * Get recovery PUK. - * @return Recovery PUK. - */ - public String getPuk() { - return puk; - } - - /** - * Set recovery PUK. - * @param puk Recovery PUK. - */ - public void setPuk(String puk) { - this.puk = puk; - } -} \ No newline at end of file diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/model/entity/ActivationType.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/model/entity/ActivationType.java index 2db45861..bc75c9bd 100644 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/model/entity/ActivationType.java +++ b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/model/entity/ActivationType.java @@ -23,6 +23,5 @@ public enum ActivationType { CODE, DIRECT, - CUSTOM, - RECOVERY + CUSTOM } diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/model/request/ConfirmRecoveryRequestPayload.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/model/request/ConfirmRecoveryRequestPayload.java deleted file mode 100644 index c28c3c68..00000000 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/model/request/ConfirmRecoveryRequestPayload.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2019 Wultra s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.getlime.security.powerauth.networking.model.request; - -/** - * Request object for confirm recovery code ECIES payload. - * - * @author Roman Strobl, roman.strobl@wultra.com - * - */ -public class ConfirmRecoveryRequestPayload { - - private String recoveryCode; - - /** - * Get recovery code. - * @return Recovery code. - */ - public String getRecoveryCode() { - return recoveryCode; - } - - /** - * Set recovery code. - * @param recoveryCode Recovery code. - */ - public void setRecoveryCode(String recoveryCode) { - this.recoveryCode = recoveryCode; - } -} \ No newline at end of file diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/model/response/ActivationLayer2Response.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/model/response/ActivationLayer2Response.java index 3f828f7b..37e01df1 100644 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/model/response/ActivationLayer2Response.java +++ b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/model/response/ActivationLayer2Response.java @@ -15,8 +15,6 @@ */ package io.getlime.security.powerauth.networking.model.response; -import io.getlime.security.powerauth.networking.model.entity.ActivationRecovery; - /** * Response object for activation layer 2. * @@ -28,7 +26,6 @@ public class ActivationLayer2Response { private String activationId; private String serverPublicKey; private String ctrData; - private ActivationRecovery activationRecovery; /** * Get activation ID. @@ -77,21 +74,4 @@ public String getCtrData() { public void setCtrData(String ctrData) { this.ctrData = ctrData; } - - /** - * Get activation recovery information. - * @return Activation recovery information. - */ - public ActivationRecovery getActivationRecovery() { - return activationRecovery; - } - - /** - * Set activation recovery information. - * @param activationRecovery Activation recovery information. - */ - public void setActivationRecovery(ActivationRecovery activationRecovery) { - this.activationRecovery = activationRecovery; - } - } diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/model/response/ConfirmRecoveryResponsePayload.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/model/response/ConfirmRecoveryResponsePayload.java deleted file mode 100644 index 142f8084..00000000 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/model/response/ConfirmRecoveryResponsePayload.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2019 Wultra s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.getlime.security.powerauth.networking.model.response; - -/** - * Response object for confirm recovery code ECIES payload. - * - * @author Roman Strobl, roman.strobl@wultra.com - * - */ -public class ConfirmRecoveryResponsePayload { - - private boolean alreadyConfirmed; - - /** - * Get whether recovery code was already confirmed. - * @return Whether recovery code was already confirmed. - */ - public boolean getAlreadyConfirmed() { - return alreadyConfirmed; - } - - /** - * Set whether recovery code was already confirmed. - * @param alreadyConfirmed Whether recovery code was already confirmed. - */ - public void setAlreadyConfirmed(boolean alreadyConfirmed) { - this.alreadyConfirmed = alreadyConfirmed; - } -} \ No newline at end of file diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/response/CreateActivationResult.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/response/CreateActivationResult.java index d9fbf4c8..96b15bbb 100644 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/response/CreateActivationResult.java +++ b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/response/CreateActivationResult.java @@ -21,8 +21,6 @@ import java.util.Map; -import io.getlime.security.powerauth.core.RecoveryData; - /** * The {@code CreateActivationResult} class represents result of activation creation process. * You can typically obtain this object in {@link ICreateActivationListener#onActivationCreateSucceed(CreateActivationResult)} @@ -42,12 +40,6 @@ public class CreateActivationResult { */ private final @Nullable Map customActivationAttributes; - /** - * Optional information about activation recovery. The value may be null in case that feature - * is not supported, or not enabled on the server. - */ - private final @Nullable RecoveryData recoveryData; - /** * Optional information about user. The value may be null in case that feature is not supported * on the server. @@ -60,20 +52,15 @@ public class CreateActivationResult { * identifier. * @param customActivationAttributes Custom attributes received from the server. The value may * be null in case that there are no custom attributes available. - * @param recoveryData {@link RecoveryData} object with information about activation - * recovery. The value may be null if feature is not supported, - * or configured on the server. * @param userInfo {@link UserInfo} object with optional information * about user. */ public CreateActivationResult( @NonNull String activationFingerprint, @Nullable Map customActivationAttributes, - @Nullable RecoveryData recoveryData, @Nullable UserInfo userInfo) { this.activationFingerprint = activationFingerprint; this.customActivationAttributes = customActivationAttributes; - this.recoveryData = recoveryData; this.userInfo = userInfo; } @@ -93,21 +80,6 @@ public CreateActivationResult( return customActivationAttributes; } - /** - * Returns object containing information about activation recovery. - * - * If supported and enabled on the server, then the object contains "Recovery Code" and PUK, - * created for this particular activation. Your application should display that values to the user - * and forget the values immediately. You should NEVER store values from the object persistently - * on the device. - * - * @return {@link RecoveryData} object with information about activation recovery. The value - * may be null if feature is not supported, or configured on the server. - */ - public @Nullable RecoveryData getRecoveryData() { - return recoveryData; - } - /** * @return {@link UserInfo} with optional information about user. The value is available * only if the server provide such information about the user. diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/response/IConfirmRecoveryCodeListener.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/response/IConfirmRecoveryCodeListener.java deleted file mode 100644 index 999a5553..00000000 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/response/IConfirmRecoveryCodeListener.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2019 Wultra s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.getlime.security.powerauth.networking.response; - -import androidx.annotation.MainThread; -import androidx.annotation.NonNull; - -/** - * Listener for confirming recovery code. - */ -public interface IConfirmRecoveryCodeListener { - /** - * Called when recovery code confirmation succeeds. - * - * @param alreadyConfirmed true if recovery code has been already confirmed. - */ - @MainThread - void onRecoveryCodeConfirmed(boolean alreadyConfirmed); - - /** - * Called when recovery code confirmation fails. - * - * @param t error that occurred during the confirmation. - */ - @MainThread - void onRecoveryCodeConfirmFailed(@NonNull Throwable t); -} diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/response/IGetRecoveryDataListener.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/response/IGetRecoveryDataListener.java deleted file mode 100644 index f6d4ac4d..00000000 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/networking/response/IGetRecoveryDataListener.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2019 Wultra s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.getlime.security.powerauth.networking.response; - -import androidx.annotation.MainThread; -import androidx.annotation.NonNull; - -import io.getlime.security.powerauth.core.RecoveryData; - -/** - * Listener for getting recovery activation data. - */ -public interface IGetRecoveryDataListener { - - /** - * Called when getting activation recovery data succeeds. - * - * @param recoveryData {@link RecoveryData} object with activation recovery infomation. - */ - @MainThread - void onGetRecoveryDataSucceeded(@NonNull RecoveryData recoveryData); - - /** - * Called when operation fails. - * - * @param t error that occurred during the operation. - */ - @MainThread - void onGetRecoveryDataFailed(@NonNull Throwable t); -} diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/sdk/PowerAuthActivation.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/sdk/PowerAuthActivation.java index 1180398d..67fd22ff 100644 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/sdk/PowerAuthActivation.java +++ b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/sdk/PowerAuthActivation.java @@ -151,18 +151,6 @@ private Builder(@NonNull ActivationType activationType, return customActivation(identityAttributes, null); } - /** - * Construct a {@link Builder} object with recovery activation code and PUK. - * - * @param recoveryCode Recovery code, obtained either via QR code scanning or by manual entry. - * @param puk PUK obtained by manual entry. - * @return {@link Builder} instance. - * @throws PowerAuthErrorException In case that recovery code or PUK is invalid. - */ - public static @NonNull Builder recoveryActivation(@NonNull String recoveryCode, @NonNull String puk) throws PowerAuthErrorException { - return recoveryActivation(recoveryCode, puk, null); - } - // Obsolete methods (will be deprecated in some future version) /** @@ -208,33 +196,6 @@ private Builder(@NonNull ActivationType activationType, return new Builder(ActivationType.CUSTOM, identityAttributes, activationName, null); } - /** - * Construct a {@link Builder} object with recovery activation code and PUK. - *

    - * The activation's name parameter is optional, but recommended to set. You can use the value obtained from - * {@code Settings.System.getString(getContentResolver(), "device_name")} or let the user set the name. - * The name of activation will be associated with an activation record on PowerAuth Server. - * - * @param recoveryCode Recovery code, obtained either via QR code scanning or by manual entry. - * @param puk PUK obtained by manual entry. - * @param activationName Activation name to be used for the activation. - * @return {@link Builder} instance. - * @throws PowerAuthErrorException In case that recovery code or PUK is invalid. - */ - public static @NonNull Builder recoveryActivation(@NonNull String recoveryCode, @NonNull String puk, @Nullable String activationName) throws PowerAuthErrorException { - final ActivationCode code = ActivationCodeUtil.parseFromRecoveryCode(recoveryCode); - if (code == null) { - throw new PowerAuthErrorException(PowerAuthErrorCodes.INVALID_ACTIVATION_CODE, "Invalid recovery code"); - } - if (!ActivationCodeUtil.validateRecoveryPuk(puk)) { - throw new PowerAuthErrorException(PowerAuthErrorCodes.INVALID_ACTIVATION_CODE, "Invalid recovery PUK"); - } - final Map identityAttributes = new HashMap<>(2); - identityAttributes.put("recoveryCode", code.activationCode); - identityAttributes.put("puk", puk); - return new Builder(ActivationType.RECOVERY, identityAttributes, activationName, null); - } - // Activation object customization /** diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/sdk/PowerAuthSDK.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/sdk/PowerAuthSDK.java index 0c194e0d..f7583712 100644 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/sdk/PowerAuthSDK.java +++ b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/sdk/PowerAuthSDK.java @@ -49,7 +49,6 @@ import io.getlime.security.powerauth.networking.interfaces.ICancelable; import io.getlime.security.powerauth.networking.interfaces.IExecutorProvider; import io.getlime.security.powerauth.networking.interfaces.INetworkResponseListener; -import io.getlime.security.powerauth.networking.model.entity.ActivationRecovery; import io.getlime.security.powerauth.networking.model.request.*; import io.getlime.security.powerauth.networking.model.response.*; import io.getlime.security.powerauth.networking.response.*; @@ -734,20 +733,13 @@ public void onNetworkResponse(@NonNull ActivationLayer1Response response) { final EciesEncryptor encryptor = endpointDefinition.getLayer2Encryptor(); final ActivationLayer2Response layer2Response = serialization.decryptObjectFromResponse(response.getActivationData(), encryptor, TypeToken.get(ActivationLayer2Response.class)); // Prepare Step2 param for low level session - final RecoveryData recoveryData; - if (layer2Response.getActivationRecovery() != null) { - final ActivationRecovery rd = layer2Response.getActivationRecovery(); - recoveryData = new RecoveryData(rd.getRecoveryCode(), rd.getPuk()); - } else { - recoveryData = null; - } - final ActivationStep2Param step2Param = new ActivationStep2Param(layer2Response.getActivationId(), layer2Response.getServerPublicKey(), layer2Response.getCtrData(), recoveryData); + final ActivationStep2Param step2Param = new ActivationStep2Param(layer2Response.getActivationId(), layer2Response.getServerPublicKey(), layer2Response.getCtrData()); // Validate the response final ActivationStep2Result step2Result = mSession.validateActivationResponse(step2Param); // if (step2Result.errorCode == ErrorCode.OK) { final UserInfo userInfo = response.getUserInfo() != null ? new UserInfo(response.getUserInfo()) : null; - final CreateActivationResult result = new CreateActivationResult(step2Result.activationFingerprint, response.getCustomAttributes(), recoveryData, userInfo); + final CreateActivationResult result = new CreateActivationResult(step2Result.activationFingerprint, response.getCustomAttributes(), userInfo); setLastFetchedUserInfo(userInfo); listener.onActivationCreateSucceed(result); return; @@ -870,39 +862,6 @@ public void run() { } } - - /** - * Create a new recovery activation with given name, recovery code and puk, by calling a PowerAuth Standard RESTful API. - * - * @param name Activation name, for example "John's iPhone". - * @param recoveryCode Recovery code, obtained either via QR code scanning or by manual entry. - * @param puk Recovery PUK, obtained by manual entry - * @param extras Extra attributes of the activation, used for application specific purposes (for example, info about the client device or system). The attribute is visible only for PowerAuth Server. - * @param customAttributes Extra attributes of the activation, used for application specific purposes. Unlike the {code extras} parameter, this dictionary is visible for the Application Server. - * @param listener A callback listener called when the process finishes - it contains an activation fingerprint in case of success or error in case of failure. - * @return {@link ICancelable} object associated with the running HTTP request. - * @throws PowerAuthMissingConfigException thrown in case configuration is not present. - */ - public @Nullable - ICancelable createRecoveryActivation(@Nullable String name, @NonNull String recoveryCode, @NonNull String puk, @Nullable String extras, @Nullable Map customAttributes, @NonNull final ICreateActivationListener listener) { - try { - final PowerAuthActivation activation = PowerAuthActivation.Builder.recoveryActivation(recoveryCode, puk, name) - .setExtras(extras) - .setCustomAttributes(customAttributes) - .build(); - return createActivation(activation, listener); - - } catch (final PowerAuthErrorException e) { - dispatchCallback(new Runnable() { - @Override - public void run() { - listener.onActivationCreateFailed(e); - } - }); - return null; - } - } - // // Persist activation // @@ -2453,115 +2412,6 @@ void dispatchCallback(@NonNull Runnable runnable) { } - // Recovery codes - - /** - * @return true if underlying session contains an activation recovery data. - * @throws PowerAuthMissingConfigException thrown in case configuration is not present. - */ - public boolean hasActivationRecoveryData() { - checkForValidSetup(); - return mSession.hasActivationRecoveryData(); - } - - /** - * Get an activation recovery data. This method calls PowerAuth Standard RESTful API endpoint '/pa/vault/unlock' to obtain the vault - * encryption key used for private recovery data decryption. - * - * @param context Android {@link Context} object - * @param authentication Authentication used for vault unlocking call. - * @param listener The callback called when operation succeeds or fails. - * @return {@link ICancelable} object associated with the running HTTP request. - * @throws PowerAuthMissingConfigException thrown in case configuration is not present. - */ - public @Nullable - ICancelable getActivationRecoveryData(@NonNull final Context context, @NonNull final PowerAuthAuthentication authentication, @NonNull final IGetRecoveryDataListener listener) { - - if (!mSession.hasActivationRecoveryData()) { - dispatchCallback(new Runnable() { - @Override - public void run() { - listener.onGetRecoveryDataFailed(new PowerAuthErrorException(PowerAuthErrorCodes.INVALID_ACTIVATION_STATE, "Session has no recovery data available.")); - } - }); - return null; - } - - return fetchEncryptedVaultUnlockKey(context, authentication, VaultUnlockReason.RECOVERY_CODE, new IFetchEncryptedVaultUnlockKeyListener() { - @Override - public void onFetchEncryptedVaultUnlockKeySucceed(String encryptedEncryptionKey) { - final SignatureUnlockKeys keys = signatureKeysForAuthentication(context, authentication); - final RecoveryData recoveryData = mSession.getActivationRecoveryData(encryptedEncryptionKey, keys); - if (recoveryData != null) { - listener.onGetRecoveryDataSucceeded(recoveryData); - } else { - listener.onGetRecoveryDataFailed(new PowerAuthErrorException(PowerAuthErrorCodes.ENCRYPTION_ERROR, "Cannot decrypt recovery data.")); - } - } - - @Override - public void onFetchEncryptedVaultUnlockKeyFailed(Throwable throwable) { - listener.onGetRecoveryDataFailed(throwable); - } - }); - } - - /** - * Confirm given recovery code on the server. - * - * The method is useful for situations when user receives a recovery information via OOB channel (for example via postcard). Such - * recovery codes cannot be used without a proper confirmation on the server. To confirm codes, user has to authenticate himself - * with a knowledge factor. - * - * Note that the provided recovery code can contain a `"R:"` prefix, if it's scanned from QR code. - * - * @param context Android {@link Context} object - * @param authentication Authentication used for recovery code confirmation. The knowledge factor is required. - * @param recoveryCode Recovery code, obtained either via QR code scanning or by manual entry. - * @param listener The callback called when operation succeeds or fails. - * @return {@link ICancelable} object associated with the running HTTP request. - * @throws PowerAuthMissingConfigException thrown in case configuration is not present. - */ - public @Nullable - ICancelable confirmRecoveryCode(@NonNull final Context context, @NonNull final PowerAuthAuthentication authentication, @NonNull String recoveryCode, @NonNull final IConfirmRecoveryCodeListener listener) { - - // Validate recovery code - final ActivationCode code = ActivationCodeUtil.parseFromRecoveryCode(recoveryCode); - if (code == null) { - dispatchCallback(new Runnable() { - @Override - public void run() { - listener.onRecoveryCodeConfirmFailed(new PowerAuthErrorException(PowerAuthErrorCodes.INVALID_ACTIVATION_CODE)); - } - }); - return null; - } - - // Execute HTTP request - final ConfirmRecoveryRequestPayload request = new ConfirmRecoveryRequestPayload(); - request.setRecoveryCode(code.activationCode); - return mClient.post( - request, - new ConfirmRecoveryCodeEndpoint(), - getCryptoHelper(context), - authentication, - new INetworkResponseListener() { - @Override - public void onNetworkResponse(@NonNull ConfirmRecoveryResponsePayload confirmRecoveryResponsePayload) { - listener.onRecoveryCodeConfirmed(confirmRecoveryResponsePayload.getAlreadyConfirmed()); - } - - @Override - public void onNetworkError(@NonNull Throwable throwable) { - listener.onRecoveryCodeConfirmFailed(throwable); - } - - @Override - public void onCancel() { - } - }); - } - // External Encryption key /** diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/sdk/impl/VaultUnlockReason.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/sdk/impl/VaultUnlockReason.java index fbfc65ea..7000f7f8 100644 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/sdk/impl/VaultUnlockReason.java +++ b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/sdk/impl/VaultUnlockReason.java @@ -28,7 +28,7 @@ * Constants for Vault Unlock reasons. */ @Retention(RetentionPolicy.SOURCE) -@StringDef({ADD_BIOMETRY, FETCH_ENCRYPTION_KEY, SIGN_WITH_DEVICE_PRIVATE_KEY, RECOVERY_CODE}) +@StringDef({ADD_BIOMETRY, FETCH_ENCRYPTION_KEY, SIGN_WITH_DEVICE_PRIVATE_KEY}) public @interface VaultUnlockReason { /** @@ -43,8 +43,4 @@ * Sign with device private key is the reason for vault unlock. */ String SIGN_WITH_DEVICE_PRIVATE_KEY = "SIGN_WITH_DEVICE_PRIVATE_KEY"; - /** - * Get recovery code is the reason for vault unlock. - */ - String RECOVERY_CODE = "RECOVERY_CODE"; } From 47a33c06e3bbcdaa081deef9097fea5c4e3cf279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juraj=20=C4=8Eurech?= Date: Thu, 16 Jan 2025 14:51:23 +0100 Subject: [PATCH 04/10] Android: Fixed various lint warnings --- .../powerauth/core/SignatureResult.java | 2 +- .../powerauth/keychain/KeychainFactory.java | 21 ++++++++++++------- .../keychain/KeychainProtection.java | 2 +- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/SignatureResult.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/SignatureResult.java index 059920bd..d7459099 100644 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/SignatureResult.java +++ b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/core/SignatureResult.java @@ -45,7 +45,7 @@ public class SignatureResult { * Constructor used from JNI code. */ public SignatureResult() { - this.errorCode = 0; + this.errorCode = ErrorCode.OK; this.authHeaderValue = null; this.signatureCode = null; } diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/keychain/KeychainFactory.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/keychain/KeychainFactory.java index 337f19f6..391aa60c 100644 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/keychain/KeychainFactory.java +++ b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/keychain/KeychainFactory.java @@ -155,7 +155,12 @@ static void setKeychainProtectionSupport(@Nullable KeychainProtectionSupport key @NonNull private static Keychain createKeychain(@NonNull Context context, @NonNull SharedData sharedData, @NonNull String identifier) { final SharedPreferences preferences = context.getSharedPreferences(identifier, Context.MODE_PRIVATE); - final boolean isAlreadyEncrypted = EncryptedKeychain.isEncryptedContentInSharedPreferences(preferences); + final boolean isAlreadyEncrypted; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + isAlreadyEncrypted = EncryptedKeychain.isEncryptedContentInSharedPreferences(preferences); + } else { + isAlreadyEncrypted = false; + } final int keychainProtection = sharedData.getKeychainProtection(context); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (keychainProtection != KeychainProtection.NONE || isAlreadyEncrypted) { @@ -181,10 +186,12 @@ private static Keychain createKeychain(@NonNull Context context, @NonNull Shared // Otherwise just return the legacy keychain. final Keychain keychain = new LegacyKeychain(context, identifier); - if (EncryptedKeychain.isEncryptedContentInSharedPreferences(preferences)) { - // Print error in case that keychain was previously encrypted and now it's not. - PowerAuthLog.e("KeychainFactory: " + identifier + ": The content was previously encrypted but the encryption is no longer available."); - keychain.removeAll(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (EncryptedKeychain.isEncryptedContentInSharedPreferences(preferences)) { + // Print error in case that keychain was previously encrypted and now it's not. + PowerAuthLog.e("KeychainFactory: " + identifier + ": The content was previously encrypted but the encryption is no longer available."); + keychain.removeAll(); + } } return keychain; } @@ -225,7 +232,7 @@ private static class SharedData { * Contains {@code 0} if keychain protection level is not determined yet, or the determined * level of {@link KeychainProtection}. */ - private @KeychainProtection int keychainProtection; + private int keychainProtection; /** * @return Map containing an already instantiated keychain objects. @@ -371,7 +378,7 @@ SymmetricKeyProvider getBackupEncryptionKeyProvider(@NonNull Context context) { } } // If keychain protection is still undetermined, then it means that some operation - // above failed. So, we have to fallback to NONE. + // above failed. So, we have to fall back to NONE. if (keychainProtection == 0) { keychainProtection = KeychainProtection.NONE; } diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/keychain/KeychainProtection.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/keychain/KeychainProtection.java index 917b35a7..31539598 100644 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/keychain/KeychainProtection.java +++ b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/keychain/KeychainProtection.java @@ -63,7 +63,7 @@ /** * The content of the keychain is encrypted with key generated by Android KeyStore and the key - * is stored inside of Secure Element (e.g. StrongBox). This is the highest level of Keychain + * is stored inside Secure Element (e.g. StrongBox). This is the highest level of Keychain * protection currently available. */ int STRONGBOX = 4; From 26f64714b6608dc3e5b7116edb84c08429ac23ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juraj=20=C4=8Eurech?= Date: Thu, 16 Jan 2025 14:51:42 +0100 Subject: [PATCH 05/10] docs: Added 1.10 and 2.0 migration guides --- docs/Migration-from-1.10-to-2.0.md | 43 ++++++++++++++++ docs/Migration-from-1.9-to-1.10.md | 79 ++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 docs/Migration-from-1.10-to-2.0.md create mode 100644 docs/Migration-from-1.9-to-1.10.md diff --git a/docs/Migration-from-1.10-to-2.0.md b/docs/Migration-from-1.10-to-2.0.md new file mode 100644 index 00000000..cb62bf46 --- /dev/null +++ b/docs/Migration-from-1.10-to-2.0.md @@ -0,0 +1,43 @@ +# Migration from 1.10.x to 2.0.x + +PowerAuth Mobile SDK in version `2.0.0` provides the following improvements: + +- TBA + +### Compatibility with PowerAuth Server + +- This release is fully compatible with PowerAuth Server version `2.0.0` and newer. + +## Android + +### API changes + +- Removed all interfaces deprecated in release `1.10.x` + +### Other changes + +- TBA + +## iOS & tvOS + +### API changes + +- Removed all interfaces deprecated in release `1.10.x` + +### Other changes + +- TBA + +## iOS & tvOS App Extensions + +- Removed all interfaces deprecated in release `1.10.x` + +## Known Bugs + +The PowerAuth SDKs for iOS and tvOS App Extensions, as well as for watchOS, do not use time synchronized with the server for token-based authentication. To avoid any compatibility issues with the server, the authentication headers generated in your App Extension or on watchOS still use the older protocol version 3.1. This issue will be fixed in a future SDK update. + +You can watch the following related issues: + +- [wultra/powerauth-mobile-sdk#551](https://github.com/wultra/powerauth-mobile-sdk/issues/551) +- [wultra/powerauth-mobile-watch-sdk#7](https://github.com/wultra/powerauth-mobile-watch-sdk/issues/7) +- [wultra/powerauth-mobile-extensions-sdk#7](https://github.com/wultra/powerauth-mobile-extensions-sdk/issues/7) \ No newline at end of file diff --git a/docs/Migration-from-1.9-to-1.10.md b/docs/Migration-from-1.9-to-1.10.md new file mode 100644 index 00000000..38db733e --- /dev/null +++ b/docs/Migration-from-1.9-to-1.10.md @@ -0,0 +1,79 @@ +# Migration from 1.9.x to 1.10.x + +PowerAuth Mobile SDK in version `1.10.0` provides the following improvements: + +- Removed support of activation by recovery code. + + +### Compatibility with PowerAuth Server + +- This release is fully compatible with PowerAuth Server version `1.9.0` and newer. + +## Android + +### API changes + +- Due to removed support of recovery codes, the following classes and methods are no longer available: + - Methods removed in `PowerAuthSDK`: + - `createRecoveryActivation()` + - `hasActivationRecoveryData()` + - `getActivationRecoveryData()` + - `confirmRecoveryCode()` + - Methods removed in `PowerAuthActivation.Builder`: + - all variants of `recoveryActivation()` + - Methods removed in `ActivationCodeUtil`: + - `parseFromRecoveryCode()` + - `validateRecoveryCode()` + - `validateRecoveryPuk()` + - Other removed methods: + - `CreateActivationResult.getRecoveryData()` + - `ErrorResponseApiException.getCurrentRecoveryPukIndex()` + - Removed classes and interfaces: + - `IGetRecoveryDataListener` + - `IConfirmRecoveryCodeListener` + - `RecoveryData` + +- Removed all interfaces deprecated in release `1.9.x` + +### Other changes + +- TBA + +## iOS & tvOS + +### API changes + +- Due to removed support of recovery codes, the following classes and methods are no longer available: + - Methods removed in `PowerAuthSDK`: + - `createActivation(withName:, recoveryCode:, recoveryPuk:, extras:, callback:)` + - `hasActivationRecoveryData()` + - `activationRecoveryData(authentication:, callback:)` + - `confirm(recoveryCode:, authentication:, callback:)` + - Methods removed in `PowerAuthActivationCodeUtil`: + - `validateRecoveryCode()` + - `validateRecoveryPuk()` + - `parseFromRecoveryCode()` + - Other changes: + - removed class `PowerAuthActivationRecoveryData` + - removed property `PowerAuthActivationResult.activationRecovery` + - removed constructor `PowerAuthActivation(recoveryCode:, recoveryPuk:, name:)` + +- Removed all interfaces deprecated in release `1.9.x` + +### Other changes + +- TBA + +## iOS & tvOS App Extensions + +- Removed all interfaces deprecated in release `1.9.x` + +## Known Bugs + +The PowerAuth SDKs for iOS and tvOS App Extensions, as well as for watchOS, do not use time synchronized with the server for token-based authentication. To avoid any compatibility issues with the server, the authentication headers generated in your App Extension or on watchOS still use the older protocol version 3.1. This issue will be fixed in a future SDK update. + +You can watch the following related issues: + +- [wultra/powerauth-mobile-sdk#551](https://github.com/wultra/powerauth-mobile-sdk/issues/551) +- [wultra/powerauth-mobile-watch-sdk#7](https://github.com/wultra/powerauth-mobile-watch-sdk/issues/7) +- [wultra/powerauth-mobile-extensions-sdk#7](https://github.com/wultra/powerauth-mobile-extensions-sdk/issues/7) \ No newline at end of file From ba44c3fdf55f7e2c8ac9d262d328a0033de3a86d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juraj=20=C4=8Eurech?= Date: Fri, 17 Jan 2025 09:55:05 +0100 Subject: [PATCH 06/10] build: Fixed not-supported macOS platform in build pipeline --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6f4a0ffa..d051fe85 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,7 +13,7 @@ on: jobs: build: name: Build - runs-on: macos-12 + runs-on: macos-15 steps: - name: Checkout the repo uses: actions/checkout@v3 From b05d2b71fcd95d47eccf2b8fae259749d8a8d860 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juraj=20=C4=8Eurech?= Date: Fri, 17 Jan 2025 10:45:53 +0100 Subject: [PATCH 07/10] docs: Activation data sharing in one place Fix #628 --- docs/PowerAuth-SDK-for-iOS.md | 78 ++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 6 deletions(-) diff --git a/docs/PowerAuth-SDK-for-iOS.md b/docs/PowerAuth-SDK-for-iOS.md index 5fd7996c..507f6f4d 100644 --- a/docs/PowerAuth-SDK-for-iOS.md +++ b/docs/PowerAuth-SDK-for-iOS.md @@ -1693,17 +1693,62 @@ You can remove EEK from an existing activation if the key is no longer required. ## Share Activation Data -This chapter explains how to share the `PowerAuthSDK` activation state between multiple applications from the same vendor, or between application and its extensions. Before you start, you should read [Prepare Data Sharing](PowerAuth-SDK-for-iOS-Extensions.md#prepare-data-sharing) chapter from PowerAuth SDK for iOS Extensions to configure *Keychain Sharing* and *App Groups* in your Xcode project. +This chapter explains how to share the `PowerAuthSDK` activation state between application and its extensions, or between multiple applications from the same vendor. This feature is not supported on the macOS Catalyst platform. +### Prepare Activation Data Sharing + +The App Extension normally doesn't have access to data created by the main application, so the first step is to set up data sharing for your project. + +#### Keychain Sharing + +iOS SDK stores its most sensitive data into the iOS keychain, so you need to configure the keychain sharing first. If you're not familiar with keychain sharing, then don't worry about that, the keychain is shared only between the vendor's applications. So the sensitive information is not exposed to 3rd party applications. + +1. Select your application project in the **Project Navigator** to navigate to the target configuration window and select the applications's target under the **TARGETS** heading in the sidebar. +2. Now select **Signing & Capabilities** tab and click **+ Capability** button. +3. Find and add **Keychain Sharing** capability. +4. Click "+" in just created **Keychain Sharing** capability and Xcode will predefine first **Keychain Group** to your application's bundle name. Let's call this value as `KEYCHAIN_GROUP_NAME` + + +The predefined group is usually beneficial because iOS is by default using that group for storing all keychain entries created in the application. So, If your application is already using PowerAuth and you're going to just add extension support, then this is the most simple way to set up a keychain sharing. + + +Now you have to do a similar setup for your application's extension: + +5. Select your application project in the **Project Navigator** to navigate to the target configuration window and select the extensions's target under the **TARGETS** heading in the sidebar. +6. Select **Signing & Capabilities** tab and click **+ Capability** button. +7. Find and add **Keychain Sharing** capability. +8. Click "+" in just created **Keychain Sharing** capability and add the same `KEYCHAIN_GROUP_NAME` as you did for the application's target. +9. (optional) Repeat steps 4 to 6 for all other extensions which supposed to use shared activation data. + +Now you need to know your **Team ID** (the unique identifier assigned to your team by Apple). Unfortunately, the identifier is not simply visible in Xcode, so you'll have to log in to Apple's [development portal](http://developer.apple.com/account) and look for that identifier on your membership details page. + +If you know the Team ID, then the final `KEYCHAIN_GROUP_IDENTIFIER` constant is composed as `TEAM_ID.KEYCHAIN_GROUP_NAME`. So, it should look like: `KTT00000MR.com.powerauth.demo.App`. + +#### App Groups + +The PowerAuth SDK for iOS is using one boolean flag stored in the `UserDefaults` facility, to determine whether the application has been reinstalled. Unfortunately, the `UserDefaults.standard` created by the application cannot be shared with the app extension, so you have to create a new application group to share that data. + +1. Select your application project in the **Project Navigator** to navigate to the target configuration window and select the applications's target under the **TARGETS** heading in the sidebar. +2. Now select **Signing & Capabilities** tab and click **+ Capability** button. +3. Find and add **App Groups** capability. +3. Click "+" in just created **App Groups** capability add a group with the desired identifier and turn this particular group ON (e.g. make sure that the checkmark close to the group's name is selected). Let's call this value `APP_GROUP_IDENTIFIER`. If the group already exists, then just click the checkmark to turn it ON. +4. Now switch to the application's extension target, select the **Capabilities** tab, and also expand the **App Groups** section. +5. Turn "ON" **App Groups** for extension and add an app group with the same name as you did in step 3. + +You can optionally check a troubleshooting section if you need to [migrate the keychain initialization flag](#userdefaults-migration) from standard user defaults to a shared one. + ### Configure Activation Data Sharing To share the activation's state just assign an instance of the `PowerAuthSharingConfiguration` object into `PowerAuthConfiguration`: ```swift +// Keychain sharing and App Group constants +let keychainSharing = "KTT00000MR.com.powerauth.demo.App" // KEYCHAIN_GROUP_IDENTIFIER constant +let appGroup = "group.your.app.group" // APP_GROUP_IDENTIFIER constant // Prepare the configuration let configuration = PowerAuthConfiguration( instanceId: Bundle.main.bundleIdentifier!, @@ -1711,9 +1756,9 @@ let configuration = PowerAuthConfiguration( configuration: "ARDDj6EB6iAUtNm...KKEcBxbnH9bMk8Ju3K1wmjbA==") // Assign sharing configuration configuration.sharingConfiguration = PowerAuthSharingConfiguration( - appGroup: "group.your.app.group", + appGroup: appGroup, appIdentifier: "com.powerauth.demo.App", - keychainAccessGroup: "KTT00000MR.com.powerauth.demo.App") + keychainAccessGroup: keychainSharing) // Create a PowerAuthSDK instance let powerAuthSDK = PowerAuthSDK(configuration) @@ -1722,11 +1767,10 @@ let powerAuthSDK = PowerAuthSDK(configuration) The `PowerAuthSharingConfiguration` object contains the following properties: - `appGroup` is the name of the app group shared between your applications. Be aware, that the length of app group encoded in UTF-8, should not exceed 26 characters. See [troubleshooting](#length-of-application-group) section for more details. -- `appIdentifier` is an identifier unique across your all applications that are supposed to use the shared activation data. You can use your applications' bundle identifiers or any other identifier that can be then processed in all your applications. Due to technical limitations, the length of the identifier must not exceed 127 bytes, if represented in UTF-8. +- `appIdentifier` is an identifier unique across your all applications or extensions that are supposed to use the shared activation data. You can use your applications' bundle identifiers or any other identifier that can be then processed in all your applications. Due to technical limitations, the length of the identifier must not exceed 127 bytes, if represented in UTF-8. - `keychainAccessGroup` is an access group for keychain sharing. -Unlike the regular configuration the `instanceId` value in `PowerAuthConfiguration` should not be based on the application's bundle identifier. This is because all your applications must use the same identifier, so it's recommended to use some predefined constant string. - +Unlike the regular configuration the `instanceId` value in `PowerAuthConfiguration` should not be derived on the application's bundle identifier. This is because all applications and extensions that share PowerAuth data must use the same identifier. To ensure consistency, use a predefined constant string or an identifier based on the first application that integrated PowerAuth. This guarantees that all related components can access the same PowerAuth instance without conflicts. ### External pending operations @@ -2158,3 +2202,25 @@ The total length is limited to 31 characters, but the shared memory object name ``` You can extend the length of the application group slightly by providing your own `sharedMemoryIdentifier` in the `PowerAuthSharingConfiguration`. In theory, this allows you to use an app group name of up to 29 characters, leaving 1 character for the shared memory identifier. However, this is generally not recommended. A custom identifier should only be used if your application already employs shared memory and the SDK’s generated identifier conflicts with your existing shared memory objects. + +### UserDefaults Migration + +If your previous version of the application did not use shared data between the application and the extension, then you probably need to migrate the keychain status flag from `UserDefaults.standard` to a shared one. We recommend performing this migration at the main application's startup code and **BEFORE** the `PowerAuthSDK` object is configured and used: + +```swift +private func migrateUserDefaults(appGroup: String) { + guard let shared = UserDefaults(suiteName: appGroup) else { + fatalError("AppGroup is not configured properly") + } + if shared.bool(forKey: PowerAuthKeychain_Initialized) { + return // migration is not required + } + let standard = UserDefaults.standard + if standard.bool(forKey: PowerAuthKeychain_Initialized) { + standard.removeObject(forKey: PowerAuthKeychain_Initialized) + standard.synchronize() + shared.set(true, forKey: PowerAuthKeychain_Initialized) + shared.synchronize() + } +} +``` From c715c298e70e1956cedc4368161fe3c43eb8a2e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juraj=20=C4=8Eurech?= Date: Fri, 17 Jan 2025 10:55:03 +0100 Subject: [PATCH 08/10] docs: Remove iOS App Extensions documentation Fix #632 --- README.md | 1 - docs/Migration-from-1.9-to-1.10.md | 7 +- docs/PowerAuth-SDK-for-iOS-Extensions.md | 283 ----------------------- docs/PowerAuth-SDK-for-iOS.md | 23 +- docs/PowerAuth-SDK-for-watchOS.md | 23 -- docs/Readme.md | 1 - docs/_Sidebar.md | 1 - 7 files changed, 4 insertions(+), 335 deletions(-) delete mode 100644 docs/PowerAuth-SDK-for-iOS-Extensions.md diff --git a/README.md b/README.md index fd7f71bd..787b4a9d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ In order to connect to the [PowerAuth](https://www.wultra.com/product/powerauth- ## Integration Tutorials - [PowerAuth SDK for iOS and tvOS Apps](./docs/PowerAuth-SDK-for-iOS.md) -- [PowerAuth SDK for iOS and tvOS Extensions](./docs/PowerAuth-SDK-for-iOS-Extensions.md) - [PowerAuth SDK for watchOS](./docs/PowerAuth-SDK-for-watchOS.md) - [PowerAuth SDK for Android Apps](./docs/PowerAuth-SDK-for-Android.md) diff --git a/docs/Migration-from-1.9-to-1.10.md b/docs/Migration-from-1.9-to-1.10.md index 38db733e..b33cecf4 100644 --- a/docs/Migration-from-1.9-to-1.10.md +++ b/docs/Migration-from-1.9-to-1.10.md @@ -66,14 +66,13 @@ PowerAuth Mobile SDK in version `1.10.0` provides the following improvements: ## iOS & tvOS App Extensions -- Removed all interfaces deprecated in release `1.9.x` +- The `PowerAuth2ForExtensions` library is now deprecated and no longer supported and maintained. You can use full feature PowerAuth mobile SDK as a replacement in your app extension. ## Known Bugs -The PowerAuth SDKs for iOS and tvOS App Extensions, as well as for watchOS, do not use time synchronized with the server for token-based authentication. To avoid any compatibility issues with the server, the authentication headers generated in your App Extension or on watchOS still use the older protocol version 3.1. This issue will be fixed in a future SDK update. +The PowerAuth SDKs for watchOS, do not use time synchronized with the server for token-based authentication. To avoid any compatibility issues with the server, the authentication headers generated in your App Extension or on watchOS still use the older protocol version 3.1. This issue will be fixed in a future SDK update. You can watch the following related issues: - [wultra/powerauth-mobile-sdk#551](https://github.com/wultra/powerauth-mobile-sdk/issues/551) -- [wultra/powerauth-mobile-watch-sdk#7](https://github.com/wultra/powerauth-mobile-watch-sdk/issues/7) -- [wultra/powerauth-mobile-extensions-sdk#7](https://github.com/wultra/powerauth-mobile-extensions-sdk/issues/7) \ No newline at end of file +- [wultra/powerauth-mobile-watch-sdk#7](https://github.com/wultra/powerauth-mobile-watch-sdk/issues/7) \ No newline at end of file diff --git a/docs/PowerAuth-SDK-for-iOS-Extensions.md b/docs/PowerAuth-SDK-for-iOS-Extensions.md deleted file mode 100644 index 4c497b76..00000000 --- a/docs/PowerAuth-SDK-for-iOS-Extensions.md +++ /dev/null @@ -1,283 +0,0 @@ -# PowerAuth Mobile SDK for iOS and tvOS Extensions - - -## Table of Contents - -- [Introduction](#introduction) -- [Installation](#installation) - - [CocoaPods Installation](#cocoapods) - - [Manual Installation](#manual) -- [SDK Configuration](#configuration) - - [Prepare Data Sharing](#prepare-data-sharing) - - [Configure PowerAuth for Extension](#configure-powerauth-for-extension) -- [Getting Device Activation Status](#getting-device-activation-status) -- [Token-Based Authentication](#token-based-authentication) - - [Getting token](#getting-token) - - [Generating Authorization Header](#generating-authorization-header) - - [Removing Token Locally](#removing-token-locally) - - [Removing Token From the Server](#removing-tokenf-from-the-server) -- [Common SDK Tasks](#common-sdk-tasks) -- [Troubleshooting](#troubleshooting) - -Related documents: - -- [PowerAuth SDK for iOS](./PowerAuth-SDK-for-iOS.md) -- [PowerAuth SDK for watchOS](./PowerAuth-SDK-for-watchOS.md) - - -## Introduction - -The PowerAuth Mobile SDK Extensions library is a lightweight counterpart to the full-featured PowerAuth Mobile SDK, providing limited functionality, such as: - -- Retrieving information about activation presence -- Obtaining authentication tokens - -If you need to perform more operations in your extension, such as calculating [PowerAuth symmetric signatures](./PowerAuth-SDK-for-iOS.md#symmetric-multi-factor-signature), you can use the full-featured [PowerAuth mobile SDK](./PowerAuth-SDK-for-iOS.md). This can be achieved by configuring [activation data sharing](./PowerAuth-SDK-for-iOS.md#share-activation-data) in both your application and the extension. - -## Installation - -This chapter describes how to get PowerAuth SDK for iOS and tvOS Extensions up and running in your app. In the current version, you can choose between CocoaPods and manual library integration. Both types of installation will lead to your app extension linked with a dynamic library, provided by the `PowerAuth2ForExtensions.[xc]framework`. - -To distinguish between SDKs, the following short terms will be used in this document: - -- **iOS SDK**, as short term for *PowerAuth SDK for iOS and tvOS* -- **Extensions SDK** as short term for *PowerAuth SDK for iOS and tvOS Extensions* - -### CocoaPods - -[CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command: -```bash -$ gem install cocoapods -``` - -To integrate the PowerAuth library into your Xcode project using CocoaPods, specify it in your `Podfile`: -```ruby -platform :ios, '11.0' - -target 'YourAppTarget' do - pod 'PowerAuth2' -end - -target 'YourExtensionTarget' do - pod 'PowerAuth2ForExtensions' -end -``` - -Then, run the following command: -```bash -$ pod install -``` - -### Manual - -If you prefer not to use CocoaPods as a dependency manager, you can integrate Extensions SDK into your project manually as a git [submodule](http://git-scm.com/docs/git-submodule). - -#### Git Submodules - -The integration process is quite similar to the integration of our iOS library: - -1. Open up the Terminal.app and go to your top-level project directory and add the library as a submodule: - ```sh - $ git submodule add https://github.com/wultra/powerauth-mobile-sdk.git PowerAuthLib - $ git submodule update --init --recursive - ``` - The first command will clone PowerAuth SDK into the `PowerAuthLib` folder and the second, will update all nested submodules. We're expecting that you already did this when you integrated PowerAuth into your application. - -2. Open the new `PowerAuthLib` folder, and go to the `proj-xcode` sub-folder -3. Drag the `PowerAuthExtensionSdk.xcodeproj` project file into **Project Navigator** of your application's Xcode project. It should appear nested underneath your application's blue project icon. -4. Select your application project in the Project Navigator to navigate to the target configuration window and select the extension's target under the **TARGETS** heading in the sidebar. -5. Now select **Build Phases** tab and expand **Target Dependencies** section. Click on the "Plus Sign" and choose **"PowerAuth2ForExtensions"** framework from the **"PowerAuthExtensionSdk"** project. -6. Next, in the same **Build Phases** tab expand **Link With Libraries** section. Click on the "Plus Sign" and choose **"PowerAuth2ForExtensions.framework"** from the **"PowerAuthExtensionSdk"** project. - - - -## Configuration - -The Extensions SDK shares several source codes and configuration principles with the main iOS SDK. So, you can prepare the same set of constants as you're already using in your IOS application. The SDK provides just a limited functionality for app extension (for example, you cannot create an activation or calculate a full PowerAuth signature from an extension) and to do that it requires access to an activation data, created in the main application. - -### Prepare Data Sharing - -The App Extension normally doesn't have access to data created by the main application, so the first step is to set up data sharing for your project. - -#### Keychain Sharing - -iOS SDK stores its most sensitive data into the iOS keychain, so you need to configure the keychain sharing first. If you're not familiar with keychain sharing, then don't worry about that, the keychain is shared only between the vendor's applications. So the sensitive information is not exposed to 3rd party applications. - -1. Select your application project in the **Project Navigator** to navigate to the target configuration window and select the applications's target under the **TARGETS** heading in the sidebar. -2. Now select **Signing & Capabilities** tab and click **+ Capability** button. -3. Find and add **Keychain Sharing** capability. -4. Click "+" in just created **Keychain Sharing** capability and Xcode will predefine first **Keychain Group** to your application's bundle name. Let's call this value as `KEYCHAIN_GROUP_NAME` - - -The predefined group is usually beneficial because iOS is by default using that group for storing all keychain entries created in the application. So, If your application is already using PowerAuth and you're going to just add extension support, then this is the most simple way to set up a keychain sharing. - - -Now you have to do a similar setup for your application's extension: - -5. Select your application project in the **Project Navigator** to navigate to the target configuration window and select the extensions's target under the **TARGETS** heading in the sidebar. -6. Select **Signing & Capabilities** tab and click **+ Capability** button. -7. Find and add **Keychain Sharing** capability. -8. Click "+" in just created **Keychain Sharing** capability and add the same `KEYCHAIN_GROUP_NAME` as you did for the application's target. -9. (optional) Repeat steps 4 to 6 for all other extensions which supposed to use Extensions SDK. - -Now you need to know your **Team ID** (the unique identifier assigned to your team by Apple). Unfortunately, the identifier is not simply visible in Xcode, so you'll have to log in to Apple's [development portal](http://developer.apple.com) and look for that identifier on your membership details page. - -If you know the Team ID, then the final `KEYCHAIN_GROUP_IDENTIFIER` constant is composed as `TEAM_ID.KEYCHAIN_GROUP_NAME`. So, it should look like: `KTT00000MR.com.powerauth.demo.App`. - -#### App Groups - -The PowerAuth SDK for iOS is using one boolean flag stored in the `UserDefaults` facility, to determine whether the application has been reinstalled. Unfortunately, the `UserDefaults.standard` created by the application cannot be shared with the app extension, so you have to create a new application group to share that data. - -1. Select your application project in the **Project Navigator** to navigate to the target configuration window and select the applications's target under the **TARGETS** heading in the sidebar. -2. Now select **Signing & Capabilities** tab and click **+ Capability** button. -3. Find and add **App Groups** capability. -3. Click "+" in just created **App Groups** capability add a group with the desired identifier and turn this particular group ON (e.g. make sure that the checkmark close to the group's name is selected). Let's call this value `APP_GROUP_IDENTIFIER`. If the group already exists, then just click the checkmark to turn it ON. -4. Now switch to the application's extension target, select the **Capabilities** tab, and also expand the **App Groups** section. -5. Turn "ON" **App Groups** for extension and add an app group with the same name as you did in step 3. - -You can optionally check a troubleshooting section if you need to [migrate the keychain initialization flag](#userdefaults-migration) from standard user defaults to a shared one. - - -While all previous steps are optional, they are highly recommended. If the keychain is properly shared, then the Extension SDK can determine the status of the PowerAuth activation just from the content of keychain data. But still, this has a drawback, because the keychain data persists between the application's reinstallation. As you can see, in a couple of rare usage scenarios the extension may get inaccurate information about the activation. - - -### Configure PowerAuth for Extension - -If the data sharing is right, then the configuration of PowerAuth SDK for iOS Extension is pretty straightforward: - -```swift -import PowerAuth2ForExtensions - -class TodayViewController: UIViewController, NCWidgetProviding { - - // Lazy initialized variable - private var powerAuthExt: PowerAuthExtensionSDK = { - return TodayViewController.setupPowerAuth() - }() - - private static func setupPowerAuth() -> PowerAuthExtensionSDK { - let config = PowerAuthConfiguration( - instanceId: Bundle.main.bundleIdentifier!, - baseEndpointUrl: "https://localhost:8080/demo-server", - configuration: "ARDDj6EB6iAUtNm...KKEcBxbnH9bMk8Ju3K1wmjbA==") - - let keychainConfig = PowerAuthKeychainConfiguration.sharedInstance() - keychainConfig.keychainAttribute_AccessGroup = "KEYCHAIN_GROUP_IDENTIFIER" - keychainConfig.keychainAttribute_UserDefaultsSuiteName = "APP_GROUP_IDENTIFIER" - - return PowerAuthExtensionSDK(configuration: config, keychainConfiguration: keychainConfig)! - } - - // ... the rest of the controller's code ... -} -``` - - -**IMPORTANT:** The configuration used above must match the configuration used in the application otherwise your extension will never get a proper activation status. - - -The Extensions SDK doesn't provide a shared instance for the `PowerAuthExtensionSDK` class and therefore you have to manage that instance on your own. The example above shows the beginning of a simple controller implementing an extension for the Today Widget. For all other code examples, we're going to use `this.powerAuthExt` as a properly initialized instance of the `PowerAuthExtensionSDK` object. - - -## Getting Device Activation Status - -Unlike the iOS SDK, the Extension SDK provides only limited information about activation status. You can check only whether there's locally stored activation or not: - -```swift -if this.powerAuthExt.hasValidActivation() { - // main application has a valid activation locally stored -} -``` - - -## Token-Based Authentication - - -**WARNING:** Before you start using access tokens, please visit our [wiki page for powerauth-crypto](https://github.com/wultra/powerauth-crypto/blob/develop/docs/MAC-Token-Based-Authentication.md) for more information about this feature. You can also check the documentation about tokens available in [PowerAuth SDK for iOS](./PowerAuth-SDK-for-iOS.md#token-based-authentication). - - - -### Getting Token - -To get an access token, you can use the following code: - -```swift -if let token = this.powerAuthExt.tokenStore.localToken(withName: "MyToken") { - // you have a token that can generate authorization headers -} -``` - -Note that the token store also provides the `requestAccessToken()` method, but that always returns the `PowerAuthErrorCode.invalidToken` error. Unlike the iOS SDK API, you cannot get a token from the server from the app extension. Only the main application can do that and once the token is available, then it's also available for the app extension. Check PowerAuth SDK for iOS [documentation for more details](./PowerAuth-SDK-for-iOS.md#getting-token). - -### Generating Authorization Header - -Once you have a `PowerAuthToken` object, use the following code to generate an authorization header: - -```swift -if let header = token.generateHeader() { - let httpHeader = [ header.key : header.value ] - // now you can attach that httpHeader to your HTTP request -} else { - // in case of nil, the token is no longer valid -} -``` - -### Removing Token Locally - -The token store exposes the `removeLocalToken()` method, but the implementation does nothing. - -### Removing Token From the Server - -The token store exposes the `removeAccessToken()` method, but the implementation always returns the `PowerAuthErrorCode.invalidToken` error. - -## Common SDK Tasks - -### Error Handling - -You can follow the same practices as for iOS SDK because the Extensions SDK codebase shares the same error constants with a full PowerAuth SDK for iOS. - -### Debug Build Detection - -It is sometimes useful to switch Extensions SDK to a DEBUG build configuration, to get more logs from the library: - -- **CocoaPods:** we currently don't provide DEBUG pod. This will be resolved in some future versions of Extensions SDK. -- **Manual installation:** Xcode matches build configuration across all nested projects, so you usually don't need to care about the configuration switching. - -The DEBUG build is usually helpful during application development, but on the other side, it's highly unwanted in production applications. For this purpose, the `PowerAuthSystem.isInDebug()` method provides information on whether the PowerAuth for Extensions library was compiled in DEBUG configuration. It is a good practice to check this flag and crash the process when the production application is linked against the DEBUG library: - -```swift -#if YOUR_APPSTORE_BUILD_FLAG - // Final vs Debug library trap - if PowerAuthSystem.isInDebug() { - fatalError("CRITICAL ERROR: You're using Debug PowerAuth library in production build.") - } -#endif -``` - -## Troubleshooting - -This section of the document contains various workarounds and tips for Extensions SDK usage. - -### UserDefaults Migration - -If your previous version of the application did not use shared data between the application and the extension, then you probably need to migrate the keychain status flag from `UserDefaults.standard` to a shared one. We recommend performing this migration at the main application's startup code and **BEFORE** the `PowerAuthSDK` object is configured and used: - -```swift -private func migrateUserDefaults() { - let keychainConfig = PowerAuthKeychainConfiguration.sharedInstance() - let suiteName = keychainConfig.keychainAttribute_UserDefaultsSuiteName - guard let shared = UserDefaults(suiteName: suiteName) else { - return // data sharing is probably not configured properly - } - if shared.bool(forKey: PowerAuthKeychain_Initialized) { - return // migration is not required - } - let standard = UserDefaults.standard - if standard.bool(forKey: PowerAuthKeychain_Initialized) { - standard.removeObject(forKey: PowerAuthKeychain_Initialized) - standard.synchronize() - shared.set(true, forKey: PowerAuthKeychain_Initialized) - shared.synchronize() - } -} -``` diff --git a/docs/PowerAuth-SDK-for-iOS.md b/docs/PowerAuth-SDK-for-iOS.md index 507f6f4d..31124f60 100644 --- a/docs/PowerAuth-SDK-for-iOS.md +++ b/docs/PowerAuth-SDK-for-iOS.md @@ -6,7 +6,6 @@ - [Installation](#installation) - [Supported Platforms](#supported-platforms) - [CocoaPods Installation](#cocoapods) - - [Manual Installation](#manual) - [Carthage Installation](#carthage) - [Post-Installation Steps](#post-installation-steps) - [Include PowerAuth SDK in Your Sources](#include-powerauth-sdk-in-your-sources) @@ -52,13 +51,12 @@ Related documents: -- [PowerAuth SDK for iOS App Extensions](./PowerAuth-SDK-for-iOS-Extensions.md) - [PowerAuth SDK for watchOS](./PowerAuth-SDK-for-watchOS.md) ## Installation -This chapter describes how to get PowerAuth SDK for iOS and tvOS up and running in your app. In the current version, you can choose between CocoaPods and manual library integration. +This chapter describes how to get PowerAuth SDK for iOS and tvOS up and running in your app. In the current version, you can choose between CocoaPods and Swift Package Manager library integration. ### Supported Platforms @@ -97,25 +95,6 @@ $ pod install If you wish to integrate the PowerAuth SDK into your app via SPM, please visit the [PowerAuth mobile SDK for Swift PM ](https://github.com/wultra/powerauth-mobile-sdk-spm) -### Manual - -If you prefer not to use CocoaPods as a dependency manager, you can integrate PowerAuth into your project manually as a git [submodule](http://git-scm.com/docs/git-submodule). - -#### Git Submodules - -1. Open up the Terminal app and go to your top-level project directory and add the library as a submodule: - ```sh - $ git submodule add https://github.com/wultra/powerauth-mobile-sdk.git PowerAuthLib - $ git submodule update --init --recursive - ``` - The first command will clone PowerAuth SDK into the `PowerAuthLib` folder, and the second will update all nested submodules. - -2. Open the new `PowerAuthLib` folder, and go to the `proj-xcode` sub-folder -3. Drag the `PowerAuthLib.xcodeproj` project file into **Project Navigator** of your application's Xcode project. It should appear nested underneath your application's blue project icon. -4. Select your application project in the Project Navigator to navigate to the target configuration window and select the extension's target under the **TARGETS** heading in the sidebar. -5. Now select **Build Phases** tab and expand the **Target Dependencies** section. Click on the "Plus Sign" and choose the **"PowerAuth2"** framework from the **"PowerAuthLib"** project. -6. Next, in the same **Build Phases** tab, expand **Link With Libraries** section. Click on the "Plus Sign" and choose the **"PowerAuth2.framework"** from the **"PowerAuthLib"** project. - ### Carthage We provide limited and experimental support for the [Carthage dependency manager](https://github.com/Carthage/Carthage). The current problem with Carthage is that we cannot specify which Xcode project and which scheme has to be used for a particular library build. It kind of works automatically, but the build process is extremely slow. So, if you still want to try to integrate our library with Carthage, try the following tips: diff --git a/docs/PowerAuth-SDK-for-watchOS.md b/docs/PowerAuth-SDK-for-watchOS.md index 4df76ed6..99ab2bf3 100644 --- a/docs/PowerAuth-SDK-for-watchOS.md +++ b/docs/PowerAuth-SDK-for-watchOS.md @@ -5,7 +5,6 @@ - [Installation](#installation) - [CocoaPods Installation](#cocoapods) - - [Manual Installation](#manual) - [SDK Configuration](#configuration) - [Prepare Watch Connectivity](#prepare-watch-connectivity) - [Configure PowerAuth for WatchKit](#configure-powerauth-for-watchkit) @@ -22,7 +21,6 @@ Related documents: - [PowerAuth SDK for iOS](./PowerAuth-SDK-for-iOS.md) / or go directly to [Apple Watch section](./PowerAuth-SDK-for-iOS.md#apple-watch-support) -- [PowerAuth SDK for iOS App Extensions](./PowerAuth-SDK-for-iOS-Extensions.md) ## Installation @@ -66,27 +64,6 @@ $ pod install Check [troubleshooting section](#cocoapods-integration-fails) of this document when `pod update` or `pod install` doesn't work. -### Manual - -If you prefer not to use CocoaPods as dependency manager, you can integrate Watch SDK into your project manually as a git [submodule](http://git-scm.com/docs/git-submodule). - -#### Git Submodules - -The integration process is quite similar to integration of our library for IOS: - -1. Open up the Terminal.app and go to your top-level project directory and add the library as a submodule: - ```sh - $ git submodule add https://github.com/wultra/powerauth-mobile-sdk.git PowerAuthLib - $ git submodule update --init --recursive - ``` - The first command will clone PowerAuth SDK into the `PowerAuthLib` folder and second will update all nested submodules. We're expecting that you already did this when you integrated PowerAuth into your application. - -2. Open the new `PowerAuthLib` folder, and go to the `proj-xcode` sub-folder -3. Drag the `PowerAuthExtensionSdk.xcodeproj` project file into **Project Navigator** of your application's Xcode project. It should appear nested underneath your application's blue project icon. -4. Select your application project in the Project Navigator to navigate to the target configuration window and select the watch app's target under the **TARGETS** heading in the sidebar. -5. Now select **Build Phases** tab and expand **Target Dependencies** section. Click on the "Plus Sign" and choose **"PowerAuth2ForWatch"** framework from the **"PowerAuthExtensionSdk"** project. -6. Next, in the same **Build Phases** tab expand **Link With Libraries** section. Click on the "Plus Sign" and choose **"PowerAuth2ForWatch.framework"** from the **"PowerAuthExtensionSdk"** project. - ## Configuration The Watch SDK shares several source codes and configuration principles with the main iOS SDK. So, you can prepare the same set of constants as you're already using in your IOS application. The SDK provides just a limited functionality for the watch app (for example, you cannot create an activation or calculate a full PowerAuth signature from a watch application) and to do that it requires that your application's code will participate in data synchronization. diff --git a/docs/Readme.md b/docs/Readme.md index ace5d819..73519fd9 100644 --- a/docs/Readme.md +++ b/docs/Readme.md @@ -5,7 +5,6 @@ To connect to the [PowerAuth](https://www.wultra.com/product/powerauth-mobile-se ## Integration Tutorials - [PowerAuth SDK for iOS and tvOS Apps](PowerAuth-SDK-for-iOS.md) -- [PowerAuth SDK for iOS and tvOS Extensions](PowerAuth-SDK-for-iOS-Extensions.md) - [PowerAuth SDK for watchOS](PowerAuth-SDK-for-watchOS.md) - [PowerAuth SDK for Android Apps](PowerAuth-SDK-for-Android.md) diff --git a/docs/_Sidebar.md b/docs/_Sidebar.md index b7f90e59..a12ee3a4 100644 --- a/docs/_Sidebar.md +++ b/docs/_Sidebar.md @@ -7,7 +7,6 @@ **Integration Tutorials** - [iOS Applications](./PowerAuth-SDK-for-iOS.md) -- [iOS App Extensions](./PowerAuth-SDK-for-iOS-Extensions.md) - [watchOS Applications](./PowerAuth-SDK-for-watchOS.md) - [Android Applications](./PowerAuth-SDK-for-Android.md) From 4bfe328c8c421efc6caea9514b6af0563de4d702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juraj=20=C4=8Eurech?= Date: Fri, 17 Jan 2025 13:26:00 +0100 Subject: [PATCH 09/10] Deprecate unsafeChangePassword() methods. Fix #530 --- docs/Migration-from-1.9-to-1.10.md | 14 +++++++---- .../security/powerauth/sdk/PowerAuthSDK.java | 23 ++++++++++++++++--- proj-xcode/PowerAuth2/PowerAuthSDK.h | 10 ++++++-- proj-xcode/PowerAuth2/PowerAuthSDK.m | 6 +++-- 4 files changed, 42 insertions(+), 11 deletions(-) diff --git a/docs/Migration-from-1.9-to-1.10.md b/docs/Migration-from-1.9-to-1.10.md index b33cecf4..3fb2ba48 100644 --- a/docs/Migration-from-1.9-to-1.10.md +++ b/docs/Migration-from-1.9-to-1.10.md @@ -13,6 +13,9 @@ PowerAuth Mobile SDK in version `1.10.0` provides the following improvements: ### API changes +- The following methods in `PowerAuthSDK` class are deprecated: + - `changePasswordUnsafe()` - use asynchronous `changePassword()` as a replacement. + - Due to removed support of recovery codes, the following classes and methods are no longer available: - Methods removed in `PowerAuthSDK`: - `createRecoveryActivation()` @@ -43,12 +46,15 @@ PowerAuth Mobile SDK in version `1.10.0` provides the following improvements: ### API changes +- The following methods in `PowerAuthSDK` class are deprecated: + - `unsafeChangePassword(from:to:)` - use asynchronous `changePassword(from:to:callback:)` as a replacement. + - Due to removed support of recovery codes, the following classes and methods are no longer available: - Methods removed in `PowerAuthSDK`: - - `createActivation(withName:, recoveryCode:, recoveryPuk:, extras:, callback:)` + - `createActivation(withName:recoveryCode:recoveryPuk:extras:callback:)` - `hasActivationRecoveryData()` - - `activationRecoveryData(authentication:, callback:)` - - `confirm(recoveryCode:, authentication:, callback:)` + - `activationRecoveryData(authentication:callback:)` + - `confirm(recoveryCode:, authentication:callback:)` - Methods removed in `PowerAuthActivationCodeUtil`: - `validateRecoveryCode()` - `validateRecoveryPuk()` @@ -56,7 +62,7 @@ PowerAuth Mobile SDK in version `1.10.0` provides the following improvements: - Other changes: - removed class `PowerAuthActivationRecoveryData` - removed property `PowerAuthActivationResult.activationRecovery` - - removed constructor `PowerAuthActivation(recoveryCode:, recoveryPuk:, name:)` + - removed constructor `PowerAuthActivation(recoveryCode:recoveryPuk:name:)` - Removed all interfaces deprecated in release `1.9.x` diff --git a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/sdk/PowerAuthSDK.java b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/sdk/PowerAuthSDK.java index f7583712..4bb0d2c8 100644 --- a/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/sdk/PowerAuthSDK.java +++ b/proj-android/PowerAuthLibrary/src/main/java/io/getlime/security/powerauth/sdk/PowerAuthSDK.java @@ -1632,7 +1632,7 @@ public void onFetchEncryptedVaultUnlockKeyFailed(Throwable t) { /** * Change the password using local re-encryption, do not validate old password by calling any endpoint. - * + *

    * You are responsible for validating the old password against some server endpoint yourself before using it in this method. * If you do not validate the old password to make sure it is correct, calling this method will corrupt the local data, since * existing data will be decrypted using invalid PIN code and re-encrypted with a new one. @@ -1641,14 +1641,16 @@ public void onFetchEncryptedVaultUnlockKeyFailed(Throwable t) { * @param newPassword New password to be set to store the data. * @return Returns 'true' in case password was changed without error, 'false' otherwise. * @throws PowerAuthMissingConfigException thrown in case configuration is not present. + * @deprecated Method is deprecated, use {@link #changePassword(Context, String, String, IChangePasswordListener)} as a replacement. */ + @Deprecated // 1.10.0 public boolean changePasswordUnsafe(@NonNull final String oldPassword, @NonNull final String newPassword) { - return changePasswordUnsafe(new Password(oldPassword), new Password(newPassword)); + return changePasswordUnsafeImpl(new Password(oldPassword), new Password(newPassword)); } /** * Change the password using local re-encryption, do not validate old password by calling any endpoint. - * + *

    * You are responsible for validating the old password against some server endpoint yourself before using it in this method. * If you do not validate the old password to make sure it is correct, calling this method will corrupt the local data, since * existing data will be decrypted using invalid PIN code and re-encrypted with a new one. @@ -1657,8 +1659,23 @@ public boolean changePasswordUnsafe(@NonNull final String oldPassword, @NonNull * @param newPassword New password to be set to store the data. * @return Returns 'true' in case password was changed without error, 'false' otherwise. * @throws PowerAuthMissingConfigException thrown in case configuration is not present. + * @deprecated Method is deprecated, use {@link #changePassword(Context, Password, Password, IChangePasswordListener)} as a replacement. */ + @Deprecated // 1.10.0 public boolean changePasswordUnsafe(@NonNull final Password oldPassword, @NonNull final Password newPassword) { + return changePasswordUnsafeImpl(oldPassword, newPassword); + } + + /** + * Change the password using local re-encryption. This is private implementation of deprecated function. + * + * @param oldPassword Old password, currently set to store the data. + * @param newPassword New password to be set to store the data. + * @return Returns 'true' in case password was changed without error, 'false' otherwise. + * @throws PowerAuthMissingConfigException thrown in case configuration is not present. + */ + //@Deprecated // 1.10.0 + private boolean changePasswordUnsafeImpl(@NonNull final Password oldPassword, @NonNull final Password newPassword) { final int result = mSession.changeUserPassword(oldPassword, newPassword); if (result == ErrorCode.OK) { saveSerializedState(); diff --git a/proj-xcode/PowerAuth2/PowerAuthSDK.h b/proj-xcode/PowerAuth2/PowerAuthSDK.h index 77979842..9f8253ed 100644 --- a/proj-xcode/PowerAuth2/PowerAuthSDK.h +++ b/proj-xcode/PowerAuth2/PowerAuthSDK.h @@ -333,6 +333,8 @@ If you do not validate the old password to make sure it is correct, calling this method will corrupt the local data, since existing data will be decrypted using invalid PIN code and re-encrypted with a new one. + Method is deprecated and you should use `changePassword(from:to:callback:)` as a replacement. + @param oldPassword Old password, currently set to store the data. @param newPassword New password, to be set in case authentication with old password passes. @return Returns YES in case password was changed without error, NO otherwise. @@ -340,7 +342,8 @@ */ - (BOOL) unsafeChangePasswordFrom:(nonnull NSString*)oldPassword to:(nonnull NSString*)newPassword - NS_SWIFT_NAME(unsafeChangePassword(from:to:)); + NS_SWIFT_NAME(unsafeChangePassword(from:to:)) + PA2_DEPRECATED(1.10.0); /** Change the password using local re-encryption, do not validate old password by calling any endpoint. @@ -348,6 +351,8 @@ If you do not validate the old password to make sure it is correct, calling this method will corrupt the local data, since existing data will be decrypted using invalid PIN code and re-encrypted with a new one. + Method is deprecated and you should use `changePassword(from:to:callback:)` as a replacement. + @param oldPassword Old password, currently set to store the data. @param newPassword New password, to be set in case authentication with old password passes. @return Returns YES in case password was changed without error, NO otherwise. @@ -355,7 +360,8 @@ */ - (BOOL) unsafeChangeCorePasswordFrom:(nonnull PowerAuthCorePassword*)oldPassword to:(nonnull PowerAuthCorePassword*)newPassword - NS_SWIFT_NAME(unsafeChangePassword(from:to:)); + NS_SWIFT_NAME(unsafeChangePassword(from:to:)) + PA2_DEPRECATED(1.10.0); /** Change the password, validate old password by calling a PowerAuth Standard RESTful API endpoint '/pa/signature/validate'. diff --git a/proj-xcode/PowerAuth2/PowerAuthSDK.m b/proj-xcode/PowerAuth2/PowerAuthSDK.m index 7e7ab7fa..9c366ff7 100644 --- a/proj-xcode/PowerAuth2/PowerAuthSDK.m +++ b/proj-xcode/PowerAuth2/PowerAuthSDK.m @@ -1144,8 +1144,10 @@ - (BOOL) unsafeChangeCorePasswordFrom:(PowerAuthCorePassword*)oldPassword - (BOOL) unsafeChangePasswordFrom:(NSString*)oldPassword to:(NSString*)newPassword { - return [self unsafeChangeCorePasswordFrom:[PowerAuthCorePassword passwordWithString:oldPassword] - to:[PowerAuthCorePassword passwordWithString:newPassword]]; + return [_sessionInterface writeBoolTaskWithSession:^BOOL(PowerAuthCoreSession * session) { + return [session changeUserPassword:[PowerAuthCorePassword passwordWithString:oldPassword] + newPassword:[PowerAuthCorePassword passwordWithString:newPassword]]; + }]; } - (id) changePasswordFrom:(NSString*)oldPassword From 8673f889c54601e1bfc49afa929532ba2a17dac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juraj=20=C4=8Eurech?= Date: Mon, 20 Jan 2025 13:23:31 +0100 Subject: [PATCH 10/10] Fixed issues found in review --- .../powerauth/integration/support/model/ServerVersion.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/model/ServerVersion.java b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/model/ServerVersion.java index 5256cb43..06d93135 100644 --- a/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/model/ServerVersion.java +++ b/proj-android/PowerAuthLibrary/src/androidTest/java/io/getlime/security/powerauth/integration/support/model/ServerVersion.java @@ -37,7 +37,7 @@ public enum ServerVersion { V1_7_0("1.7", 1007000, ProtocolVersion.V3_2), V1_8_0("1.8", 1008000, ProtocolVersion.V3_2), V1_9_0("1.9", 1009000, ProtocolVersion.V3_3), - V1_10_0("1.10", 1010000, ProtocolVersion.V3_3), + V1_10_0("1.10", 1010000, ProtocolVersion.V3_3), ; /**