android: automatically trigger login flow for authKey

Signed-off-by: Jonathan Nobels <jonathan@tailscale.com>
jonathan/login
Jonathan Nobels 6 months ago
parent 2cfebbe495
commit 0edad33c89

@ -494,10 +494,6 @@ class MainActivity : ComponentActivity() {
lifecycleScope.launch(Dispatchers.IO) { MDMSettings.update(App.get(), restrictionsManager) }
}
override fun onStart() {
super.onStart()
}
override fun onStop() {
super.onStop()
val restrictionsManager =
@ -515,6 +511,11 @@ class MainActivity : ComponentActivity() {
}
private fun introScreenViewed(): Boolean {
// If the auth key is set, there is no need to render the intro screen.
if (MDMSettings.authKey.flow.value.value != null ||
MDMSettings.onboardingFlow.flow.value.value) {
return true
}
return getSharedPreferences("introScreen", Context.MODE_PRIVATE).getBoolean("seen", false)
}

@ -20,6 +20,8 @@ object MDMSettings {
val forceEnabled = BooleanMDMSetting("ForceEnabled", "Force Enabled Connection Toggle")
val onboardingFlow = BooleanMDMSetting("OnboardingFlow", "Skip Onboarding Flow")
// Handled on the backed
val exitNodeID = StringMDMSetting("ExitNodeID", "Forced Exit Node: Stable ID")
@ -61,7 +63,8 @@ object MDMSettings {
// Handled on the backend
val deviceSerialNumber =
StringMDMSetting("DeviceSerialNumber", "Serial number of the device that is running Tailscale")
StringMDMSetting(
"DeviceSerialNumber", "Serial number of the device that is running Tailscale")
val useTailscaleDNSSettings =
AlwaysNeverUserDecidesMDMSetting("UseTailscaleDNSSettings", "Use Tailscale DNS Settings")
@ -97,6 +100,7 @@ object MDMSettings {
// Handled on the backend
val authKey = StringMDMSetting("AuthKey", "Auth Key for login")
// tskey-auth-kBUy7NiRQ411CNTRL-a8sEkPG4KcDP2Kts1CTRdDfjkDSxat5T
// Overrides the value provided by os.Hostname() in Go
val hostname = StringMDMSetting("Hostname", "Device Hostname")

@ -182,18 +182,18 @@ open class IpnViewModel : ViewModel() {
completionHandler(Result.failure(it))
}
.onSuccess {
if (authKey.isNullOrEmpty()) {
client.startLoginInteractive { loginResult ->
loginResult
.onFailure {
TSLog.e(TAG, "startLoginInteractive() failed: ${it.message}")
completionHandler(Result.failure(it))
}
.onSuccess { completionHandler(Result.success(Unit)) }
}
} else {
completionHandler(Result.success(Unit))
// if (authKey.isNullOrEmpty()) {
client.startLoginInteractive { loginResult ->
loginResult
.onFailure {
TSLog.e(TAG, "startLoginInteractive() failed: ${it.message}")
completionHandler(Result.failure(it))
}
.onSuccess { completionHandler(Result.success(Unit)) }
}
// } else {
// completionHandler(Result.success(Unit))
// }
}
}
}

@ -50,6 +50,14 @@ class MainViewModelFactory(private val vpnViewModel: VpnViewModel) : ViewModelPr
@OptIn(FlowPreview::class)
class MainViewModel(private val vpnViewModel: VpnViewModel) : IpnViewModel() {
companion object AuthKeyTracking {
data class AuthKeyFailure(val authKey: String? = null, var attempts: Int = 0)
// Non-null if we have tried to login with an auth key and it failed.
var authKeyFailure: AuthKeyFailure? = null
}
// The user readable state of the system
val stateRes: StateFlow<Int> = MutableStateFlow(userStringRes(State.NoState, State.NoState, true))
@ -149,6 +157,40 @@ class MainViewModel(private val vpnViewModel: VpnViewModel) : IpnViewModel() {
// Update the VPN toggle state
_vpnToggleState.value = isOn
val authKey = getMDMAuthKey()
if (currentState == State.NeedsLogin &&
previousState != State.NeedsLogin &&
authKey != null) {
// Same auth key? Too many attempts? Stop trying, at least for the duration
// of this app session.
if (authKeyFailure != null &&
authKeyFailure!!.authKey != authKey &&
authKeyFailure!!.attempts > 3) {
TSLog.e("MainViewModel", "Failed to login with auth key: too many failed attempts")
} else {
// If we have an MDM'd auth key, try to login automatically
TSLog.d("MainViewModel", "Logging in with MDM auth key")
loginWithAuthKey(authKey) {
it.onFailure { error ->
TSLog.e("MainViewModel", "Failed to auto login with auth key: $error")
var failureState = authKeyFailure ?: AuthKeyFailure(authKey, 0)
if (authKey == failureState.authKey) {
failureState.attempts = failureState.attempts + 1
} else {
// New auth key... Reset our attempts
failureState.attempts = 0
}
authKeyFailure = failureState
}
it.onSuccess {
authKeyFailure = null
// Successfully logged in, no further action needed
}
}
}
}
// Update the previous state
previousState = currentState
}
@ -197,6 +239,11 @@ class MainViewModel(private val vpnViewModel: VpnViewModel) : IpnViewModel() {
}
}
fun getMDMAuthKey(): String {
return "tskey-auth-kBUy7NiRQ411CNTRL-a8sEkPG4KcDP2Kts1CTRdDfjkDSxat5T"
/// return MDMSettings.authKey.flow.value.value
}
fun maybeRequestVpnPermission() {
_requestVpnPermission.value = true
}

Loading…
Cancel
Save