diff --git a/scm-core/src/main/java/sonia/scm/repository/Branch.java b/scm-core/src/main/java/sonia/scm/repository/Branch.java index a1d500078c..bdcbc66a82 100644 --- a/scm-core/src/main/java/sonia/scm/repository/Branch.java +++ b/scm-core/src/main/java/sonia/scm/repository/Branch.java @@ -21,18 +21,20 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.repository; //~--- non-JDK imports -------------------------------------------------------- import com.google.common.base.MoreObjects; import com.google.common.base.Objects; +import sonia.scm.Validateable; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlRootElement; import java.io.Serializable; +import java.util.regex.Pattern; //~--- JDK imports ------------------------------------------------------------ @@ -44,9 +46,14 @@ import java.io.Serializable; */ @XmlRootElement(name = "branch") @XmlAccessorType(XmlAccessType.FIELD) -public final class Branch implements Serializable +public final class Branch implements Serializable, Validateable { + private static final String VALID_CHARACTERS_AT_START_AND_END = "\\w-,;\\]{}@&+=$#`|<>"; + private static final String VALID_CHARACTERS = VALID_CHARACTERS_AT_START_AND_END + "/."; + public static final String VALID_BRANCH_NAMES = "[" + VALID_CHARACTERS_AT_START_AND_END + "]([" + VALID_CHARACTERS + "]*[" + VALID_CHARACTERS_AT_START_AND_END + "])?"; + public static final Pattern VALID_BRANCH_NAME_PATTERN = Pattern.compile(VALID_BRANCH_NAMES); + /** Field description */ private static final long serialVersionUID = -4602244691711222413L; @@ -83,6 +90,11 @@ public final class Branch implements Serializable //~--- methods -------------------------------------------------------------- + @Override + public boolean isValid() { + return VALID_BRANCH_NAME_PATTERN.matcher(name).matches(); + } + /** * {@inheritDoc} * diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitConfigDto.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitConfigDto.java index a6cd437856..9f30692bca 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitConfigDto.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitConfigDto.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.api.v2.resources; import de.otto.edison.hal.HalRepresentation; @@ -30,6 +30,11 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Pattern; + +import static sonia.scm.repository.Branch.VALID_BRANCH_NAMES; + @NoArgsConstructor @Getter @Setter @@ -41,6 +46,8 @@ public class GitConfigDto extends HalRepresentation { private boolean nonFastForwardDisallowed; + @NotEmpty + @Pattern(regexp = VALID_BRANCH_NAMES, message = "") private String defaultBranch; @Override diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitConfigResource.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitConfigResource.java index 17f76913c5..71d97f27be 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitConfigResource.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitConfigResource.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.api.v2.resources; import io.swagger.v3.oas.annotations.OpenAPIDefinition; @@ -38,6 +38,7 @@ import sonia.scm.web.VndMediaType; import javax.inject.Inject; import javax.inject.Provider; +import javax.validation.Valid; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.PUT; @@ -126,7 +127,7 @@ public class GitConfigResource { mediaType = VndMediaType.ERROR_TYPE, schema = @Schema(implementation = ErrorDto.class) )) - public Response update(GitConfigDto configDto) { + public Response update(@Valid GitConfigDto configDto) { GitConfig config = dtoToConfigMapper.map(configDto); diff --git a/scm-ui/ui-components/src/validation.ts b/scm-ui/ui-components/src/validation.ts index fcdb1a6dfd..9e2b372dcb 100644 --- a/scm-ui/ui-components/src/validation.ts +++ b/scm-ui/ui-components/src/validation.ts @@ -28,6 +28,12 @@ export const isNameValid = (name: string) => { return nameRegex.test(name); }; +export const branchRegex = /^[\w-,;\]{}@&+=$#`|<>]([\w-,;\]{}@&+=$#`|<>/.]*[\w-,;\]{}@&+=$#`|<>])?$/; + +export const isBranchValid = (name: string) => { + return branchRegex.test(name); +}; + const mailRegex = /^[ -~]+@[A-Za-z0-9][\w\-.]*\.[A-Za-z0-9][A-Za-z0-9-]+$/; export const isMailValid = (mail: string) => { diff --git a/scm-ui/ui-webapp/src/repos/branches/components/BranchForm.tsx b/scm-ui/ui-webapp/src/repos/branches/components/BranchForm.tsx index 35d2a42bd9..e4d9864c1f 100644 --- a/scm-ui/ui-webapp/src/repos/branches/components/BranchForm.tsx +++ b/scm-ui/ui-webapp/src/repos/branches/components/BranchForm.tsx @@ -124,15 +124,13 @@ class BranchForm extends React.Component { handleSourceChange = (source: string) => { this.setState({ - ...this.state, source }); }; handleNameChange = (name: string) => { this.setState({ - nameValidationError: !validator.isNameValid(name), - ...this.state, + nameValidationError: !validator.isBranchValid(name), name }); }; diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BranchDto.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BranchDto.java index db144c18b2..4825291c1b 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BranchDto.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BranchDto.java @@ -35,16 +35,14 @@ import org.hibernate.validator.constraints.Length; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.Pattern; +import static sonia.scm.repository.Branch.VALID_BRANCH_NAMES; + @Getter @Setter @NoArgsConstructor @SuppressWarnings("java:S2160") // we do not need this for dto public class BranchDto extends HalRepresentation { - private static final String VALID_CHARACTERS_AT_START_AND_END = "\\w-,;\\]{}@&+=$#`|<>"; - private static final String VALID_CHARACTERS = VALID_CHARACTERS_AT_START_AND_END + "/."; - static final String VALID_BRANCH_NAMES = "[" + VALID_CHARACTERS_AT_START_AND_END + "]([" + VALID_CHARACTERS + "]*[" + VALID_CHARACTERS_AT_START_AND_END + "])?"; - @NotEmpty @Length(min = 1, max = 100) @Pattern(regexp = VALID_BRANCH_NAMES) diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BranchRequestDto.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BranchRequestDto.java index c81aaf18c7..f56de8c38b 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BranchRequestDto.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BranchRequestDto.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.api.v2.resources; import lombok.Getter; @@ -31,7 +31,7 @@ import javax.validation.constraints.NotEmpty; import javax.validation.constraints.Pattern; -import static sonia.scm.api.v2.resources.BranchDto.VALID_BRANCH_NAMES; +import static sonia.scm.repository.Branch.VALID_BRANCH_NAMES; @Getter @Setter diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchDtoTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchDtoTest.java index 57e9b3b031..7f11520f33 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchDtoTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchDtoTest.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.api.v2.resources; import org.junit.jupiter.params.ParameterizedTest; @@ -29,6 +29,7 @@ import org.junit.jupiter.params.provider.ValueSource; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import static sonia.scm.repository.Branch.VALID_BRANCH_NAMES; class BranchDtoTest { @@ -54,10 +55,11 @@ class BranchDtoTest { "val{d", "val{}d", "val|kill", - "val}" + "val}", + "va/li/d" }) void shouldAcceptValidBranchName(String branchName) { - assertTrue(branchName.matches(BranchDto.VALID_BRANCH_NAMES)); + assertTrue(branchName.matches(VALID_BRANCH_NAMES)); } @ParameterizedTest @@ -70,6 +72,6 @@ class BranchDtoTest { "val id" }) void shouldRejectInvalidBranchName(String branchName) { - assertFalse(branchName.matches(BranchDto.VALID_BRANCH_NAMES)); + assertFalse(branchName.matches(VALID_BRANCH_NAMES)); } }