Skip to content

Commit

Permalink
Got a stable version without the token refreshing.| #716
Browse files Browse the repository at this point in the history
  • Loading branch information
DenBond7 committed Aug 12, 2020
1 parent 02611bf commit 9df7464
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 74 deletions.
1 change: 1 addition & 0 deletions FlowCrypt/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -426,4 +426,5 @@ dependencies {
implementation 'ja.burhanrashid52:photoeditor:1.0.0'
implementation "org.jetbrains.kotlin:kotlin-reflect:1.3.72"
implementation 'net.openid:appauth:0.7.1'
implementation 'org.bitbucket.b_c:jose4j:0.7.2'
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ data class AuthCredentials constructor(val email: String,
val smtpSigInUsername: String? = null,
var smtpSignInPassword: String? = null,
val faqUrl: String? = null,
val useOAuth2: Boolean = false) : Parcelable {
val useOAuth2: Boolean = false,
val displayName: String? = null) : Parcelable {
constructor(source: Parcel) : this(
source.readString()!!,
source.readString()!!,
Expand All @@ -46,7 +47,8 @@ data class AuthCredentials constructor(val email: String,
source.readString(),
source.readString(),
source.readString(),
source.readByte() != 0.toByte()
source.readByte() != 0.toByte(),
source.readString()
)

override fun describeContents() = 0
Expand All @@ -67,6 +69,7 @@ data class AuthCredentials constructor(val email: String,
writeString(smtpSignInPassword)
writeString(faqUrl)
writeInt((if (useOAuth2) 1 else 0))
writeString(displayName)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ class OAuth2Helper {
*
* https://outlook.office.com/SMTP.Send - Allows the app to be able to send emails from the user’s mailbox using the SMTP AUTH client submission protocol.
*/
const val SCOPE_MICROSOFT_OAUTH2_FOR_MAIL = "offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send"
const val SCOPE_MICROSOFT_OAUTH2_FOR_PROFILE = "openid profile email"
const val SCOPE_MICROSOFT_OAUTH2_FOR_MAIL = "openid offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send"

const val MICROSOFT_OAUTH2_AUTHORIZE_URL = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize"
const val MICROSOFT_OAUTH2_TOKEN_URL = "https://login.microsoftonline.com/common/oauth2/v2.0/token"
Expand All @@ -48,7 +47,7 @@ class OAuth2Helper {
MICROSOFT_AZURE_APP_ID,
ResponseTypeValues.CODE,
Uri.parse(MICROSOFT_REDIRECT_URI))
.setScope("$SCOPE_MICROSOFT_OAUTH2_FOR_PROFILE $SCOPE_MICROSOFT_OAUTH2_FOR_MAIL")
.setScope("profile email $SCOPE_MICROSOFT_OAUTH2_FOR_MAIL")
.build()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ data class AccountEntity constructor(
this(
email = authCredentials.email,
accountType = authCredentials.email.substring(authCredentials.email.indexOf('@') + 1).toLowerCase(Locale.getDefault()),
displayName = null,
displayName = authCredentials.displayName,
givenName = null,
familyName = null,
photoUrl = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,15 @@ import com.flowcrypt.email.api.oauth.OAuth2Helper
import com.flowcrypt.email.api.retrofit.ApiRepository
import com.flowcrypt.email.api.retrofit.FlowcryptApiRepository
import com.flowcrypt.email.api.retrofit.response.base.Result
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import net.openid.appauth.AuthorizationRequest
import org.jose4j.jwk.HttpsJwks
import org.jose4j.jwt.JwtClaims
import org.jose4j.jwt.consumer.JwtConsumerBuilder
import org.jose4j.keys.resolvers.HttpsJwksVerificationKeyResolver
import java.util.*


/**
Expand All @@ -31,83 +38,67 @@ class OAuth2AuthCredentialsViewModel(application: Application) : BaseAndroidView
fun getMicrosoftOAuth2Token(requestCode: Long = 0L, authorizeCode: String, authRequest: AuthorizationRequest) {
viewModelScope.launch {
microsoftOAuth2TokenLiveData.postValue(Result.loading())
val microsoftOAuth2TokenResponseResultForProfile = apiRepository.getMicrosoftOAuth2Token(
requestCode = requestCode,
context = getApplication(),
authorizeCode = authorizeCode,
scopes = OAuth2Helper.SCOPE_MICROSOFT_OAUTH2_FOR_PROFILE,
codeVerifier = authRequest.codeVerifier ?: ""
)

if (microsoftOAuth2TokenResponseResultForProfile.status != Result.Status.SUCCESS) {
when (microsoftOAuth2TokenResponseResultForProfile.status) {
Result.Status.ERROR -> {
microsoftOAuth2TokenLiveData.postValue(Result.exception(IllegalStateException()))
}

Result.Status.EXCEPTION -> {
microsoftOAuth2TokenLiveData.postValue(Result.exception(microsoftOAuth2TokenResponseResultForProfile.exception
?: RuntimeException()))
}

else -> {
try {
val response = apiRepository.getMicrosoftOAuth2Token(
requestCode = requestCode,
context = getApplication(),
authorizeCode = authorizeCode,
scopes = OAuth2Helper.SCOPE_MICROSOFT_OAUTH2_FOR_MAIL,
codeVerifier = authRequest.codeVerifier ?: ""
)

if (response.status != Result.Status.SUCCESS) {
when (response.status) {
Result.Status.ERROR -> {
microsoftOAuth2TokenLiveData.postValue(Result.exception(IllegalStateException()))
}

Result.Status.EXCEPTION -> {
microsoftOAuth2TokenLiveData.postValue(Result.exception(response.exception
?: RuntimeException()))
}

else -> {
}
}
return@launch
}
return@launch
}

//validate id_token


val tokenForProfile = microsoftOAuth2TokenResponseResultForProfile.data?.accessToken
if (tokenForProfile == null) {
microsoftOAuth2TokenLiveData.postValue(Result.exception(NullPointerException("token is null")))
return@launch
}


val userEmailAddress = "[email protected]"//microsoftAccount.data?.userPrincipalName
if (userEmailAddress == null) {
microsoftOAuth2TokenLiveData.postValue(Result.exception(NullPointerException("User email is null")))
return@launch
}
val claims = validateTokenAndGetClaims(response.data?.idToken ?: "")
val email: String? = claims.getClaimValueAsString(CLAIM_EMAIL)?.toLowerCase(Locale.US)
val displayName: String? = claims.getClaimValueAsString(CLAIM_NAME)

val microsoftOAuth2TokenResponseResultForEmail = apiRepository.getMicrosoftOAuth2Token(
requestCode = requestCode,
context = getApplication(),
authorizeCode = authorizeCode,
scopes = OAuth2Helper.SCOPE_MICROSOFT_OAUTH2_FOR_MAIL,
codeVerifier = authRequest.codeVerifier ?: ""
)

if (microsoftOAuth2TokenResponseResultForEmail.status != Result.Status.SUCCESS) {
when (microsoftOAuth2TokenResponseResultForEmail.status) {
Result.Status.ERROR -> {
microsoftOAuth2TokenLiveData.postValue(Result.exception(IllegalStateException()))
}

Result.Status.EXCEPTION -> {
microsoftOAuth2TokenLiveData.postValue(Result.exception(microsoftOAuth2TokenResponseResultForEmail.exception
?: RuntimeException()))
}

else -> {
}
if (email == null) {
microsoftOAuth2TokenLiveData.postValue(Result.exception(NullPointerException("User email is null!")))
return@launch
}
return@launch
}

val tokenForEmail = microsoftOAuth2TokenResponseResultForEmail.data?.accessToken
val token = response.data?.accessToken ?: throw NullPointerException("token is null")
val recommendAuthCredentials = EmailProviderSettingsHelper.getBaseSettings(
email, token)?.copy(useOAuth2 = true, displayName = displayName)
?: throw NullPointerException("Couldn't find default settings!")

if (tokenForEmail == null) {
microsoftOAuth2TokenLiveData.postValue(Result.exception(NullPointerException("token is null")))
return@launch
microsoftOAuth2TokenLiveData.postValue(Result.success(recommendAuthCredentials))
} catch (e: Exception) {
microsoftOAuth2TokenLiveData.postValue(Result.exception(e))
}
}
}

val recommendAuthCredentials = EmailProviderSettingsHelper.getBaseSettings(
"microsoftAccount.data.userPrincipalName", tokenForEmail)?.copy(useOAuth2 = true)
private suspend fun validateTokenAndGetClaims(idToken: String): JwtClaims =
withContext(Dispatchers.IO) {
//https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration
val httpsJkws = HttpsJwks("https://login.microsoftonline.com/common/discovery/v2.0/keys")
val httpsJwksKeyResolver = HttpsJwksVerificationKeyResolver(httpsJkws)
val jwtConsumer = JwtConsumerBuilder()
.setVerificationKeyResolver(httpsJwksKeyResolver)
.setExpectedAudience("3be51534-5f76-4970-9a34-40ef197aa018")
.build()
return@withContext jwtConsumer.processToClaims(idToken)
}

microsoftOAuth2TokenLiveData.postValue(Result.success(recommendAuthCredentials!!))
}
companion object {
private const val CLAIM_EMAIL = "email"
private const val CLAIM_NAME = "name"
}
}

0 comments on commit 9df7464

Please sign in to comment.