Fix artifact filename validation (#770)
* use validated ArtifactUpload object when creating a new artifact Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com> * rename method Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com> * add regular expression classes Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com> * add filename validation to UI upload button Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com> * move filename validation to uploadStarted Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com> * clean up code for UI error handling during artifact upload, assert filename validation Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com> * update visibilities Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com> * clean up code Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com> * clean up code Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com> * change RegexChar class to enum and use i18n Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com> * typo, use StringBuilder Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com> * typo Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com> * use dedicated class for collections of regular expression characters Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com> * remove Optional, remove stringBuilder Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com> * PR findings Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com> * make regex validation method static Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com> * use WhiteListType.NONE for filename validation via mgmt-api Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>
This commit is contained in:
committed by
Dominic Schabel
parent
a2c1e5f132
commit
20d84a10eb
@@ -8,9 +8,10 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.validation.ConstraintViolationException;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@@ -23,6 +24,7 @@ import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidMD5HashException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidSHA1HashException;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.ArtifactUpload;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
@@ -45,50 +47,8 @@ public interface ArtifactManagement {
|
||||
* Persists artifact binary as provided by given InputStream. assign the
|
||||
* artifact in addition to given {@link SoftwareModule}.
|
||||
*
|
||||
* @param inputStream
|
||||
* to read from for artifact binary
|
||||
* @param moduleId
|
||||
* to assign the new artifact to
|
||||
* @param filename
|
||||
* of the artifact
|
||||
* @param overrideExisting
|
||||
* to <code>true</code> if the artifact binary can be overridden
|
||||
* if it already exists
|
||||
* @param filesize
|
||||
* the size of the file in bytes.
|
||||
*
|
||||
* @return uploaded {@link Artifact}
|
||||
*
|
||||
* @throws ArtifactUploadFailedException
|
||||
* if upload fails
|
||||
* @throws EntityNotFoundException
|
||||
* if given software module does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY)
|
||||
Artifact create(@NotNull InputStream inputStream, long moduleId, final String filename,
|
||||
final boolean overrideExisting, final long filesize);
|
||||
|
||||
/**
|
||||
* Persists artifact binary as provided by given InputStream. assign the
|
||||
* artifact in addition to given {@link SoftwareModule}.
|
||||
*
|
||||
* @param stream
|
||||
* to read from for artifact binary
|
||||
* @param moduleId
|
||||
* to assign the new artifact to
|
||||
* @param filename
|
||||
* of the artifact
|
||||
* @param providedSha1Sum
|
||||
* optional sha1 checksum to check the new file against
|
||||
* @param providedMd5Sum
|
||||
* optional md5 checksum to check the new file against
|
||||
* @param overrideExisting
|
||||
* to <code>true</code> if the artifact binary can be overridden
|
||||
* if it already exists
|
||||
* @param contentType
|
||||
* the contentType of the file
|
||||
* @param filesize
|
||||
* the size of the file in bytes.
|
||||
* @param artifactUpload
|
||||
* {@link ArtifactUpload} containing the upload information
|
||||
*
|
||||
* @return uploaded {@link Artifact}
|
||||
*
|
||||
@@ -102,10 +62,11 @@ public interface ArtifactManagement {
|
||||
* if check against provided MD5 checksum failed
|
||||
* @throws InvalidSHA1HashException
|
||||
* if check against provided SHA1 checksum failed
|
||||
* @throws ConstraintViolationException
|
||||
* if {@link ArtifactUpload} contains invalid values
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY)
|
||||
Artifact create(@NotNull InputStream stream, long moduleId, @NotEmpty String filename, String providedMd5Sum,
|
||||
String providedSha1Sum, boolean overrideExisting, String contentType, long filesize);
|
||||
Artifact create(@NotNull @Valid ArtifactUpload artifactUpload);
|
||||
|
||||
/**
|
||||
* Garbage collects artifact binaries if only referenced by given
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Collection of regular expression characters to check strings
|
||||
*/
|
||||
public class RegexCharacterCollection {
|
||||
|
||||
private final EnumSet<RegexChar> characters;
|
||||
private final Pattern findAnyCharacter;
|
||||
|
||||
public RegexCharacterCollection(final RegexChar... characters) {
|
||||
this.characters = EnumSet.copyOf(Arrays.asList(characters));
|
||||
this.findAnyCharacter = getPatternFindAnyCharacter();
|
||||
}
|
||||
|
||||
public static boolean stringContainsCharacter(final String stringToCheck,
|
||||
final RegexCharacterCollection regexCharacterCollection) {
|
||||
return regexCharacterCollection.findAnyCharacter.matcher(stringToCheck).matches();
|
||||
}
|
||||
|
||||
private Pattern getPatternFindAnyCharacter() {
|
||||
final String regexCharacters = characters.stream().map(RegexChar::getRegExp)
|
||||
.collect(Collectors.joining());
|
||||
final String regularExpression = String.format(".*[%s]+.*", regexCharacters);
|
||||
return Pattern.compile(regularExpression);
|
||||
}
|
||||
|
||||
public enum RegexChar {
|
||||
WHITESPACE("\\s", "character.whitespace"), DIGITS("0-9", "character.digits"), QUOTATION_MARKS("'\"",
|
||||
"character.quotationMarks"), SLASHES("\\/\\\\", "character.slashes"), GREATER_THAN(
|
||||
">"), LESS_THAN("<"), EQUALS_SYMBOL("="), EXCLAMATION_MARK("!"), QUESTION_MARK("?"), COLON(":");
|
||||
|
||||
private final String regExp;
|
||||
private final String l18nReferenceDescription;
|
||||
|
||||
RegexChar(final String character) {
|
||||
this(character, null);
|
||||
}
|
||||
|
||||
RegexChar(final String regExp, final String l18nReferenceDescription) {
|
||||
this.regExp = regExp;
|
||||
this.l18nReferenceDescription = l18nReferenceDescription;
|
||||
}
|
||||
|
||||
public String getRegExp() {
|
||||
return regExp;
|
||||
}
|
||||
|
||||
public Optional<String> getL18nReferenceDescription() {
|
||||
return Optional.ofNullable(l18nReferenceDescription);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.model;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.hibernate.validator.constraints.SafeHtml;
|
||||
import org.hibernate.validator.constraints.SafeHtml.WhiteListType;
|
||||
|
||||
/**
|
||||
* Use to create a new artifact.
|
||||
*
|
||||
*/
|
||||
public class ArtifactUpload {
|
||||
|
||||
@NotNull
|
||||
private final InputStream inputStream;
|
||||
|
||||
private final long moduleId;
|
||||
|
||||
@NotEmpty
|
||||
@SafeHtml(whitelistType = WhiteListType.NONE, message = "Invalid characters in string")
|
||||
private final String filename;
|
||||
|
||||
private final String providedMd5Sum;
|
||||
|
||||
private final String providedSha1Sum;
|
||||
|
||||
private final boolean overrideExisting;
|
||||
|
||||
private final String contentType;
|
||||
|
||||
private final long filesize;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param inputStream
|
||||
* to read from for artifact binary
|
||||
* @param moduleId
|
||||
* to assign the new artifact to
|
||||
* @param filename
|
||||
* of the artifact
|
||||
* @param overrideExisting
|
||||
* to <code>true</code> if the artifact binary can be overridden
|
||||
* if it already exists
|
||||
* @param filesize
|
||||
* the size of the file in bytes.
|
||||
*/
|
||||
public ArtifactUpload(final InputStream inputStream, final long moduleId, final String filename,
|
||||
final boolean overrideExisting, final long filesize) {
|
||||
this(inputStream, moduleId, filename, null, null, overrideExisting, null, filesize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param inputStream
|
||||
* to read from for artifact binary
|
||||
* @param moduleId
|
||||
* to assign the new artifact to
|
||||
* @param filename
|
||||
* of the artifact
|
||||
* @param providedSha1Sum
|
||||
* optional sha1 checksum to check the new file against
|
||||
* @param providedMd5Sum
|
||||
* optional md5 checksum to check the new file against
|
||||
* @param overrideExisting
|
||||
* to <code>true</code> if the artifact binary can be overridden
|
||||
* if it already exists
|
||||
* @param contentType
|
||||
* the contentType of the file
|
||||
* @param filesize
|
||||
* the size of the file in bytes.
|
||||
*/
|
||||
public ArtifactUpload(final InputStream inputStream, final long moduleId, final String filename,
|
||||
final String providedMd5Sum, final String providedSha1Sum, final boolean overrideExisting,
|
||||
final String contentType, final long filesize) {
|
||||
this.inputStream = inputStream;
|
||||
this.moduleId = moduleId;
|
||||
this.filename = filename;
|
||||
this.providedMd5Sum = providedMd5Sum;
|
||||
this.providedSha1Sum = providedSha1Sum;
|
||||
this.overrideExisting = overrideExisting;
|
||||
this.contentType = contentType;
|
||||
this.filesize = filesize;
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
public long getModuleId() {
|
||||
return moduleId;
|
||||
}
|
||||
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
public String getProvidedMd5Sum() {
|
||||
return providedMd5Sum;
|
||||
}
|
||||
|
||||
public String getProvidedSha1Sum() {
|
||||
return providedSha1Sum;
|
||||
}
|
||||
|
||||
public boolean overrideExisting() {
|
||||
return overrideExisting;
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
public long getFilesize() {
|
||||
return filesize;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.eclipse.hawkbit.repository.RegexCharacterCollection.RegexChar;
|
||||
import org.junit.Test;
|
||||
|
||||
import io.qameta.allure.Description;
|
||||
import io.qameta.allure.Feature;
|
||||
import io.qameta.allure.Story;
|
||||
|
||||
@Feature("Unit Tests - Repository")
|
||||
@Story("Regular expression helper")
|
||||
public class RegexCharTest {
|
||||
|
||||
private static final String TEST_STRING = getPrintableAsciiCharacters();
|
||||
|
||||
private static final int INDEX_FIRST_PRINTABLE_ASCII_CHAR = 32;
|
||||
private static final int INDEX_LAST_PRINTABLE_ASCII_CHAR = 127;
|
||||
|
||||
@Test
|
||||
@Description("Verifies every RegexChar can be used to exclusively find the desired characters in a String.")
|
||||
public void allRegexCharsOnlyFindExpectedChars() {
|
||||
for (final RegexChar character : RegexChar.values()) {
|
||||
switch (character) {
|
||||
case DIGITS:
|
||||
assertRegexCharExclusivelyFindsGivenCharacters(character, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
|
||||
break;
|
||||
case WHITESPACE:
|
||||
assertRegexCharExclusivelyFindsGivenCharacters(character, " ", "\t");
|
||||
break;
|
||||
case SLASHES:
|
||||
assertRegexCharExclusivelyFindsGivenCharacters(character, "/", "\\");
|
||||
break;
|
||||
case QUOTATION_MARKS:
|
||||
assertRegexCharExclusivelyFindsGivenCharacters(character, "\"", "'");
|
||||
break;
|
||||
default:
|
||||
assertRegexCharExclusivelyFindsGivenCharacters(character, character.getRegExp());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that combinations of RegexChars can be used to find the desired characters in a String.")
|
||||
public void combinedRegexCharsFindExpectedChars() {
|
||||
final RegexCharacterCollection greaterAndLessThan = new RegexCharacterCollection(RegexChar.GREATER_THAN,
|
||||
RegexChar.LESS_THAN);
|
||||
final RegexCharacterCollection equalsAndQuestionMark = new RegexCharacterCollection(RegexChar.EQUALS_SYMBOL,
|
||||
RegexChar.QUESTION_MARK);
|
||||
final RegexCharacterCollection colonAndWhitespace = new RegexCharacterCollection(RegexChar.COLON,
|
||||
RegexChar.WHITESPACE);
|
||||
|
||||
assertRegexCharsExclusivelyFindsGivenCharacters(greaterAndLessThan, "<", ">");
|
||||
assertRegexCharsExclusivelyFindsGivenCharacters(equalsAndQuestionMark, "=", "?");
|
||||
assertRegexCharsExclusivelyFindsGivenCharacters(colonAndWhitespace, ":", " ", "\t");
|
||||
}
|
||||
|
||||
private void assertRegexCharExclusivelyFindsGivenCharacters(final RegexChar characterToVerify,
|
||||
final String... charactersExpectedToBeFoundByRegex) {
|
||||
assertRegexCharsExclusivelyFindsGivenCharacters(new RegexCharacterCollection(characterToVerify),
|
||||
charactersExpectedToBeFoundByRegex);
|
||||
}
|
||||
|
||||
private void assertRegexCharsExclusivelyFindsGivenCharacters(final RegexCharacterCollection regexToVerify,
|
||||
final String... charactersExpectedToBeFoundByRegex) {
|
||||
String notMatchingString = TEST_STRING;
|
||||
for(final String character : charactersExpectedToBeFoundByRegex) {
|
||||
notMatchingString = notMatchingString.replace(character, "");
|
||||
}
|
||||
for(final String character : charactersExpectedToBeFoundByRegex) {
|
||||
assertThat(RegexCharacterCollection.stringContainsCharacter("", regexToVerify)).isFalse();
|
||||
assertThat(RegexCharacterCollection.stringContainsCharacter(notMatchingString, regexToVerify)).isFalse();
|
||||
assertThat(RegexCharacterCollection.stringContainsCharacter(character, regexToVerify)).isTrue();
|
||||
assertThat(RegexCharacterCollection
|
||||
.stringContainsCharacter(insertStringIntoString(notMatchingString, character, 0), regexToVerify))
|
||||
.isTrue();
|
||||
assertThat(RegexCharacterCollection.stringContainsCharacter(
|
||||
insertStringIntoString(notMatchingString, character, notMatchingString.length()), regexToVerify)).isTrue();
|
||||
assertThat(RegexCharacterCollection.stringContainsCharacter(
|
||||
insertStringIntoString(notMatchingString, character, notMatchingString.length() / 2), regexToVerify)).isTrue();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static String getPrintableAsciiCharacters() {
|
||||
final StringBuilder stringBuilder = new StringBuilder();
|
||||
for (int i = INDEX_FIRST_PRINTABLE_ASCII_CHAR; i < INDEX_LAST_PRINTABLE_ASCII_CHAR; i++) {
|
||||
stringBuilder.append((char) i);
|
||||
}
|
||||
stringBuilder.append("\t");
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
private static String insertStringIntoString(final String baseString, final String stringToInsert,
|
||||
final int position) {
|
||||
final StringBuilder stringBuilder = new StringBuilder(baseString);
|
||||
return stringBuilder.insert(position, stringToInsert).toString();
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.hawkbit.artifact.repository.ArtifactRepository;
|
||||
@@ -30,6 +29,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.ArtifactUpload;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.slf4j.Logger;
|
||||
@@ -95,22 +95,24 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public Artifact create(final InputStream stream, final long moduleId, final String filename,
|
||||
final String providedMd5Sum, final String providedSha1Sum, final boolean overrideExisting,
|
||||
final String contentType, final long filesize) {
|
||||
public Artifact create(final ArtifactUpload artifactUpload) {
|
||||
final String filename = artifactUpload.getFilename();
|
||||
final long moduleId = artifactUpload.getModuleId();
|
||||
AbstractDbArtifact result = null;
|
||||
|
||||
final SoftwareModule softwareModule = getModuleAndThrowExceptionIfThatFails(moduleId);
|
||||
|
||||
final Artifact existing = checkForExistingArtifact(filename, overrideExisting, softwareModule);
|
||||
final Artifact existing = checkForExistingArtifact(filename, artifactUpload.overrideExisting(),
|
||||
softwareModule);
|
||||
|
||||
assertArtifactQuota(moduleId, 1);
|
||||
assertMaxArtifactSizeQuota(filename, moduleId, filesize);
|
||||
assertMaxArtifactStorageQuota(filename, filesize);
|
||||
assertMaxArtifactSizeQuota(filename, moduleId, artifactUpload.getFilesize());
|
||||
assertMaxArtifactStorageQuota(filename, artifactUpload.getFilesize());
|
||||
|
||||
try {
|
||||
result = artifactRepository.store(tenantAware.getCurrentTenant(), stream, filename, contentType,
|
||||
new DbArtifactHash(providedSha1Sum, providedMd5Sum));
|
||||
result = artifactRepository.store(tenantAware.getCurrentTenant(), artifactUpload.getInputStream(), filename,
|
||||
artifactUpload.getContentType(),
|
||||
new DbArtifactHash(artifactUpload.getProvidedSha1Sum(), artifactUpload.getProvidedMd5Sum()));
|
||||
} catch (final ArtifactStoreException e) {
|
||||
throw new ArtifactUploadFailedException(e);
|
||||
} catch (final HashNotMatchException e) {
|
||||
@@ -248,15 +250,6 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
||||
return localArtifactRepository.save(artifact);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public Artifact create(final InputStream inputStream, final long moduleId, final String filename,
|
||||
final boolean overrideExisting, final long filesize) {
|
||||
return create(inputStream, moduleId, filename, null, null, overrideExisting, null, filesize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long count() {
|
||||
return localArtifactRepository.count();
|
||||
|
||||
@@ -20,6 +20,8 @@ import java.net.URISyntaxException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.validation.ConstraintViolationException;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
@@ -31,6 +33,7 @@ import org.eclipse.hawkbit.repository.exception.QuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.ArtifactUpload;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.Expect;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
|
||||
@@ -74,11 +77,14 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
final String artifactData = "test";
|
||||
final int artifactSize = artifactData.length();
|
||||
verifyThrownExceptionBy(() -> artifactManagement.create(IOUtils.toInputStream(artifactData, "UTF-8"),
|
||||
NOT_EXIST_IDL, "xxx", null, null, false, null, artifactSize), "SoftwareModule");
|
||||
verifyThrownExceptionBy(
|
||||
() -> artifactManagement.create(new ArtifactUpload(IOUtils.toInputStream(artifactData, "UTF-8"),
|
||||
NOT_EXIST_IDL, "xxx", null, null, false, null, artifactSize)),
|
||||
"SoftwareModule");
|
||||
|
||||
verifyThrownExceptionBy(() -> artifactManagement.create(IOUtils.toInputStream(artifactData, "UTF-8"), 1234L,
|
||||
"xxx", false, artifactSize), "SoftwareModule");
|
||||
verifyThrownExceptionBy(() -> artifactManagement.create(
|
||||
new ArtifactUpload(IOUtils.toInputStream(artifactData, "UTF-8"), 1234L, "xxx", false, artifactSize)),
|
||||
"SoftwareModule");
|
||||
|
||||
verifyThrownExceptionBy(() -> artifactManagement.delete(NOT_EXIST_IDL), "Artifact");
|
||||
|
||||
@@ -137,6 +143,21 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that artifact management does not create artifacts with illegal filename.")
|
||||
public void entityQueryWithIllegalFilenameThrowsException() throws URISyntaxException {
|
||||
final String illegalFilename = "<img src=ernw onerror=alert(1)>.xml";
|
||||
final String artifactData = "test";
|
||||
final int artifactSize = artifactData.length();
|
||||
|
||||
final long smID = softwareModuleRepository
|
||||
.save(new JpaSoftwareModule(osType, "smIllegalFilenameTest", "1.0", null, null)).getId();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> artifactManagement.create(
|
||||
new ArtifactUpload(IOUtils.toInputStream(artifactData, "UTF-8"), smID, illegalFilename, false,
|
||||
artifactSize)));
|
||||
assertThat(softwareModuleManagement.get(smID).get().getArtifacts()).hasSize(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that the quota specifying the maximum number of artifacts per software module is enforced.")
|
||||
public void createArtifactsUntilQuotaIsExceeded() throws NoSuchAlgorithmException, IOException {
|
||||
@@ -408,7 +429,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
private Artifact createArtifactForSoftwareModule(final String filename, final long moduleId, final int artifactSize,
|
||||
final InputStream inputStream) throws IOException {
|
||||
return artifactManagement.create(inputStream, moduleId, filename, false, artifactSize);
|
||||
return artifactManagement.create(new ArtifactUpload(inputStream, moduleId, filename, false, artifactSize));
|
||||
}
|
||||
|
||||
private static byte[] randomBytes(final int len) {
|
||||
|
||||
@@ -46,6 +46,7 @@ import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.ArtifactUpload;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
@@ -444,10 +445,10 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
Target savedTarget = testdataFactory.createTarget();
|
||||
|
||||
// create two artifacts with identical SHA1 hash
|
||||
final Artifact artifact = artifactManagement.create(new ByteArrayInputStream(random),
|
||||
ds.findFirstModuleByType(osType).get().getId(), "file1", false, artifactSize);
|
||||
final Artifact artifact2 = artifactManagement.create(new ByteArrayInputStream(random),
|
||||
ds2.findFirstModuleByType(osType).get().getId(), "file1", false, artifactSize);
|
||||
final Artifact artifact = artifactManagement.create(new ArtifactUpload(new ByteArrayInputStream(random),
|
||||
ds.findFirstModuleByType(osType).get().getId(), "file1", false, artifactSize));
|
||||
final Artifact artifact2 = artifactManagement.create(new ArtifactUpload(new ByteArrayInputStream(random),
|
||||
ds2.findFirstModuleByType(osType).get().getId(), "file1", false, artifactSize));
|
||||
assertThat(artifact.getSha1Hash()).isEqualTo(artifact2.getSha1Hash());
|
||||
|
||||
assertThat(
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.ArtifactUpload;
|
||||
import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
@@ -370,7 +371,8 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
SoftwareModule moduleX = createSoftwareModuleWithArtifacts(osType, "modulex", "v1.0", 0);
|
||||
|
||||
// [STEP2]: Create newArtifactX and add it to SoftwareModuleX
|
||||
artifactManagement.create(new ByteArrayInputStream(source), moduleX.getId(), "artifactx", false, artifactSize);
|
||||
artifactManagement.create(new ArtifactUpload(new ByteArrayInputStream(source), moduleX.getId(), "artifactx",
|
||||
false, artifactSize));
|
||||
moduleX = softwareModuleManagement.get(moduleX.getId()).get();
|
||||
final Artifact artifactX = moduleX.getArtifacts().iterator().next();
|
||||
|
||||
@@ -378,7 +380,8 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
SoftwareModule moduleY = createSoftwareModuleWithArtifacts(osType, "moduley", "v1.0", 0);
|
||||
|
||||
// [STEP4]: Assign the same ArtifactX to SoftwareModuleY
|
||||
artifactManagement.create(new ByteArrayInputStream(source), moduleY.getId(), "artifactx", false, artifactSize);
|
||||
artifactManagement.create(new ArtifactUpload(new ByteArrayInputStream(source), moduleY.getId(), "artifactx",
|
||||
false, artifactSize));
|
||||
moduleY = softwareModuleManagement.get(moduleY.getId()).get();
|
||||
final Artifact artifactY = moduleY.getArtifacts().iterator().next();
|
||||
|
||||
@@ -413,14 +416,16 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
// [STEP1]: Create SoftwareModuleX and add a new ArtifactX
|
||||
SoftwareModule moduleX = createSoftwareModuleWithArtifacts(osType, "modulex", "v1.0", 0);
|
||||
|
||||
artifactManagement.create(new ByteArrayInputStream(source), moduleX.getId(), "artifactx", false, artifactSize);
|
||||
artifactManagement.create(new ArtifactUpload(new ByteArrayInputStream(source), moduleX.getId(), "artifactx",
|
||||
false, artifactSize));
|
||||
moduleX = softwareModuleManagement.get(moduleX.getId()).get();
|
||||
final Artifact artifactX = moduleX.getArtifacts().iterator().next();
|
||||
|
||||
// [STEP2]: Create SoftwareModuleY and add the same ArtifactX
|
||||
SoftwareModule moduleY = createSoftwareModuleWithArtifacts(osType, "moduley", "v1.0", 0);
|
||||
|
||||
artifactManagement.create(new ByteArrayInputStream(source), moduleY.getId(), "artifactx", false, artifactSize);
|
||||
artifactManagement.create(new ArtifactUpload(new ByteArrayInputStream(source), moduleY.getId(), "artifactx",
|
||||
false, artifactSize));
|
||||
moduleY = softwareModuleManagement.get(moduleY.getId()).get();
|
||||
final Artifact artifactY = moduleY.getArtifacts().iterator().next();
|
||||
|
||||
@@ -468,8 +473,8 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
final int artifactSize = 5 * 1024;
|
||||
for (int i = 0; i < numberArtifacts; i++) {
|
||||
artifactManagement.create(new RandomGeneratedInputStream(artifactSize), softwareModule.getId(),
|
||||
"file" + (i + 1), false, artifactSize);
|
||||
artifactManagement.create(new ArtifactUpload(new RandomGeneratedInputStream(artifactSize),
|
||||
softwareModule.getId(), "file" + (i + 1), false, artifactSize));
|
||||
}
|
||||
|
||||
// Verify correct Creation of SoftwareModule and corresponding artifacts
|
||||
|
||||
@@ -15,6 +15,7 @@ import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
||||
import org.eclipse.hawkbit.repository.model.ArtifactUpload;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
@@ -134,13 +135,15 @@ public class SystemManagementTest extends AbstractJpaIntegrationTest {
|
||||
private void createTestArtifact(final byte[] random) {
|
||||
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
|
||||
|
||||
artifactManagement.create(new ByteArrayInputStream(random), sm.getId(), "file1", false, random.length);
|
||||
artifactManagement.create(
|
||||
new ArtifactUpload(new ByteArrayInputStream(random), sm.getId(), "file1", false, random.length));
|
||||
}
|
||||
|
||||
private void createDeletedTestArtifact(final byte[] random) {
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet("deleted garbage", true);
|
||||
ds.getModules().stream().forEach(module -> {
|
||||
artifactManagement.create(new ByteArrayInputStream(random), module.getId(), "file1", false, random.length);
|
||||
artifactManagement.create(new ArtifactUpload(new ByteArrayInputStream(random), module.getId(), "file1",
|
||||
false, random.length));
|
||||
softwareModuleManagement.delete(module.getId());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.ArtifactUpload;
|
||||
import org.eclipse.hawkbit.repository.model.BaseEntity;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
@@ -466,7 +467,8 @@ public class TestdataFactory {
|
||||
final String artifactData = "some test data" + i;
|
||||
final InputStream stubInputStream = IOUtils.toInputStream(artifactData, Charset.forName("UTF-8"));
|
||||
artifacts.add(
|
||||
artifactManagement.create(stubInputStream, moduleId, "filename" + i, false, artifactData.length()));
|
||||
artifactManagement.create(new ArtifactUpload(stubInputStream, moduleId, "filename" + i, false,
|
||||
artifactData.length())));
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user