diff --git a/src/main/java/com/github/packageurl/PackageURL.java b/src/main/java/com/github/packageurl/PackageURL.java index 0e686a9..e8cc27b 100644 --- a/src/main/java/com/github/packageurl/PackageURL.java +++ b/src/main/java/com/github/packageurl/PackageURL.java @@ -98,7 +98,7 @@ public PackageURL(final String type, final String namespace, final String name, this.type = toLowerCase(validateType(type)); this.namespace = validateNamespace(namespace); this.name = validateName(name); - this.version = validateVersion(version); + this.version = validateVersion(type, version); this.qualifiers = parseQualifiers(qualifiers); this.subpath = validatePath(subpath, true); verifyTypeConstraints(this.type, this.namespace, this.name); @@ -307,13 +307,25 @@ private String validateNamespace(final String[] values) throws MalformedPackageU final String tempNamespace = validatePath(values, false); String retVal; switch (type) { + case StandardTypes.APK: case StandardTypes.BITBUCKET: - case StandardTypes.DEBIAN: + case StandardTypes.COMPOSER: + case StandardTypes.DEB: case StandardTypes.GITHUB: case StandardTypes.GOLANG: + case StandardTypes.HEX: + case StandardTypes.LUAROCKS: + case StandardTypes.QPKG: case StandardTypes.RPM: retVal = tempNamespace != null ? toLowerCase(tempNamespace) : null; break; + case StandardTypes.MLFLOW: + case StandardTypes.OCI: + if (tempNamespace != null) { + throw new MalformedPackageURLException("The PackageURL specified contains a namespace which is not allowed for type: " + type); + } + retVal = null; + break; default: retVal = tempNamespace; break; @@ -327,12 +339,21 @@ private String validateName(final String value) throws MalformedPackageURLExcept } String temp; switch (type) { + case StandardTypes.APK: case StandardTypes.BITBUCKET: - case StandardTypes.DEBIAN: + case StandardTypes.BITNAMI: + case StandardTypes.COMPOSER: + case StandardTypes.DEB: case StandardTypes.GITHUB: case StandardTypes.GOLANG: + case StandardTypes.HEX: + case StandardTypes.LUAROCKS: + case StandardTypes.OCI: temp = toLowerCase(value); break; + case StandardTypes.PUB: + temp = toLowerCase(value).replaceAll("[^a-z0-9_]", "_"); + break; case StandardTypes.PYPI: temp = toLowerCase(value).replace('_', '-'); break; @@ -343,14 +364,26 @@ private String validateName(final String value) throws MalformedPackageURLExcept return temp; } - private String validateVersion(final String value) { - return value; + private String validateVersion(final String type, final String value) { + if (value == null) { + return null; + } + + switch (type) { + case StandardTypes.HUGGINGFACE: + case StandardTypes.LUAROCKS: + case StandardTypes.OCI: + return toLowerCase(value); + default: + return value; + } } private Map validateQualifiers(final Map values) throws MalformedPackageURLException { if (values == null || values.isEmpty()) { return null; } + for (Map.Entry entry : values.entrySet()) { validateKey(entry.getKey()); final String value = entry.getValue(); @@ -652,7 +685,7 @@ private void parse(final String purl) throws MalformedPackageURLException { // version is optional - check for existence index = remainder.lastIndexOf('@'); if (index >= start) { - this.version = validateVersion(percentDecode(remainder.substring(index + 1))); + this.version = validateVersion(this.type, percentDecode(remainder.substring(index + 1))); remainder = remainder.substring(0, index); } @@ -820,24 +853,48 @@ public int hashCode() { * * @since 1.0.0 */ - public static class StandardTypes { + public static final class StandardTypes { + public static final String ALPM = "alpm"; + public static final String APK = "apk"; public static final String BITBUCKET = "bitbucket"; + public static final String BITNAMI = "bitnami"; public static final String CARGO = "cargo"; + public static final String COCOAPODS = "cocoapods"; public static final String COMPOSER = "composer"; - public static final String DEBIAN = "deb"; + public static final String CONAN = "conan"; + public static final String CONDA = "conda"; + public static final String CPAN = "cpan"; + public static final String CRAN = "cran"; + public static final String DEB = "deb"; public static final String DOCKER = "docker"; public static final String GEM = "gem"; public static final String GENERIC = "generic"; public static final String GITHUB = "github"; public static final String GOLANG = "golang"; + public static final String HACKAGE = "hackage"; public static final String HEX = "hex"; + public static final String HUGGINGFACE = "huggingface"; + public static final String LUAROCKS = "luarocks"; public static final String MAVEN = "maven"; + public static final String MLFLOW = "mlflow"; + public static final String NIX = "nix"; public static final String NPM = "npm"; public static final String NUGET = "nuget"; + public static final String OCI = "oci"; + public static final String PUB = "pub"; public static final String PYPI = "pypi"; + public static final String QPKG = "qpkg"; public static final String RPM = "rpm"; - public static final String NIXPKGS = "nixpkgs"; - public static final String HACKAGE = "hackage"; + public static final String SWID = "swid"; + public static final String SWIFT = "swift"; + @Deprecated + public static final String DEBIAN = "deb"; + @Deprecated + public static final String NIXPKGS = "nix"; + + private StandardTypes() { + + } } } diff --git a/src/test/java/com/github/packageurl/PackageURLTest.java b/src/test/java/com/github/packageurl/PackageURLTest.java index db3896c..c39bd22 100644 --- a/src/test/java/com/github/packageurl/PackageURLTest.java +++ b/src/test/java/com/github/packageurl/PackageURLTest.java @@ -322,23 +322,38 @@ public void testConstructorWithEmptyKey() throws MalformedPackageURLException { @Test public void testStandardTypes() { + Assert.assertEquals("alpm", PackageURL.StandardTypes.ALPM); + Assert.assertEquals("apk", PackageURL.StandardTypes.APK); Assert.assertEquals("bitbucket", PackageURL.StandardTypes.BITBUCKET); + Assert.assertEquals("bitnami", PackageURL.StandardTypes.BITNAMI); + Assert.assertEquals("cocoapods", PackageURL.StandardTypes.COCOAPODS); Assert.assertEquals("cargo", PackageURL.StandardTypes.CARGO); Assert.assertEquals("composer", PackageURL.StandardTypes.COMPOSER); - Assert.assertEquals("deb", PackageURL.StandardTypes.DEBIAN); + Assert.assertEquals("conan", PackageURL.StandardTypes.CONAN); + Assert.assertEquals("conda", PackageURL.StandardTypes.CONDA); + Assert.assertEquals("cpan", PackageURL.StandardTypes.CPAN); + Assert.assertEquals("cran", PackageURL.StandardTypes.CRAN); + Assert.assertEquals("deb", PackageURL.StandardTypes.DEB); Assert.assertEquals("docker", PackageURL.StandardTypes.DOCKER); Assert.assertEquals("gem", PackageURL.StandardTypes.GEM); Assert.assertEquals("generic", PackageURL.StandardTypes.GENERIC); Assert.assertEquals("github", PackageURL.StandardTypes.GITHUB); Assert.assertEquals("golang", PackageURL.StandardTypes.GOLANG); + Assert.assertEquals("hackage", PackageURL.StandardTypes.HACKAGE); Assert.assertEquals("hex", PackageURL.StandardTypes.HEX); + Assert.assertEquals("huggingface", PackageURL.StandardTypes.HUGGINGFACE); + Assert.assertEquals("luarocks", PackageURL.StandardTypes.LUAROCKS); Assert.assertEquals("maven", PackageURL.StandardTypes.MAVEN); + Assert.assertEquals("mlflow", PackageURL.StandardTypes.MLFLOW); Assert.assertEquals("npm", PackageURL.StandardTypes.NPM); Assert.assertEquals("nuget", PackageURL.StandardTypes.NUGET); + Assert.assertEquals("qpkg", PackageURL.StandardTypes.QPKG); + Assert.assertEquals("oci", PackageURL.StandardTypes.OCI); + Assert.assertEquals("pub", PackageURL.StandardTypes.PUB); Assert.assertEquals("pypi", PackageURL.StandardTypes.PYPI); Assert.assertEquals("rpm", PackageURL.StandardTypes.RPM); - Assert.assertEquals("nixpkgs", PackageURL.StandardTypes.NIXPKGS); - Assert.assertEquals("hackage", PackageURL.StandardTypes.HACKAGE); + Assert.assertEquals("swid", PackageURL.StandardTypes.SWID); + Assert.assertEquals("swift", PackageURL.StandardTypes.SWIFT); } @Test