From 4c90bfe67ff32607c384accf96ab7fead1c12a3c Mon Sep 17 00:00:00 2001 From: Denys Bondarenko Date: Tue, 11 Oct 2022 22:48:35 +0300 Subject: [PATCH 01/12] wip --- .../ImportPrivateKeyNoPubOrgRulesFlowTest.kt | 1 - .../email/api/retrofit/ApiRepository.kt | 17 +++--------- .../email/api/retrofit/ApiService.kt | 27 +++++-------------- .../api/retrofit/FlowcryptApiRepository.kt | 18 ++++--------- .../request/model/InitialLegacySubmitModel.kt | 23 ---------------- .../jetpack/viewmodel/PrivateKeysViewModel.kt | 17 ++++++++---- .../viewmodel/SubmitPubKeyViewModel.kt | 10 ++++--- .../actions/RegisterUserPublicKeyAction.kt | 6 ++--- 8 files changed, 35 insertions(+), 84 deletions(-) delete mode 100644 FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/request/model/InitialLegacySubmitModel.kt diff --git a/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/ImportPrivateKeyNoPubOrgRulesFlowTest.kt b/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/ImportPrivateKeyNoPubOrgRulesFlowTest.kt index 2cee191a5c..9cc81d57e9 100644 --- a/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/ImportPrivateKeyNoPubOrgRulesFlowTest.kt +++ b/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/ImportPrivateKeyNoPubOrgRulesFlowTest.kt @@ -17,7 +17,6 @@ import androidx.test.filters.MediumTest import androidx.test.platform.app.InstrumentationRegistry import com.flowcrypt.email.TestConstants import com.flowcrypt.email.api.retrofit.ApiHelper -import com.flowcrypt.email.api.retrofit.request.model.InitialLegacySubmitModel import com.flowcrypt.email.api.retrofit.response.attester.InitialLegacySubmitResponse import com.flowcrypt.email.base.BaseTest import com.flowcrypt.email.junit.annotations.NotReadyForCI diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiRepository.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiRepository.kt index 61efd020e8..94becf444b 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiRepository.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiRepository.kt @@ -7,7 +7,6 @@ package com.flowcrypt.email.api.retrofit import android.content.Context import com.flowcrypt.email.api.retrofit.base.BaseApiRepository -import com.flowcrypt.email.api.retrofit.request.model.InitialLegacySubmitModel import com.flowcrypt.email.api.retrofit.request.model.LoginModel import com.flowcrypt.email.api.retrofit.request.model.MessageUploadRequest import com.flowcrypt.email.api.retrofit.request.model.PostHelpFeedbackModel @@ -60,20 +59,12 @@ interface ApiRepository : BaseApiRepository { /** * @param context Interface to global information about an application environment. - * @param model An instance of [InitialLegacySubmitModel]. */ - suspend fun submitPubKey( + suspend fun submitPrimaryEmailPubKey( context: Context, - model: InitialLegacySubmitModel - ): Result - - /** - * @param context Interface to global information about an application environment. - * @param model An instance of [InitialLegacySubmitModel]. - */ - suspend fun postInitialLegacySubmit( - context: Context, - model: InitialLegacySubmitModel + email: String, + pubkey: String, + idToken: String, ): Result /** diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiService.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiService.kt index 50f4b41f56..80decd2a70 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiService.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiService.kt @@ -7,7 +7,6 @@ package com.flowcrypt.email.api.retrofit import com.flowcrypt.email.BuildConfig import com.flowcrypt.email.api.oauth.OAuth2Helper -import com.flowcrypt.email.api.retrofit.request.model.InitialLegacySubmitModel import com.flowcrypt.email.api.retrofit.request.model.LoginModel import com.flowcrypt.email.api.retrofit.request.model.PostHelpFeedbackModel import com.flowcrypt.email.api.retrofit.request.model.TestWelcomeModel @@ -50,24 +49,6 @@ import retrofit2.http.Url * E-mail: DenBond7@gmail.com */ interface ApiService { - /** - * This method create a [Call] object for the API "https://flowcrypt.com/attester/initial/legacy_submit" - * - * @param body POJO model for requests - * @return [<] - */ - @POST("initial/legacy_submit") - fun postInitialLegacySubmit(@Body body: InitialLegacySubmitModel): Call - - /** - * This method create a [Response] object for the API "https://flowcrypt.com/attester/initial/legacy_submit" - * - * @param body POJO model for requests - * @return [<] - */ - @POST("initial/legacy_submit") - suspend fun postInitialLegacySubmitSuspend(@Body body: InitialLegacySubmitModel): Response - /** * This method create a [Call] object for the API "https://flowcrypt.com/attester/test/welcome" * @@ -174,8 +155,12 @@ interface ApiService { * @param body POJO model for requests * @return [<] */ - @POST("initial/legacy_submit") - suspend fun submitPubKey(@Body body: InitialLegacySubmitModel): Response + @POST("pub/{email}") + suspend fun submitPrimaryEmailPubKey( + @Path("email") email: String, + @Body pubkey: String, + @Header("Authorization") authorization: String + ): Response @FormUrlEncoded @POST(OAuth2Helper.MICROSOFT_OAUTH2_TOKEN_URL) diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/FlowcryptApiRepository.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/FlowcryptApiRepository.kt index f7ccfa789f..f1f7f5e2dc 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/FlowcryptApiRepository.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/FlowcryptApiRepository.kt @@ -8,7 +8,6 @@ package com.flowcrypt.email.api.retrofit import android.content.Context import com.flowcrypt.email.Constants import com.flowcrypt.email.R -import com.flowcrypt.email.api.retrofit.request.model.InitialLegacySubmitModel import com.flowcrypt.email.api.retrofit.request.model.LoginModel import com.flowcrypt.email.api.retrofit.request.model.MessageUploadRequest import com.flowcrypt.email.api.retrofit.request.model.PostHelpFeedbackModel @@ -84,22 +83,15 @@ class FlowcryptApiRepository : ApiRepository { } } - override suspend fun submitPubKey( + override suspend fun submitPrimaryEmailPubKey( context: Context, - model: InitialLegacySubmitModel - ): Result = - withContext(Dispatchers.IO) { - val apiService = ApiHelper.getInstance(context).retrofit.create(ApiService::class.java) - getResult { apiService.submitPubKey(model) } - } - - override suspend fun postInitialLegacySubmit( - context: Context, - model: InitialLegacySubmitModel + email: String, + pubkey: String, + idToken: String, ): Result = withContext(Dispatchers.IO) { val apiService = ApiHelper.getInstance(context).retrofit.create(ApiService::class.java) - getResult { apiService.postInitialLegacySubmitSuspend(model) } + getResult { apiService.submitPrimaryEmailPubKey(email, pubkey, "Bearer $idToken") } } override suspend fun postTestWelcome( diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/request/model/InitialLegacySubmitModel.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/request/model/InitialLegacySubmitModel.kt deleted file mode 100644 index 6e3cd4f93b..0000000000 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/request/model/InitialLegacySubmitModel.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com - * Contributors: DenBond7 - */ - -package com.flowcrypt.email.api.retrofit.request.model - -import com.google.gson.annotations.Expose -import com.google.gson.annotations.SerializedName - -/** - * This is a POJO object which used to make a request - * to the API "https://flowcrypt.com/api/initial/legacy_submit" - * - * @author DenBond7 - * Date: 15.01.2018 - * Time: 16:37 - * E-mail: DenBond7@gmail.com - */ -data class InitialLegacySubmitModel( - @Expose val email: String, - @SerializedName("pubkey") @Expose val pubKey: String -) : RequestModel diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt index addd0683c2..c03dd72e5d 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt @@ -23,7 +23,6 @@ import com.flowcrypt.email.api.email.protocol.OpenStoreHelper import com.flowcrypt.email.api.email.protocol.SmtpProtocolUtil import com.flowcrypt.email.api.retrofit.ApiRepository import com.flowcrypt.email.api.retrofit.FlowcryptApiRepository -import com.flowcrypt.email.api.retrofit.request.model.InitialLegacySubmitModel import com.flowcrypt.email.api.retrofit.request.model.TestWelcomeModel import com.flowcrypt.email.api.retrofit.response.base.Result import com.flowcrypt.email.api.retrofit.response.model.OrgRules @@ -427,8 +426,12 @@ class PrivateKeysViewModel(application: Application) : AccountViewModel(applicat pgpKeyDetails: PgpKeyDetails ) { if (accountEntity.isRuleExist(OrgRules.DomainRule.ENFORCE_ATTESTER_SUBMIT)) { - val model = InitialLegacySubmitModel(accountEntity.email, pgpKeyDetails.publicKey) - val initialLegacySubmitResult = apiRepository.postInitialLegacySubmit(getApplication(), model) + val initialLegacySubmitResult = apiRepository.submitPrimaryEmailPubKey( + context = getApplication(), + email = accountEntity.email, + pubkey = pgpKeyDetails.publicKey, + idToken = "" + ) when (initialLegacySubmitResult.status) { Result.Status.EXCEPTION -> { @@ -600,8 +603,12 @@ class PrivateKeysViewModel(application: Application) : AccountViewModel(applicat keyDetails: PgpKeyDetails ): Boolean = withContext(Dispatchers.IO) { return@withContext try { - val model = InitialLegacySubmitModel(accountEntity.email, keyDetails.publicKey) - val initialLegacySubmitResult = apiRepository.postInitialLegacySubmit(getApplication(), model) + val initialLegacySubmitResult = apiRepository.submitPrimaryEmailPubKey( + context = getApplication(), + email = accountEntity.email, + pubkey = keyDetails.publicKey, + idToken = "" + ) when (initialLegacySubmitResult.status) { Result.Status.SUCCESS -> { val body = initialLegacySubmitResult.data diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/SubmitPubKeyViewModel.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/SubmitPubKeyViewModel.kt index 95007c3625..317c92d268 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/SubmitPubKeyViewModel.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/SubmitPubKeyViewModel.kt @@ -11,7 +11,6 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import com.flowcrypt.email.api.retrofit.ApiRepository import com.flowcrypt.email.api.retrofit.FlowcryptApiRepository -import com.flowcrypt.email.api.retrofit.request.model.InitialLegacySubmitModel import com.flowcrypt.email.api.retrofit.response.attester.InitialLegacySubmitResponse import com.flowcrypt.email.api.retrofit.response.base.ApiResponse import com.flowcrypt.email.api.retrofit.response.base.Result @@ -41,9 +40,12 @@ class SubmitPubKeyViewModel(application: Application) : BaseAndroidViewModel(app keyDetails?.publicKey?.let { viewModelScope.launch { - val result = repository.submitPubKey( - context, - InitialLegacySubmitModel(account.email, it) + + val result = repository.submitPrimaryEmailPubKey( + context = getApplication(), + email = "accountEntity.email", + pubkey = "pgpKeyDetails.publicKey", + idToken = "" ) when (result.status) { diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/service/actionqueue/actions/RegisterUserPublicKeyAction.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/service/actionqueue/actions/RegisterUserPublicKeyAction.kt index 40019e4aa2..cb34e121e1 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/service/actionqueue/actions/RegisterUserPublicKeyAction.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/service/actionqueue/actions/RegisterUserPublicKeyAction.kt @@ -10,8 +10,6 @@ import android.os.Parcel import android.os.Parcelable import com.flowcrypt.email.api.retrofit.ApiHelper import com.flowcrypt.email.api.retrofit.ApiService -import com.flowcrypt.email.api.retrofit.request.model.InitialLegacySubmitModel -import com.flowcrypt.email.util.exception.ApiException import com.google.gson.annotations.SerializedName /** @@ -34,7 +32,7 @@ data class RegisterUserPublicKeyAction @JvmOverloads constructor( override suspend fun run(context: Context) { val apiService = ApiHelper.getInstance(context).retrofit.create(ApiService::class.java) - val body = InitialLegacySubmitModel(email!!, publicKey) + /*val body = InitialLegacySubmitModel(email!!, publicKey) val response = apiService.postInitialLegacySubmit(body).execute() val (apiError) = response.body() ?: throw IllegalArgumentException("The response is null!") @@ -44,7 +42,7 @@ data class RegisterUserPublicKeyAction @JvmOverloads constructor( if (code < 400 || code >= 500) { throw ApiException(apiError) } - } + }*/ } constructor(source: Parcel) : this( From a9701100e6b63fe53590be484ce5546c9e472908 Mon Sep 17 00:00:00 2001 From: DenBond7 Date: Wed, 12 Oct 2022 11:50:53 +0300 Subject: [PATCH 02/12] Added API changes.| #1984 --- .../ImportPrivateKeyNoPubOrgRulesFlowTest.kt | 4 +-- .../email/api/retrofit/ApiRepository.kt | 16 +++++++---- .../email/api/retrofit/ApiService.kt | 24 +++++++++++----- .../api/retrofit/FlowcryptApiRepository.kt | 22 +++++++++++---- ...mitResponse.kt => SubmitPubKeyResponse.kt} | 28 ++++++------------- .../jetpack/viewmodel/PrivateKeysViewModel.kt | 10 +++---- .../viewmodel/SubmitPubKeyViewModel.kt | 8 +++--- 7 files changed, 62 insertions(+), 50 deletions(-) rename FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/response/attester/{InitialLegacySubmitResponse.kt => SubmitPubKeyResponse.kt} (56%) diff --git a/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/ImportPrivateKeyNoPubOrgRulesFlowTest.kt b/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/ImportPrivateKeyNoPubOrgRulesFlowTest.kt index 9cc81d57e9..8b8efe98f3 100644 --- a/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/ImportPrivateKeyNoPubOrgRulesFlowTest.kt +++ b/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/ImportPrivateKeyNoPubOrgRulesFlowTest.kt @@ -17,7 +17,7 @@ import androidx.test.filters.MediumTest import androidx.test.platform.app.InstrumentationRegistry import com.flowcrypt.email.TestConstants import com.flowcrypt.email.api.retrofit.ApiHelper -import com.flowcrypt.email.api.retrofit.response.attester.InitialLegacySubmitResponse +import com.flowcrypt.email.api.retrofit.response.attester.SubmitPubKeyResponse import com.flowcrypt.email.base.BaseTest import com.flowcrypt.email.junit.annotations.NotReadyForCI import com.flowcrypt.email.rules.ClearAppSettingsRule @@ -129,7 +129,7 @@ class ImportPrivateKeyNoPubOrgRulesFlowTest : BaseTest() { ) ) ), - InitialLegacySubmitResponse::class.java + SubmitPubKeyResponse::class.java ) return MockResponse().setResponseCode(HttpURLConnection.HTTP_OK) .setBody(gson.toJson(model)) diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiRepository.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiRepository.kt index 94becf444b..a0bbdd2376 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiRepository.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiRepository.kt @@ -17,8 +17,8 @@ import com.flowcrypt.email.api.retrofit.response.api.LoginResponse import com.flowcrypt.email.api.retrofit.response.api.MessageReplyTokenResponse import com.flowcrypt.email.api.retrofit.response.api.MessageUploadResponse import com.flowcrypt.email.api.retrofit.response.api.PostHelpFeedbackResponse -import com.flowcrypt.email.api.retrofit.response.attester.InitialLegacySubmitResponse import com.flowcrypt.email.api.retrofit.response.attester.PubResponse +import com.flowcrypt.email.api.retrofit.response.attester.SubmitPubKeyResponse import com.flowcrypt.email.api.retrofit.response.attester.TestWelcomeResponse import com.flowcrypt.email.api.retrofit.response.base.ApiResponse import com.flowcrypt.email.api.retrofit.response.base.Result @@ -59,13 +59,19 @@ interface ApiRepository : BaseApiRepository { /** * @param context Interface to global information about an application environment. + * @param email For this email address will be applied changes. + * @param pubKey A new public key. + * @param idToken If idToken != null we will use submitPrimaryEmailPubKey, + * otherwise submitPubKeyWithConditionalEmailVerification. + * @param orgRules An instance of [OrgRules]. We have to check if submitting pub keys is allowed. */ - suspend fun submitPrimaryEmailPubKey( + suspend fun submitPubKey( context: Context, email: String, - pubkey: String, - idToken: String, - ): Result + pubKey: String, + idToken: String? = null, + orgRules: OrgRules? = null + ): Result /** * @param context Interface to global information about an application environment. diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiService.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiService.kt index 80decd2a70..ebf0acae6b 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiService.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiService.kt @@ -18,7 +18,7 @@ import com.flowcrypt.email.api.retrofit.response.api.LoginResponse import com.flowcrypt.email.api.retrofit.response.api.MessageReplyTokenResponse import com.flowcrypt.email.api.retrofit.response.api.MessageUploadResponse import com.flowcrypt.email.api.retrofit.response.api.PostHelpFeedbackResponse -import com.flowcrypt.email.api.retrofit.response.attester.InitialLegacySubmitResponse +import com.flowcrypt.email.api.retrofit.response.attester.SubmitPubKeyResponse import com.flowcrypt.email.api.retrofit.response.attester.TestWelcomeResponse import com.flowcrypt.email.api.retrofit.response.oauth2.MicrosoftOAuth2TokenResponse import com.google.gson.JsonObject @@ -150,17 +150,27 @@ interface ApiService { suspend fun getOrgRulesFromFes(@Url fesUrl: String): Response /** - * This method calls API "https://flowcrypt.com/attester/initial/legacy_submit" via coroutines - * - * @param body POJO model for requests - * @return [<] + * Set or replace public key with idToken as an auth mechanism + * Used during setup + * Can only be used for primary email because idToken does not contain info about aliases */ @POST("pub/{email}") suspend fun submitPrimaryEmailPubKey( @Path("email") email: String, - @Body pubkey: String, + @Body pubKey: String, @Header("Authorization") authorization: String - ): Response + ): Response + + /** + * Request to replace public key that will be verified by clicking email + * Used when user manually chooses to replace key + * Can also be used for aliases + */ + @POST("pub/{email}") + suspend fun submitPubKeyWithConditionalEmailVerification( + @Path("email") email: String, + @Body pubKey: String + ): Response @FormUrlEncoded @POST(OAuth2Helper.MICROSOFT_OAUTH2_TOKEN_URL) diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/FlowcryptApiRepository.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/FlowcryptApiRepository.kt index f1f7f5e2dc..52aa35b24d 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/FlowcryptApiRepository.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/FlowcryptApiRepository.kt @@ -18,8 +18,8 @@ import com.flowcrypt.email.api.retrofit.response.api.LoginResponse import com.flowcrypt.email.api.retrofit.response.api.MessageReplyTokenResponse import com.flowcrypt.email.api.retrofit.response.api.MessageUploadResponse import com.flowcrypt.email.api.retrofit.response.api.PostHelpFeedbackResponse -import com.flowcrypt.email.api.retrofit.response.attester.InitialLegacySubmitResponse import com.flowcrypt.email.api.retrofit.response.attester.PubResponse +import com.flowcrypt.email.api.retrofit.response.attester.SubmitPubKeyResponse import com.flowcrypt.email.api.retrofit.response.attester.TestWelcomeResponse import com.flowcrypt.email.api.retrofit.response.base.ApiResponse import com.flowcrypt.email.api.retrofit.response.base.Result @@ -83,15 +83,25 @@ class FlowcryptApiRepository : ApiRepository { } } - override suspend fun submitPrimaryEmailPubKey( + override suspend fun submitPubKey( context: Context, email: String, - pubkey: String, - idToken: String, - ): Result = + pubKey: String, + idToken: String?, + orgRules: OrgRules? + ): Result = withContext(Dispatchers.IO) { + if (orgRules?.canSubmitPubToAttester() == false) { + return@withContext Result.exception( + IllegalStateException("Cannot replace pubkey at attester because your organisation rules forbid it.") + ) + } val apiService = ApiHelper.getInstance(context).retrofit.create(ApiService::class.java) - getResult { apiService.submitPrimaryEmailPubKey(email, pubkey, "Bearer $idToken") } + getResult { + idToken?.let { nonNullIdToken -> + apiService.submitPrimaryEmailPubKey(email, pubKey, "Bearer $nonNullIdToken") + } ?: apiService.submitPubKeyWithConditionalEmailVerification(email, pubKey) + } } override suspend fun postTestWelcome( diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/response/attester/InitialLegacySubmitResponse.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/response/attester/SubmitPubKeyResponse.kt similarity index 56% rename from FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/response/attester/InitialLegacySubmitResponse.kt rename to FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/response/attester/SubmitPubKeyResponse.kt index a24e448b4d..90254c1c2f 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/response/attester/InitialLegacySubmitResponse.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/response/attester/SubmitPubKeyResponse.kt @@ -14,28 +14,19 @@ import com.google.gson.annotations.Expose import com.google.gson.annotations.SerializedName /** - * This class describes a response from the https://flowcrypt.com/attester/initial/legacy_submit API. - * - * - * `POST /initial/legacy_submit - * response(200): { - * "saved" (True, False) # successfuly saved pubkey - * [voluntary] "error" ('str'>) # error detail, if not saved - * }` + * This class describes a response from the https://flowcrypt.com/attester/pub API. * * @author Denis Bondarenko * Date: 15.01.2018 * Time: 16:30 * E-mail: DenBond7@gmail.com */ -data class InitialLegacySubmitResponse constructor( +data class SubmitPubKeyResponse constructor( @SerializedName("error") @Expose override val - apiError: ApiError? = null, - @Expose val isSaved: Boolean + apiError: ApiError? = null ) : ApiResponse { constructor(source: Parcel) : this( - source.readParcelable(ApiError::class.java.classLoader), - 1 == source.readInt() + source.readParcelable(ApiError::class.java.classLoader) ) override fun describeContents(): Int { @@ -45,17 +36,14 @@ data class InitialLegacySubmitResponse constructor( override fun writeToParcel(dest: Parcel, flags: Int) = with(dest) { writeParcelable(apiError, 0) - writeInt((if (isSaved) 1 else 0)) } companion object { @JvmField - val CREATOR: Parcelable.Creator = - object : Parcelable.Creator { - override fun createFromParcel(source: Parcel): InitialLegacySubmitResponse = - InitialLegacySubmitResponse(source) - - override fun newArray(size: Int): Array = arrayOfNulls(size) + val CREATOR: Parcelable.Creator = + object : Parcelable.Creator { + override fun createFromParcel(source: Parcel) = SubmitPubKeyResponse(source) + override fun newArray(size: Int): Array = arrayOfNulls(size) } } } diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt index c03dd72e5d..222f98d045 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt @@ -426,11 +426,10 @@ class PrivateKeysViewModel(application: Application) : AccountViewModel(applicat pgpKeyDetails: PgpKeyDetails ) { if (accountEntity.isRuleExist(OrgRules.DomainRule.ENFORCE_ATTESTER_SUBMIT)) { - val initialLegacySubmitResult = apiRepository.submitPrimaryEmailPubKey( + val initialLegacySubmitResult = apiRepository.submitPubKey( context = getApplication(), email = accountEntity.email, - pubkey = pgpKeyDetails.publicKey, - idToken = "" + pubKey = pgpKeyDetails.publicKey ) when (initialLegacySubmitResult.status) { @@ -603,11 +602,10 @@ class PrivateKeysViewModel(application: Application) : AccountViewModel(applicat keyDetails: PgpKeyDetails ): Boolean = withContext(Dispatchers.IO) { return@withContext try { - val initialLegacySubmitResult = apiRepository.submitPrimaryEmailPubKey( + val initialLegacySubmitResult = apiRepository.submitPubKey( context = getApplication(), email = accountEntity.email, - pubkey = keyDetails.publicKey, - idToken = "" + pubKey = keyDetails.publicKey ) when (initialLegacySubmitResult.status) { Result.Status.SUCCESS -> { diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/SubmitPubKeyViewModel.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/SubmitPubKeyViewModel.kt index 317c92d268..742277dd7f 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/SubmitPubKeyViewModel.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/SubmitPubKeyViewModel.kt @@ -11,7 +11,7 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import com.flowcrypt.email.api.retrofit.ApiRepository import com.flowcrypt.email.api.retrofit.FlowcryptApiRepository -import com.flowcrypt.email.api.retrofit.response.attester.InitialLegacySubmitResponse +import com.flowcrypt.email.api.retrofit.response.attester.SubmitPubKeyResponse import com.flowcrypt.email.api.retrofit.response.base.ApiResponse import com.flowcrypt.email.api.retrofit.response.base.Result import com.flowcrypt.email.api.retrofit.response.model.OrgRules @@ -41,10 +41,10 @@ class SubmitPubKeyViewModel(application: Application) : BaseAndroidViewModel(app keyDetails?.publicKey?.let { viewModelScope.launch { - val result = repository.submitPrimaryEmailPubKey( + val result = repository.submitPubKey( context = getApplication(), email = "accountEntity.email", - pubkey = "pgpKeyDetails.publicKey", + pubKey = "pgpKeyDetails.publicKey", idToken = "" ) @@ -59,7 +59,7 @@ class SubmitPubKeyViewModel(application: Application) : BaseAndroidViewModel(app FlowCryptRoomDatabase.getDatabase(getApplication()).actionQueueDao() .insertSuspend(action) } - submitPubKeyLiveData.value = Result.success(InitialLegacySubmitResponse(null, false)) + submitPubKeyLiveData.value = Result.success(SubmitPubKeyResponse(null)) } } else -> { From 7885c39cdb2f9db38d8d1db4ef86a3d84da5d989 Mon Sep 17 00:00:00 2001 From: DenBond7 Date: Wed, 12 Oct 2022 13:10:11 +0300 Subject: [PATCH 03/12] Extracted strings.| #1984 --- .../com/flowcrypt/email/api/retrofit/FlowcryptApiRepository.kt | 2 +- FlowCrypt/src/main/res/values-ru/strings.xml | 1 + FlowCrypt/src/main/res/values-uk/strings.xml | 1 + FlowCrypt/src/main/res/values/strings.xml | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/FlowcryptApiRepository.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/FlowcryptApiRepository.kt index 52aa35b24d..f81658381e 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/FlowcryptApiRepository.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/FlowcryptApiRepository.kt @@ -93,7 +93,7 @@ class FlowcryptApiRepository : ApiRepository { withContext(Dispatchers.IO) { if (orgRules?.canSubmitPubToAttester() == false) { return@withContext Result.exception( - IllegalStateException("Cannot replace pubkey at attester because your organisation rules forbid it.") + IllegalStateException(context.getString(R.string.can_not_replace_public_key_at_attester)) ) } val apiService = ApiHelper.getInstance(context).retrofit.create(ApiService::class.java) diff --git a/FlowCrypt/src/main/res/values-ru/strings.xml b/FlowCrypt/src/main/res/values-ru/strings.xml index 72c7cebbf4..51cad3e4b9 100644 --- a/FlowCrypt/src/main/res/values-ru/strings.xml +++ b/FlowCrypt/src/main/res/values-ru/strings.xml @@ -491,4 +491,5 @@ Не удалось загрузить информацию о черновиках. Пожалуйста, попробуйте еще раз. (без получателей) Не удалось сохранить черновик\n\nДетали ошибки:\n%1$s + Невозможно заменить публичный ключ на сервере attester. Правила организации запрещают это. diff --git a/FlowCrypt/src/main/res/values-uk/strings.xml b/FlowCrypt/src/main/res/values-uk/strings.xml index 227c9f648c..dc36460cd0 100644 --- a/FlowCrypt/src/main/res/values-uk/strings.xml +++ b/FlowCrypt/src/main/res/values-uk/strings.xml @@ -492,4 +492,5 @@ Не вдалося отримати інформацію про чорновики. Будь ласка, спробуйте ще раз. (без отримувачів) Не вдалося зберегти чорновик\n\nДеталі помилки:\n%1$s + Неможливо замінити публічний ключ на сервері attester. Правила організації забороняють це. diff --git a/FlowCrypt/src/main/res/values/strings.xml b/FlowCrypt/src/main/res/values/strings.xml index ec7d5a375b..f50fa6ebea 100644 --- a/FlowCrypt/src/main/res/values/strings.xml +++ b/FlowCrypt/src/main/res/values/strings.xml @@ -577,4 +577,5 @@ Fetching drafts info failed. Please try again. (no recipients) Could not save a draft\n\nError details:\n%1$s + Cannot replace public key at attester because your organisation rules forbid it. From cad24b55869256fc13693debe80d9bcaa0ba050f Mon Sep 17 00:00:00 2001 From: DenBond7 Date: Wed, 12 Oct 2022 13:45:05 +0300 Subject: [PATCH 04/12] Migrated to use a new version to submit a pub key during the private key creation. Refactored code.| #1984 --- .../jetpack/viewmodel/PrivateKeysViewModel.kt | 133 ++++++------------ .../activity/fragment/MainSignInFragment.kt | 3 +- 2 files changed, 47 insertions(+), 89 deletions(-) diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt index 222f98d045..ed2facd858 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt @@ -18,7 +18,6 @@ import androidx.lifecycle.switchMap import androidx.lifecycle.viewModelScope import com.flowcrypt.email.R import com.flowcrypt.email.api.email.EmailUtil -import com.flowcrypt.email.api.email.gmail.GmailApiHelper import com.flowcrypt.email.api.email.protocol.OpenStoreHelper import com.flowcrypt.email.api.email.protocol.SmtpProtocolUtil import com.flowcrypt.email.api.retrofit.ApiRepository @@ -51,7 +50,6 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.pgpainless.key.collection.PGPKeyRingCollection -import org.pgpainless.key.util.UserId import org.pgpainless.util.Passphrase /** @@ -334,12 +332,17 @@ class PrivateKeysViewModel(application: Application) : AccountViewModel(applicat fun doAdditionalActionsAfterPrivateKeyCreation( accountEntity: AccountEntity, - pgpKeyDetails: PgpKeyDetails + pgpKeyDetails: PgpKeyDetails, + idToken: String? = null, ) { viewModelScope.launch { additionalActionsAfterPrivateKeyCreationLiveData.value = Result.loading() try { - doAdditionalOperationsAfterKeyCreation(accountEntity, pgpKeyDetails) + doAdditionalOperationsAfterKeyCreation( + accountEntity = accountEntity, + pgpKeyDetails = pgpKeyDetails, + idToken = idToken, + ) additionalActionsAfterPrivateKeyCreationLiveData.value = Result.success(Pair(accountEntity, pgpKeyDetails)) } catch (e: Exception) { @@ -405,46 +408,13 @@ class PrivateKeysViewModel(application: Application) : AccountViewModel(applicat } } - private suspend fun savePrivateKeyToDatabase( - accountEntity: AccountEntity, - pgpKeyDetails: PgpKeyDetails, - passphrase: String - ) { - val keyEntity = pgpKeyDetails.toKeyEntity(accountEntity).copy( - source = KeyImportDetails.SourceType.NEW.toPrivateKeySourceTypeString(), - privateKey = KeyStoreCryptoManager.encryptSuspend(pgpKeyDetails.privateKey).toByteArray(), - storedPassphrase = KeyStoreCryptoManager.encryptSuspend(passphrase) - ) - - if (roomDatabase.keysDao().insertSuspend(keyEntity) == -1L) { - throw NullPointerException("Cannot save a generated private key") - } - } - private suspend fun doAdditionalOperationsAfterKeyCreation( accountEntity: AccountEntity, - pgpKeyDetails: PgpKeyDetails + pgpKeyDetails: PgpKeyDetails, + idToken: String? = null, ) { if (accountEntity.isRuleExist(OrgRules.DomainRule.ENFORCE_ATTESTER_SUBMIT)) { - val initialLegacySubmitResult = apiRepository.submitPubKey( - context = getApplication(), - email = accountEntity.email, - pubKey = pgpKeyDetails.publicKey - ) - - when (initialLegacySubmitResult.status) { - Result.Status.EXCEPTION -> { - initialLegacySubmitResult.exception?.let { exception -> throw exception } - } - - Result.Status.ERROR -> { - initialLegacySubmitResult.data?.apiError?.let { apiError -> throw ApiException(apiError) } - } - - else -> { - // all looks well - } - } + registerUserPublicKey(accountEntity, pgpKeyDetails, idToken, false) if (!accountEntity.isRuleExist(OrgRules.DomainRule.NO_PRV_BACKUP)) { if (!saveCreatedPrivateKeyAsBackupToInbox(accountEntity, pgpKeyDetails)) { @@ -470,7 +440,7 @@ class PrivateKeysViewModel(application: Application) : AccountViewModel(applicat } } - if (!registerUserPublicKey(accountEntity, pgpKeyDetails)) { + if (!registerUserPublicKey(accountEntity, pgpKeyDetails, idToken)) { val registerAction = ActionQueueEntity.fromAction( RegisterUserPublicKeyAction( 0, @@ -555,38 +525,6 @@ class PrivateKeysViewModel(application: Application) : AccountViewModel(applicat } } - private suspend fun genUserIds(accountEntity: AccountEntity): List = - withContext(Dispatchers.IO) { - val userIds = ArrayList() - userIds.add(UserId.newBuilder().withEmail(accountEntity.email).apply { - accountEntity.displayName?.let { name -> - withName(name) - } - }.build()) - - if (accountEntity.accountType == AccountEntity.ACCOUNT_TYPE_GOOGLE) { - try { - val gmail = GmailApiHelper.generateGmailApiService(getApplication(), accountEntity) - val aliases = - gmail.users().settings().sendAs().list(GmailApiHelper.DEFAULT_USER_ID).execute() - for (alias in aliases.sendAs) { - if (alias.verificationStatus != null) { - userIds.add(UserId.newBuilder().withEmail(alias.sendAsEmail).apply { - alias.displayName?.let { name -> - withName(name) - } - }.build()) - } - } - } catch (e: Exception) { - //skip any issues - e.printStackTrace() - } - } - - return@withContext userIds - } - /** * Registering a key with attester API. * Note: this will only be successful if it's the first time submitting a key for this email address, or if the @@ -599,27 +537,46 @@ class PrivateKeysViewModel(application: Application) : AccountViewModel(applicat */ private suspend fun registerUserPublicKey( accountEntity: AccountEntity, - keyDetails: PgpKeyDetails + keyDetails: PgpKeyDetails, + idToken: String? = null, + isSilent: Boolean = true, ): Boolean = withContext(Dispatchers.IO) { - return@withContext try { - val initialLegacySubmitResult = apiRepository.submitPubKey( - context = getApplication(), - email = accountEntity.email, - pubKey = keyDetails.publicKey - ) - when (initialLegacySubmitResult.status) { - Result.Status.SUCCESS -> { - val body = initialLegacySubmitResult.data - body != null && (body.apiError == null || body.apiError.code !in 400..499) + val submitPubKeyResult = apiRepository.submitPubKey( + context = getApplication(), + email = accountEntity.email, + pubKey = keyDetails.publicKey, + idToken = idToken, + orgRules = accountEntity.clientConfiguration + ) + + when (submitPubKeyResult.status) { + Result.Status.SUCCESS -> { + val body = submitPubKeyResult.data + val isSuccess = body != null && (body.apiError == null || body.apiError.code !in 400..499) + if (isSilent) { + isSuccess + } else { + throw IllegalStateException(body?.apiError?.msg) + } + } + + else -> if (isSilent) { + false + } else when (submitPubKeyResult.status) { + Result.Status.EXCEPTION -> { + submitPubKeyResult.exception?.let { exception -> throw exception } + ?: throw IllegalStateException("Unknown exception") + } + + Result.Status.ERROR -> { + submitPubKeyResult.data?.apiError?.let { apiError -> throw ApiException(apiError) } + ?: throw IllegalStateException("Unknown API error") } else -> { - false + throw IllegalStateException("Undefined case") } } - } catch (e: Exception) { - e.printStackTrace() - false } } diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/ui/activity/fragment/MainSignInFragment.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/ui/activity/fragment/MainSignInFragment.kt index c68e8f9f63..48e3239b29 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/ui/activity/fragment/MainSignInFragment.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/ui/activity/fragment/MainSignInFragment.kt @@ -451,7 +451,8 @@ class MainSignInFragment : BaseSingInFragment() { account ?: return@setFragmentResultListener privateKeysViewModel.doAdditionalActionsAfterPrivateKeyCreation( account, - pgpKeyDetails + pgpKeyDetails, + googleSignInAccount?.idToken ) } From a89ee223f456b23a59e55b81a94a1392bc2bc880 Mon Sep 17 00:00:00 2001 From: DenBond7 Date: Wed, 12 Oct 2022 14:03:03 +0300 Subject: [PATCH 05/12] Removed unused code.| #1984 --- .../viewmodel/SubmitPubKeyViewModel.kt | 73 ------------------- 1 file changed, 73 deletions(-) delete mode 100644 FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/SubmitPubKeyViewModel.kt diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/SubmitPubKeyViewModel.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/SubmitPubKeyViewModel.kt deleted file mode 100644 index 742277dd7f..0000000000 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/SubmitPubKeyViewModel.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com - * Contributors: DenBond7 - */ - -package com.flowcrypt.email.jetpack.viewmodel - -import android.app.Application -import android.content.Context -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.viewModelScope -import com.flowcrypt.email.api.retrofit.ApiRepository -import com.flowcrypt.email.api.retrofit.FlowcryptApiRepository -import com.flowcrypt.email.api.retrofit.response.attester.SubmitPubKeyResponse -import com.flowcrypt.email.api.retrofit.response.base.ApiResponse -import com.flowcrypt.email.api.retrofit.response.base.Result -import com.flowcrypt.email.api.retrofit.response.model.OrgRules -import com.flowcrypt.email.database.FlowCryptRoomDatabase -import com.flowcrypt.email.database.entity.AccountEntity -import com.flowcrypt.email.database.entity.ActionQueueEntity -import com.flowcrypt.email.security.model.PgpKeyDetails -import com.flowcrypt.email.service.actionqueue.actions.RegisterUserPublicKeyAction -import kotlinx.coroutines.launch - -/** - * @author Denis Bondarenko - * Date: 11/11/19 - * Time: 3:56 PM - * E-mail: DenBond7@gmail.com - */ -class SubmitPubKeyViewModel(application: Application) : BaseAndroidViewModel(application) { - private val repository: ApiRepository = FlowcryptApiRepository() - val submitPubKeyLiveData: MutableLiveData?> = MutableLiveData() - - fun submitPubKey(account: AccountEntity, keys: List) { - submitPubKeyLiveData.value = Result.loading() - val context: Context = getApplication() - - val keyDetails = keys.firstOrNull() - - keyDetails?.publicKey?.let { - viewModelScope.launch { - - val result = repository.submitPubKey( - context = getApplication(), - email = "accountEntity.email", - pubKey = "pgpKeyDetails.publicKey", - idToken = "" - ) - - when (result.status) { - Result.Status.ERROR, Result.Status.EXCEPTION -> { - if (account.isRuleExist(OrgRules.DomainRule.ENFORCE_ATTESTER_SUBMIT)) { - submitPubKeyLiveData.value = result - } else { - val registerAction = - ActionQueueEntity.fromAction(RegisterUserPublicKeyAction(0, account.email, 0, it)) - registerAction?.let { action -> - FlowCryptRoomDatabase.getDatabase(getApplication()).actionQueueDao() - .insertSuspend(action) - } - submitPubKeyLiveData.value = Result.success(SubmitPubKeyResponse(null)) - } - } - else -> { - submitPubKeyLiveData.value = result - } - } - } - } - } -} - From f3683189de9cc1686eb56b9a0ad8359a092decdf Mon Sep 17 00:00:00 2001 From: DenBond7 Date: Wed, 12 Oct 2022 14:07:24 +0300 Subject: [PATCH 06/12] Removed unused code.| #1984 --- .../jetpack/viewmodel/PrivateKeysViewModel.kt | 11 +-- .../service/actionqueue/actions/Action.kt | 1 - .../actions/RegisterUserPublicKeyAction.kt | 77 ------------------- .../google/gson/ActionJsonDeserializer.kt | 6 -- 4 files changed, 1 insertion(+), 94 deletions(-) delete mode 100644 FlowCrypt/src/main/java/com/flowcrypt/email/service/actionqueue/actions/RegisterUserPublicKeyAction.kt diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt index ed2facd858..7f44531795 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt @@ -39,7 +39,6 @@ import com.flowcrypt.email.security.SecurityUtils import com.flowcrypt.email.security.model.PgpKeyDetails import com.flowcrypt.email.security.pgp.PgpKey import com.flowcrypt.email.service.actionqueue.actions.BackupPrivateKeyToInboxAction -import com.flowcrypt.email.service.actionqueue.actions.RegisterUserPublicKeyAction import com.flowcrypt.email.service.actionqueue.actions.SendWelcomeTestEmailAction import com.flowcrypt.email.util.GeneralUtil import com.flowcrypt.email.util.exception.ApiException @@ -440,15 +439,7 @@ class PrivateKeysViewModel(application: Application) : AccountViewModel(applicat } } - if (!registerUserPublicKey(accountEntity, pgpKeyDetails, idToken)) { - val registerAction = ActionQueueEntity.fromAction( - RegisterUserPublicKeyAction( - 0, - accountEntity.email, 0, pgpKeyDetails.publicKey - ) - ) - registerAction?.let { action -> roomDatabase.actionQueueDao().insertSuspend(action) } - } + registerUserPublicKey(accountEntity, pgpKeyDetails, idToken) } if (!requestingTestMsgWithNewPublicKey(accountEntity, pgpKeyDetails)) { diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/service/actionqueue/actions/Action.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/service/actionqueue/actions/Action.kt index 2aea985264..6cdad6f0e6 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/service/actionqueue/actions/Action.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/service/actionqueue/actions/Action.kt @@ -30,7 +30,6 @@ interface Action : Parcelable { */ enum class Type constructor(val value: String) : Parcelable { BACKUP_PRIVATE_KEY_TO_INBOX("backup_private_key_to_inbox"), - REGISTER_USER_PUBLIC_KEY("register_user_public_key"), SEND_WELCOME_TEST_EMAIL("send_welcome_test_email"), ENCRYPT_PRIVATE_KEYS("encrypt_private_keys"), LOAD_GMAIL_ALIASES("load_gmail_aliases"); diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/service/actionqueue/actions/RegisterUserPublicKeyAction.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/service/actionqueue/actions/RegisterUserPublicKeyAction.kt deleted file mode 100644 index cb34e121e1..0000000000 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/service/actionqueue/actions/RegisterUserPublicKeyAction.kt +++ /dev/null @@ -1,77 +0,0 @@ -/* - * © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com - * Contributors: DenBond7 - */ - -package com.flowcrypt.email.service.actionqueue.actions - -import android.content.Context -import android.os.Parcel -import android.os.Parcelable -import com.flowcrypt.email.api.retrofit.ApiHelper -import com.flowcrypt.email.api.retrofit.ApiService -import com.google.gson.annotations.SerializedName - -/** - * This action describes a task which registers a user public key - * using API "https://flowcrypt.com/attester/initial/legacy_submit". - * - * @author Denis Bondarenko - * Date: 30.01.2018 - * Time: 18:01 - * E-mail: DenBond7@gmail.com - */ -data class RegisterUserPublicKeyAction @JvmOverloads constructor( - override var id: Long = 0, - override var email: String? = null, - override val version: Int = 0, - private val publicKey: String -) : Action { - @SerializedName(Action.TAG_NAME_ACTION_TYPE) - override val type: Action.Type = Action.Type.REGISTER_USER_PUBLIC_KEY - - override suspend fun run(context: Context) { - val apiService = ApiHelper.getInstance(context).retrofit.create(ApiService::class.java) - /*val body = InitialLegacySubmitModel(email!!, publicKey) - val response = apiService.postInitialLegacySubmit(body).execute() - - val (apiError) = response.body() ?: throw IllegalArgumentException("The response is null!") - - if (apiError != null) { - val code = apiError.code ?: 0 - if (code < 400 || code >= 500) { - throw ApiException(apiError) - } - }*/ - } - - constructor(source: Parcel) : this( - source.readLong(), - source.readString(), - source.readInt(), - source.readString()!! - ) - - override fun describeContents(): Int { - return 0 - } - - override fun writeToParcel(dest: Parcel, flags: Int) = - with(dest) { - writeLong(id) - writeString(email) - writeInt(version) - writeString(publicKey) - } - - companion object { - @JvmField - val CREATOR: Parcelable.Creator = - object : Parcelable.Creator { - override fun createFromParcel(source: Parcel): RegisterUserPublicKeyAction = - RegisterUserPublicKeyAction(source) - - override fun newArray(size: Int): Array = arrayOfNulls(size) - } - } -} diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/util/google/gson/ActionJsonDeserializer.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/util/google/gson/ActionJsonDeserializer.kt index 8a4692a139..64af891b54 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/util/google/gson/ActionJsonDeserializer.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/util/google/gson/ActionJsonDeserializer.kt @@ -9,7 +9,6 @@ import com.flowcrypt.email.service.actionqueue.actions.Action import com.flowcrypt.email.service.actionqueue.actions.BackupPrivateKeyToInboxAction import com.flowcrypt.email.service.actionqueue.actions.EncryptPrivateKeysIfNeededAction import com.flowcrypt.email.service.actionqueue.actions.LoadGmailAliasesAction -import com.flowcrypt.email.service.actionqueue.actions.RegisterUserPublicKeyAction import com.flowcrypt.email.service.actionqueue.actions.SendWelcomeTestEmailAction import com.google.gson.Gson import com.google.gson.JsonDeserializationContext @@ -40,11 +39,6 @@ class ActionJsonDeserializer : JsonDeserializer { BackupPrivateKeyToInboxAction::class.java ) - Action.Type.REGISTER_USER_PUBLIC_KEY -> context.deserialize( - json, - RegisterUserPublicKeyAction::class.java - ) - Action.Type.SEND_WELCOME_TEST_EMAIL -> context.deserialize( json, SendWelcomeTestEmailAction::class.java From dfd4023d50ab1d1b6b159c7465671becc51f9d22 Mon Sep 17 00:00:00 2001 From: DenBond7 Date: Wed, 12 Oct 2022 14:11:34 +0300 Subject: [PATCH 07/12] Commented some code in tests.| #1984 --- .../email/ui/ImportPrivateKeyNoPubOrgRulesFlowTest.kt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/ImportPrivateKeyNoPubOrgRulesFlowTest.kt b/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/ImportPrivateKeyNoPubOrgRulesFlowTest.kt index 8b8efe98f3..6035f81aa0 100644 --- a/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/ImportPrivateKeyNoPubOrgRulesFlowTest.kt +++ b/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/ImportPrivateKeyNoPubOrgRulesFlowTest.kt @@ -17,7 +17,6 @@ import androidx.test.filters.MediumTest import androidx.test.platform.app.InstrumentationRegistry import com.flowcrypt.email.TestConstants import com.flowcrypt.email.api.retrofit.ApiHelper -import com.flowcrypt.email.api.retrofit.response.attester.SubmitPubKeyResponse import com.flowcrypt.email.base.BaseTest import com.flowcrypt.email.junit.annotations.NotReadyForCI import com.flowcrypt.email.rules.ClearAppSettingsRule @@ -28,7 +27,6 @@ import com.flowcrypt.email.security.model.PgpKeyDetails import com.flowcrypt.email.ui.activity.MainActivity import com.flowcrypt.email.util.AccountDaoManager import com.flowcrypt.email.util.PrivateKeysManager -import com.flowcrypt.email.util.TestGeneralUtil import okhttp3.mockwebserver.Dispatcher import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.RecordedRequest @@ -39,8 +37,6 @@ import org.junit.Test import org.junit.rules.RuleChain import org.junit.rules.TestRule import org.junit.runner.RunWith -import java.io.ByteArrayInputStream -import java.io.InputStreamReader import java.net.HttpURLConnection /** @@ -113,7 +109,7 @@ class ImportPrivateKeyNoPubOrgRulesFlowTest : BaseTest() { override fun dispatch(request: RecordedRequest): MockResponse { val gson = ApiHelper.getInstance(InstrumentationRegistry.getInstrumentation().targetContext).gson - if (request.path.equals("/initial/legacy_submit")) { + /*if (request.path.equals("/initial/legacy_submit")) { val requestModel = gson.fromJson( InputStreamReader(request.body.inputStream()), InitialLegacySubmitModel::class.java @@ -135,7 +131,7 @@ class ImportPrivateKeyNoPubOrgRulesFlowTest : BaseTest() { .setBody(gson.toJson(model)) } } - } + }*/ return MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_FOUND) } From 62166d484291e9cf9b9b6d709d96a2e7802df099 Mon Sep 17 00:00:00 2001 From: Denys Bondarenko Date: Wed, 12 Oct 2022 21:28:15 +0300 Subject: [PATCH 08/12] Replaced 'attester/test/welcome' with 'attester/welcome-message'. Refactored code. Removed unused code.| #1984 --- .../email/api/retrofit/ApiRepository.kt | 13 ++-- .../email/api/retrofit/ApiService.kt | 25 ++---- .../api/retrofit/FlowcryptApiRepository.kt | 13 ++-- ...WelcomeModel.kt => WelcomeMessageModel.kt} | 2 +- ...eResponse.kt => WelcomeMessageResponse.kt} | 8 +- .../jetpack/viewmodel/PrivateKeysViewModel.kt | 24 ++---- .../service/actionqueue/actions/Action.kt | 1 - .../actions/SendWelcomeTestEmailAction.kt | 76 ------------------- .../google/gson/ActionJsonDeserializer.kt | 6 -- 9 files changed, 35 insertions(+), 133 deletions(-) rename FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/request/model/{TestWelcomeModel.kt => WelcomeMessageModel.kt} (94%) rename FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/response/attester/{TestWelcomeResponse.kt => WelcomeMessageResponse.kt} (80%) delete mode 100644 FlowCrypt/src/main/java/com/flowcrypt/email/service/actionqueue/actions/SendWelcomeTestEmailAction.kt diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiRepository.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiRepository.kt index a0bbdd2376..f54e3e993b 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiRepository.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiRepository.kt @@ -10,7 +10,7 @@ import com.flowcrypt.email.api.retrofit.base.BaseApiRepository import com.flowcrypt.email.api.retrofit.request.model.LoginModel import com.flowcrypt.email.api.retrofit.request.model.MessageUploadRequest import com.flowcrypt.email.api.retrofit.request.model.PostHelpFeedbackModel -import com.flowcrypt.email.api.retrofit.request.model.TestWelcomeModel +import com.flowcrypt.email.api.retrofit.request.model.WelcomeMessageModel import com.flowcrypt.email.api.retrofit.response.api.EkmPrivateKeysResponse import com.flowcrypt.email.api.retrofit.response.api.FesServerResponse import com.flowcrypt.email.api.retrofit.response.api.LoginResponse @@ -19,7 +19,7 @@ import com.flowcrypt.email.api.retrofit.response.api.MessageUploadResponse import com.flowcrypt.email.api.retrofit.response.api.PostHelpFeedbackResponse import com.flowcrypt.email.api.retrofit.response.attester.PubResponse import com.flowcrypt.email.api.retrofit.response.attester.SubmitPubKeyResponse -import com.flowcrypt.email.api.retrofit.response.attester.TestWelcomeResponse +import com.flowcrypt.email.api.retrofit.response.attester.WelcomeMessageResponse import com.flowcrypt.email.api.retrofit.response.base.ApiResponse import com.flowcrypt.email.api.retrofit.response.base.Result import com.flowcrypt.email.api.retrofit.response.model.OrgRules @@ -75,12 +75,13 @@ interface ApiRepository : BaseApiRepository { /** * @param context Interface to global information about an application environment. - * @param model An instance of [TestWelcomeModel]. + * @param model An instance of [WelcomeMessageModel]. */ - suspend fun postTestWelcome( + suspend fun postWelcomeMessage( context: Context, - model: TestWelcomeModel - ): Result + model: WelcomeMessageModel, + idToken: String + ): Result /** * @param requestCode A unique request code for this call diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiService.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiService.kt index ebf0acae6b..682308b97c 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiService.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiService.kt @@ -9,7 +9,7 @@ import com.flowcrypt.email.BuildConfig import com.flowcrypt.email.api.oauth.OAuth2Helper import com.flowcrypt.email.api.retrofit.request.model.LoginModel import com.flowcrypt.email.api.retrofit.request.model.PostHelpFeedbackModel -import com.flowcrypt.email.api.retrofit.request.model.TestWelcomeModel +import com.flowcrypt.email.api.retrofit.request.model.WelcomeMessageModel import com.flowcrypt.email.api.retrofit.response.api.ClientConfigurationResponse import com.flowcrypt.email.api.retrofit.response.api.DomainOrgRulesResponse import com.flowcrypt.email.api.retrofit.response.api.EkmPrivateKeysResponse @@ -19,7 +19,7 @@ import com.flowcrypt.email.api.retrofit.response.api.MessageReplyTokenResponse import com.flowcrypt.email.api.retrofit.response.api.MessageUploadResponse import com.flowcrypt.email.api.retrofit.response.api.PostHelpFeedbackResponse import com.flowcrypt.email.api.retrofit.response.attester.SubmitPubKeyResponse -import com.flowcrypt.email.api.retrofit.response.attester.TestWelcomeResponse +import com.flowcrypt.email.api.retrofit.response.attester.WelcomeMessageResponse import com.flowcrypt.email.api.retrofit.response.oauth2.MicrosoftOAuth2TokenResponse import com.google.gson.JsonObject import okhttp3.MultipartBody @@ -50,22 +50,13 @@ import retrofit2.http.Url */ interface ApiService { /** - * This method create a [Call] object for the API "https://flowcrypt.com/attester/test/welcome" - * - * @param body POJO model for requests - * @return [<] - */ - @POST("test/welcome") - fun postTestWelcome(@Body body: TestWelcomeModel): Call - - /** - * This method create a [Response] object for the API "https://flowcrypt.com/attester/test/welcome" - * - * @param body POJO model for requests - * @return [<] + * This method create a [Response] object for the API "https://flowcrypt.com/attester/welcome-message" */ - @POST("test/welcome") - suspend fun postTestWelcomeSuspend(@Body body: TestWelcomeModel): Response + @POST("welcome-message") + suspend fun postWelcomeMessage( + @Body body: WelcomeMessageModel, + @Header("Authorization") authorization: String + ): Response /** * This method create a [Call] object for the API "https://flowcrypt.com/api/help/feedback" diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/FlowcryptApiRepository.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/FlowcryptApiRepository.kt index f81658381e..8e0328a2b8 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/FlowcryptApiRepository.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/FlowcryptApiRepository.kt @@ -11,7 +11,7 @@ import com.flowcrypt.email.R import com.flowcrypt.email.api.retrofit.request.model.LoginModel import com.flowcrypt.email.api.retrofit.request.model.MessageUploadRequest import com.flowcrypt.email.api.retrofit.request.model.PostHelpFeedbackModel -import com.flowcrypt.email.api.retrofit.request.model.TestWelcomeModel +import com.flowcrypt.email.api.retrofit.request.model.WelcomeMessageModel import com.flowcrypt.email.api.retrofit.response.api.EkmPrivateKeysResponse import com.flowcrypt.email.api.retrofit.response.api.FesServerResponse import com.flowcrypt.email.api.retrofit.response.api.LoginResponse @@ -20,7 +20,7 @@ import com.flowcrypt.email.api.retrofit.response.api.MessageUploadResponse import com.flowcrypt.email.api.retrofit.response.api.PostHelpFeedbackResponse import com.flowcrypt.email.api.retrofit.response.attester.PubResponse import com.flowcrypt.email.api.retrofit.response.attester.SubmitPubKeyResponse -import com.flowcrypt.email.api.retrofit.response.attester.TestWelcomeResponse +import com.flowcrypt.email.api.retrofit.response.attester.WelcomeMessageResponse import com.flowcrypt.email.api.retrofit.response.base.ApiResponse import com.flowcrypt.email.api.retrofit.response.base.Result import com.flowcrypt.email.api.retrofit.response.model.OrgRules @@ -104,13 +104,14 @@ class FlowcryptApiRepository : ApiRepository { } } - override suspend fun postTestWelcome( + override suspend fun postWelcomeMessage( context: Context, - model: TestWelcomeModel - ): Result = + model: WelcomeMessageModel, + idToken: String + ): Result = withContext(Dispatchers.IO) { val apiService = ApiHelper.getInstance(context).retrofit.create(ApiService::class.java) - getResult { apiService.postTestWelcomeSuspend(model) } + getResult { apiService.postWelcomeMessage(model, "Bearer $idToken") } } override suspend fun pubLookup( diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/request/model/TestWelcomeModel.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/request/model/WelcomeMessageModel.kt similarity index 94% rename from FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/request/model/TestWelcomeModel.kt rename to FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/request/model/WelcomeMessageModel.kt index 16f3f89102..f7c56a2c51 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/request/model/TestWelcomeModel.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/request/model/WelcomeMessageModel.kt @@ -16,7 +16,7 @@ import com.google.gson.annotations.SerializedName * Time: 16:40 * E-mail: DenBond7@gmail.com */ -data class TestWelcomeModel( +data class WelcomeMessageModel( @SerializedName("email") @Expose val email: String, @SerializedName("pubkey") @Expose val pubKey: String ) : RequestModel diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/response/attester/TestWelcomeResponse.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/response/attester/WelcomeMessageResponse.kt similarity index 80% rename from FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/response/attester/TestWelcomeResponse.kt rename to FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/response/attester/WelcomeMessageResponse.kt index 8499253854..167a8516d0 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/response/attester/TestWelcomeResponse.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/response/attester/WelcomeMessageResponse.kt @@ -28,7 +28,7 @@ import com.google.gson.annotations.SerializedName * Time: 14:38 * E-mail: DenBond7@gmail.com */ -data class TestWelcomeResponse constructor( +data class WelcomeMessageResponse constructor( @SerializedName("error") @Expose override val apiError: ApiError? ) : ApiResponse { @@ -47,9 +47,9 @@ data class TestWelcomeResponse constructor( companion object { @JvmField - val CREATOR = object : Parcelable.Creator { - override fun createFromParcel(source: Parcel) = TestWelcomeResponse(source) - override fun newArray(size: Int): Array = arrayOfNulls(size) + val CREATOR = object : Parcelable.Creator { + override fun createFromParcel(source: Parcel) = WelcomeMessageResponse(source) + override fun newArray(size: Int): Array = arrayOfNulls(size) } } } diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt index 7f44531795..f6d438f392 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt @@ -22,7 +22,7 @@ import com.flowcrypt.email.api.email.protocol.OpenStoreHelper import com.flowcrypt.email.api.email.protocol.SmtpProtocolUtil import com.flowcrypt.email.api.retrofit.ApiRepository import com.flowcrypt.email.api.retrofit.FlowcryptApiRepository -import com.flowcrypt.email.api.retrofit.request.model.TestWelcomeModel +import com.flowcrypt.email.api.retrofit.request.model.WelcomeMessageModel import com.flowcrypt.email.api.retrofit.response.base.Result import com.flowcrypt.email.api.retrofit.response.model.OrgRules import com.flowcrypt.email.database.entity.AccountEntity @@ -39,7 +39,6 @@ import com.flowcrypt.email.security.SecurityUtils import com.flowcrypt.email.security.model.PgpKeyDetails import com.flowcrypt.email.security.pgp.PgpKey import com.flowcrypt.email.service.actionqueue.actions.BackupPrivateKeyToInboxAction -import com.flowcrypt.email.service.actionqueue.actions.SendWelcomeTestEmailAction import com.flowcrypt.email.util.GeneralUtil import com.flowcrypt.email.util.exception.ApiException import com.flowcrypt.email.util.exception.ExceptionUtil @@ -442,15 +441,7 @@ class PrivateKeysViewModel(application: Application) : AccountViewModel(applicat registerUserPublicKey(accountEntity, pgpKeyDetails, idToken) } - if (!requestingTestMsgWithNewPublicKey(accountEntity, pgpKeyDetails)) { - val welcomeEmailAction = ActionQueueEntity.fromAction( - SendWelcomeTestEmailAction( - 0, - accountEntity.email, 0, pgpKeyDetails.publicKey - ) - ) - welcomeEmailAction?.let { action -> roomDatabase.actionQueueDao().insertSuspend(action) } - } + idToken?.let { postWelcomeMessage(accountEntity, pgpKeyDetails, it) } } private suspend fun getModifiedPgpKeyDetails( @@ -572,19 +563,20 @@ class PrivateKeysViewModel(application: Application) : AccountViewModel(applicat } /** - * Request a test email from FlowCrypt. + * Send a welcome message. * * @param keyDetails Details of the created key. * @return true if no errors. */ - private suspend fun requestingTestMsgWithNewPublicKey( + private suspend fun postWelcomeMessage( accountEntity: AccountEntity, - keyDetails: PgpKeyDetails + keyDetails: PgpKeyDetails, + idToken: String, ): Boolean = withContext(Dispatchers.IO) { return@withContext try { - val model = TestWelcomeModel(accountEntity.email, keyDetails.publicKey) - val testWelcomeResult = apiRepository.postTestWelcome(getApplication(), model) + val model = WelcomeMessageModel(accountEntity.email, keyDetails.publicKey) + val testWelcomeResult = apiRepository.postWelcomeMessage(getApplication(), model, idToken) when (testWelcomeResult.status) { Result.Status.SUCCESS -> { testWelcomeResult.data?.apiError == null diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/service/actionqueue/actions/Action.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/service/actionqueue/actions/Action.kt index 6cdad6f0e6..c4ac9b6fdf 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/service/actionqueue/actions/Action.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/service/actionqueue/actions/Action.kt @@ -30,7 +30,6 @@ interface Action : Parcelable { */ enum class Type constructor(val value: String) : Parcelable { BACKUP_PRIVATE_KEY_TO_INBOX("backup_private_key_to_inbox"), - SEND_WELCOME_TEST_EMAIL("send_welcome_test_email"), ENCRYPT_PRIVATE_KEYS("encrypt_private_keys"), LOAD_GMAIL_ALIASES("load_gmail_aliases"); diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/service/actionqueue/actions/SendWelcomeTestEmailAction.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/service/actionqueue/actions/SendWelcomeTestEmailAction.kt deleted file mode 100644 index 8b2c4f8f9d..0000000000 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/service/actionqueue/actions/SendWelcomeTestEmailAction.kt +++ /dev/null @@ -1,76 +0,0 @@ -/* - * © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com - * Contributors: DenBond7 - */ - -package com.flowcrypt.email.service.actionqueue.actions - -import android.content.Context -import android.os.Parcel -import android.os.Parcelable -import com.flowcrypt.email.api.retrofit.ApiHelper -import com.flowcrypt.email.api.retrofit.ApiService -import com.flowcrypt.email.api.retrofit.request.model.TestWelcomeModel -import com.flowcrypt.email.util.exception.ApiException -import com.google.gson.annotations.SerializedName - -/** - * This action describes a task which sends a welcome message to the user - * using API "https://flowcrypt.com/attester/test/welcome". - * - * @author Denis Bondarenko - * Date: 30.01.2018 - * Time: 18:10 - * E-mail: DenBond7@gmail.com - */ -data class SendWelcomeTestEmailAction @JvmOverloads constructor( - override var id: Long = 0, - override var email: String? = null, - override val version: Int = 0, - private val publicKey: String -) : Action, Parcelable { - @SerializedName(Action.TAG_NAME_ACTION_TYPE) - override val type: Action.Type = Action.Type.SEND_WELCOME_TEST_EMAIL - - override suspend fun run(context: Context) { - val apiService = ApiHelper.getInstance(context).retrofit.create(ApiService::class.java) - val body = TestWelcomeModel(email!!, publicKey) - val response = apiService.postTestWelcome(body).execute() - - val (apiError) = response.body() ?: throw IllegalArgumentException("The response is null!") - - if (apiError != null) { - throw ApiException(apiError) - } - } - - constructor(source: Parcel) : this( - source.readLong(), - source.readString(), - source.readInt(), - source.readString()!! - ) - - override fun describeContents(): Int { - return 0 - } - - override fun writeToParcel(dest: Parcel, flags: Int) = - with(dest) { - writeLong(id) - writeString(email) - writeInt(version) - writeString(publicKey) - } - - companion object { - @JvmField - val CREATOR: Parcelable.Creator = - object : Parcelable.Creator { - override fun createFromParcel(source: Parcel): SendWelcomeTestEmailAction = - SendWelcomeTestEmailAction(source) - - override fun newArray(size: Int): Array = arrayOfNulls(size) - } - } -} diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/util/google/gson/ActionJsonDeserializer.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/util/google/gson/ActionJsonDeserializer.kt index 64af891b54..4a33c5a529 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/util/google/gson/ActionJsonDeserializer.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/util/google/gson/ActionJsonDeserializer.kt @@ -9,7 +9,6 @@ import com.flowcrypt.email.service.actionqueue.actions.Action import com.flowcrypt.email.service.actionqueue.actions.BackupPrivateKeyToInboxAction import com.flowcrypt.email.service.actionqueue.actions.EncryptPrivateKeysIfNeededAction import com.flowcrypt.email.service.actionqueue.actions.LoadGmailAliasesAction -import com.flowcrypt.email.service.actionqueue.actions.SendWelcomeTestEmailAction import com.google.gson.Gson import com.google.gson.JsonDeserializationContext import com.google.gson.JsonDeserializer @@ -39,11 +38,6 @@ class ActionJsonDeserializer : JsonDeserializer { BackupPrivateKeyToInboxAction::class.java ) - Action.Type.SEND_WELCOME_TEST_EMAIL -> context.deserialize( - json, - SendWelcomeTestEmailAction::class.java - ) - Action.Type.ENCRYPT_PRIVATE_KEYS -> context.deserialize( json, EncryptPrivateKeysIfNeededAction::class.java From 6c5d38cca135e331e1aece9432886975ee6cf58b Mon Sep 17 00:00:00 2001 From: DenBond7 Date: Thu, 13 Oct 2022 10:32:33 +0300 Subject: [PATCH 09/12] ImportPrivateKeyNoPubOrgRulesFlowTest. Added @Ignore("Need to fix").| #1984 --- .../email/ui/ImportPrivateKeyNoPubOrgRulesFlowTest.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/ImportPrivateKeyNoPubOrgRulesFlowTest.kt b/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/ImportPrivateKeyNoPubOrgRulesFlowTest.kt index 6035f81aa0..8ee782349d 100644 --- a/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/ImportPrivateKeyNoPubOrgRulesFlowTest.kt +++ b/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/ImportPrivateKeyNoPubOrgRulesFlowTest.kt @@ -32,6 +32,7 @@ import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.RecordedRequest import org.junit.BeforeClass import org.junit.ClassRule +import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.rules.RuleChain @@ -40,6 +41,8 @@ import org.junit.runner.RunWith import java.net.HttpURLConnection /** + * https://github.com/FlowCrypt/flowcrypt-android/issues/768 + * * @author Denis Bondarenko * Date: 7/10/20 * Time: 4:57 PM @@ -47,6 +50,7 @@ import java.net.HttpURLConnection */ @MediumTest @RunWith(AndroidJUnit4::class) +@Ignore("Need to fix") class ImportPrivateKeyNoPubOrgRulesFlowTest : BaseTest() { private val account = AccountDaoManager.getAccountDao("no.pub@org-rules-test.flowcrypt.com.json") From 6ad5474ecf0497c6ab5272087622ba4a3932738b Mon Sep 17 00:00:00 2001 From: DenBond7 Date: Thu, 13 Oct 2022 15:17:06 +0300 Subject: [PATCH 10/12] Added SubmitPublicKeyAfterCreationNonGoogleAccountFlowTest.| #1984 --- ...eyAfterCreationNonGoogleAccountFlowTest.kt | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/SubmitPublicKeyAfterCreationNonGoogleAccountFlowTest.kt diff --git a/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/SubmitPublicKeyAfterCreationNonGoogleAccountFlowTest.kt b/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/SubmitPublicKeyAfterCreationNonGoogleAccountFlowTest.kt new file mode 100644 index 0000000000..884f47c2d1 --- /dev/null +++ b/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/SubmitPublicKeyAfterCreationNonGoogleAccountFlowTest.kt @@ -0,0 +1,139 @@ +/* + * © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com + * Contributors: DenBond7 + */ + +package com.flowcrypt.email.ui + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.clearText +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.action.ViewActions.closeSoftKeyboard +import androidx.test.espresso.action.ViewActions.replaceText +import androidx.test.espresso.action.ViewActions.typeText +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.ext.junit.rules.activityScenarioRule +import com.flowcrypt.email.R +import com.flowcrypt.email.TestConstants +import com.flowcrypt.email.api.email.IMAPStoreConnection +import com.flowcrypt.email.junit.annotations.DependsOnMailServer +import com.flowcrypt.email.rules.ClearAppSettingsRule +import com.flowcrypt.email.rules.FlowCryptMockWebServerRule +import com.flowcrypt.email.rules.RetryRule +import com.flowcrypt.email.rules.ScreenshotTestRule +import com.flowcrypt.email.ui.activity.MainActivity +import com.flowcrypt.email.ui.base.BaseSignTest +import com.flowcrypt.email.util.AccountDaoManager +import com.sun.mail.imap.IMAPFolder +import jakarta.mail.Flags +import jakarta.mail.Folder +import junit.framework.Assert.assertTrue +import kotlinx.coroutines.runBlocking +import okhttp3.mockwebserver.MockResponse +import okhttp3.mockwebserver.RecordedRequest +import org.junit.Rule +import org.junit.Test +import org.junit.rules.RuleChain +import org.junit.rules.TestRule +import java.net.HttpURLConnection +import java.util.UUID + +/** + * https://github.com/FlowCrypt/flowcrypt-android/issues/1984 + * + * @author Denis Bondarenko + * Date: 10/13/22 + * Time: 10:34 AM + * E-mail: DenBond7@gmail.com + */ +@DependsOnMailServer +class SubmitPublicKeyAfterCreationNonGoogleAccountFlowTest : BaseSignTest() { + override val useIntents: Boolean = true + override val activityScenarioRule = activityScenarioRule() + + private val userWithoutBackups = AccountDaoManager.getUserWithoutBackup() + private var isSubmitPubKeyCalled = false + + val mockWebServerRule = FlowCryptMockWebServerRule(TestConstants.MOCK_WEB_SERVER_PORT, + object : okhttp3.mockwebserver.Dispatcher() { + override fun dispatch(request: RecordedRequest): MockResponse { + if (request.path?.startsWith("/pub", ignoreCase = true) == true) { + val lastSegment = request.requestUrl?.pathSegments?.lastOrNull() + + when { + userWithoutBackups.email.equals(lastSegment, true) -> { + isSubmitPubKeyCalled = true + return MockResponse() + .setResponseCode(HttpURLConnection.HTTP_OK) + } + } + } + + return MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_FOUND) + } + }) + + @get:Rule + var ruleChain: TestRule = RuleChain + .outerRule(RetryRule.DEFAULT) + .around(ClearAppSettingsRule()) + .around(mockWebServerRule) + .around(activityScenarioRule) + .around(ScreenshotTestRule()) + + @Test + fun testCallSubmitPubKeyAfterKeyCreation() { + try { + onView(withId(R.id.buttonOtherEmailProvider)) + .check(matches(isDisplayed())) + .perform(click()) + + onView(withId(R.id.editTextEmail)) + .perform(clearText(), typeText(userWithoutBackups.email), closeSoftKeyboard()) + onView(withId(R.id.editTextPassword)) + .perform(clearText(), typeText(userWithoutBackups.password), closeSoftKeyboard()) + + onView(withId(R.id.buttonTryToConnect)) + .check(matches(isDisplayed())) + .perform(click()) + + onView(withId(R.id.buttonCreateNewKey)) + .check(matches(isDisplayed())) + .perform(click()) + + val passphrase = UUID.randomUUID().toString() + UUID.randomUUID().toString() + onView(withId(R.id.editTextKeyPassword)) + .check(matches(isDisplayed())) + .perform(replaceText(passphrase), closeSoftKeyboard()) + onView(withId(R.id.buttonSetPassPhrase)) + .check(matches(isDisplayed())) + .perform(click()) + onView(withId(R.id.editTextKeyPasswordSecond)) + .check(matches(isDisplayed())) + .perform(replaceText(passphrase), closeSoftKeyboard()) + onView(withId(R.id.buttonConfirmPassPhrases)) + .check(matches(isDisplayed())) + .perform(click()) + + assertTrue(isSubmitPubKeyCalled) + } finally { + runBlocking { + val imapStoreConnection = IMAPStoreConnection(getTargetContext(), userWithoutBackups) + imapStoreConnection.connect() + imapStoreConnection.store.use { store -> + store.getFolder("INBOX").use { folder -> + val imapFolder = (folder as IMAPFolder).apply { open(Folder.READ_WRITE) } + val msgs = + imapFolder.messages.filter { it.subject == "Your FlowCrypt Backup" }.toTypedArray() + if (msgs.isNotEmpty()) { + imapFolder.setFlags(msgs, Flags(Flags.Flag.DELETED), true) + } + folder.expunge() + } + } + } + } + } +} From acdaa0e1901014533997f2e21a625f680e52897e Mon Sep 17 00:00:00 2001 From: DenBond7 Date: Thu, 13 Oct 2022 18:54:27 +0300 Subject: [PATCH 11/12] Fixed a bug in PrivateKeysViewModel.registerUserPublicKey().| #1984 --- .../jetpack/viewmodel/PrivateKeysViewModel.kt | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt index f6d438f392..1258e01829 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt @@ -508,14 +508,14 @@ class PrivateKeysViewModel(application: Application) : AccountViewModel(applicat } /** - * Registering a key with attester API. - * Note: this will only be successful if it's the first time submitting a key for this email address, or if the - * key being submitted has the same fingerprint as the one already recorded. If it's an error due to key - * conflict, ignore the error. + * Set or replace public key. If idToken != null an auth mechanism will be used to upload + * the given pub key. Otherwise will be used a request to replace public key that will + * be verified by clicking email. * * @param accountEntity [AccountEntity] which will be used for registration. * @param keyDetails Details of the created key. - * @return true if no errors. + * @param idToken A value from [com.google.android.gms.auth.api.signin.GoogleSignInAccount]. + * @param isSilent If true - skip errors or exceptions. */ private suspend fun registerUserPublicKey( accountEntity: AccountEntity, @@ -534,11 +534,16 @@ class PrivateKeysViewModel(application: Application) : AccountViewModel(applicat when (submitPubKeyResult.status) { Result.Status.SUCCESS -> { val body = submitPubKeyResult.data - val isSuccess = body != null && (body.apiError == null || body.apiError.code !in 400..499) - if (isSilent) { - isSuccess - } else { - throw IllegalStateException(body?.apiError?.msg) + when { + isSilent -> { + body != null && (body.apiError == null || body.apiError.code !in 400..499) + } + + body?.apiError != null -> { + throw IllegalStateException(ApiException(body.apiError)) + } + + else -> body != null } } From 8161b741b97f9d8c9cbdbd37b2dbd29fcd5e31c1 Mon Sep 17 00:00:00 2001 From: DenBond7 Date: Thu, 13 Oct 2022 19:43:16 +0300 Subject: [PATCH 12/12] Refactored code.| #1984 --- .../email/api/retrofit/ApiRepository.kt | 20 ++++++++++++--- .../api/retrofit/FlowcryptApiRepository.kt | 24 +++++++++++++----- .../jetpack/viewmodel/PrivateKeysViewModel.kt | 25 +++++++++++++------ 3 files changed, 51 insertions(+), 18 deletions(-) diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiRepository.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiRepository.kt index f54e3e993b..083e93b461 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiRepository.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/ApiRepository.kt @@ -61,15 +61,27 @@ interface ApiRepository : BaseApiRepository { * @param context Interface to global information about an application environment. * @param email For this email address will be applied changes. * @param pubKey A new public key. - * @param idToken If idToken != null we will use submitPrimaryEmailPubKey, - * otherwise submitPubKeyWithConditionalEmailVerification. + * @param idToken JSON Web Token signed by Google that can be used to identify a user to a backend. * @param orgRules An instance of [OrgRules]. We have to check if submitting pub keys is allowed. */ - suspend fun submitPubKey( + suspend fun submitPrimaryEmailPubKey( + context: Context, + email: String, + pubKey: String, + idToken: String, + orgRules: OrgRules? = null + ): Result + + /** + * @param context Interface to global information about an application environment. + * @param email For this email address will be applied changes. + * @param pubKey A new public key. + * @param orgRules An instance of [OrgRules]. We have to check if submitting pub keys is allowed. + */ + suspend fun submitPubKeyWithConditionalEmailVerification( context: Context, email: String, pubKey: String, - idToken: String? = null, orgRules: OrgRules? = null ): Result diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/FlowcryptApiRepository.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/FlowcryptApiRepository.kt index 8e0328a2b8..ec5775da9c 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/FlowcryptApiRepository.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/FlowcryptApiRepository.kt @@ -83,11 +83,11 @@ class FlowcryptApiRepository : ApiRepository { } } - override suspend fun submitPubKey( + override suspend fun submitPrimaryEmailPubKey( context: Context, email: String, pubKey: String, - idToken: String?, + idToken: String, orgRules: OrgRules? ): Result = withContext(Dispatchers.IO) { @@ -97,11 +97,23 @@ class FlowcryptApiRepository : ApiRepository { ) } val apiService = ApiHelper.getInstance(context).retrofit.create(ApiService::class.java) - getResult { - idToken?.let { nonNullIdToken -> - apiService.submitPrimaryEmailPubKey(email, pubKey, "Bearer $nonNullIdToken") - } ?: apiService.submitPubKeyWithConditionalEmailVerification(email, pubKey) + getResult { apiService.submitPrimaryEmailPubKey(email, pubKey, "Bearer $idToken") } + } + + override suspend fun submitPubKeyWithConditionalEmailVerification( + context: Context, + email: String, + pubKey: String, + orgRules: OrgRules? + ): Result = + withContext(Dispatchers.IO) { + if (orgRules?.canSubmitPubToAttester() == false) { + return@withContext Result.exception( + IllegalStateException(context.getString(R.string.can_not_replace_public_key_at_attester)) + ) } + val apiService = ApiHelper.getInstance(context).retrofit.create(ApiService::class.java) + getResult { apiService.submitPubKeyWithConditionalEmailVerification(email, pubKey) } } override suspend fun postWelcomeMessage( diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt index 1258e01829..daebdb9347 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/PrivateKeysViewModel.kt @@ -514,7 +514,7 @@ class PrivateKeysViewModel(application: Application) : AccountViewModel(applicat * * @param accountEntity [AccountEntity] which will be used for registration. * @param keyDetails Details of the created key. - * @param idToken A value from [com.google.android.gms.auth.api.signin.GoogleSignInAccount]. + * @param idToken JSON Web Token signed by Google that can be used to identify a user to a backend. * @param isSilent If true - skip errors or exceptions. */ private suspend fun registerUserPublicKey( @@ -523,13 +523,22 @@ class PrivateKeysViewModel(application: Application) : AccountViewModel(applicat idToken: String? = null, isSilent: Boolean = true, ): Boolean = withContext(Dispatchers.IO) { - val submitPubKeyResult = apiRepository.submitPubKey( - context = getApplication(), - email = accountEntity.email, - pubKey = keyDetails.publicKey, - idToken = idToken, - orgRules = accountEntity.clientConfiguration - ) + val submitPubKeyResult = if (idToken != null) { + apiRepository.submitPrimaryEmailPubKey( + context = getApplication(), + email = accountEntity.email, + pubKey = keyDetails.publicKey, + idToken = idToken, + orgRules = accountEntity.clientConfiguration, + ) + } else { + apiRepository.submitPubKeyWithConditionalEmailVerification( + context = getApplication(), + email = accountEntity.email, + pubKey = keyDetails.publicKey, + orgRules = accountEntity.clientConfiguration, + ) + } when (submitPubKeyResult.status) { Result.Status.SUCCESS -> {