From 44e798e6ad4fe60ae0ae4a8480f1b4f29887b8aa Mon Sep 17 00:00:00 2001 From: URUSHIHARA Akihiro Date: Fri, 4 Oct 2024 03:49:05 +0900 Subject: [PATCH] add well known endpoints. --- .../kotlin/work/socialhub/kbsky/ATProtocol.kt | 3 + .../work/socialhub/kbsky/ATProtocolConfig.kt | 10 +++ .../meta/WellKnownOAuthAuthorizationServer.kt | 89 +++++++++++++++++++ ...WellKnownOAuthProtectedResourceResponse.kt | 23 +++++ .../socialhub/kbsky/api/meta/MetaResource.kt | 23 +++++ .../socialhub/kbsky/internal/_ATProtocol.kt | 8 ++ .../kbsky/internal/meta/_MetaResource.kt | 46 ++++++++++ .../com/atproto/server/CreateSessionTest.kt | 2 + .../work/socialhub/kbsky/meta/MetaTest.kt | 28 ++++++ 9 files changed, 232 insertions(+) create mode 100644 core/src/commonMain/kotlin/work/socialhub/kbsky/api/entity/meta/WellKnownOAuthAuthorizationServer.kt create mode 100644 core/src/commonMain/kotlin/work/socialhub/kbsky/api/entity/meta/WellKnownOAuthProtectedResourceResponse.kt create mode 100644 core/src/commonMain/kotlin/work/socialhub/kbsky/api/meta/MetaResource.kt create mode 100644 core/src/commonMain/kotlin/work/socialhub/kbsky/internal/meta/_MetaResource.kt create mode 100644 core/src/jvmTest/kotlin/work/socialhub/kbsky/meta/MetaTest.kt diff --git a/core/src/commonMain/kotlin/work/socialhub/kbsky/ATProtocol.kt b/core/src/commonMain/kotlin/work/socialhub/kbsky/ATProtocol.kt index 439b322..250f11c 100644 --- a/core/src/commonMain/kotlin/work/socialhub/kbsky/ATProtocol.kt +++ b/core/src/commonMain/kotlin/work/socialhub/kbsky/ATProtocol.kt @@ -3,9 +3,12 @@ package work.socialhub.kbsky import work.socialhub.kbsky.api.com.atproto.IdentityResource import work.socialhub.kbsky.api.com.atproto.RepoResource import work.socialhub.kbsky.api.com.atproto.ServerResource +import work.socialhub.kbsky.api.meta.MetaResource interface ATProtocol { fun identity(): IdentityResource fun server(): ServerResource fun repo(): RepoResource + + fun meta(): MetaResource } diff --git a/core/src/commonMain/kotlin/work/socialhub/kbsky/ATProtocolConfig.kt b/core/src/commonMain/kotlin/work/socialhub/kbsky/ATProtocolConfig.kt index 8f5e837..c304e2f 100644 --- a/core/src/commonMain/kotlin/work/socialhub/kbsky/ATProtocolConfig.kt +++ b/core/src/commonMain/kotlin/work/socialhub/kbsky/ATProtocolConfig.kt @@ -9,9 +9,19 @@ open class ATProtocolConfig { */ var pdsUri: String = Service.BSKY_SOCIAL.uri + /** + * URI of authorization server. + */ + var authUri: String = Service.BSKY_SOCIAL.uri + /** * Change the URI to the PDS to which you belong when requesting a session-based API? * (If you use the Chat feature, you will need to change the URI to the PDS you belong to if you turn it off) */ var updatePdsUri: Boolean = true + + /** + * Update AuthURI when retrieving Meta resources? + */ + var updateAuthUri: Boolean = true } \ No newline at end of file diff --git a/core/src/commonMain/kotlin/work/socialhub/kbsky/api/entity/meta/WellKnownOAuthAuthorizationServer.kt b/core/src/commonMain/kotlin/work/socialhub/kbsky/api/entity/meta/WellKnownOAuthAuthorizationServer.kt new file mode 100644 index 0000000..fc328e1 --- /dev/null +++ b/core/src/commonMain/kotlin/work/socialhub/kbsky/api/entity/meta/WellKnownOAuthAuthorizationServer.kt @@ -0,0 +1,89 @@ +package work.socialhub.kbsky.api.entity.meta + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +class WellKnownOAuthAuthorizationServer { + + @SerialName("issuer") + lateinit var issuer: String + + @SerialName("scopes_supported") + lateinit var scopesSupported: List + + @SerialName("subject_types_supported") + lateinit var subjectTypesSupported: List + + @SerialName("response_types_supported") + lateinit var responseTypesSupported: List + + @SerialName("response_modes_supported") + lateinit var responseModesSupported: List + + @SerialName("grant_types_supported") + lateinit var grantTypesSupported: List + + @SerialName("code_challenge_methods_supported") + lateinit var codeChallengeMethodsSupported: List + + @SerialName("ui_locales_supported") + lateinit var uiLocalesSupported: List + + @SerialName("display_values_supported") + lateinit var displayValuesSupported: List + + @SerialName("authorization_response_iss_parameter_supported") + var authorizationResponseIssParameterSupported: Boolean = false + + @SerialName("request_object_signing_alg_values_supported") + lateinit var requestObjectSigningAlgValuesSupported: List + + @SerialName("request_object_encryption_alg_values_supported") + lateinit var requestObjectEncryptionAlgValuesSupported: List + + @SerialName("request_object_encryption_enc_values_supported") + lateinit var requestObjectEncryptionEncValuesSupported: List + + @SerialName("request_parameter_supported") + var requestParameterSupported: Boolean = false + + @SerialName("request_uri_parameter_supported") + var requestUriParameterSupported: Boolean = false + + @SerialName("require_request_uri_registration") + var requireRequestUriRegistration: Boolean = false + + @SerialName("jwks_uri") + lateinit var jwksUri: String + + @SerialName("authorization_endpoint") + lateinit var authorizationEndpoint: String + + @SerialName("token_endpoint") + lateinit var tokenEndpoint: String + + @SerialName("token_endpoint_auth_methods_supported") + lateinit var tokenEndpointAuthMethodsSupported: List + + @SerialName("token_endpoint_auth_signing_alg_values_supported") + lateinit var tokenEndpointAuthSigningAlgValuesSupported: List + + @SerialName("revocation_endpoint") + lateinit var revocationEndpoint: String + + @SerialName("introspection_endpoint") + lateinit var introspectionEndpoint: String + + @SerialName("pushed_authorization_request_endpoint") + lateinit var pushedAuthorizationRequestEndpoint: String + + @SerialName("require_pushed_authorization_requests") + var requirePushedAuthorizationRequests: Boolean = false + + @SerialName("dpop_signing_alg_values_supported") + lateinit var dpopSigningAlgValuesSupported: List + + @SerialName("client_id_metadata_document_supported") + var clientIdMetadataDocumentSupported: Boolean = false +} \ No newline at end of file diff --git a/core/src/commonMain/kotlin/work/socialhub/kbsky/api/entity/meta/WellKnownOAuthProtectedResourceResponse.kt b/core/src/commonMain/kotlin/work/socialhub/kbsky/api/entity/meta/WellKnownOAuthProtectedResourceResponse.kt new file mode 100644 index 0000000..66043b0 --- /dev/null +++ b/core/src/commonMain/kotlin/work/socialhub/kbsky/api/entity/meta/WellKnownOAuthProtectedResourceResponse.kt @@ -0,0 +1,23 @@ +package work.socialhub.kbsky.api.entity.meta + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +class WellKnownOAuthProtectedResourceResponse { + + @SerialName("resource") + lateinit var resource: String + + @SerialName("authorization_servers") + lateinit var authorizationServers: List + + @SerialName("scopes_supported") + lateinit var scopesSupported: List + + @SerialName("bearer_methods_supported") + lateinit var bearerMethodsSupported: List + + @SerialName("resource_documentation") + lateinit var resourceDocumentation: String +} \ No newline at end of file diff --git a/core/src/commonMain/kotlin/work/socialhub/kbsky/api/meta/MetaResource.kt b/core/src/commonMain/kotlin/work/socialhub/kbsky/api/meta/MetaResource.kt new file mode 100644 index 0000000..d5cc38a --- /dev/null +++ b/core/src/commonMain/kotlin/work/socialhub/kbsky/api/meta/MetaResource.kt @@ -0,0 +1,23 @@ +package work.socialhub.kbsky.api.meta + +import work.socialhub.kbsky.api.entity.meta.WellKnownOAuthAuthorizationServer +import work.socialhub.kbsky.api.entity.meta.WellKnownOAuthProtectedResourceResponse +import work.socialhub.kbsky.api.entity.share.Response + +interface MetaResource { + + /** + * Get OAuth Protected Resource + * https://oyster.us-east.host.bsky.network/.well-known/oauth-protected-resource + */ + fun wellKnownOAuthProtectedResource() + : Response + + + /** + * Get OAuth authorization server + * https://bsky.social/.well-known/oauth-authorization-server + */ + fun wellKnownOAuthAuthorizationServer() + : Response +} \ No newline at end of file diff --git a/core/src/commonMain/kotlin/work/socialhub/kbsky/internal/_ATProtocol.kt b/core/src/commonMain/kotlin/work/socialhub/kbsky/internal/_ATProtocol.kt index c26d8a1..4f7f2dc 100644 --- a/core/src/commonMain/kotlin/work/socialhub/kbsky/internal/_ATProtocol.kt +++ b/core/src/commonMain/kotlin/work/socialhub/kbsky/internal/_ATProtocol.kt @@ -5,9 +5,11 @@ import work.socialhub.kbsky.ATProtocolConfig import work.socialhub.kbsky.api.com.atproto.IdentityResource import work.socialhub.kbsky.api.com.atproto.RepoResource import work.socialhub.kbsky.api.com.atproto.ServerResource +import work.socialhub.kbsky.api.meta.MetaResource import work.socialhub.kbsky.internal.com.atproto._IdentityResource import work.socialhub.kbsky.internal.com.atproto._RepoResource import work.socialhub.kbsky.internal.com.atproto._ServerResource +import work.socialhub.kbsky.internal.meta._MetaResource open class _ATProtocol( config: ATProtocolConfig @@ -16,6 +18,7 @@ open class _ATProtocol( protected val identity: IdentityResource = _IdentityResource(config) protected val server: ServerResource = _ServerResource(config) protected val repo: RepoResource = _RepoResource(config) + protected val meta: MetaResource = _MetaResource(config) /** * {@inheritDoc} @@ -31,4 +34,9 @@ open class _ATProtocol( * {@inheritDoc} */ override fun repo() = repo + + /** + * {@inheritDoc} + */ + override fun meta() = meta } diff --git a/core/src/commonMain/kotlin/work/socialhub/kbsky/internal/meta/_MetaResource.kt b/core/src/commonMain/kotlin/work/socialhub/kbsky/internal/meta/_MetaResource.kt new file mode 100644 index 0000000..18552da --- /dev/null +++ b/core/src/commonMain/kotlin/work/socialhub/kbsky/internal/meta/_MetaResource.kt @@ -0,0 +1,46 @@ +package work.socialhub.kbsky.internal.meta + +import kotlinx.coroutines.runBlocking +import work.socialhub.kbsky.ATProtocolConfig +import work.socialhub.kbsky.api.entity.meta.WellKnownOAuthAuthorizationServer +import work.socialhub.kbsky.api.entity.meta.WellKnownOAuthProtectedResourceResponse +import work.socialhub.kbsky.api.entity.share.Response +import work.socialhub.kbsky.api.meta.MetaResource +import work.socialhub.kbsky.internal.share._InternalUtility.proceed +import work.socialhub.kbsky.util.MediaType +import work.socialhub.khttpclient.HttpRequest + +class _MetaResource( + private val config: ATProtocolConfig +) : MetaResource { + + override fun wellKnownOAuthProtectedResource() + : Response { + return proceed { + runBlocking { + HttpRequest() + .url("${config.pdsUri}.well-known/oauth-protected-resource") + .accept(MediaType.JSON) + .get() + } + }.also { + if (config.updateAuthUri) { + var authUri = it.data.authorizationServers[0] + if (!authUri.endsWith("/")) authUri += "/" + config.authUri = authUri + } + } + } + + override fun wellKnownOAuthAuthorizationServer() + : Response { + return proceed { + runBlocking { + HttpRequest() + .url("${config.pdsUri}.well-known/oauth-authorization-server") + .accept(MediaType.JSON) + .get() + } + } + } +} \ No newline at end of file diff --git a/core/src/jvmTest/kotlin/work/socialhub/kbsky/com/atproto/server/CreateSessionTest.kt b/core/src/jvmTest/kotlin/work/socialhub/kbsky/com/atproto/server/CreateSessionTest.kt index bedbd08..61fc021 100644 --- a/core/src/jvmTest/kotlin/work/socialhub/kbsky/com/atproto/server/CreateSessionTest.kt +++ b/core/src/jvmTest/kotlin/work/socialhub/kbsky/com/atproto/server/CreateSessionTest.kt @@ -28,6 +28,8 @@ class CreateSessionTest : AbstractTest() { println(response.data.email) println(response.data.emailConfirmed) println(response.data.didDoc?.asDIDDetails?.id) + println(response.data.didDoc?.asDIDDetails?.service?.get(0)?.serviceEndpoint) + // Save the accessJwt for testing other APIs accessJwt = checkNotNull(response.data.accessJwt) diff --git a/core/src/jvmTest/kotlin/work/socialhub/kbsky/meta/MetaTest.kt b/core/src/jvmTest/kotlin/work/socialhub/kbsky/meta/MetaTest.kt new file mode 100644 index 0000000..d939cd5 --- /dev/null +++ b/core/src/jvmTest/kotlin/work/socialhub/kbsky/meta/MetaTest.kt @@ -0,0 +1,28 @@ +package work.socialhub.kbsky.meta + +import work.socialhub.kbsky.AbstractTest +import work.socialhub.kbsky.BlueskyFactory +import work.socialhub.kbsky.domain.Service.BSKY_SOCIAL +import work.socialhub.kbsky.domain.Service.OYSTER_US_EAST +import kotlin.test.Test + +class MetaTest : AbstractTest() { + + @Test + fun testWellKnownOAuthProtectedResource() { + val response = BlueskyFactory + .instance(OYSTER_US_EAST.uri) + .meta() + .wellKnownOAuthProtectedResource() + println(response.data.authorizationServers[0]) + } + + @Test + fun testWell() { + val response = BlueskyFactory + .instance(BSKY_SOCIAL.uri) + .meta() + .wellKnownOAuthAuthorizationServer() + println(response.data.issuer) + } +}