From 58667fb6cd2ef521e4aa38f27cafe5c057e5656b Mon Sep 17 00:00:00 2001 From: Sujoy Adhikary Date: Fri, 10 Apr 2026 12:41:15 +0530 Subject: [PATCH 1/5] datadog setup - setup - service name - user id set - config change --- apps/build.gradle | 1 + .../src/main/java/GlobalDependencies.kt | 3 + apps/student/build.gradle | 9 ++- .../student/fragment/DashboardFragment.kt | 2 + .../instructure/student/util/AppManager.kt | 79 ++++++++++++++++++- 5 files changed, 92 insertions(+), 2 deletions(-) diff --git a/apps/build.gradle b/apps/build.gradle index e74b6b143..57bbb70a5 100644 --- a/apps/build.gradle +++ b/apps/build.gradle @@ -34,6 +34,7 @@ buildscript { classpath Plugins.FIREBASE_CRASHLYTICS if (project.coverageEnabled) { classpath Plugins.JACOCO_ANDROID } classpath Plugins.HILT + classpath Plugins.DATADOG } } diff --git a/apps/buildSrc/src/main/java/GlobalDependencies.kt b/apps/buildSrc/src/main/java/GlobalDependencies.kt index 25aa35d53..6622d7079 100644 --- a/apps/buildSrc/src/main/java/GlobalDependencies.kt +++ b/apps/buildSrc/src/main/java/GlobalDependencies.kt @@ -41,6 +41,7 @@ object Versions { const val DATASTORE = "1.1.1" const val LOTTIE = "6.5.2" const val ENCRYPTED_SHARED_PREFERENCES = "1.0.0" + const val DATADOG = "1.22.0" } object Libs { @@ -200,4 +201,6 @@ object Plugins { const val GOOGLE_SERVICES = "com.google.gms:google-services:${Versions.GOOGLE_SERVICES}" const val JACOCO_ANDROID = "com.dicedmelon.gradle:jacoco-android:${Versions.JACOCO_ANDROID}" const val HILT = "com.google.dagger:hilt-android-gradle-plugin:${Versions.HILT}" + + const val DATADOG = "com.datadoghq:dd-sdk-android-gradle-plugin:${Versions.DATADOG}" } diff --git a/apps/student/build.gradle b/apps/student/build.gradle index 1d0d6f50e..7c2967fdf 100644 --- a/apps/student/build.gradle +++ b/apps/student/build.gradle @@ -46,7 +46,8 @@ android { testInstrumentationRunnerArguments disableAnalytics: 'true' buildConfigField "boolean", "IS_TESTING", "false" buildConfigField "String", "BUGFENDER_KEY", "\"${Keys.BUGFENDER_KEY}\"" - + buildConfigField "String", "DATADOG_CLIENT_TOKEN", "\"${Keys.DATADOG_CLIENT_TOKEN}\"" + buildConfigField "String", "DATADOG_APPLICATION_ID", "\"${Keys.DATADOG_APPLICATION_ID}\"" /* Add private data */ PrivateData.merge(project, "student") @@ -359,6 +360,12 @@ dependencies { implementation "com.amazonaws:aws-android-sdk-lambda:2.71.0" implementation "com.amazonaws:aws-android-sdk-sns:2.71.0" implementation("com.bugfender.sdk:android:3.0.17") + + //DATADOG + implementation("com.datadoghq:dd-sdk-android-rum:3.5.0") + implementation("com.datadoghq:dd-sdk-android-logs:3.5.0") + implementation("com.datadoghq:dd-sdk-android-okhttp:3.5.0") + implementation("com.datadoghq:dd-sdk-android-trace:3.5.0") } // Comment out this line if the reporting logic starts going wonky. diff --git a/apps/student/src/main/java/com/instructure/student/fragment/DashboardFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/DashboardFragment.kt index 084492212..301251297 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/DashboardFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/DashboardFragment.kt @@ -38,6 +38,7 @@ import androidx.recyclerview.widget.RecyclerView import androidx.work.WorkInfo.State import androidx.work.WorkManager import androidx.work.WorkQuery +import com.datadog.android.Datadog import com.google.firebase.crashlytics.FirebaseCrashlytics import com.instructure.canvasapi2.managers.CourseNicknameManager import com.instructure.canvasapi2.managers.UserManager @@ -568,6 +569,7 @@ class DashboardFragment : ParentFragment() { private fun initFirebase() { val user = ApiPrefs.user ?: return FirebaseAnalytics.identifyUser(user.id) + Datadog.setUserInfo(user.id.toString(), null, null) } companion object { diff --git a/apps/student/src/main/java/com/instructure/student/util/AppManager.kt b/apps/student/src/main/java/com/instructure/student/util/AppManager.kt index e20cb40f9..18bc818d4 100644 --- a/apps/student/src/main/java/com/instructure/student/util/AppManager.kt +++ b/apps/student/src/main/java/com/instructure/student/util/AppManager.kt @@ -18,6 +18,7 @@ package com.instructure.student.util import android.content.Intent +import android.util.Log import androidx.core.content.ContextCompat import androidx.hilt.work.HiltWorkerFactory import androidx.work.Constraints @@ -27,6 +28,14 @@ import androidx.work.PeriodicWorkRequestBuilder import androidx.work.WorkManager import androidx.work.WorkerFactory import com.bugfender.sdk.Bugfender +import com.datadog.android.Datadog +import com.datadog.android.core.configuration.Configuration +import com.datadog.android.log.Logger +import com.datadog.android.log.Logs +import com.datadog.android.log.LogsConfiguration +import com.datadog.android.privacy.TrackingConsent +import com.datadog.android.rum.RumConfiguration +import com.datadog.android.trace.DatadogTracing import com.instructure.canvasapi2.utils.MasqueradeHelper import com.instructure.loginapi.login.tasks.LogoutTask import com.instructure.pandautils.analytics.pageview.PageViewUploadWorker @@ -47,9 +56,14 @@ import com.twou.offline.util.BaseOfflineUtils.Companion.isOnline import com.twou.offline.util.OfflineLoggerType import com.twou.offline.util.OfflineLogs import dagger.hilt.android.HiltAndroidApp -import sdk.pendo.io.Pendo import java.util.concurrent.TimeUnit import javax.inject.Inject +import com.datadog.android.trace.GlobalDatadogTracer +import com.datadog.android.trace.Trace +import com.datadog.android.trace.TraceConfiguration +import com.datadog.android.trace.event.SpanEventMapper +import com.datadog.android.trace.model.SpanEvent +import com.datadog.android.rum.Rum @HiltAndroidApp class AppManager : BaseAppManager() { @@ -68,6 +82,7 @@ class AppManager : BaseAppManager() { @Inject lateinit var workManager: WorkManager + lateinit var logger: Logger override fun onCreate() { super.onCreate() @@ -197,8 +212,70 @@ class AppManager : BaseAppManager() { schedulePandataUpload() initPendo() + setupDataDog() } + private fun setupDataDog() { + val configuration = Configuration.Builder( + clientToken = BuildConfig.DATADOG_CLIENT_TOKEN, + env = if (BuildConfig.BUILD_TYPE == "release") "production" else "staging", + service = "degrees-mobile" + ).build() + + Datadog.initialize(this, configuration, trackingConsent = TrackingConsent.GRANTED) + + Trace.equals( + TraceConfiguration.Builder().setEventMapper(object : SpanEventMapper { + override fun map(event: SpanEvent): SpanEvent { + val originalUrl = event.resource + event.resource = redactSensitiveData(originalUrl) + return event + } + }) + .build() + ) + + GlobalDatadogTracer.registerIfAbsent( + DatadogTracing.newTracerBuilder() + .build() + ) + + Datadog.setVerbosity(Log.INFO) + + val logsConfig = LogsConfiguration.Builder().build() + Logs.enable(logsConfig) + + logger = Logger.Builder() + .setNetworkInfoEnabled(true) + .setLogcatLogsEnabled(true) + .setName("GetSmarterAndroid") + .build() + + val rumConfig = RumConfiguration.Builder(BuildConfig.DATADOG_APPLICATION_ID) + .setResourceEventMapper { event -> + val originalUrl = event.resource.url + event.resource.url = redactSensitiveData(originalUrl) + event + } + .setErrorEventMapper { event -> + event.error.message = redactSensitiveData(event.error.message) + event.error.resource?.url = redactSensitiveData(event.error.resource?.url.orEmpty()) + event + } + .trackUserInteractions() + .trackAnonymousUser(true) + .trackLongTasks() + .trackBackgroundEvents(true) + .trackNonFatalAnrs(true) + .build() + Rum.enable(rumConfig) + } + private fun redactSensitiveData(message: String) = message.replace( + Regex( + "(username|password|wstoken|token)=[^&]*", + RegexOption.IGNORE_CASE + ), "$1=****" + ) private fun initPendo() { // val options = Pendo.PendoOptions.Builder().setJetpackComposeBeta(true).build() // Pendo.setup(this, BuildConfig.PENDO_TOKEN, options, null) From 43aaa977f6de05ad5c485f2068c0af52797110c1 Mon Sep 17 00:00:00 2001 From: Sujoy Adhikary Date: Mon, 13 Apr 2026 21:06:00 +0530 Subject: [PATCH 2/5] dg Interceptor --- automation/dataseedingapi/build.gradle | 2 + .../dataseeding/util/CanvasNetworkAdapter.kt | 68 ++++++++++--------- 2 files changed, 39 insertions(+), 31 deletions(-) diff --git a/automation/dataseedingapi/build.gradle b/automation/dataseedingapi/build.gradle index 4828823e1..55dbe5ab6 100644 --- a/automation/dataseedingapi/build.gradle +++ b/automation/dataseedingapi/build.gradle @@ -47,6 +47,8 @@ dependencies { implementation 'com.github.javafaker:javafaker:0.17.2' implementation Libs.APOLLO_RUNTIME + /* Datadog */ + implementation 'com.datadoghq:dd-sdk-android-okhttp:3.5.0' /* Test Dependencies */ testImplementation Libs.JUNIT diff --git a/automation/dataseedingapi/src/main/kotlin/com/instructure/dataseeding/util/CanvasNetworkAdapter.kt b/automation/dataseedingapi/src/main/kotlin/com/instructure/dataseeding/util/CanvasNetworkAdapter.kt index e83efde3f..ae105a699 100644 --- a/automation/dataseedingapi/src/main/kotlin/com/instructure/dataseeding/util/CanvasNetworkAdapter.kt +++ b/automation/dataseedingapi/src/main/kotlin/com/instructure/dataseeding/util/CanvasNetworkAdapter.kt @@ -19,6 +19,7 @@ package com.instructure.dataseeding.util import com.apollographql.apollo.ApolloClient import com.apollographql.apollo.network.okHttpClient +import com.datadog.android.okhttp.DatadogInterceptor import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor import retrofit2.Retrofit @@ -48,38 +49,45 @@ object CanvasNetworkAdapter { return loggingInterceptor } + private fun createClientBuilder( + token: String? = null, + retryOnConnectionFailure: Boolean, + includeRestRetry: Boolean, + ): OkHttpClient.Builder { + val builder = OkHttpClient.Builder() + .retryOnConnectionFailure(retryOnConnectionFailure) + .addInterceptor(DatadogInterceptor()) + .addInterceptor(getLoggingInterceptor()) + .readTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS) + + token?.let { builder.addInterceptor(AuthRequestInterceptor(it)) } + if (includeRestRetry) builder.addInterceptor(RestRetryInterceptor) + + return builder + } + private val adminOkHttpClient: OkHttpClient by lazy { - val authInterceptor = AuthRequestInterceptor(adminToken) - - OkHttpClient.Builder() - .retryOnConnectionFailure(true) - .addInterceptor(authInterceptor) - .addInterceptor(getLoggingInterceptor()) - .addInterceptor(RestRetryInterceptor) - .readTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS) - .build() + createClientBuilder( + token = adminToken, + retryOnConnectionFailure = true, + includeRestRetry = true, + ).build() } private fun okHttpClientWithToken(token: String): OkHttpClient { - val authInterceptor = AuthRequestInterceptor(token) - - return OkHttpClient.Builder() - .retryOnConnectionFailure(true) - .addInterceptor(authInterceptor) - .addInterceptor(getLoggingInterceptor()) - .addInterceptor(RestRetryInterceptor) - .readTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS) - .build() + return createClientBuilder( + token = token, + retryOnConnectionFailure = true, + includeRestRetry = true, + ).build() } private fun okHttpClientForApollo(token: String): OkHttpClient { - val authInterceptor = AuthRequestInterceptor(token) - - return OkHttpClient.Builder() - .addInterceptor(authInterceptor) - .addInterceptor(getLoggingInterceptor()) - .readTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS) - .build() + return createClientBuilder( + token = token, + retryOnConnectionFailure = false, + includeRestRetry = false, + ).build() } fun getApolloClient(token: String): ApolloClient { @@ -90,12 +98,10 @@ object CanvasNetworkAdapter { } private val noAuthOkHttpClient: OkHttpClient by lazy { - OkHttpClient.Builder() - .retryOnConnectionFailure(true) - .addInterceptor(getLoggingInterceptor()) - .addInterceptor(RestRetryInterceptor) - .readTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS) - .build() + createClientBuilder( + retryOnConnectionFailure = true, + includeRestRetry = true, + ).build() } val adminRetrofit: Retrofit by lazy { From 5a3c4d87605785b663733663f4dcaaa7bec29e43 Mon Sep 17 00:00:00 2001 From: srajupusapati Date: Wed, 22 Apr 2026 13:33:03 +0530 Subject: [PATCH 3/5] Added Datadog Network calls --- apps/student/build.gradle | 8 ++++---- automation/dataseedingapi/build.gradle | 3 ++- .../instructure/dataseeding/util/CanvasNetworkAdapter.kt | 4 +++- libs/canvas-api-2/build.gradle | 4 ++++ .../java/com/instructure/canvasapi2/CanvasRestAdapter.kt | 8 ++++++++ 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/apps/student/build.gradle b/apps/student/build.gradle index 7c2967fdf..a37bbb7d1 100644 --- a/apps/student/build.gradle +++ b/apps/student/build.gradle @@ -362,10 +362,10 @@ dependencies { implementation("com.bugfender.sdk:android:3.0.17") //DATADOG - implementation("com.datadoghq:dd-sdk-android-rum:3.5.0") - implementation("com.datadoghq:dd-sdk-android-logs:3.5.0") - implementation("com.datadoghq:dd-sdk-android-okhttp:3.5.0") - implementation("com.datadoghq:dd-sdk-android-trace:3.5.0") + implementation("com.datadoghq:dd-sdk-android-rum:3.8.0") + implementation("com.datadoghq:dd-sdk-android-logs:3.8.0") + implementation("com.datadoghq:dd-sdk-android-okhttp:3.8.0") + implementation("com.datadoghq:dd-sdk-android-trace:3.8.0") } // Comment out this line if the reporting logic starts going wonky. diff --git a/automation/dataseedingapi/build.gradle b/automation/dataseedingapi/build.gradle index 55dbe5ab6..25c37b71c 100644 --- a/automation/dataseedingapi/build.gradle +++ b/automation/dataseedingapi/build.gradle @@ -48,7 +48,8 @@ dependencies { implementation Libs.APOLLO_RUNTIME /* Datadog */ - implementation 'com.datadoghq:dd-sdk-android-okhttp:3.5.0' + implementation 'com.datadoghq:dd-sdk-android-okhttp:3.8.0' + implementation("com.datadoghq:dd-sdk-android-trace:3.8.0") /* Test Dependencies */ testImplementation Libs.JUNIT diff --git a/automation/dataseedingapi/src/main/kotlin/com/instructure/dataseeding/util/CanvasNetworkAdapter.kt b/automation/dataseedingapi/src/main/kotlin/com/instructure/dataseeding/util/CanvasNetworkAdapter.kt index ae105a699..4501b54a9 100644 --- a/automation/dataseedingapi/src/main/kotlin/com/instructure/dataseeding/util/CanvasNetworkAdapter.kt +++ b/automation/dataseedingapi/src/main/kotlin/com/instructure/dataseeding/util/CanvasNetworkAdapter.kt @@ -19,6 +19,7 @@ package com.instructure.dataseeding.util import com.apollographql.apollo.ApolloClient import com.apollographql.apollo.network.okHttpClient +import com.datadog.android.okhttp.DatadogEventListener import com.datadog.android.okhttp.DatadogInterceptor import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor @@ -56,7 +57,8 @@ object CanvasNetworkAdapter { ): OkHttpClient.Builder { val builder = OkHttpClient.Builder() .retryOnConnectionFailure(retryOnConnectionFailure) - .addInterceptor(DatadogInterceptor()) + .addInterceptor(DatadogInterceptor.Builder(listOf("*.com")).build()) + .eventListenerFactory(DatadogEventListener.Factory()) .addInterceptor(getLoggingInterceptor()) .readTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS) diff --git a/libs/canvas-api-2/build.gradle b/libs/canvas-api-2/build.gradle index 8428d48ad..a70abc5bc 100644 --- a/libs/canvas-api-2/build.gradle +++ b/libs/canvas-api-2/build.gradle @@ -112,6 +112,10 @@ dependencies { implementation Libs.OKHTTP_URL_CONNECTION implementation Libs.OKIO + /* Datadog */ + implementation 'com.datadoghq:dd-sdk-android-okhttp:3.8.0' + implementation("com.datadoghq:dd-sdk-android-trace:3.8.0") + /* GraphQL */ /* NOTE: Newer versions of OkHttp affect the encoding of square brackets in @Query names. We're excluding the * okhttp module here to avoid updating to a newer version until we're ready to handle the change. */ diff --git a/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/CanvasRestAdapter.kt b/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/CanvasRestAdapter.kt index 0f9421a23..f03018986 100644 --- a/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/CanvasRestAdapter.kt +++ b/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/CanvasRestAdapter.kt @@ -17,6 +17,8 @@ package com.instructure.canvasapi2 import android.net.http.HttpResponseCache +import com.datadog.android.okhttp.DatadogEventListener +import com.datadog.android.okhttp.DatadogInterceptor import com.google.gson.GsonBuilder import com.instructure.canvasapi2.builders.RestParams import com.instructure.canvasapi2.calladapter.DataResultCallAdapterFactory @@ -65,6 +67,8 @@ protected constructor(var statusCallback: StatusCallback<*>?, private val authUs OkHttpClient.Builder() .addNetworkInterceptor(PactRequestInterceptor(authUser)) .addNetworkInterceptor(ResponseInterceptor()) + .addInterceptor(DatadogInterceptor.Builder(listOf("*.com")).build()) + .eventListenerFactory(DatadogEventListener.Factory()) .readTimeout(TIMEOUT_IN_SECONDS.toLong(), TimeUnit.SECONDS) .authenticator(canvasAuthenticator) .dispatcher(mDispatcher) @@ -169,6 +173,8 @@ protected constructor(var statusCallback: StatusCallback<*>?, private val authUs OkHttpClient.Builder() .addInterceptor(loggingInterceptor) .addInterceptor(RollCallInterceptor()) + .addInterceptor(DatadogInterceptor.Builder(listOf("*.com")).build()) + .eventListenerFactory(DatadogEventListener.Factory()) .authenticator(canvasAuthenticator) .readTimeout(TIMEOUT_IN_SECONDS.toLong(), TimeUnit.SECONDS) .dispatcher(mDispatcher) @@ -310,6 +316,8 @@ protected constructor(var statusCallback: StatusCallback<*>?, private val authUs .addInterceptor(loggingInterceptor) .addInterceptor(RequestInterceptor()) .addNetworkInterceptor(ResponseInterceptor()) + .addInterceptor(DatadogInterceptor.Builder(listOf("*.com")).build()) + .eventListenerFactory(DatadogEventListener.Factory()) .readTimeout(TIMEOUT_IN_SECONDS.toLong(), TimeUnit.SECONDS) .dispatcher(mDispatcher) .authenticator(canvasAuthenticator) From ef9b1665ac4ef887c3d69da070ea73b7608dcecc Mon Sep 17 00:00:00 2001 From: srajupusapati Date: Wed, 22 Apr 2026 13:48:52 +0530 Subject: [PATCH 4/5] Update AppManager.kt --- .../src/main/java/com/instructure/student/util/AppManager.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/student/src/main/java/com/instructure/student/util/AppManager.kt b/apps/student/src/main/java/com/instructure/student/util/AppManager.kt index 18bc818d4..1c81fc44a 100644 --- a/apps/student/src/main/java/com/instructure/student/util/AppManager.kt +++ b/apps/student/src/main/java/com/instructure/student/util/AppManager.kt @@ -248,7 +248,7 @@ class AppManager : BaseAppManager() { logger = Logger.Builder() .setNetworkInfoEnabled(true) .setLogcatLogsEnabled(true) - .setName("GetSmarterAndroid") + .setName("degrees-android") .build() val rumConfig = RumConfiguration.Builder(BuildConfig.DATADOG_APPLICATION_ID) From be5fc02b42ffb43165a5cb50fddf746b885e978f Mon Sep 17 00:00:00 2001 From: srajupusapati Date: Wed, 2 Sep 2026 12:36:07 +0530 Subject: [PATCH 5/5] Updated and fix the free tier login screen issue --- .../canvasapi2/apis/AccountDomainAPI.kt | 2 +- .../canvasapi2/apis/ErrorReportAPI.kt | 2 +- .../canvasapi2/models/OAuthToken.kt | 4 ++- .../instructure/canvasapi2/utils/ApiPrefs.kt | 2 ++ .../activities/BaseLoginFindSchoolActivity.kt | 2 +- .../activities/BaseLoginSignInActivity.kt | 25 +++++++++++++------ .../loginapi/login/api/MobileVerifyAPI.kt | 5 ++-- .../com/instructure/pandautils/utils/Const.kt | 2 +- 8 files changed, 30 insertions(+), 14 deletions(-) diff --git a/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/apis/AccountDomainAPI.kt b/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/apis/AccountDomainAPI.kt index bb4cea460..037ff195e 100644 --- a/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/apis/AccountDomainAPI.kt +++ b/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/apis/AccountDomainAPI.kt @@ -29,7 +29,7 @@ import retrofit2.http.Url object AccountDomainAPI { - private const val DEFAULT_DOMAIN = "https://canvas.instructure.com/" + private const val DEFAULT_DOMAIN = "https://sso.canvaslms.com/" interface AccountDomainInterface { @GET diff --git a/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/apis/ErrorReportAPI.kt b/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/apis/ErrorReportAPI.kt index f1838f1fc..0c949246f 100644 --- a/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/apis/ErrorReportAPI.kt +++ b/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/apis/ErrorReportAPI.kt @@ -30,7 +30,7 @@ import retrofit2.http.Query object ErrorReportAPI { - const val DEFAULT_DOMAIN = "https://canvas.instructure.com" + const val DEFAULT_DOMAIN = "https://sso.canvaslms.com" enum class Severity(val tag: String) { COMMENT("just_a_comment"), diff --git a/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/models/OAuthToken.kt b/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/models/OAuthToken.kt index eaca5cf5a..a28053c7f 100644 --- a/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/models/OAuthToken.kt +++ b/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/models/OAuthToken.kt @@ -31,7 +31,9 @@ data class OAuthTokenResponse( val refreshToken: String? = null, @SerializedName("real_user") val realUser: TokenUser? = null, - val user: TokenUser? = null + val user: TokenUser? = null, + @SerializedName("canvas_region") + val canvasRegion: String? = null, ) /** diff --git a/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/utils/ApiPrefs.kt b/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/utils/ApiPrefs.kt index 15ca8bb55..a7f5eec5e 100644 --- a/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/utils/ApiPrefs.kt +++ b/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/utils/ApiPrefs.kt @@ -58,6 +58,8 @@ object ApiPrefs : PrefManager(PREFERENCE_FILE_NAME) { var clientSecret by StringPref("", "client_secret") + var canvasRegion by NStringPref(null, "canvas_region") + var perPageCount = 100 var theme: CanvasTheme? by GsonPref(CanvasTheme::class.java, null) diff --git a/libs/login-api-2/src/main/java/com/instructure/loginapi/login/activities/BaseLoginFindSchoolActivity.kt b/libs/login-api-2/src/main/java/com/instructure/loginapi/login/activities/BaseLoginFindSchoolActivity.kt index 26140718e..2304a6c6c 100644 --- a/libs/login-api-2/src/main/java/com/instructure/loginapi/login/activities/BaseLoginFindSchoolActivity.kt +++ b/libs/login-api-2/src/main/java/com/instructure/loginapi/login/activities/BaseLoginFindSchoolActivity.kt @@ -220,7 +220,7 @@ abstract class BaseLoginFindSchoolActivity : BaseCanvasActivity() { //if the user enters nothing, try to connect to canvas.instructure.com if (url!!.trim { it <= ' ' }.isEmpty()) { - url = "canvas.instructure.com" + url = "sso.canvaslms.com" } //remove invalid characters at the end of the domain diff --git a/libs/login-api-2/src/main/java/com/instructure/loginapi/login/activities/BaseLoginSignInActivity.kt b/libs/login-api-2/src/main/java/com/instructure/loginapi/login/activities/BaseLoginSignInActivity.kt index fe96ba95b..1735dd8f8 100644 --- a/libs/login-api-2/src/main/java/com/instructure/loginapi/login/activities/BaseLoginSignInActivity.kt +++ b/libs/login-api-2/src/main/java/com/instructure/loginapi/login/activities/BaseLoginSignInActivity.kt @@ -41,6 +41,8 @@ import androidx.annotation.StringRes import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.widget.Toolbar +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat import com.instructure.canvasapi2.RequestInterceptor.Companion.acceptedLanguageString import com.instructure.canvasapi2.StatusCallback import com.instructure.canvasapi2.TokenRefreshState @@ -55,6 +57,7 @@ import com.instructure.canvasapi2.utils.AnalyticsEventConstants import com.instructure.canvasapi2.utils.AnalyticsParamConstants import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.canvasapi2.utils.ApiPrefs.accessToken +import com.instructure.canvasapi2.utils.ApiPrefs.canvasRegion import com.instructure.canvasapi2.utils.ApiPrefs.clientId import com.instructure.canvasapi2.utils.ApiPrefs.clientSecret import com.instructure.canvasapi2.utils.ApiPrefs.domain @@ -101,8 +104,14 @@ abstract class BaseLoginSignInActivity : BaseCanvasActivity(), OnAuthenticationS companion object { const val ACCOUNT_DOMAIN = "accountDomain" - const val SUCCESS_URL = "/login/oauth2/auth?code=" - const val ERROR_URL = "/login/oauth2/auth?error=access_denied" + val SUCCESS_URL_COLLECTION = listOf( + "/canvas/login?code=", //success url + "login/oauth2/auth?code=" //legacy success url (needed for the fallback redirect_uri) + ) + val ERROR_URL_COLLECTION = listOf( + "/canvas/login?error=access_denied", //error url + "/login/oauth2/auth?error=access_denied" //legacy error url (needed for the fallback redirect_uri) + ) init { AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) @@ -217,13 +226,14 @@ abstract class BaseLoginSignInActivity : BaseCanvasActivity(), OnAuthenticationS private fun handleShouldOverrideUrlLoading(view: WebView, url: String): Boolean { if (overrideUrlLoading(view, url)) return true return when { - url.contains(SUCCESS_URL) -> { + SUCCESS_URL_COLLECTION.any { url.contains(it) } -> { + val responseUrl = SUCCESS_URL_COLLECTION.first { url.contains(it) } domain = accountDomain.domain!! - val oAuthRequest = url.substring(url.indexOf(SUCCESS_URL) + SUCCESS_URL.length) + val oAuthRequest = url.substring(url.indexOf(responseUrl) + responseUrl.length) getToken(clientId, clientSecret, oAuthRequest, mGetTokenCallback) true } - url.contains(ERROR_URL) -> { + ERROR_URL_COLLECTION.any { url.contains(it) } -> { clearCookies() loadUrl(view, authenticationURL, headers) true @@ -454,7 +464,7 @@ abstract class BaseLoginSignInActivity : BaseCanvasActivity(), OnAuthenticationS //Skip mobile verify builder.appendQueryParameter("redirect_uri", "urn:ietf:wg:oauth:2.0:oob") } else { - builder.appendQueryParameter("redirect_uri", "https://canvas.instructure.com/login/oauth2/auth") + builder.appendQueryParameter("redirect_uri", "https://sso.canvaslms.com/canvas/login") } //If an authentication provider is supplied we need to pass that along. This should only be appended if one exists. @@ -486,6 +496,7 @@ abstract class BaseLoginSignInActivity : BaseCanvasActivity(), OnAuthenticationS logEvent(AnalyticsEventConstants.LOGIN_SUCCESS, bundle) refreshToken = token!!.refreshToken!! accessToken = token.accessToken!! + canvasRegion = token.canvasRegion @Suppress("DEPRECATION") ApiPrefs.token = "" // TODO: Remove when we're 100% using refresh tokens @@ -577,4 +588,4 @@ abstract class BaseLoginSignInActivity : BaseCanvasActivity(), OnAuthenticationS } }, 750) } //endregion -} +} \ No newline at end of file diff --git a/libs/login-api-2/src/main/java/com/instructure/loginapi/login/api/MobileVerifyAPI.kt b/libs/login-api-2/src/main/java/com/instructure/loginapi/login/api/MobileVerifyAPI.kt index 2cedf322e..9dfb2fa46 100644 --- a/libs/login-api-2/src/main/java/com/instructure/loginapi/login/api/MobileVerifyAPI.kt +++ b/libs/login-api-2/src/main/java/com/instructure/loginapi/login/api/MobileVerifyAPI.kt @@ -46,7 +46,8 @@ object MobileVerifyAPI { .cacheControl(CacheControl.FORCE_NETWORK) .build() chain.proceed(request) - }.build() + } + .build() val mobileVerifyBetaEnabled = RemoteConfigUtils.getString( RemoteConfigParam.MOBILE_VERIFY_BETA_ENABLED)?.equals("true", ignoreCase = true) @@ -56,7 +57,7 @@ object MobileVerifyAPI { val baseUrl = if (mobileVerifyBetaEnabled && domain?.contains(".beta.") == true) { "https://canvas.beta.instructure.com/api/v1/" } else { - "https://canvas.instructure.com/api/v1/" + "https://sso.canvaslms.com/api/v1/" } return Retrofit.Builder() diff --git a/libs/pandautils/src/main/java/com/instructure/pandautils/utils/Const.kt b/libs/pandautils/src/main/java/com/instructure/pandautils/utils/Const.kt index f7610dde4..1e5e366f0 100644 --- a/libs/pandautils/src/main/java/com/instructure/pandautils/utils/Const.kt +++ b/libs/pandautils/src/main/java/com/instructure/pandautils/utils/Const.kt @@ -110,7 +110,7 @@ object Const { const val DISCUSSION_REPLY_SUBMITTED = "discussion_reply_submitted" const val TITLE = "title" const val BODY = "body" - const val PROFILE_URL = "canvas.instructure.com" + const val PROFILE_URL = "sso.canvaslms.com" const val CONVERSATION = "conversations" const val COURSES = "courses" const val GROUPS = "groups"