/**
* Yobi, Project Hosting SW
*
* Copyright 2012 NAVER Corp.
* http://yobi.io
*
* @author Ahn Hyeok Jun
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package controllers;
import java.io.IOException;
import javax.servlet.ServletException;
import models.Project;
import models.enumeration.Operation;
import com.github.zafarkhaja.semver.Version;
import play.api.i18n.Lang;
import play.i18n.Messages;
import play.mvc.Controller;
import play.mvc.Result;
import play.mvc.With;
import playRepository.PlayRepository;
import playRepository.RepositoryService;
import utils.AccessControl;
import utils.BasicAuthAction;
import utils.Config;
public class GitApp extends Controller {
public static boolean isSupportedService(String service) {
return service != null
&& (service.equals("git-upload-pack") || service.equals("git-receive-pack"));
}
private static boolean isAllowed(Project project, String service) throws
UnsupportedOperationException, IOException, ServletException {
Operation operation = Operation.UPDATE;
if (service.equals("git-upload-pack")) {
operation = Operation.READ;
}
PlayRepository repository = RepositoryService.getRepository(project);
return AccessControl
.isAllowed(UserApp.currentUser(), repository.asResource(), operation);
}
/**
* Checks whether the Git client allows Content-Type has a charset.
*
* Charset is allowed since Git 2.1.0.
*
* @param userAgent
* @return
*/
private static boolean isCharsetAllowed(String userAgent) {
try {
String version = Config.semverize(userAgent.substring(userAgent.indexOf('/') + 1));
if (Version.valueOf(version).greaterThanOrEqualTo(Version.forIntegers(2, 1, 0))) {
return true;
}
} catch (Exception e) {
return false;
}
return false;
}
public static Result service(String ownerName, String projectName, String service,
boolean isAdvertise) throws IOException, UnsupportedOperationException,
ServletException {
if (!isSupportedService(service)) {
return forbidden(String.format("Unsupported service: '%s'", service));
}
Project project = Project.findByOwnerAndProjectName(ownerName, projectName);
if (project == null) {
return notFound();
}
if (!project.vcs.equals(RepositoryService.VCS_GIT)) {
return notFound();
}
models.User user = UserApp.currentUser();
if (!isAllowed(project, service)) {
if (user.isAnonymous()) {
return BasicAuthAction.unauthorized(response());
} else {
String contentType = "text/plain", message;
if (isCharsetAllowed(request().getHeader("User-Agent"))) {
contentType += ";charset=" + Config.getCharset();
message = Messages.get(
"git.error.permission", user.loginId, ownerName, projectName);
} else {
message = Messages.get(Lang.defaultLang(),
"git.error.permission", user.loginId, ownerName, projectName);
}
response().setHeader("Content-Type", contentType);
return forbidden(message);
}
}
if (isAdvertise) {
return ok(RepositoryService
.gitAdvertise(project, service, response()));
} else {
if (request().body().isMaxSizeExceeded()) {
return status(REQUEST_ENTITY_TOO_LARGE);
} else {
user.visits(project);
return ok(RepositoryService
.gitRpc(project, service, request(), response()));
}
}
}
@With(BasicAuthAction.class)
public static Result advertise(String ownerName, String projectName, String service)
throws UnsupportedOperationException, IOException, ServletException {
if (service == null) {
// If service parameter is not specified then git server should do getanyfile service,
// but we don't support that.
return forbidden("Unsupported service: getanyfile");
}
return GitApp.service(ownerName, projectName, service, true);
}
@With(BasicAuthAction.class)
public static Result serviceRpc(String ownerName, String projectName, String service)
throws UnsupportedOperationException, IOException, ServletException {
return GitApp.service(ownerName, projectName, service, false);
}
}