Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions src/main/java/land/oras/ContainerRef.java
Original file line number Diff line number Diff line change
Expand Up @@ -274,10 +274,7 @@ public static ContainerRef parse(String name) {

// Validate digest algorithm
if (digest != null) {
String prefix = digest.split(":")[0];
if (!SupportedAlgorithm.isSupported(prefix)) {
throw new OrasException("Unsupported digest algorithm: " + prefix);
}
SupportedAlgorithm.fromDigest(digest);
}

return new ContainerRef(registry, namespace, repository, tag, digest);
Expand Down
24 changes: 10 additions & 14 deletions src/main/java/land/oras/utils/SupportedAlgorithm.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import java.io.InputStream;
import java.nio.file.Path;
import java.util.regex.Pattern;
import land.oras.exception.OrasException;
import org.jspecify.annotations.NullMarked;

Expand Down Expand Up @@ -53,6 +54,12 @@ public enum SupportedAlgorithm {
*/
private final String prefix;

/**
* Regex for a digest
* <a href="https://github.com/opencontainers/image-spec/blob/main/descriptor.md#digests">Digests</a>
*/
private static final Pattern DIGEST_REGEX = Pattern.compile("^[a-z0-9]+(?:[+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$");

/**
* Get the algorithm
* @param algorithm The algorithm
Expand Down Expand Up @@ -98,26 +105,15 @@ public String digest(InputStream inputStream) {
return DigestUtils.digest(algorithm, inputStream);
}

/**
* Check if the algorithm is supported
* @param prefix The algorithm prefix
* @return True if supported
*/
public static boolean isSupported(String prefix) {
for (SupportedAlgorithm supportedAlgorithm : SupportedAlgorithm.values()) {
if (supportedAlgorithm.getPrefix().equals(prefix)) {
return true;
}
}
return false;
}

/**
* Get the algorithm from a digest
* @param digest The digest
* @return The algorithm
*/
public static SupportedAlgorithm fromDigest(String digest) {
if (!DIGEST_REGEX.matcher(digest).matches()) {
throw new OrasException("Invalid digest: " + digest);
}
for (SupportedAlgorithm algorithm : SupportedAlgorithm.values()) {
if (digest.startsWith(algorithm.getPrefix())) {
return algorithm;
Expand Down
4 changes: 4 additions & 0 deletions src/test/java/land/oras/ContainerRefTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ void shouldFailWithUnSupportedAlgorithm() {
OrasException.class,
() -> ContainerRef.parse("docker.io/library/foo/alpine:latest@test:1234567890abcdef"),
"Unsupported algorithm: test");
assertThrows(
OrasException.class,
() -> ContainerRef.parse("docker.io/library/foo/alpine:latest@sha256:sha256:1234567890abcdef"),
"Unsupported algorithm: test");
}

@Test
Expand Down
21 changes: 21 additions & 0 deletions src/test/java/land/oras/utils/SupportedAlgorithmTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

package land.oras.utils;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

import land.oras.exception.OrasException;
Expand All @@ -34,4 +35,24 @@ public class SupportedAlgorithmTest {
void shouldThrowIfInvalidDigest() {
assertThrows(OrasException.class, () -> SupportedAlgorithm.fromDigest("invalid"));
}

@Test
void shouldPreventDuplicatePrefix() {
assertThrows(
OrasException.class,
() -> SupportedAlgorithm.fromDigest(
"sha256:sha256:245d81d351d8d3b00ae1880ac480c593abd357d5bae561052ae23cbffbecbfe8"));
}

@Test
void shouldWorkWithRegisteredDigest() {
assertEquals(
SupportedAlgorithm.SHA256,
SupportedAlgorithm.fromDigest(
"sha256:245d81d351d8d3b00ae1880ac480c593abd357d5bae561052ae23cbffbecbfe8"));
assertEquals(
SupportedAlgorithm.SHA512,
SupportedAlgorithm.fromDigest(
"sha512:cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"));
}
}