2014-02-19 13:50:53 +04:00
package main
import (
"fmt"
"os"
"os/exec"
"strconv"
"strings"
"github.com/codegangsta/cli"
"github.com/gogits/gogs/models"
)
var (
COMMANDS_READONLY = map [ string ] int {
2014-02-25 10:01:52 +04:00
"git-upload-pack" : models . AU_WRITABLE ,
"git upload-pack" : models . AU_WRITABLE ,
"git-upload-archive" : models . AU_WRITABLE ,
2014-02-19 13:50:53 +04:00
}
COMMANDS_WRITE = map [ string ] int {
"git-receive-pack" : models . AU_READABLE ,
"git receive-pack" : models . AU_READABLE ,
}
)
var CmdServ = cli . Command {
Name : "serv" ,
2014-02-25 10:01:52 +04:00
Usage : "This command just should be called by ssh shell" ,
2014-02-19 13:50:53 +04:00
Description : `
2014-02-25 10:01:52 +04:00
gogs serv provide access auth for repositories ` ,
2014-02-19 13:50:53 +04:00
Action : runServ ,
Flags : [ ] cli . Flag {
//cli.BoolFlag{"update, u", "update pakcage(s) and dependencies if any"},
//cli.BoolFlag{"verbose, v", "show process details"},
} ,
}
func In ( b string , sl map [ string ] int ) bool {
_ , e := sl [ b ]
return e
}
func runServ ( * cli . Context ) {
keys := strings . Split ( os . Args [ 2 ] , "-" )
if len ( keys ) != 2 {
fmt . Println ( "auth file format error" )
return
}
keyId , err := strconv . ParseInt ( keys [ 1 ] , 10 , 64 )
if err != nil {
fmt . Println ( "auth file format error" )
return
}
user , err := models . GetUserByKeyId ( keyId )
if err != nil {
fmt . Println ( "You have no right to access" )
return
}
cmd := os . Getenv ( "SSH_ORIGINAL_COMMAND" )
if cmd == "" {
2014-02-25 10:01:52 +04:00
println ( "Hi %s! You've successfully authenticated, but Gogits does not provide shell access.\n" , user . Name )
2014-02-19 13:50:53 +04:00
return
}
verb , args := parseCmd ( cmd )
2014-02-25 10:01:52 +04:00
rRepo := strings . Trim ( args , "'" )
rr := strings . SplitN ( rRepo , "/" , 2 )
2014-02-19 13:50:53 +04:00
if len ( rr ) != 2 {
2014-02-20 10:53:56 +04:00
println ( "Unavilable repository" , args )
2014-02-19 13:50:53 +04:00
return
}
repoName := rr [ 1 ]
if strings . HasSuffix ( repoName , ".git" ) {
repoName = repoName [ : len ( repoName ) - 4 ]
}
isWrite := In ( verb , COMMANDS_WRITE )
isRead := In ( verb , COMMANDS_READONLY )
2014-02-20 10:53:56 +04:00
2014-02-19 13:50:53 +04:00
switch {
case isWrite :
2014-02-25 11:28:04 +04:00
has , err := models . HasAccess ( user . Name , repoName , models . AU_WRITABLE )
2014-02-19 13:50:53 +04:00
if err != nil {
2014-02-25 10:01:52 +04:00
println ( "Inernel error:" , err )
2014-02-19 13:50:53 +04:00
return
}
if ! has {
2014-02-25 11:28:04 +04:00
println ( "You have no right to write this repository" )
2014-02-19 13:50:53 +04:00
return
}
case isRead :
2014-02-25 11:28:04 +04:00
has , err := models . HasAccess ( user . Name , repoName , models . AU_READABLE )
2014-02-19 13:50:53 +04:00
if err != nil {
2014-02-25 10:01:52 +04:00
println ( "Inernel error" )
2014-02-19 13:50:53 +04:00
return
}
if ! has {
2014-02-25 11:28:04 +04:00
has , err = models . HasAccess ( user . Name , repoName , models . AU_WRITABLE )
2014-02-19 13:50:53 +04:00
if err != nil {
2014-02-25 10:01:52 +04:00
println ( "Inernel error" )
2014-02-19 13:50:53 +04:00
return
}
}
if ! has {
2014-02-20 10:53:56 +04:00
println ( "You have no right to access this repository" )
2014-02-19 13:50:53 +04:00
return
}
default :
2014-02-20 10:53:56 +04:00
println ( "Unknown command" )
2014-02-19 13:50:53 +04:00
return
}
isExist , err := models . IsRepositoryExist ( user , repoName )
if err != nil {
2014-02-20 10:53:56 +04:00
println ( "Inernel error:" , err . Error ( ) )
2014-02-19 13:50:53 +04:00
return
}
if ! isExist {
if isRead {
2014-02-20 10:53:56 +04:00
println ( "Repository" , user . Name + "/" + repoName , "is not exist" )
2014-02-19 13:50:53 +04:00
return
} else if isWrite {
_ , err := models . CreateRepository ( user , repoName )
if err != nil {
2014-02-20 10:53:56 +04:00
println ( "Create repository failed" )
2014-02-19 13:50:53 +04:00
return
}
}
}
2014-02-25 10:01:52 +04:00
gitcmd := exec . Command ( verb , rRepo )
gitcmd . Dir = models . RepoRootPath
2014-02-19 13:50:53 +04:00
gitcmd . Stdout = os . Stdout
2014-02-25 10:01:52 +04:00
gitcmd . Stdin = os . Stdin
2014-02-19 13:50:53 +04:00
gitcmd . Stderr = os . Stderr
err = gitcmd . Run ( )
if err != nil {
2014-02-25 10:01:52 +04:00
println ( "execute command error:" , err . Error ( ) )
2014-02-19 13:50:53 +04:00
}
}
func parseCmd ( cmd string ) ( string , string ) {
2014-02-20 10:53:56 +04:00
ss := strings . SplitN ( cmd , " " , 2 )
2014-02-19 13:50:53 +04:00
if len ( ss ) != 2 {
return "" , ""
}
2014-02-20 10:53:56 +04:00
2014-02-19 13:50:53 +04:00
verb , args := ss [ 0 ] , ss [ 1 ]
if verb == "git" {
2014-02-20 10:53:56 +04:00
ss = strings . SplitN ( args , " " , 2 )
2014-02-19 13:50:53 +04:00
args = ss [ 1 ]
verb = fmt . Sprintf ( "%s %s" , verb , ss [ 0 ] )
}
return verb , args
}