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
23 changes: 0 additions & 23 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -128,29 +128,6 @@
</dependencyManagement>

<dependencies>
<!-- Apache Commons -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.22.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.22.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.20.0</version>
</dependency>

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.5.0</version>
</dependency>

<!-- Package URL -->

<dependency>
Expand Down
10 changes: 8 additions & 2 deletions src/main/java/org/cyclonedx/parsers/BomParserFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
*/
package org.cyclonedx.parsers;

import org.apache.commons.io.IOUtils;
import org.cyclonedx.exception.ParseException;

import java.io.File;
Expand All @@ -35,7 +34,14 @@ private BomParserFactory() {}
public static Parser createParser(final File file) throws ParseException {
try (final InputStream fis = Files.newInputStream(file.toPath())) {
final byte[] prefix = new byte[4]; // potential 3-byte UTF-8 byte-order mark + 1 content byte
final int actualPrefixLength = IOUtils.read(fis, prefix);
int actualPrefixLength = 0;
while (actualPrefixLength < prefix.length) {
final int read = fis.read(prefix, actualPrefixLength, prefix.length - actualPrefixLength);
if (read == -1) {
break;
}
actualPrefixLength += read;
}
return createParser(Arrays.copyOf(prefix, actualPrefixLength));
} catch (IOException e) {
throw new ParseException("An error occurred creating parser from file", e);
Expand Down
19 changes: 12 additions & 7 deletions src/main/java/org/cyclonedx/parsers/JsonParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.networknt.schema.Error;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.cyclonedx.CycloneDxSchema;
import org.cyclonedx.Format;
import org.cyclonedx.Version;
Expand All @@ -32,8 +30,8 @@
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

Expand Down Expand Up @@ -106,7 +104,7 @@ public List<ParseException> validate(final File file) throws IOException {
* {@inheritDoc}
*/
public List<ParseException> validate(final File file, final Version schemaVersion) throws IOException {
return validate(FileUtils.readFileToString(file, StandardCharsets.UTF_8), schemaVersion);
return validate(mapper.readTree(file), schemaVersion);
}

/**
Expand All @@ -120,7 +118,7 @@ public List<ParseException> validate(final byte[] bomBytes) throws IOException {
* {@inheritDoc}
*/
public List<ParseException> validate(final byte[] bomBytes, final Version schemaVersion) throws IOException {
return validate(new String(bomBytes), schemaVersion);
return validate(mapper.readTree(bomBytes), schemaVersion);
}

/**
Expand All @@ -134,7 +132,14 @@ public List<ParseException> validate(final Reader reader) throws IOException {
* {@inheritDoc}
*/
public List<ParseException> validate(final Reader reader, final Version schemaVersion) throws IOException {
return validate(IOUtils.toString(reader), schemaVersion);
// NB: Jackson does not strip a UTF-8 BOM from char-based input, but it DOES do that
// for byte-based input, hence the manual handling here.
final PushbackReader pushbackReader = new PushbackReader(reader);
final int firstChar = pushbackReader.read();
if (firstChar != -1 && firstChar != '\uFEFF') {
pushbackReader.unread(firstChar);
}
return validate(mapper.readTree(pushbackReader), schemaVersion);
}

/**
Expand All @@ -148,7 +153,7 @@ public List<ParseException> validate(final InputStream inputStream) throws IOExc
* {@inheritDoc}
*/
public List<ParseException> validate(final InputStream inputStream, final Version schemaVersion) throws IOException {
return validate(IOUtils.toString(inputStream, StandardCharsets.UTF_8), schemaVersion);
return validate(mapper.readTree(inputStream), schemaVersion);
}

/**
Expand Down
39 changes: 13 additions & 26 deletions src/main/java/org/cyclonedx/util/BomUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
*/
package org.cyclonedx.util;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.cyclonedx.Version;
import org.cyclonedx.model.Hash;
import org.cyclonedx.model.VersionFilter;
Expand Down Expand Up @@ -109,7 +107,7 @@ public static List<Hash> calculateHashes(final File file, final Version schemaVe
digests.stream().parallel().forEach(d -> d.update(buf, 0, read));
}
}
digests.stream().map(d -> new Hash(toAlgorithm(d), Hex.encodeHexString(d.digest()))).forEach(hashes::add);
digests.stream().map(d -> new Hash(toAlgorithm(d), toHexString(d.digest()))).forEach(hashes::add);
return hashes;
}

Expand All @@ -133,41 +131,30 @@ private static void validateAlgorithmForVersion(Hash.Algorithm algorithm, Versio
private static MessageDigest getDigestForAlgorithm(Hash.Algorithm algorithm) {
try {
switch (algorithm) {
case MD5:
return DigestUtils.getMd5Digest();
case SHA1:
return DigestUtils.getSha1Digest();
case SHA_256:
return DigestUtils.getSha256Digest();
case SHA_384:
return DigestUtils.getSha384Digest();
case SHA_512:
return DigestUtils.getSha512Digest();
case SHA3_256:
return DigestUtils.getSha3_256Digest();
case SHA3_384:
return DigestUtils.getSha3_384Digest();
case SHA3_512:
return DigestUtils.getSha3_512Digest();
case BLAKE2b_256:
case BLAKE2b_384:
case BLAKE2b_512:
case BLAKE3:
return MessageDigest.getInstance(algorithm.getSpec());
case STREEBOG_256:
// NB: Requires a 3rd party library such as BouncyCastle.
return MessageDigest.getInstance("GOST3411-2012-256");
case STREEBOG_512:
// NB: Requires a 3rd party library such as BouncyCastle.
return MessageDigest.getInstance("GOST3411-2012-512");
default:
throw new IllegalArgumentException("Unsupported algorithm: " + algorithm.getSpec());
// BLAKE2b and BLAKE3 also require a 3rd party library such as BouncyCastle.
return MessageDigest.getInstance(algorithm.getSpec());
}
} catch (NoSuchAlgorithmException | NoSuchMethodError e) {
} catch (NoSuchAlgorithmException e) {
throw new IllegalArgumentException("Algorithm not available: " + algorithm.getSpec(), e);
}
}

private static String toHexString(final byte[] bytes) {
final StringBuilder sb = new StringBuilder(bytes.length * 2);
for (final byte b : bytes) {
sb.append(Character.forDigit((b >> 4) & 0xF, 16));
sb.append(Character.forDigit(b & 0xF, 16));
}
return sb.toString();
}

private static Hash.Algorithm toAlgorithm(MessageDigest digest) {
for (Hash.Algorithm value : Hash.Algorithm.values()) {
if (value.getSpec().equals(digest.getAlgorithm())) {
Expand Down
35 changes: 24 additions & 11 deletions src/main/java/org/cyclonedx/util/LicenseResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,14 @@
package org.cyclonedx.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.cyclonedx.model.AttachmentText;
import org.cyclonedx.model.License;
import org.cyclonedx.model.LicenseChoice;
import org.cyclonedx.model.AttachmentText;
import org.cyclonedx.model.license.Expression;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;
Expand Down Expand Up @@ -112,7 +110,7 @@ private static LicenseChoice resolveLicenseString(String licenseString, LicenseT
licenses = mapper.readValue(is, LicenseList.class);
}

if (licenses != null && CollectionUtils.isNotEmpty(licenses.licenses)) {
if (licenses != null && (licenses.licenses != null && !licenses.licenses.isEmpty())) {
for (LicenseDetail licenseDetail : licenses.licenses) {

final String primaryLicenseUrl = (licenseDetail.seeAlso != null && !licenseDetail.seeAlso.isEmpty()) ? licenseDetail.seeAlso.get(0) : null;
Expand Down Expand Up @@ -163,7 +161,7 @@ private static LicenseChoice resolveFuzzyMatching(final String licenseString, fi

if (mappings != null) {
for (final SpdxLicenseMapping licenseMapping : mappings) {
if (CollectionUtils.isNotEmpty(licenseMapping.names)) {
if (licenseMapping.names != null && !licenseMapping.names.isEmpty()) {
for (final String name : licenseMapping.names) {
if (licenseString.equalsIgnoreCase(name)) {
if (licenseMapping.exp.startsWith("(") && licenseMapping.exp.endsWith(")")) {
Expand Down Expand Up @@ -197,19 +195,18 @@ private static LicenseChoice createLicenseChoice(String licenseId, String primar
license.setId(licenseId);
license.setUrl(primaryLicenseUrl);
if (!isDeprecatedLicenseId && licenseTextSettings.isTextIncluded()) {
final InputStream is = LicenseResolver.class.getResourceAsStream("/licenses/" + licenseId + ".txt");
if (is != null) {
final String text = IOUtils.toString(is, StandardCharsets.UTF_8);
final byte[] text = readLicenseText(licenseId);
if (text != null) {
final AttachmentText attachment = new AttachmentText();
attachment.setContentType("text/plain");
switch(licenseTextSettings.getEncoding()){
case NONE:
attachment.setEncoding(null);
attachment.setText(text);
attachment.setText(new String(text, StandardCharsets.UTF_8));
break;
case BASE64:
attachment.setEncoding(licenseTextSettings.getEncoding().toString());
attachment.setText(Base64.getEncoder().encodeToString(text.getBytes(Charset.defaultCharset())));
attachment.setText(Base64.getEncoder().encodeToString(text));
break;
default:
throw new IllegalArgumentException("Unhandled License Encoding:" + licenseTextSettings.getEncoding().toString() );
Expand Down Expand Up @@ -267,6 +264,22 @@ public void setEncoding(LicenseEncoding encoding) {
}
}

private static byte[] readLicenseText(final String licenseId) throws IOException {
try (final InputStream is = LicenseResolver.class.getResourceAsStream("/licenses/" + licenseId + ".txt")) {
if (is == null) {
return null;
}

final ByteArrayOutputStream out = new ByteArrayOutputStream();
final byte[] buf = new byte[8192];
int n;
while ((n = is.read(buf)) != -1) {
out.write(buf, 0, n);
}
return out.toByteArray();
}
}

private static class LicenseDetail {
public String reference;
public boolean isDeprecatedLicenseId;
Expand Down
5 changes: 2 additions & 3 deletions src/main/java/org/cyclonedx/util/ObjectLocator.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
*/
package org.cyclonedx.util;

import org.apache.commons.collections4.CollectionUtils;
import org.cyclonedx.model.Bom;
import org.cyclonedx.model.Component;
import org.cyclonedx.model.Service;
Expand Down Expand Up @@ -103,7 +102,7 @@ private static Component findComponent(final List<Component> components, final S
for (final Component component: components) {
if (bomRef.equals(component.getBomRef())) {
return component;
} else if (CollectionUtils.isNotEmpty(component.getComponents())) {
} else if (component.getComponents() != null && !component.getComponents().isEmpty()) {
final Component child = findComponent(component.getComponents(), bomRef);
if (child != null) return child;
}
Expand All @@ -116,7 +115,7 @@ private static Service findService(final List<Service> services, final String bo
for (final Service service: services) {
if (bomRef.equals(service.getBomRef())) {
return service;
} else if (CollectionUtils.isNotEmpty(service.getServices())) {
} else if (service.getServices() != null && !service.getServices().isEmpty()) {
final Service child = findService(service.getServices(), bomRef);
if (child != null) return child;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,12 @@
*/
package org.cyclonedx.util.deserializer;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.dataformat.xml.deser.FromXmlParser;
import org.apache.commons.lang3.math.NumberUtils;
import org.cyclonedx.model.ExtensibleType;
import org.cyclonedx.model.Extension;
import org.cyclonedx.model.Extension.ExtensionType;
Expand All @@ -44,6 +36,13 @@
import org.cyclonedx.model.vulnerability.Vulnerability10.ScoreSource;
import org.cyclonedx.model.vulnerability.Vulnerability10.Severity;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ExtensionDeserializer extends StdDeserializer<Extension>
{
public ExtensionDeserializer() {
Expand Down Expand Up @@ -183,8 +182,10 @@ private List<Cwe> processCwes(final JsonNode cwes) {

private Cwe processCwe(final JsonNode cwe) {
Cwe c = new Cwe();
if (NumberUtils.isParsable(cwe.textValue())) {
try {
c.setText(Integer.valueOf(cwe.textValue()));
} catch (NumberFormatException e) {
// Not a CWE ID; leave unset.
}
return c;
}
Expand Down
Loading
Loading