diff --git a/src/main/scala/gitbucket/core/plugin/GitRepositoryRouting.scala b/src/main/scala/gitbucket/core/plugin/GitRepositoryRouting.scala index e7535b8..47654e8 100644 --- a/src/main/scala/gitbucket/core/plugin/GitRepositoryRouting.scala +++ b/src/main/scala/gitbucket/core/plugin/GitRepositoryRouting.scala @@ -1,16 +1,20 @@ package gitbucket.core.plugin -import javax.servlet.http.{HttpServletResponse, HttpServletRequest} +import gitbucket.core.model.Session import gitbucket.core.service.SystemSettingsService.SystemSettings case class GitRepositoryRouting(urlPattern: String, localPath: String, filter: GitRepositoryFilter){ + def this(urlPattern: String, localPath: String) = { this(urlPattern, localPath, new GitRepositoryFilter(){ - def filter(request: HttpServletRequest, response: HttpServletResponse, settings: SystemSettings, isUpdating: Boolean): Boolean = true + def filter(repositoryName: String, userName: Option[String], settings: SystemSettings, isUpdating: Boolean) + (implicit session: Session): Boolean = true }) } + } trait GitRepositoryFilter { - def filter(request: HttpServletRequest, response: HttpServletResponse, settings: SystemSettings, isUpdating: Boolean): Boolean + def filter(path: String, userName: Option[String], settings: SystemSettings, isUpdating: Boolean) + (implicit session: Session): Boolean } \ No newline at end of file diff --git a/src/main/scala/gitbucket/core/plugin/PluginRegistory.scala b/src/main/scala/gitbucket/core/plugin/PluginRegistory.scala index 3bf3ee3..98c7ea4 100644 --- a/src/main/scala/gitbucket/core/plugin/PluginRegistory.scala +++ b/src/main/scala/gitbucket/core/plugin/PluginRegistory.scala @@ -90,12 +90,10 @@ repositoryRoutings.toSeq } - def getRepositoryRouting(requestURI: String): Option[GitRepositoryRouting] = { - val path = requestURI.replaceFirst("^/git/", "") - + def getRepositoryRouting(repositoryPath: String): Option[GitRepositoryRouting] = { PluginRegistry().getRepositoryRoutings().find { case GitRepositoryRouting(urlPath, _, _) => { - path.matches(urlPath + "(/.*)?") + repositoryPath.matches("/" + urlPath + "(/.*)?") } } } diff --git a/src/main/scala/gitbucket/core/servlet/BasicAuthenticationFilter.scala b/src/main/scala/gitbucket/core/servlet/BasicAuthenticationFilter.scala index f6e130f..421a461 100644 --- a/src/main/scala/gitbucket/core/servlet/BasicAuthenticationFilter.scala +++ b/src/main/scala/gitbucket/core/servlet/BasicAuthenticationFilter.scala @@ -2,7 +2,7 @@ import javax.servlet._ import javax.servlet.http._ -import gitbucket.core.plugin.{GitRepositoryRouting, PluginRegistry} +import gitbucket.core.plugin.{GitRepositoryFilter, GitRepositoryRouting, PluginRegistry} import gitbucket.core.service.SystemSettingsService.SystemSettings import gitbucket.core.service.{RepositoryService, AccountService, SystemSettingsService} import gitbucket.core.util.{Keys, Implicits} @@ -32,13 +32,10 @@ val settings = loadSystemSettings() try { - PluginRegistry().getRepositoryRouting(request.getRequestURI).map { case GitRepositoryRouting(_, _, f) => + PluginRegistry().getRepositoryRouting(request.gitRepositoryPath).map { case GitRepositoryRouting(_, _, filter) => // served by plug-ins - if(f.filter(request, wrappedResponse, settings, isUpdating)){ - pluginRepository(request, wrappedResponse, chain, settings, isUpdating) - } else { - requireAuth(response) - } + pluginRepository(request, wrappedResponse, chain, settings, isUpdating, filter) + }.getOrElse { // default repositories defaultRepository(request, wrappedResponse, chain, settings, isUpdating) @@ -52,26 +49,22 @@ } private def pluginRepository(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain, - settings: SystemSettings, isUpdating: Boolean): Unit = { + settings: SystemSettings, isUpdating: Boolean, filter: GitRepositoryFilter): Unit = { implicit val r = request - if(!isUpdating && settings.allowAnonymousAccess){ + val account = for { + auth <- Option(request.getHeader("Authorization")) + Array(username, password) = decodeAuthHeader(auth).split(":", 2) + account <- authenticate(settings, username, password) + } yield { + request.setAttribute(Keys.Request.UserName, account.userName) + account + } + + if(filter.filter(request.gitRepositoryPath, account.map(_.userName), settings, isUpdating)){ chain.doFilter(request, response) } else { - val passed = for { - auth <- Option(request.getHeader("Authorization")) - Array(username, password) = decodeAuthHeader(auth).split(":", 2) - account <- authenticate(settings, username, password) - } yield { - request.setAttribute(Keys.Request.UserName, account.userName) - true - } - - if(passed.getOrElse(false)){ - chain.doFilter(request, response) - } else { - requireAuth(response) - } + requireAuth(response) } } diff --git a/src/main/scala/gitbucket/core/servlet/GitRepositoryServlet.scala b/src/main/scala/gitbucket/core/servlet/GitRepositoryServlet.scala index 68402bd..cd10311 100644 --- a/src/main/scala/gitbucket/core/servlet/GitRepositoryServlet.scala +++ b/src/main/scala/gitbucket/core/servlet/GitRepositoryServlet.scala @@ -62,13 +62,13 @@ private val resolver = new FileResolver[HttpServletRequest](new File(Directory.GitBucketHome), true) override def open(req: HttpServletRequest, name: String): Repository = { - // Check routing which are provided by plug-in - val routing = PluginRegistry().getRepositoryRoutings().find { - case GitRepositoryRouting(urlPattern, _, _) => name.matches(urlPattern) - } +// // Check routing which are provided by plug-in +// val routing = PluginRegistry().getRepositoryRoutings().find { +// case GitRepositoryRouting(urlPattern, _, _) => name.matches(urlPattern) +// } // Rewrite repository path if routing is marched - routing.map { case GitRepositoryRouting(urlPattern, localPath, _) => + PluginRegistry().getRepositoryRouting(name).map { case GitRepositoryRouting(urlPattern, localPath, _) => val path = urlPattern.r.replaceFirstIn(name, localPath) resolver.open(req, path) }.getOrElse { @@ -85,7 +85,7 @@ override def create(request: HttpServletRequest, db: Repository): ReceivePack = { val receivePack = new ReceivePack(db) - if(PluginRegistry().getRepositoryRouting(request.getRequestURI).isEmpty){ + if(PluginRegistry().getRepositoryRouting(request.gitRepositoryPath).isEmpty){ val pusher = request.getAttribute(Keys.Request.UserName).asInstanceOf[String] logger.debug("requestURI: " + request.getRequestURI) diff --git a/src/main/scala/gitbucket/core/ssh/GitCommand.scala b/src/main/scala/gitbucket/core/ssh/GitCommand.scala index c78ff82..2140002 100644 --- a/src/main/scala/gitbucket/core/ssh/GitCommand.scala +++ b/src/main/scala/gitbucket/core/ssh/GitCommand.scala @@ -1,12 +1,13 @@ package gitbucket.core.ssh import gitbucket.core.model.Session +import gitbucket.core.plugin.{GitRepositoryRouting, PluginRegistry} import gitbucket.core.service.{RepositoryService, AccountService, SystemSettingsService} import gitbucket.core.servlet.{Database, CommitLogHook} import gitbucket.core.util.{Directory, ControlUtil} import org.apache.sshd.server.{CommandFactory, Environment, ExitCallback, Command} import org.slf4j.LoggerFactory -import java.io.{InputStream, OutputStream} +import java.io.{File, InputStream, OutputStream} import ControlUtil._ import org.eclipse.jgit.api.Git import Directory._ @@ -15,11 +16,11 @@ import org.eclipse.jgit.errors.RepositoryNotFoundException object GitCommand { - val CommandRegex = """\Agit-(upload|receive)-pack '/([a-zA-Z0-9\-_.]+)/([a-zA-Z0-9\-_.]+).git'\Z""".r + val DefaultCommandRegex = """\Agit-(upload|receive)-pack '/([a-zA-Z0-9\-_.]+)/([a-zA-Z0-9\-_.]+).git'\Z""".r + val SimpleCommandRegex = """\Agit-(upload|receive)-pack '/(.+\.git)'\Z""".r } -abstract class GitCommand(val owner: String, val repoName: String) extends Command { - self: RepositoryService with AccountService => +abstract class GitCommand() extends Command { private val logger = LoggerFactory.getLogger(classOf[GitCommand]) protected var err: OutputStream = null @@ -71,6 +72,11 @@ this.in = in } +} + +abstract class DefaultGitCommand(val owner: String, val repoName: String) extends GitCommand { + self: RepositoryService with AccountService => + protected def isWritableUser(username: String, repositoryInfo: RepositoryService.RepositoryInfo) (implicit session: Session): Boolean = getAccountByUserName(username) match { @@ -80,7 +86,8 @@ } -class GitUploadPack(owner: String, repoName: String, baseUrl: String) extends GitCommand(owner, repoName) + +class DefaultGitUploadPack(owner: String, repoName: String, baseUrl: String) extends DefaultGitCommand(owner, repoName) with RepositoryService with AccountService { override protected def runTask(user: String)(implicit session: Session): Unit = { @@ -94,10 +101,9 @@ } } } - } -class GitReceivePack(owner: String, repoName: String, baseUrl: String) extends GitCommand(owner, repoName) +class DefaultGitReceivePack(owner: String, repoName: String, baseUrl: String) extends DefaultGitCommand(owner, repoName) with SystemSettingsService with RepositoryService with AccountService { override protected def runTask(user: String)(implicit session: Session): Unit = { @@ -116,18 +122,52 @@ } } } - } +class PluginGitUploadPack(repoName: String, baseUrl: String, routing: GitRepositoryRouting) extends GitCommand { + + override protected def runTask(user: String)(implicit session: Session): Unit = { + // TODO filter?? + val path = routing.urlPattern.r.replaceFirstIn(repoName, routing.localPath) + using(Git.open(new File(Directory.GitBucketHome, path))){ git => + val repository = git.getRepository + val upload = new UploadPack(repository) + upload.upload(in, out, err) + } + } +} + +class PluginGitReceivePack(repoName: String, baseUrl: String, routing: GitRepositoryRouting) extends GitCommand { + + override protected def runTask(user: String)(implicit session: Session): Unit = { + // TODO filter?? + val path = routing.urlPattern.r.replaceFirstIn(repoName, routing.localPath) + using(Git.open(new File(Directory.GitBucketHome, path))){ git => + val repository = git.getRepository + val receive = new ReceivePack(repository) + receive.receive(in, out, err) + } + } +} + + class GitCommandFactory(baseUrl: String) extends CommandFactory { private val logger = LoggerFactory.getLogger(classOf[GitCommandFactory]) override def createCommand(command: String): Command = { + import GitCommand._ logger.debug(s"command: $command") + command match { - case GitCommand.CommandRegex("upload", owner, repoName) => new GitUploadPack(owner, repoName, baseUrl) - case GitCommand.CommandRegex("receive", owner, repoName) => new GitReceivePack(owner, repoName, baseUrl) + case SimpleCommandRegex ("upload" , repoName) if(pluginRepository(repoName)) => new PluginGitUploadPack (repoName, baseUrl, routing(repoName)) + case SimpleCommandRegex ("receive", repoName) if(pluginRepository(repoName)) => new PluginGitReceivePack(repoName, baseUrl, routing(repoName)) + case DefaultCommandRegex("upload" , owner, repoName) => new DefaultGitUploadPack (owner, repoName, baseUrl) + case DefaultCommandRegex("receive", owner, repoName) => new DefaultGitReceivePack(owner, repoName, baseUrl) case _ => new UnknownCommand(command) } } + + private def pluginRepository(repoName: String): Boolean = PluginRegistry().getRepositoryRouting(repoName).isDefined + private def routing(repoName: String): GitRepositoryRouting = PluginRegistry().getRepositoryRouting(repoName).get + } diff --git a/src/main/scala/gitbucket/core/util/Implicits.scala b/src/main/scala/gitbucket/core/util/Implicits.scala index 13c316a..5b6f71b 100644 --- a/src/main/scala/gitbucket/core/util/Implicits.scala +++ b/src/main/scala/gitbucket/core/util/Implicits.scala @@ -72,6 +72,8 @@ def hasAttribute(name: String): Boolean = request.getAttribute(name) != null + def gitRepositoryPath: String = request.getRequestURI.replaceFirst("^/git/", "/") + } implicit class RichSession(session: HttpSession){