From 7e35514b15059578a0539a41f34d129e1c7db845 Mon Sep 17 00:00:00 2001 From: Silvio Giebl Date: Mon, 17 Jun 2024 15:14:20 +0200 Subject: [PATCH] New rest api path schema in OciRepositoryHandler - replace base64 encoding of registryUrl, imageName and imageReference with escaping only slashes previous schema: /v0.11/ / // / <...>.module /v0.11/ / // / ////<...>oci-component.json /v0.11/ / // / ///<...>oci-layer new schema: /v0.11/ / // / <...>.module /v0.11/ / // / ////<...>oci-component.json /v0.11/ / // / ///<...>oci-layer --- .../oci/internal/dsl/OciRegistriesImpl.kt | 13 +++++------ .../internal/registry/OciRepositoryHandler.kt | 22 +++++++++++-------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/dsl/OciRegistriesImpl.kt b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/dsl/OciRegistriesImpl.kt index 6d385cd7..3ac7578a 100644 --- a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/dsl/OciRegistriesImpl.kt +++ b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/dsl/OciRegistriesImpl.kt @@ -8,10 +8,7 @@ import io.github.sgtsilvio.gradle.oci.internal.gradle.optionalPasswordCredential import io.github.sgtsilvio.gradle.oci.internal.gradle.passwordCredentials import io.github.sgtsilvio.gradle.oci.internal.reactor.netty.OciLoopResources import io.github.sgtsilvio.gradle.oci.internal.reactor.netty.OciRegistryHttpClient -import io.github.sgtsilvio.gradle.oci.internal.registry.Credentials -import io.github.sgtsilvio.gradle.oci.internal.registry.OciComponentRegistry -import io.github.sgtsilvio.gradle.oci.internal.registry.OciRegistryApi -import io.github.sgtsilvio.gradle.oci.internal.registry.OciRepositoryHandler +import io.github.sgtsilvio.gradle.oci.internal.registry.* import io.github.sgtsilvio.gradle.oci.mapping.OciImageMappingData import io.github.sgtsilvio.gradle.oci.mapping.OciImageMappingImpl import io.netty.buffer.UnpooledByteBufAllocator @@ -22,6 +19,7 @@ import org.gradle.api.Project import org.gradle.api.artifacts.ConfigurationContainer import org.gradle.api.artifacts.ResolvableDependencies import org.gradle.api.artifacts.dsl.RepositoryHandler +import org.gradle.api.artifacts.repositories.IvyArtifactRepository import org.gradle.api.credentials.HttpHeaderCredentials import org.gradle.api.credentials.PasswordCredentials import org.gradle.api.model.ObjectFactory @@ -41,7 +39,6 @@ import reactor.netty.http.server.HttpServerRequest import reactor.netty.http.server.HttpServerResponse import java.net.InetSocketAddress import java.net.URI -import java.util.* import java.util.function.BiFunction import javax.inject.Inject @@ -124,11 +121,11 @@ internal abstract class OciRegistryImpl @Inject constructor( final override val finalUrl: Provider = providerFactory.gradleProperty(url.map(URI::toString)).map(::URI).orElse(url) final override val credentials = objectFactory.property() - final override val repository = repositoryHandler.ivy { + final override val repository: IvyArtifactRepository = repositoryHandler.ivy { name = this@OciRegistryImpl.name + "OciRegistry" setUrl(finalUrl.zip(registries.repositoryPort) { url, repositoryPort -> - val urlBase64 = Base64.getUrlEncoder().encodeToString(url.toString().toByteArray()) - URI("http://localhost:$repositoryPort/v0.11/$urlBase64") + val escapedUrl = url.toString().escapePathSegment() + URI("http://localhost:$repositoryPort/v0.11/$escapedUrl") }) isAllowInsecureProtocol = true layout("gradle") diff --git a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/registry/OciRepositoryHandler.kt b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/registry/OciRepositoryHandler.kt index d1ba5641..1077168f 100644 --- a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/registry/OciRepositoryHandler.kt +++ b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/registry/OciRepositoryHandler.kt @@ -40,8 +40,8 @@ import java.util.function.BiFunction /v2/repository/ / // / ///<...>oci-layer /v0.11/ / // / <...>.module -/v0.11/ / // / ////<...>oci-component.json -/v0.11/ / // / ///<...>oci-layer +/v0.11/ / // / ////<...>oci-component.json +/v0.11/ / // / ///<...>oci-layer */ /** @@ -87,7 +87,7 @@ internal class OciRepositoryHandler( response.sendNotFound() } val registryUri = try { - URI(Base64.getUrlDecoder().decode(segments[0]).decodeToString()) + URI(segments[0].unescapePathSegment()) } catch (e: IllegalArgumentException) { return response.sendBadRequest() } catch (e: URISyntaxException) { @@ -116,7 +116,7 @@ internal class OciRepositoryHandler( return response.sendNotFound() } val imageReference = try { - Base64.getUrlDecoder().decode(segments[4]).decodeToString().toOciImageReference() + segments[4].unescapePathSegment().toOciImageReference() } catch (e: IllegalArgumentException) { return response.sendBadRequest() } @@ -157,7 +157,7 @@ internal class OciRepositoryHandler( return response.sendNotFound() } val imageName = try { - Base64.getUrlDecoder().decode(segments[4]).decodeToString() + segments[4].unescapePathSegment() } catch (e: IllegalArgumentException) { return response.sendBadRequest() } @@ -219,17 +219,17 @@ internal class OciRepositoryHandler( addObject { val componentJson = component.encodeToJsonString().toByteArray() val componentName = "$fileNamePrefix-${createOciComponentClassifier(variantName)}.json" - val imageReferenceBase64 = Base64.getUrlEncoder().encodeToString(component.imageReference.toString().toByteArray()) + val escapedImageReference = component.imageReference.toString().escapePathSegment() val capabilitiesBase64 = Base64.getUrlEncoder().encodeToString(jsonArray { encodeCapabilities(component.capabilities) }.toByteArray()) addString("name", componentName) - addString("url", "$imageReferenceBase64/$componentDigest/$componentSize/$capabilitiesBase64/$componentName") + addString("url", "$escapedImageReference/$componentDigest/$componentSize/$capabilitiesBase64/$componentName") addNumber("size", componentJson.size.toLong()) addString("sha512", DigestUtils.sha512Hex(componentJson)) addString("sha256", DigestUtils.sha256Hex(componentJson)) addString("sha1", DigestUtils.sha1Hex(componentJson)) addString("md5", DigestUtils.md5Hex(componentJson)) } - val imageNameBase64 = Base64.getUrlEncoder().encodeToString(component.imageReference.name.toByteArray()) + val escapedImageName = component.imageReference.name.escapePathSegment() for ((mediaType, digest, size) in component.allLayerDescriptors.distinctBy { it.digest }) { addObject { val algorithmId = digest.algorithm.id @@ -240,7 +240,7 @@ internal class OciRepositoryHandler( ) val layerName = "$fileNamePrefix-$classifier" addString("name", layerName + mapLayerMediaTypeToExtension(mediaType)) - addString("url", "$imageNameBase64/$digest/$size/$layerName") + addString("url", "$escapedImageName/$digest/$size/$layerName") addNumber("size", size) addString(algorithmId, encodedHash) } @@ -351,3 +351,7 @@ internal fun JsonArrayStringBuilder.encodeCapabilities(capabilities: SortedSet