Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
gitbucket.core.ssh.GitCommand.scala Maven / Gradle / Ivy
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, SessionAware}
import org.apache.sshd.server.session.ServerSession
import org.slf4j.LoggerFactory
import java.io.{File, InputStream, OutputStream}
import ControlUtil._
import org.eclipse.jgit.api.Git
import Directory._
import org.eclipse.jgit.transport.{ReceivePack, UploadPack}
import org.apache.sshd.server.command.UnknownCommand
import org.eclipse.jgit.errors.RepositoryNotFoundException
object GitCommand {
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 extends Command with SessionAware {
private val logger = LoggerFactory.getLogger(classOf[GitCommand])
@volatile protected var err: OutputStream = null
@volatile protected var in: InputStream = null
@volatile protected var out: OutputStream = null
@volatile protected var callback: ExitCallback = null
@volatile private var authUser:Option[String] = None
protected def runTask(authUser: String)(implicit session: Session): Unit
private def newTask(): Runnable = new Runnable {
override def run(): Unit = {
authUser match {
case Some(authUser) =>
Database() withSession { implicit session =>
try {
runTask(authUser)
callback.onExit(0)
} catch {
case e: RepositoryNotFoundException =>
logger.info(e.getMessage)
callback.onExit(1, "Repository Not Found")
case e: Throwable =>
logger.error(e.getMessage, e)
callback.onExit(1)
}
}
case None =>
val message = "User not authenticated"
logger.error(message)
callback.onExit(1, message)
}
}
}
final override def start(env: Environment): Unit = {
val thread = new Thread(newTask())
thread.start()
}
override def destroy(): Unit = {}
override def setExitCallback(callback: ExitCallback): Unit = {
this.callback = callback
}
override def setErrorStream(err: OutputStream): Unit = {
this.err = err
}
override def setOutputStream(out: OutputStream): Unit = {
this.out = out
}
override def setInputStream(in: InputStream): Unit = {
this.in = in
}
override def setSession(serverSession:ServerSession) {
this.authUser = PublicKeyAuthenticator.getUserName(serverSession)
}
}
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 {
case Some(account) => hasWritePermission(repositoryInfo.owner, repositoryInfo.name, Some(account))
case None => false
}
}
class DefaultGitUploadPack(owner: String, repoName: String) extends DefaultGitCommand(owner, repoName)
with RepositoryService with AccountService {
override protected def runTask(user: String)(implicit session: Session): Unit = {
getRepository(owner, repoName.replaceFirst("\\.wiki\\Z", "")).foreach { repositoryInfo =>
if(!repositoryInfo.repository.isPrivate || isWritableUser(user, repositoryInfo)){
using(Git.open(getRepositoryDir(owner, repoName))) { git =>
val repository = git.getRepository
val upload = new UploadPack(repository)
upload.upload(in, out, err)
}
}
}
}
}
class DefaultGitReceivePack(owner: String, repoName: String, baseUrl: String) extends DefaultGitCommand(owner, repoName)
with RepositoryService with AccountService {
override protected def runTask(user: String)(implicit session: Session): Unit = {
getRepository(owner, repoName.replaceFirst("\\.wiki\\Z", "")).foreach { repositoryInfo =>
if(isWritableUser(user, repositoryInfo)){
using(Git.open(getRepositoryDir(owner, repoName))) { git =>
val repository = git.getRepository
val receive = new ReceivePack(repository)
if(!repoName.endsWith(".wiki")){
val hook = new CommitLogHook(owner, repoName, user, baseUrl)
receive.setPreReceiveHook(hook)
receive.setPostReceiveHook(hook)
}
receive.receive(in, out, err)
}
}
}
}
}
class PluginGitUploadPack(repoName: String, routing: GitRepositoryRouting) extends GitCommand
with SystemSettingsService {
override protected def runTask(user: String)(implicit session: Session): Unit = {
if(routing.filter.filter("/" + repoName, Some(user), loadSystemSettings(), false)){
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, routing: GitRepositoryRouting) extends GitCommand
with SystemSettingsService {
override protected def runTask(user: String)(implicit session: Session): Unit = {
if(routing.filter.filter("/" + repoName, Some(user), loadSystemSettings(), true)){
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 SimpleCommandRegex ("upload" , repoName) if(pluginRepository(repoName)) => new PluginGitUploadPack (repoName, routing(repoName))
case SimpleCommandRegex ("receive", repoName) if(pluginRepository(repoName)) => new PluginGitReceivePack(repoName, routing(repoName))
case DefaultCommandRegex("upload" , owner, repoName) => new DefaultGitUploadPack (owner, repoName)
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
}