diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 133f148..ab50c5c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -55,6 +55,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/MainActivity.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/MainActivity.kt
index 7559e8a..1d4b27a 100644
--- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/MainActivity.kt
+++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/MainActivity.kt
@@ -1,6 +1,7 @@
package com.ownd_project.tw2023_wallet_android
import android.app.Activity
+import android.content.Intent
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Bundle
@@ -78,20 +79,28 @@ class MainActivity : AppCompatActivity() {
}
}
}
-
// URIからパラメータを抽出
data?.let {
- // ここでパラメータを処理
- val parameterValue = it.getQueryParameter("credential_offer") // クエリパラメータの取得
-
- // credential_offerがある場合発行画面に遷移する
- if (!parameterValue.isNullOrEmpty()) {
- val bundle = Bundle().apply {
- putString("parameterValue", parameterValue)
+ Log.d("MainActivity", "uri: $it")
+ when (data.scheme) {
+ "openid4vp" -> {
+ handleVp(it)
+ }
+ "openid-credential-offer" -> {
+ handleOffer(it, navController)
+ }
+ "https" -> {
+ // App link
+ if (it.getQueryParameter("credential_offer").isNullOrEmpty()){
+ handleVp(it)
+ }else{
+ handleOffer(it, navController)
+ }
+ }
+ else -> {
+ Log.d("MainActivity", "unknown scheme: ${data.scheme}")
}
- navController.navigate(R.id.action_to_confirmation, bundle)
}
-
}
}
@@ -103,6 +112,27 @@ class MainActivity : AppCompatActivity() {
}
}
+ private fun handleOffer(uri: Uri, navController: androidx.navigation.NavController){
+ // ここでパラメータを処理
+ val parameterValue = uri.getQueryParameter("credential_offer") // クエリパラメータの取得
+
+ // credential_offerがある場合発行画面に遷移する
+ if (!parameterValue.isNullOrEmpty()) {
+ val bundle = Bundle().apply {
+ putString("parameterValue", parameterValue)
+ }
+ navController.navigate(R.id.action_to_confirmation, bundle)
+ }
+ }
+
+ private fun handleVp(uri: Uri) {
+ val newIntent = Intent(this, TokenSharingActivity::class.java).apply {
+ putExtra("siopRequest", uri.toString())
+ putExtra("index", -1)
+ }
+ startActivity(newIntent)
+ }
+
private var shouldLock = false
private var isLocking = false
diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/IdTokenSharingActivity.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/TokenSharingActivity.kt
similarity index 95%
rename from app/src/main/java/com/ownd_project/tw2023_wallet_android/IdTokenSharingActivity.kt
rename to app/src/main/java/com/ownd_project/tw2023_wallet_android/TokenSharingActivity.kt
index 53244cd..e0f7095 100644
--- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/IdTokenSharingActivity.kt
+++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/TokenSharingActivity.kt
@@ -5,7 +5,7 @@ import androidx.appcompat.app.ActionBar
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.fragment.NavHostFragment
-class IdTokenSharingActivity : AppCompatActivity() {
+class TokenSharingActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProvider.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProvider.kt
index e5b3804..2e1c849 100644
--- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProvider.kt
+++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProvider.kt
@@ -21,6 +21,7 @@ import okhttp3.Request
import org.bouncycastle.jce.spec.ECNamedCurveSpec
import java.math.BigInteger
import java.net.URI
+import java.net.URLEncoder
import java.security.KeyPair
import java.security.PublicKey
import java.security.interfaces.ECPublicKey
@@ -241,7 +242,11 @@ class OpenIdProvider(val uri: String, val option: ProviderOption = ProviderOptio
val redirectUrl = requireNotNull(authRequest.redirectUri)
println("send id token to $redirectUrl")
- val result = sendRequest(redirectUrl, mapOf("id_token" to idToken))
+
+ // As a temporary value, give DIRECT_POST a fixed value.
+ // It needs to be modified when responding to redirect responses.
+ val result = sendRequest(redirectUrl, mapOf("id_token" to idToken), ResponseMode.DIRECT_POST)
+
println("Received result: $result")
return Either.Right(result)
} catch (e: Exception) {
@@ -259,6 +264,14 @@ class OpenIdProvider(val uri: String, val option: ProviderOption = ProviderOptio
)
val presentationDefinition = this.siopRequest.presentationDefinition
?: throw IllegalArgumentException(SIOPErrors.BAD_PARAMS.message)
+
+ // https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#ResponseModes
+ // the default Response Mode for the OAuth 2.0 code Response Type is the query encoding
+ // the default Response Mode for the OAuth 2.0 token Response Type is the fragment encoding
+ // https://openid.net/specs/openid-4-verifiable-presentations-1_0-ID2.html#section-5
+ // If the parameter is not present, the default value is fragment.
+ val responseMode = authRequest.responseMode ?: ResponseMode.FRAGMENT
+
// presentationDefinition.inputDescriptors を使って選択項目でフィルター
val vpTokens = credentials.mapNotNull { it ->
when (it.format) {
@@ -309,8 +322,17 @@ class OpenIdProvider(val uri: String, val option: ProviderOption = ProviderOptio
}
val jsonString = objectMapper.writeValueAsString(presentationSubmission)
- // todo fragmentの場合はSame Deviceにリダイレクト
- val redirectUrl = requireNotNull(authRequest.responseUri)
+ // https://openid.net/specs/openid-4-verifiable-presentations-1_0-ID2.html#name-authorization-request
+ // response_uri parameter is present, the redirect_uri Authorization Request parameter MUST NOT be present
+ val destinationUri = if (responseMode == ResponseMode.DIRECT_POST) {
+ authRequest.responseUri
+ } else {
+ authRequest.redirectUri
+ }
+ if (destinationUri.isNullOrBlank()) {
+ return Either.Left("Unknown destination for response")
+ }
+
val body = mutableMapOf(
"vp_token" to vpTokenValue,
@@ -321,8 +343,8 @@ class OpenIdProvider(val uri: String, val option: ProviderOption = ProviderOptio
body["state"] = state
}
- println("send vp token to $redirectUrl")
- val result = sendRequest(redirectUrl, body)
+ println("send vp token to $destinationUri")
+ val result = sendRequest(destinationUri, body, responseMode)
print("status code: ${result.statusCode}")
print("location: ${result.location}")
print("cookies: ${result.cookies}")
@@ -506,7 +528,7 @@ fun mergeOAuth2AndOpenIdInRequestPayload(
return createRequestObjectPayloadFromMap(mergedMap)
}
-fun sendRequest(redirectUrl: String, formData: Map): PostResult {
+fun sendRequest(destinationUri: String, formData: Map, responseMode: ResponseMode): PostResult {
val client = OkHttpClient.Builder()
.followRedirects(false)
.build()
@@ -516,11 +538,19 @@ fun sendRequest(redirectUrl: String, formData: Map): PostResult
formBodyBuilder.add(key, value)
}
val formBody = formBodyBuilder.build()
-
- val request = Request.Builder()
- .url(redirectUrl)
- .post(formBody)
- .build()
+ val request: Request
+
+ when (responseMode) {
+ ResponseMode.DIRECT_POST -> {
+ request = Request.Builder()
+ .url(destinationUri)
+ .post(formBody)
+ .build()
+ }
+ else -> {
+ throw IllegalArgumentException("Unsupported response mode: $responseMode")
+ }
+ }
client.newCall(request).execute().use { response ->
val statusCode = response.code()
@@ -534,7 +564,7 @@ fun sendRequest(redirectUrl: String, formData: Map): PostResult
val uri = URI.create(location)
if (!uri.isAbsolute) {
// 元のURLからホスト情報を抽出して補完
- val originalUri = URI.create(redirectUrl)
+ val originalUri = URI.create(destinationUri)
val portPart = if (originalUri.port != -1) ":${originalUri.port}" else ""
location = "${originalUri.scheme}://${originalUri.host}$portPart$location"
}
diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/test/TestFragmentActivity.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/test/TestFragmentActivity.kt
index 66ecb66..78c7f94 100644
--- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/test/TestFragmentActivity.kt
+++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/test/TestFragmentActivity.kt
@@ -15,7 +15,7 @@ import com.ownd_project.tw2023_wallet_android.datastore.CredentialDataStore
import com.ownd_project.tw2023_wallet_android.test.DummyData.generateSdJwt
import com.ownd_project.tw2023_wallet_android.ui.credential_detail.CredentialDetailFragment
import com.ownd_project.tw2023_wallet_android.ui.shared.Constants
-import com.ownd_project.tw2023_wallet_android.ui.siop.IdTokenSharringFragment
+import com.ownd_project.tw2023_wallet_android.ui.siop_vp.TokenSharingFragment
import com.ownd_project.tw2023_wallet_android.utils.KeyPairUtil
import com.ownd_project.tw2023_wallet_android.utils.ZipUtil
import kotlinx.coroutines.launch
@@ -83,7 +83,7 @@ class TestFragmentActivity : AppCompatActivity() {
}
// setContentView(R.layout.activity_test_fragment);
// val fragment = IdTokenSharringFragment()
- val fragment = IdTokenSharringFragment().apply {
+ val fragment = TokenSharingFragment().apply {
arguments = args
}
val fragment3 = CredentialDetailFragment().apply {
diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/backup/BackupViewModel.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/backup/BackupViewModel.kt
index c4db2cf..8ce052e 100644
--- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/backup/BackupViewModel.kt
+++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/backup/BackupViewModel.kt
@@ -16,7 +16,7 @@ import com.ownd_project.tw2023_wallet_android.datastore.CredentialSharingHistory
import com.ownd_project.tw2023_wallet_android.datastore.IdTokenSharingHistoryStore
import com.ownd_project.tw2023_wallet_android.datastore.PreferencesDataStore
import com.ownd_project.tw2023_wallet_android.pairwise.HDKeyRing
-import com.ownd_project.tw2023_wallet_android.ui.siop.TAG
+import com.ownd_project.tw2023_wallet_android.ui.siop_vp.TAG
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/reader/ReaderFragment.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/reader/ReaderFragment.kt
index 109c9d4..8df71ec 100644
--- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/reader/ReaderFragment.kt
+++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/reader/ReaderFragment.kt
@@ -1,6 +1,6 @@
package com.ownd_project.tw2023_wallet_android.ui.reader
-import com.ownd_project.tw2023_wallet_android.IdTokenSharingActivity
+import com.ownd_project.tw2023_wallet_android.TokenSharingActivity
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
@@ -72,7 +72,7 @@ class ReaderFragment : Fragment() {
} else {
println(scanned)
if (scanned.startsWith("openid4vp://") || scanned.startsWith("siopv2://")) {
- val intent = Intent(context, IdTokenSharingActivity::class.java).apply {
+ val intent = Intent(context, TokenSharingActivity::class.java).apply {
putExtra("siopRequest", scanned)
putExtra("index", -1) // 一つ前の画面でアカウントを選択した場合のインデックス
}
diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop/IdTokenSharringFragment.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop_vp/TokenSharingFragment.kt
similarity index 95%
rename from app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop/IdTokenSharringFragment.kt
rename to app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop_vp/TokenSharingFragment.kt
index f3f1b62..fba74d0 100644
--- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop/IdTokenSharringFragment.kt
+++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop_vp/TokenSharingFragment.kt
@@ -1,4 +1,4 @@
-package com.ownd_project.tw2023_wallet_android.ui.siop
+package com.ownd_project.tw2023_wallet_android.ui.siop_vp
import android.app.AlertDialog
import android.net.Uri
@@ -30,15 +30,15 @@ import com.ownd_project.tw2023_wallet_android.utils.viewBinding
// todo レイアウト調整
// todo SVGをURLから表示
-class IdTokenSharringFragment : Fragment(R.layout.fragment_id_token_sharring) {
+class TokenSharingFragment : Fragment(R.layout.fragment_id_token_sharring) {
companion object {
- private val tag = IdTokenSharringFragment::class.simpleName
+ private val tag = TokenSharingFragment::class.simpleName
}
private val binding by viewBinding(FragmentIdTokenSharringBinding::bind)
private lateinit var issuerDetailBinding: FragmentIssuerDetailBinding
- private val args: IdTokenSharringFragmentArgs by navArgs()
+ private val args: TokenSharingFragmentArgs by navArgs()
private val sharedViewModel by activityViewModels()
private val viewModel: IdTokenSharringViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -47,7 +47,7 @@ class IdTokenSharringFragment : Fragment(R.layout.fragment_id_token_sharring) {
val activity = requireActivity()
- val menuProvider = IdTokenSharingFragmentMenuProvider(this, activity.menuInflater)
+ val menuProvider = TokenSharingFragmentMenuProvider(this, activity.menuInflater)
activity.addMenuProvider(menuProvider, viewLifecycleOwner, Lifecycle.State.RESUMED)
viewModel.initDone.observe(viewLifecycleOwner, ::onInitDone)
@@ -240,7 +240,7 @@ class IdTokenSharringFragment : Fragment(R.layout.fragment_id_token_sharring) {
private fun onOpenSelectCredential(view: View) {
Log.d(tag, "on click")
- val action = IdTokenSharringFragmentDirections.actionIdTokenSharringToNavigationCertificate()
+ val action = TokenSharingFragmentDirections.actionIdTokenSharringToNavigationCertificate()
findNavController().navigate(action)
}
@@ -281,7 +281,7 @@ class IdTokenSharringFragment : Fragment(R.layout.fragment_id_token_sharring) {
val selectedCredential = sharedViewModel.selectedCredential.value
if (selectedCredential != null) {
// todo 複数対応
- viewModel.shareCredential(this, listOf(selectedCredential))
+ viewModel.shareVpToken(this, listOf(selectedCredential))
} else {
viewModel.shareIdToken(this)
}
@@ -319,7 +319,7 @@ class IdTokenSharringFragment : Fragment(R.layout.fragment_id_token_sharring) {
if (postResult.location != null) {
val url = postResult.location
val cookies = postResult.cookies
- val action = IdTokenSharringFragmentDirections.actionIdTokenSharringToWebViewFragment(url, cookies)
+ val action = TokenSharingFragmentDirections.actionIdTokenSharringToWebViewFragment(url, cookies)
findNavController().navigate(action)
}
}
diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop/IdTokenSharingFragmentMenuProvider.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop_vp/TokenSharingFragmentMenuProvider.kt
similarity index 91%
rename from app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop/IdTokenSharingFragmentMenuProvider.kt
rename to app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop_vp/TokenSharingFragmentMenuProvider.kt
index 643a240..c85c8d1 100644
--- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop/IdTokenSharingFragmentMenuProvider.kt
+++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop_vp/TokenSharingFragmentMenuProvider.kt
@@ -1,4 +1,4 @@
-package com.ownd_project.tw2023_wallet_android.ui.siop
+package com.ownd_project.tw2023_wallet_android.ui.siop_vp
import android.view.Menu
import android.view.MenuInflater
@@ -7,7 +7,7 @@ import androidx.core.view.MenuProvider
import androidx.fragment.app.Fragment
import com.ownd_project.tw2023_wallet_android.R
-class IdTokenSharingFragmentMenuProvider(
+class TokenSharingFragmentMenuProvider(
private val fragment: Fragment,
private val menuInflater: MenuInflater
) : MenuProvider {
diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop/IdTokenSharringViewModel.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop_vp/TokenSharingViewModel.kt
similarity index 99%
rename from app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop/IdTokenSharringViewModel.kt
rename to app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop_vp/TokenSharingViewModel.kt
index cf84046..2840df8 100644
--- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop/IdTokenSharringViewModel.kt
+++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop_vp/TokenSharingViewModel.kt
@@ -1,4 +1,4 @@
-package com.ownd_project.tw2023_wallet_android.ui.siop
+package com.ownd_project.tw2023_wallet_android.ui.siop_vp
import android.content.Context
import android.util.Log
@@ -286,7 +286,7 @@ class IdTokenSharringViewModel : ViewModel() {
}
}
- fun shareCredential(fragment: Fragment, credentials: List) {
+ fun shareVpToken(fragment: Fragment, credentials: List) {
Log.d(TAG, "shareVPToken")
viewModelScope.launch(Dispatchers.IO) {
val result = openIdProvider.respondVPResponse(credentials)
diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/verification/CredentialVerificationViewModel.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/verification/CredentialVerificationViewModel.kt
index 8babbe4..be21374 100644
--- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/verification/CredentialVerificationViewModel.kt
+++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/verification/CredentialVerificationViewModel.kt
@@ -30,7 +30,7 @@ class CredentialVerificationViewModel : ViewModel() {
val result: LiveData = _result
fun verifyCredential(format: String, credential: String) {
- Log.d(com.ownd_project.tw2023_wallet_android.ui.siop.TAG, "verifyCredential seed successfully")
+ Log.d(com.ownd_project.tw2023_wallet_android.ui.siop_vp.TAG, "verifyCredential seed successfully")
viewModelScope.launch(Dispatchers.IO) {
val result = JWT.verifyJwtByX5U(credential)
result.fold(
diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml
index b247f44..a0367fe 100644
--- a/app/src/main/res/navigation/mobile_navigation.xml
+++ b/app/src/main/res/navigation/mobile_navigation.xml
@@ -132,7 +132,7 @@