diff --git a/common/src/main/java/com/linecorp/centraldogma/internal/Util.java b/common/src/main/java/com/linecorp/centraldogma/internal/Util.java index 110e9b1933..5daf79206c 100644 --- a/common/src/main/java/com/linecorp/centraldogma/internal/Util.java +++ b/common/src/main/java/com/linecorp/centraldogma/internal/Util.java @@ -57,7 +57,7 @@ public final class Util { * End with an alphanumeric character. */ private static final Pattern PROJECT_AND_REPO_NAME_PATTERN = - Pattern.compile("^[0-9A-Za-z](?:[-+_0-9A-Za-z.]*[0-9A-Za-z])?$"); + Pattern.compile("^(?!.*\\.git$)[0-9A-Za-z](?:[-+_0-9A-Za-z.]*[0-9A-Za-z])?$"); public static String validateFileName(String name, String paramName) { requireNonNull(name, paramName); diff --git a/server/src/main/java/com/linecorp/centraldogma/server/command/CreateRepositoryCommand.java b/server/src/main/java/com/linecorp/centraldogma/server/command/CreateRepositoryCommand.java index b0285dc5c4..d43fc90a78 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/command/CreateRepositoryCommand.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/command/CreateRepositoryCommand.java @@ -38,7 +38,6 @@ public final class CreateRepositoryCommand extends ProjectCommand { @JsonProperty("author") @Nullable Author author, @JsonProperty("projectName") String projectName, @JsonProperty("repositoryName") String repositoryName) { - super(CommandType.CREATE_REPOSITORY, timestamp, author, projectName); this.repositoryName = requireNonNull(repositoryName, "repositoryName"); } diff --git a/server/src/main/java/com/linecorp/centraldogma/server/internal/storage/DirectoryBasedStorageManager.java b/server/src/main/java/com/linecorp/centraldogma/server/internal/storage/DirectoryBasedStorageManager.java index f9405568b4..6a1123ae40 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/internal/storage/DirectoryBasedStorageManager.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/internal/storage/DirectoryBasedStorageManager.java @@ -65,6 +65,7 @@ public abstract class DirectoryBasedStorageManager implements StorageManager< Pattern.compile("^[0-9A-Za-z](?:[-+_0-9A-Za-z.]*[0-9A-Za-z])?$"); private static final String SUFFIX_REMOVED = ".removed"; private static final String SUFFIX_PURGED = ".purged"; + private static final String GIT_EXTENSION = ".git"; private final String childTypeName; private final File rootDir; @@ -437,7 +438,8 @@ private static boolean isValidChildName(String name) { return false; } - return !name.endsWith(SUFFIX_REMOVED) && !name.endsWith(SUFFIX_PURGED); + return !name.endsWith(SUFFIX_REMOVED) && !name.endsWith(SUFFIX_PURGED) && + !name.endsWith(GIT_EXTENSION); // Git repository whose name ends with '.git' is not allowed. } @Override diff --git a/server/src/main/java/com/linecorp/centraldogma/server/internal/thrift/CentralDogmaServiceImpl.java b/server/src/main/java/com/linecorp/centraldogma/server/internal/thrift/CentralDogmaServiceImpl.java index 126887f910..0cf08a2d67 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/internal/thrift/CentralDogmaServiceImpl.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/internal/thrift/CentralDogmaServiceImpl.java @@ -18,6 +18,8 @@ import static com.google.common.base.MoreObjects.firstNonNull; import static com.linecorp.centraldogma.common.Author.SYSTEM; import static com.linecorp.centraldogma.common.Revision.HEAD; +import static com.linecorp.centraldogma.internal.Util.validateProjectName; +import static com.linecorp.centraldogma.internal.Util.validateRepositoryName; import static com.linecorp.centraldogma.server.internal.api.ContentServiceV1.checkPush; import static com.linecorp.centraldogma.server.internal.api.RepositoryServiceV1.increaseCounterIfOldRevisionUsed; import static com.linecorp.centraldogma.server.internal.thrift.Converter.convert; @@ -121,6 +123,7 @@ private static void handleAsVoidResult(CompletableFuture future, AsyncMethodC @Override public void createProject(String name, AsyncMethodCallback resultHandler) { + validateProjectName(name, "name"); // ProjectInitializingCommandExecutor initializes a metadata for the specified project. handle(projectApiManager.createProject(name, SYSTEM), resultHandler); } @@ -161,6 +164,7 @@ public void listRemovedProjects(AsyncMethodCallback resultHandler) { @Override public void createRepository(String projectName, String repositoryName, AsyncMethodCallback resultHandler) { + validateRepositoryName(repositoryName, "repositoryName"); // HTTP v1 API will return '403 forbidden' in this case, but we deal it as '400 bad request' here. if (isReservedRepoName(repositoryName)) { resultHandler.onError(convert(RESERVED_REPOSITORY_EXCEPTION)); diff --git a/server/src/test/java/com/linecorp/centraldogma/server/internal/api/RepositoryServiceV1Test.java b/server/src/test/java/com/linecorp/centraldogma/server/internal/api/RepositoryServiceV1Test.java index 4697f11a1e..ca9660dbec 100644 --- a/server/src/test/java/com/linecorp/centraldogma/server/internal/api/RepositoryServiceV1Test.java +++ b/server/src/test/java/com/linecorp/centraldogma/server/internal/api/RepositoryServiceV1Test.java @@ -103,6 +103,13 @@ void createRepositoryWithSameName() { assertThatJson(aRes.contentUtf8()).isEqualTo(expectedJson); } + @Test + void createRepositoryWithInvalidName() { + final WebClient client = dogma.httpClient(); + final AggregatedHttpResponse aRes = createRepository(client, "myRepo.git"); + assertThat(aRes.headers().status()).isSameAs(HttpStatus.BAD_REQUEST); + } + @Test void createRepositoryInAbsentProject() { final WebClient client = dogma.httpClient(); @@ -123,7 +130,7 @@ void createRepositoryInAbsentProject() { @Test void removeRepository() { final WebClient client = dogma.httpClient(); - createRepository(client,"foo"); + createRepository(client, "foo"); final AggregatedHttpResponse aRes = client.delete(REPOS_PREFIX + "/foo").aggregate().join(); assertThat(ResponseHeaders.of(aRes.headers()).status()).isEqualTo(HttpStatus.NO_CONTENT); }