Skip to content

Commit c6f551f

Browse files
Neelansh Sahaineelanshsahai
authored andcommitted
Add Signal API implementation (RP)
1 parent c8c2890 commit c6f551f

File tree

18 files changed

+373
-30
lines changed

18 files changed

+373
-30
lines changed

Shrine/app/src/main/java/com/authentication/shrine/CredentialManagerUtils.kt

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,19 @@ import androidx.credentials.GetCredentialResponse
3333
import androidx.credentials.GetPasswordOption
3434
import androidx.credentials.GetPublicKeyCredentialOption
3535
import androidx.credentials.GetRestoreCredentialOption
36+
import androidx.credentials.SignalAllAcceptedCredentialIdsRequest
37+
import androidx.credentials.SignalCurrentUserDetailsRequest
38+
import androidx.credentials.SignalUnknownCredentialRequest
3639
import androidx.credentials.exceptions.CreateCredentialException
3740
import androidx.credentials.exceptions.GetCredentialCancellationException
3841
import androidx.credentials.exceptions.publickeycredential.GetPublicKeyCredentialDomException
3942
import com.authentication.shrine.repository.SERVER_CLIENT_ID
4043
import com.google.android.libraries.identity.googleid.GetGoogleIdOption
44+
import androidx.datastore.core.DataStore
45+
import androidx.datastore.preferences.core.Preferences
46+
import com.authentication.shrine.repository.AuthRepository.Companion.RP_ID_KEY
47+
import com.authentication.shrine.repository.AuthRepository.Companion.USER_ID_KEY
48+
import com.authentication.shrine.repository.AuthRepository.Companion.read
4149
import org.json.JSONObject
4250
import javax.inject.Inject
4351

@@ -48,6 +56,7 @@ import javax.inject.Inject
4856
*/
4957
class CredentialManagerUtils @Inject constructor(
5058
private val credentialManager: CredentialManager,
59+
private val dataStore: DataStore<Preferences>,
5160
) {
5261

5362
/**
@@ -249,6 +258,40 @@ class CredentialManagerUtils @Inject constructor(
249258
val clearRequest = ClearCredentialStateRequest(requestType = TYPE_CLEAR_RESTORE_CREDENTIAL)
250259
credentialManager.clearCredentialState(clearRequest)
251260
}
261+
262+
@SuppressLint("RestrictedApi")
263+
suspend fun signalUnknown(
264+
credentialId: String,
265+
) {
266+
credentialManager.signalCredentialState(
267+
SignalUnknownCredentialRequest(
268+
"""{"rpId":"${dataStore.read(RP_ID_KEY)}", "credentialId":"$credentialId"}""",
269+
),
270+
)
271+
}
272+
273+
@SuppressLint("RestrictedApi")
274+
suspend fun signalAcceptedIds(
275+
credentialIds: List<String>,
276+
) {
277+
credentialManager.signalCredentialState(
278+
SignalAllAcceptedCredentialIdsRequest(
279+
"""{"rpId":"${dataStore.read(RP_ID_KEY)}","userId":"${dataStore.read(USER_ID_KEY)}","allAcceptedCredentialIds":["${credentialIds.joinToString(",")}"]}""",
280+
),
281+
)
282+
}
283+
284+
@SuppressLint("RestrictedApi")
285+
suspend fun signalUserDetails(
286+
newName: String,
287+
newDisplayName: String,
288+
) {
289+
credentialManager.signalCredentialState(
290+
SignalCurrentUserDetailsRequest(
291+
"""{"rpId":"${dataStore.read(RP_ID_KEY)}","userId":"${dataStore.read(USER_ID_KEY)}", "name":"$newName","displayName":"$newDisplayName"}""",
292+
),
293+
)
294+
}
252295
}
253296

254297
sealed class GenericCredentialManagerResponse {

Shrine/app/src/main/java/com/authentication/shrine/ShrineApplication.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,12 @@ object AppModule {
109109
@Provides
110110
fun providesCredentialManagerUtils(
111111
credentialManager: CredentialManager,
112+
dataStore: DataStore<Preferences>,
112113
): CredentialManagerUtils {
113-
return CredentialManagerUtils(credentialManager)
114+
return CredentialManagerUtils(
115+
credentialManager = credentialManager,
116+
dataStore = dataStore,
117+
)
114118
}
115119

116120
@Singleton

Shrine/app/src/main/java/com/authentication/shrine/model/PasskeysList.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,5 @@ data class PasskeyCredential(
4747
val aaguid: String,
4848
val registeredAt: Long,
4949
val providerIcon: String,
50+
val isSelected: Boolean = false,
5051
)

Shrine/app/src/main/java/com/authentication/shrine/repository/AuthRepository.kt

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ class AuthRepository @Inject constructor(
7575
val USERNAME = stringPreferencesKey("username")
7676
val IS_SIGNED_IN_THROUGH_PASSKEYS = booleanPreferencesKey("is_signed_passkeys")
7777
val SESSION_ID = stringPreferencesKey("session_id")
78+
val RP_ID_KEY = stringPreferencesKey("rp_id_key")
79+
val USER_ID_KEY = stringPreferencesKey("user_id_key")
80+
val CRED_ID = stringPreferencesKey("cred_id")
7881
val RESTORE_KEY_CREDENTIAL_ID = stringPreferencesKey("restore_key_credential_id")
7982

8083
// Value for restore credential AuthApiService parameter
@@ -99,6 +102,8 @@ class AuthRepository @Inject constructor(
99102
prefs[USERNAME] = username
100103
response.getSessionId()?.also {
101104
prefs[SESSION_ID] = it
105+
} ?: run {
106+
signOut()
102107
}
103108
}
104109
return true
@@ -122,6 +127,8 @@ class AuthRepository @Inject constructor(
122127
prefs[USERNAME] = username
123128
response.getSessionId()?.also {
124129
prefs[SESSION_ID] = it
130+
} ?: run {
131+
signOut()
125132
}
126133
}
127134
setSessionWithPassword(password)
@@ -152,6 +159,8 @@ class AuthRepository @Inject constructor(
152159
prefs[USERNAME] = response.body()?.username.orEmpty()
153160
response.getSessionId()?.also {
154161
prefs[SESSION_ID] = it
162+
} ?: run {
163+
signOut()
155164
}
156165
}
157166
return true
@@ -197,8 +206,11 @@ class AuthRepository @Inject constructor(
197206
)
198207
if (response.isSuccessful) {
199208
dataStore.edit { prefs ->
209+
prefs[RP_ID_KEY] = response.body()?.rp?.id ?: ""
200210
response.getSessionId()?.also {
201211
prefs[SESSION_ID] = it
212+
} ?: run {
213+
signOut()
202214
}
203215
}
204216
return response.getJsonObject()
@@ -260,6 +272,7 @@ class AuthRepository @Inject constructor(
260272
)
261273
if (apiResult.isSuccessful) {
262274
dataStore.edit { prefs ->
275+
prefs[CRED_ID] = rawId
263276
if (credentialResponse is CreateRestoreCredentialResponse) {
264277
prefs[RESTORE_KEY_CREDENTIAL_ID] = rawId
265278
}
@@ -287,8 +300,11 @@ class AuthRepository @Inject constructor(
287300
val response = authApiService.signInRequest()
288301
if (response.isSuccessful) {
289302
dataStore.edit { prefs ->
303+
prefs[RP_ID_KEY] = response.body()?.rpId ?: ""
290304
response.getSessionId()?.also {
291305
prefs[SESSION_ID] = it
306+
} ?: run {
307+
signOut()
292308
}
293309
}
294310
return response.getJsonObject()
@@ -340,8 +356,11 @@ class AuthRepository @Inject constructor(
340356
)
341357
if (apiResult.isSuccessful) {
342358
dataStore.edit { prefs ->
359+
prefs[CRED_ID] = credentialId
343360
apiResult.getSessionId()?.also {
344361
prefs[SESSION_ID] = it
362+
} ?: run {
363+
signOut()
345364
}
346365
}
347366
return true
@@ -489,6 +508,9 @@ class AuthRepository @Inject constructor(
489508
cookie = sessionId.createCookieHeader(),
490509
)
491510
if (apiResult.isSuccessful) {
511+
dataStore.edit { prefs ->
512+
prefs[USER_ID_KEY] = apiResult.body()?.userId ?: ""
513+
}
492514
return apiResult.body()
493515
} else if (apiResult.code() == 401) {
494516
signOut()
@@ -541,7 +563,7 @@ class AuthRepository @Inject constructor(
541563
signOut()
542564
}
543565
}
544-
}catch (e: Exception) {
566+
} catch (e: Exception) {
545567
Log.e(TAG, "Cannot call deleteRestoreKey", e)
546568
}
547569
return false

Shrine/app/src/main/java/com/authentication/shrine/ui/MainMenuScreen.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ fun MainMenuScreen(
5555
onSettingsButtonClicked: () -> Unit,
5656
onHelpButtonClicked: () -> Unit,
5757
navigateToLogin: () -> Unit,
58+
navigateToUpdateProfile: () -> Unit,
5859
viewModel: HomeViewModel,
5960
modifier: Modifier = Modifier,
6061
credentialManagerUtils: CredentialManagerUtils,
@@ -71,6 +72,7 @@ fun MainMenuScreen(
7172
onHelpButtonClicked = onHelpButtonClicked,
7273
navigateToLogin = navigateToLogin,
7374
onSignOut = onSignOut,
75+
navigateToUpdateProfile = navigateToUpdateProfile,
7476
modifier = modifier,
7577
)
7678
}
@@ -93,6 +95,7 @@ fun MainMenuScreen(
9395
onSettingsButtonClicked: () -> Unit,
9496
onHelpButtonClicked: () -> Unit,
9597
navigateToLogin: () -> Unit,
98+
navigateToUpdateProfile: () -> Unit,
9699
onSignOut: () -> Unit,
97100
modifier: Modifier = Modifier,
98101
) {
@@ -121,6 +124,7 @@ fun MainMenuScreen(
121124
onHelpButtonClicked,
122125
onSignOut,
123126
navigateToLogin,
127+
navigateToUpdateProfile,
124128
)
125129
}
126130
}
@@ -142,6 +146,7 @@ private fun MainMenuButtonsList(
142146
onHelpButtonClicked: () -> Unit,
143147
onSignOut: () -> Unit,
144148
navigateToLogin: () -> Unit,
149+
navigateToUpdateProfile: () -> Unit,
145150
modifier: Modifier = Modifier,
146151
) {
147152
Column(
@@ -172,6 +177,11 @@ private fun MainMenuButtonsList(
172177
buttonText = stringResource(R.string.sign_out),
173178
isButtonDark = false,
174179
)
180+
181+
ShrineButton(
182+
onClick = navigateToUpdateProfile,
183+
buttonText = "Update Profile",
184+
)
175185
}
176186
}
177187

@@ -188,6 +198,7 @@ fun PasskeysSignedPreview() {
188198
onHelpButtonClicked = { },
189199
navigateToLogin = { },
190200
onSignOut = { },
201+
navigateToUpdateProfile = { },
191202
)
192203
}
193204
}

0 commit comments

Comments
 (0)