diff options
author | Unknwon <u@gogs.io> | 2019-10-24 01:51:46 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-10-24 01:51:46 -0700 |
commit | 01c8df01ec0608f1f25b2f1444adabb98fa5ee8a (patch) | |
tree | f8a7e5dd8d2a8c51e1ce2cabb9d33571a93314dd /cmd | |
parent | 613139e7bef81d3573e7988a47eb6765f3de347a (diff) |
internal: move packages under this directory (#5836)
* Rename pkg -> internal
* Rename routes -> route
* Move route -> internal/route
* Rename models -> db
* Move db -> internal/db
* Fix route2 -> route
* Move cmd -> internal/cmd
* Bump version
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/admin.go | 183 | ||||
-rw-r--r-- | cmd/backup.go | 137 | ||||
-rw-r--r-- | cmd/cert.go | 163 | ||||
-rw-r--r-- | cmd/cert_stub.go | 28 | ||||
-rw-r--r-- | cmd/cmd.go | 42 | ||||
-rw-r--r-- | cmd/hook.go | 277 | ||||
-rw-r--r-- | cmd/import.go | 113 | ||||
-rw-r--r-- | cmd/restore.go | 148 | ||||
-rw-r--r-- | cmd/serv.go | 272 | ||||
-rw-r--r-- | cmd/web.go | 757 |
10 files changed, 0 insertions, 2120 deletions
diff --git a/cmd/admin.go b/cmd/admin.go deleted file mode 100644 index df4dae2e..00000000 --- a/cmd/admin.go +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2016 The Gogs Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "fmt" - "reflect" - "runtime" - - "github.com/urfave/cli" - - "gogs.io/gogs/models" - "gogs.io/gogs/pkg/setting" -) - -var ( - Admin = cli.Command{ - Name: "admin", - Usage: "Perform admin operations on command line", - Description: `Allow using internal logic of Gogs without hacking into the source code -to make automatic initialization process more smoothly`, - Subcommands: []cli.Command{ - subcmdCreateUser, - subcmdDeleteInactivateUsers, - subcmdDeleteRepositoryArchives, - subcmdDeleteMissingRepositories, - subcmdGitGcRepos, - subcmdRewriteAuthorizedKeys, - subcmdSyncRepositoryHooks, - subcmdReinitMissingRepositories, - }, - } - - subcmdCreateUser = cli.Command{ - Name: "create-user", - Usage: "Create a new user in database", - Action: runCreateUser, - Flags: []cli.Flag{ - stringFlag("name", "", "Username"), - stringFlag("password", "", "User password"), - stringFlag("email", "", "User email address"), - boolFlag("admin", "User is an admin"), - stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"), - }, - } - - subcmdDeleteInactivateUsers = cli.Command{ - Name: "delete-inactive-users", - Usage: "Delete all inactive accounts", - Action: adminDashboardOperation( - models.DeleteInactivateUsers, - "All inactivate accounts have been deleted successfully", - ), - Flags: []cli.Flag{ - stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"), - }, - } - - subcmdDeleteRepositoryArchives = cli.Command{ - Name: "delete-repository-archives", - Usage: "Delete all repositories archives", - Action: adminDashboardOperation( - models.DeleteRepositoryArchives, - "All repositories archives have been deleted successfully", - ), - Flags: []cli.Flag{ - stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"), - }, - } - - subcmdDeleteMissingRepositories = cli.Command{ - Name: "delete-missing-repositories", - Usage: "Delete all repository records that lost Git files", - Action: adminDashboardOperation( - models.DeleteMissingRepositories, - "All repositories archives have been deleted successfully", - ), - Flags: []cli.Flag{ - stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"), - }, - } - - subcmdGitGcRepos = cli.Command{ - Name: "collect-garbage", - Usage: "Do garbage collection on repositories", - Action: adminDashboardOperation( - models.GitGcRepos, - "All repositories have done garbage collection successfully", - ), - Flags: []cli.Flag{ - stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"), - }, - } - - subcmdRewriteAuthorizedKeys = cli.Command{ - Name: "rewrite-authorized-keys", - Usage: "Rewrite '.ssh/authorized_keys' file (caution: non-Gogs keys will be lost)", - Action: adminDashboardOperation( - models.RewriteAuthorizedKeys, - "All public keys have been rewritten successfully", - ), - Flags: []cli.Flag{ - stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"), - }, - } - - subcmdSyncRepositoryHooks = cli.Command{ - Name: "resync-hooks", - Usage: "Resync pre-receive, update and post-receive hooks", - Action: adminDashboardOperation( - models.SyncRepositoryHooks, - "All repositories' pre-receive, update and post-receive hooks have been resynced successfully", - ), - Flags: []cli.Flag{ - stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"), - }, - } - - subcmdReinitMissingRepositories = cli.Command{ - Name: "reinit-missing-repositories", - Usage: "Reinitialize all repository records that lost Git files", - Action: adminDashboardOperation( - models.ReinitMissingRepositories, - "All repository records that lost Git files have been reinitialized successfully", - ), - Flags: []cli.Flag{ - stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"), - }, - } -) - -func runCreateUser(c *cli.Context) error { - if !c.IsSet("name") { - return fmt.Errorf("Username is not specified") - } else if !c.IsSet("password") { - return fmt.Errorf("Password is not specified") - } else if !c.IsSet("email") { - return fmt.Errorf("Email is not specified") - } - - if c.IsSet("config") { - setting.CustomConf = c.String("config") - } - - setting.NewContext() - models.LoadConfigs() - models.SetEngine() - - if err := models.CreateUser(&models.User{ - Name: c.String("name"), - Email: c.String("email"), - Passwd: c.String("password"), - IsActive: true, - IsAdmin: c.Bool("admin"), - }); err != nil { - return fmt.Errorf("CreateUser: %v", err) - } - - fmt.Printf("New user '%s' has been successfully created!\n", c.String("name")) - return nil -} - -func adminDashboardOperation(operation func() error, successMessage string) func(*cli.Context) error { - return func(c *cli.Context) error { - if c.IsSet("config") { - setting.CustomConf = c.String("config") - } - - setting.NewContext() - models.LoadConfigs() - models.SetEngine() - - if err := operation(); err != nil { - functionName := runtime.FuncForPC(reflect.ValueOf(operation).Pointer()).Name() - return fmt.Errorf("%s: %v", functionName, err) - } - - fmt.Printf("%s\n", successMessage) - return nil - } -} diff --git a/cmd/backup.go b/cmd/backup.go deleted file mode 100644 index b293d02d..00000000 --- a/cmd/backup.go +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2017 The Gogs Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "fmt" - "io/ioutil" - "os" - "path" - "time" - - "github.com/unknwon/cae/zip" - "github.com/unknwon/com" - "github.com/urfave/cli" - log "gopkg.in/clog.v1" - "gopkg.in/ini.v1" - - "gogs.io/gogs/models" - "gogs.io/gogs/pkg/setting" -) - -var Backup = cli.Command{ - Name: "backup", - Usage: "Backup files and database", - Description: `Backup dumps and compresses all related files and database into zip file, -which can be used for migrating Gogs to another server. The output format is meant to be -portable among all supported database engines.`, - Action: runBackup, - Flags: []cli.Flag{ - stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"), - boolFlag("verbose, v", "Show process details"), - stringFlag("tempdir, t", os.TempDir(), "Temporary directory path"), - stringFlag("target", "./", "Target directory path to save backup archive"), - stringFlag("archive-name", fmt.Sprintf("gogs-backup-%s.zip", time.Now().Format("20060102150405")), "Name of backup archive"), - boolFlag("database-only", "Only dump database"), - boolFlag("exclude-repos", "Exclude repositories"), - }, -} - -const _CURRENT_BACKUP_FORMAT_VERSION = 1 -const _ARCHIVE_ROOT_DIR = "gogs-backup" - -func runBackup(c *cli.Context) error { - zip.Verbose = c.Bool("verbose") - if c.IsSet("config") { - setting.CustomConf = c.String("config") - } - setting.NewContext() - models.LoadConfigs() - models.SetEngine() - - tmpDir := c.String("tempdir") - if !com.IsExist(tmpDir) { - log.Fatal(0, "'--tempdir' does not exist: %s", tmpDir) - } - rootDir, err := ioutil.TempDir(tmpDir, "gogs-backup-") - if err != nil { - log.Fatal(0, "Fail to create backup root directory '%s': %v", rootDir, err) - } - log.Info("Backup root directory: %s", rootDir) - - // Metadata - metaFile := path.Join(rootDir, "metadata.ini") - metadata := ini.Empty() - metadata.Section("").Key("VERSION").SetValue(com.ToStr(_CURRENT_BACKUP_FORMAT_VERSION)) - metadata.Section("").Key("DATE_TIME").SetValue(time.Now().String()) - metadata.Section("").Key("GOGS_VERSION").SetValue(setting.AppVer) - if err = metadata.SaveTo(metaFile); err != nil { - log.Fatal(0, "Fail to save metadata '%s': %v", metaFile, err) - } - - archiveName := path.Join(c.String("target"), c.String("archive-name")) - log.Info("Packing backup files to: %s", archiveName) - - z, err := zip.Create(archiveName) - if err != nil { - log.Fatal(0, "Fail to create backup archive '%s': %v", archiveName, err) - } - if err = z.AddFile(_ARCHIVE_ROOT_DIR+"/metadata.ini", metaFile); err != nil { - log.Fatal(0, "Fail to include 'metadata.ini': %v", err) - } - - // Database - dbDir := path.Join(rootDir, "db") - if err = models.DumpDatabase(dbDir); err != nil { - log.Fatal(0, "Fail to dump database: %v", err) - } - if err = z.AddDir(_ARCHIVE_ROOT_DIR+"/db", dbDir); err != nil { - log.Fatal(0, "Fail to include 'db': %v", err) - } - - // Custom files - if !c.Bool("database-only") { - if err = z.AddDir(_ARCHIVE_ROOT_DIR+"/custom", setting.CustomPath); err != nil { - log.Fatal(0, "Fail to include 'custom': %v", err) - } - } - - // Data files - if !c.Bool("database-only") { - for _, dir := range []string{"attachments", "avatars", "repo-avatars"} { - dirPath := path.Join(setting.AppDataPath, dir) - if !com.IsDir(dirPath) { - continue - } - - if err = z.AddDir(path.Join(_ARCHIVE_ROOT_DIR+"/data", dir), dirPath); err != nil { - log.Fatal(0, "Fail to include 'data': %v", err) - } - } - } - - // Repositories - if !c.Bool("exclude-repos") && !c.Bool("database-only") { - reposDump := path.Join(rootDir, "repositories.zip") - log.Info("Dumping repositories in '%s'", setting.RepoRootPath) - if err = zip.PackTo(setting.RepoRootPath, reposDump, true); err != nil { - log.Fatal(0, "Fail to dump repositories: %v", err) - } - log.Info("Repositories dumped to: %s", reposDump) - - if err = z.AddFile(_ARCHIVE_ROOT_DIR+"/repositories.zip", reposDump); err != nil { - log.Fatal(0, "Fail to include 'repositories.zip': %v", err) - } - } - - if err = z.Close(); err != nil { - log.Fatal(0, "Fail to save backup archive '%s': %v", archiveName, err) - } - - os.RemoveAll(rootDir) - log.Info("Backup succeed! Archive is located at: %s", archiveName) - log.Shutdown() - return nil -} diff --git a/cmd/cert.go b/cmd/cert.go deleted file mode 100644 index 7c91c2c6..00000000 --- a/cmd/cert.go +++ /dev/null @@ -1,163 +0,0 @@ -// +build cert - -// Copyright 2009 The Go Authors. All rights reserved. -// Copyright 2014 The Gogs Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "log" - "math/big" - "net" - "os" - "strings" - "time" - - "github.com/urfave/cli" -) - -var Cert = cli.Command{ - Name: "cert", - Usage: "Generate self-signed certificate", - Description: `Generate a self-signed X.509 certificate for a TLS server. -Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`, - Action: runCert, - Flags: []cli.Flag{ - stringFlag("host", "", "Comma-separated hostnames and IPs to generate a certificate for"), - stringFlag("ecdsa-curve", "", "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521"), - intFlag("rsa-bits", 2048, "Size of RSA key to generate. Ignored if --ecdsa-curve is set"), - stringFlag("start-date", "", "Creation date formatted as Jan 1 15:04:05 2011"), - durationFlag("duration", 365*24*time.Hour, "Duration that certificate is valid for"), - boolFlag("ca", "whether this cert should be its own Certificate Authority"), - }, -} - -func publicKey(priv interface{}) interface{} { - switch k := priv.(type) { - case *rsa.PrivateKey: - return &k.PublicKey - case *ecdsa.PrivateKey: - return &k.PublicKey - default: - return nil - } -} - -func pemBlockForKey(priv interface{}) *pem.Block { - switch k := priv.(type) { - case *rsa.PrivateKey: - return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)} - case *ecdsa.PrivateKey: - b, err := x509.MarshalECPrivateKey(k) - if err != nil { - log.Fatalf("Unable to marshal ECDSA private key: %v\n", err) - } - return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b} - default: - return nil - } -} - -func runCert(ctx *cli.Context) error { - if len(ctx.String("host")) == 0 { - log.Fatal("Missing required --host parameter") - } - - var priv interface{} - var err error - switch ctx.String("ecdsa-curve") { - case "": - priv, err = rsa.GenerateKey(rand.Reader, ctx.Int("rsa-bits")) - case "P224": - priv, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader) - case "P256": - priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - case "P384": - priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader) - case "P521": - priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader) - default: - log.Fatalf("Unrecognized elliptic curve: %q", ctx.String("ecdsa-curve")) - } - if err != nil { - log.Fatalf("Failed to generate private key: %s", err) - } - - var notBefore time.Time - if len(ctx.String("start-date")) == 0 { - notBefore = time.Now() - } else { - notBefore, err = time.Parse("Jan 2 15:04:05 2006", ctx.String("start-date")) - if err != nil { - log.Fatalf("Failed to parse creation date: %s", err) - } - } - - notAfter := notBefore.Add(ctx.Duration("duration")) - - serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) - serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) - if err != nil { - log.Fatalf("Failed to generate serial number: %s", err) - } - - template := x509.Certificate{ - SerialNumber: serialNumber, - Subject: pkix.Name{ - Organization: []string{"Acme Co"}, - CommonName: "Gogs", - }, - NotBefore: notBefore, - NotAfter: notAfter, - - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, - BasicConstraintsValid: true, - } - - hosts := strings.Split(ctx.String("host"), ",") - for _, h := range hosts { - if ip := net.ParseIP(h); ip != nil { - template.IPAddresses = append(template.IPAddresses, ip) - } else { - template.DNSNames = append(template.DNSNames, h) - } - } - - if ctx.Bool("ca") { - template.IsCA = true - template.KeyUsage |= x509.KeyUsageCertSign - } - - derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv) - if err != nil { - log.Fatalf("Failed to create certificate: %s", err) - } - - certOut, err := os.Create("cert.pem") - if err != nil { - log.Fatalf("Failed to open cert.pem for writing: %s", err) - } - pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) - certOut.Close() - log.Println("Written cert.pem") - - keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) - if err != nil { - log.Fatalf("Failed to open key.pem for writing: %v\n", err) - } - pem.Encode(keyOut, pemBlockForKey(priv)) - keyOut.Close() - log.Println("Written key.pem") - - return nil -} diff --git a/cmd/cert_stub.go b/cmd/cert_stub.go deleted file mode 100644 index 6164c83e..00000000 --- a/cmd/cert_stub.go +++ /dev/null @@ -1,28 +0,0 @@ -// +build !cert - -// Copyright 2009 The Go Authors. All rights reserved. -// Copyright 2014 The Gogs Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. -package cmd - -import ( - "fmt" - "os" - - "github.com/urfave/cli" -) - -var Cert = cli.Command{ - Name: "cert", - Usage: "Generate self-signed certificate", - Description: `Please use build tags "cert" to rebuild Gogs in order to have this ability`, - Action: runCert, -} - -func runCert(ctx *cli.Context) error { - fmt.Println("Command cert not available, please use build tags 'cert' to rebuild.") - os.Exit(1) - - return nil -} diff --git a/cmd/cmd.go b/cmd/cmd.go deleted file mode 100644 index 29afa625..00000000 --- a/cmd/cmd.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2015 The Gogs Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "time" - - "github.com/urfave/cli" -) - -func stringFlag(name, value, usage string) cli.StringFlag { - return cli.StringFlag{ - Name: name, - Value: value, - Usage: usage, - } -} - -func boolFlag(name, usage string) cli.BoolFlag { - return cli.BoolFlag{ - Name: name, - Usage: usage, - } -} - -func intFlag(name string, value int, usage string) cli.IntFlag { - return cli.IntFlag{ - Name: name, - Value: value, - Usage: usage, - } -} - -func durationFlag(name string, value time.Duration, usage string) cli.DurationFlag { - return cli.DurationFlag{ - Name: name, - Value: value, - Usage: usage, - } -} diff --git a/cmd/hook.go b/cmd/hook.go deleted file mode 100644 index b0657004..00000000 --- a/cmd/hook.go +++ /dev/null @@ -1,277 +0,0 @@ -// Copyright 2014 The Gogs Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "bufio" - "bytes" - "crypto/tls" - "fmt" - "os" - "os/exec" - "path" - "path/filepath" - "strings" - - "github.com/unknwon/com" - "github.com/urfave/cli" - log "gopkg.in/clog.v1" - - "github.com/gogs/git-module" - - "gogs.io/gogs/models" - "gogs.io/gogs/models/errors" - "gogs.io/gogs/pkg/httplib" - "gogs.io/gogs/pkg/mailer" - "gogs.io/gogs/pkg/setting" - "gogs.io/gogs/pkg/template" -) - -var ( - Hook = cli.Command{ - Name: "hook", - Usage: "Delegate commands to corresponding Git hooks", - Description: "All sub-commands should only be called by Git", - Flags: []cli.Flag{ - stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"), - }, - Subcommands: []cli.Command{ - subcmdHookPreReceive, - subcmdHookUpadte, - subcmdHookPostReceive, - }, - } - - subcmdHookPreReceive = cli.Command{ - Name: "pre-receive", - Usage: "Delegate pre-receive Git hook", - Description: "This command should only be called by Git", - Action: runHookPreReceive, - } - subcmdHookUpadte = cli.Command{ - Name: "update", - Usage: "Delegate update Git hook", - Description: "This command should only be called by Git", - Action: runHookUpdate, - } - subcmdHookPostReceive = cli.Command{ - Name: "post-receive", - Usage: "Delegate post-receive Git hook", - Description: "This command should only be called by Git", - Action: runHookPostReceive, - } -) - -func runHookPreReceive(c *cli.Context) error { - if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 { - return nil - } - setup(c, "hooks/pre-receive.log", true) - - isWiki := strings.Contains(os.Getenv(models.ENV_REPO_CUSTOM_HOOKS_PATH), ".wiki.git/") - - buf := bytes.NewBuffer(nil) - scanner := bufio.NewScanner(os.Stdin) - for scanner.Scan() { - buf.Write(scanner.Bytes()) - buf.WriteByte('\n') - - if isWiki { - continue - } - - fields := bytes.Fields(scanner.Bytes()) - if len(fields) != 3 { - continue - } - oldCommitID := string(fields[0]) - newCommitID := string(fields[1]) - branchName := strings.TrimPrefix(string(fields[2]), git.BRANCH_PREFIX) - - // Branch protection - repoID := com.StrTo(os.Getenv(models.ENV_REPO_ID)).MustInt64() - protectBranch, err := models.GetProtectBranchOfRepoByName(repoID, branchName) - if err != nil { - if errors.IsErrBranchNotExist(err) { - continue - } - fail("Internal error", "GetProtectBranchOfRepoByName [repo_id: %d, branch: %s]: %v", repoID, branchName, err) - } - if !protectBranch.Protected { - continue - } - - // Whitelist users can bypass require pull request check - bypassRequirePullRequest := false - - // Check if user is in whitelist when enabled - userID := com.StrTo(os.Getenv(models.ENV_AUTH_USER_ID)).MustInt64() - if protectBranch.EnableWhitelist { - if !models.IsUserInProtectBranchWhitelist(repoID, userID, branchName) { - fail(fmt.Sprintf("Branch '%s' is protected and you are not in the push whitelist", branchName), "") - } - - bypassRequirePullRequest = true - } - - // Check if branch allows direct push - if !bypassRequirePullRequest && protectBranch.RequirePullRequest { - fail(fmt.Sprintf("Branch '%s' is protected and commits must be merged through pull request", branchName), "") - } - - // check and deletion - if newCommitID == git.EMPTY_SHA { - fail(fmt.Sprintf("Branch '%s' is protected from deletion", branchName), "") - } - - // Check force push - output, err := git.NewCommand("rev-list", "--max-count=1", oldCommitID, "^"+newCommitID). - RunInDir(models.RepoPath(os.Getenv(models.ENV_REPO_OWNER_NAME), os.Getenv(models.ENV_REPO_NAME))) - if err != nil { - fail("Internal error", "Fail to detect force push: %v", err) - } else if len(output) > 0 { - fail(fmt.Sprintf("Branch '%s' is protected from force push", branchName), "") - } - } - - customHooksPath := filepath.Join(os.Getenv(models.ENV_REPO_CUSTOM_HOOKS_PATH), "pre-receive") - if !com.IsFile(customHooksPath) { - return nil - } - - var hookCmd *exec.Cmd - if setting.IsWindows { - hookCmd = exec.Command("bash.exe", "custom_hooks/pre-receive") - } else { - hookCmd = exec.Command(customHooksPath) - } - hookCmd.Dir = models.RepoPath(os.Getenv(models.ENV_REPO_OWNER_NAME), os.Getenv(models.ENV_REPO_NAME)) - hookCmd.Stdout = os.Stdout - hookCmd.Stdin = buf - hookCmd.Stderr = os.Stderr - if err := hookCmd.Run(); err != nil { - fail("Internal error", "Fail to execute custom pre-receive hook: %v", err) - } - return nil -} - -func runHookUpdate(c *cli.Context) error { - if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 { - return nil - } - setup(c, "hooks/update.log", false) - - args := c.Args() - if len(args) != 3 { - fail("Arguments received are not equal to three", "Arguments received are not equal to three") - } else if len(args[0]) == 0 { - fail("First argument 'refName' is empty", "First argument 'refName' is empty") - } - - customHooksPath := filepath.Join(os.Getenv(models.ENV_REPO_CUSTOM_HOOKS_PATH), "update") - if !com.IsFile(customHooksPath) { - return nil - } - - var hookCmd *exec.Cmd - if setting.IsWindows { - hookCmd = exec.Command("bash.exe", append([]string{"custom_hooks/update"}, args...)...) - } else { - hookCmd = exec.Command(customHooksPath, args...) - } - hookCmd.Dir = models.RepoPath(os.Getenv(models.ENV_REPO_OWNER_NAME), os.Getenv(models.ENV_REPO_NAME)) - hookCmd.Stdout = os.Stdout - hookCmd.Stdin = os.Stdin - hookCmd.Stderr = os.Stderr - if err := hookCmd.Run(); err != nil { - fail("Internal error", "Fail to execute custom pre-receive hook: %v", err) - } - return nil -} - -func runHookPostReceive(c *cli.Context) error { - if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 { - return nil - } - setup(c, "hooks/post-receive.log", true) - - // Post-receive hook does more than just gather Git information, - // so we need to setup additional services for email notifications. - setting.NewPostReceiveHookServices() - mailer.NewContext() - mailer.InitMailRender(path.Join(setting.StaticRootPath, "templates/mail"), - path.Join(setting.CustomPath, "templates/mail"), template.NewFuncMap()) - - isWiki := strings.Contains(os.Getenv(models.ENV_REPO_CUSTOM_HOOKS_PATH), ".wiki.git/") - - buf := bytes.NewBuffer(nil) - scanner := bufio.NewScanner(os.Stdin) - for scanner.Scan() { - buf.Write(scanner.Bytes()) - buf.WriteByte('\n') - - // TODO: support news feeds for wiki - if isWiki { - continue - } - - fields := bytes.Fields(scanner.Bytes()) - if len(fields) != 3 { - continue - } - - options := models.PushUpdateOptions{ - OldCommitID: string(fields[0]), - NewCommitID: string(fields[1]), - RefFullName: string(fields[2]), - PusherID: com.StrTo(os.Getenv(models.ENV_AUTH_USER_ID)).MustInt64(), - PusherName: os.Getenv(models.ENV_AUTH_USER_NAME), - RepoUserName: os.Getenv(models.ENV_REPO_OWNER_NAME), - RepoName: os.Getenv(models.ENV_REPO_NAME), - } - if err := models.PushUpdate(options); err != nil { - log.Error(2, "PushUpdate: %v", err) - } - - // Ask for running deliver hook and test pull request tasks - reqURL := setting.LocalURL + options.RepoUserName + "/" + options.RepoName + "/tasks/trigger?branch=" + - template.EscapePound(strings.TrimPrefix(options.RefFullName, git.BRANCH_PREFIX)) + - "&secret=" + os.Getenv(models.ENV_REPO_OWNER_SALT_MD5) + - "&pusher=" + os.Getenv(models.ENV_AUTH_USER_ID) - log.Trace("Trigger task: %s", reqURL) - - resp, err := httplib.Head(reqURL).SetTLSClientConfig(&tls.Config{ - InsecureSkipVerify: true, - }).Response() - if err == nil { - resp.Body.Close() - if resp.StatusCode/100 != 2 { - log.Error(2, "Fail to trigger task: not 2xx response code") - } - } else { - log.Error(2, "Fail to trigger task: %v", err) - } - } - - customHooksPath := filepath.Join(os.Getenv(models.ENV_REPO_CUSTOM_HOOKS_PATH), "post-receive") - if !com.IsFile(customHooksPath) { - return nil - } - - var hookCmd *exec.Cmd - if setting.IsWindows { - hookCmd = exec.Command("bash.exe", "custom_hooks/post-receive") - } else { - hookCmd = exec.Command(customHooksPath) - } - hookCmd.Dir = models.RepoPath(os.Getenv(models.ENV_REPO_OWNER_NAME), os.Getenv(models.ENV_REPO_NAME)) - hookCmd.Stdout = os.Stdout - hookCmd.Stdin = buf - hookCmd.Stderr = os.Stderr - if err := hookCmd.Run(); err != nil { - fail("Internal error", "Fail to execute custom post-receive hook: %v", err) - } - return nil -} diff --git a/cmd/import.go b/cmd/import.go deleted file mode 100644 index 804963f0..00000000 --- a/cmd/import.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2016 The Gogs Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "bufio" - "bytes" - "fmt" - "os" - "path/filepath" - "time" - - "github.com/unknwon/com" - "github.com/urfave/cli" - - "gogs.io/gogs/pkg/setting" -) - -var ( - Import = cli.Command{ - Name: "import", - Usage: "Import portable data as local Gogs data", - Description: `Allow user import data from other Gogs installations to local instance -without manually hacking the data files`, - Subcommands: []cli.Command{ - subcmdImportLocale, - }, - } - - subcmdImportLocale = cli.Command{ - Name: "locale", - Usage: "Import locale files to local repository", - Action: runImportLocale, - Flags: []cli.Flag{ - stringFlag("source", "", "Source directory that stores new locale files"), - stringFlag("target", "", "Target directory that stores old locale files"), - stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"), - }, - } -) - -func runImportLocale(c *cli.Context) error { - if !c.IsSet("source") { - return fmt.Errorf("Source directory is not specified") - } else if !c.IsSet("target") { - return fmt.Errorf("Target directory is not specified") - } - if !com.IsDir(c.String("source")) { - return fmt.Errorf("Source directory does not exist or is not a directory") - } else if !com.IsDir(c.String("target")) { - return fmt.Errorf("Target directory does not exist or is not a directory") - } - - if c.IsSet("config") { - setting.CustomConf = c.String("config") - } - - setting.NewContext() - - now := time.Now() - - line := make([]byte, 0, 100) - badChars := []byte(`="`) - escapedQuotes := []byte(`\"`) - regularQuotes := []byte(`"`) - // Cut out en-US. - for _, lang := range setting.Langs[1:] { - name := fmt.Sprintf("locale_%s.ini", lang) - source := filepath.Join(c.String("source"), name) - target := filepath.Join(c.String("target"), name) - if !com.IsFile(source) { - continue - } - - // Crowdin surrounds double quotes for strings contain quotes inside, - // this breaks INI parser, we need to fix that. - sr, err := os.Open(source) - if err != nil { - return fmt.Errorf("Open: %v", err) - } - - tw, err := os.Create(target) - if err != nil { - if err != nil { - return fmt.Errorf("Open: %v", err) - } - } - - scanner := bufio.NewScanner(sr) - for scanner.Scan() { - line = scanner.Bytes() - idx := bytes.Index(line, badChars) - if idx > -1 && line[len(line)-1] == '"' { - // We still want the "=" sign - line = append(line[:idx+1], line[idx+2:len(line)-1]...) - line = bytes.Replace(line, escapedQuotes, regularQuotes, -1) - } - tw.Write(line) - tw.WriteString("\n") - } - sr.Close() - tw.Close() - - // Modification time of files from Crowdin often ahead of current, - // so we need to set back to current. - os.Chtimes(target, now, now) - } - - fmt.Println("Locale files has been successfully imported!") - return nil -} diff --git a/cmd/restore.go b/cmd/restore.go deleted file mode 100644 index 7ebb8407..00000000 --- a/cmd/restore.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2017 The Gogs Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "os" - "path" - - "github.com/unknwon/cae/zip" - "github.com/unknwon/com" - "github.com/mcuadros/go-version" - "github.com/urfave/cli" - log "gopkg.in/clog.v1" - "gopkg.in/ini.v1" - - "gogs.io/gogs/models" - "gogs.io/gogs/pkg/setting" -) - -var Restore = cli.Command{ - Name: "restore", - Usage: "Restore files and database from backup", - Description: `Restore imports all related files and database from a backup archive. -The backup version must lower or equal to current Gogs version. You can also import -backup from other database engines, which is useful for database migrating. - -If corresponding files or database tables are not presented in the archive, they will -be skipped and remain unchanged.`, - Action: runRestore, - Flags: []cli.Flag{ - stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"), - boolFlag("verbose, v", "Show process details"), - stringFlag("tempdir, t", os.TempDir(), "Temporary directory path"), - stringFlag("from", "", "Path to backup archive"), - boolFlag("database-only", "Only import database"), - boolFlag("exclude-repos", "Exclude repositories"), - }, -} - -// lastSupportedVersionOfFormat returns the last supported version of the backup archive -// format that is able to import. -var lastSupportedVersionOfFormat = map[int]string{} - -func runRestore(c *cli.Context) error { - zip.Verbose = c.Bool("verbose") - - tmpDir := c.String("tempdir") - if !com.IsExist(tmpDir) { - log.Fatal(0, "'--tempdir' does not exist: %s", tmpDir) - } - - log.Info("Restore backup from: %s", c.String("from")) - if err := zip.ExtractTo(c.String("from"), tmpDir); err != nil { - log.Fatal(0, "Failed to extract backup archive: %v", err) - } - archivePath := path.Join(tmpDir, _ARCHIVE_ROOT_DIR) - defer os.RemoveAll(archivePath) - - // Check backup version - metaFile := path.Join(archivePath, "metadata.ini") - if !com.IsExist(metaFile) { - log.Fatal(0, "File 'metadata.ini' is missing") - } - metadata, err := ini.Load(metaFile) - if err != nil { - log.Fatal(0, "Failed to load metadata '%s': %v", metaFile, err) - } - backupVersion := metadata.Section("").Key("GOGS_VERSION").MustString("999.0") - if version.Compare(setting.AppVer, backupVersion, "<") { - log.Fatal(0, "Current Gogs version is lower than backup version: %s < %s", setting.AppVer, backupVersion) - } - formatVersion := metadata.Section("").Key("VERSION").MustInt() - if formatVersion == 0 { - log.Fatal(0, "Failed to determine the backup format version from metadata '%s': %s", metaFile, "VERSION is not presented") - } - if formatVersion != _CURRENT_BACKUP_FORMAT_VERSION { - log.Fatal(0, "Backup format version found is %d but this binary only supports %d\nThe last known version that is able to import your backup is %s", - formatVersion, _CURRENT_BACKUP_FORMAT_VERSION, lastSupportedVersionOfFormat[formatVersion]) - } - - // If config file is not present in backup, user must set this file via flag. - // Otherwise, it's optional to set config file flag. - configFile := path.Join(archivePath, "custom/conf/app.ini") - if c.IsSet("config") { - setting.CustomConf = c.String("config") - } else if !com.IsExist(configFile) { - log.Fatal(0, "'--config' is not specified and custom config file is not found in backup") - } else { - setting.CustomConf = configFile - } - setting.NewContext() - models.LoadConfigs() - models.SetEngine() - - // Database - dbDir := path.Join(archivePath, "db") - if err = models.ImportDatabase(dbDir, c.Bool("verbose")); err != nil { - log.Fatal(0, "Failed to import database: %v", err) - } - - // Custom files - if !c.Bool("database-only") { - if com.IsExist(setting.CustomPath) { - if err = os.Rename(setting.CustomPath, setting.CustomPath+".bak"); err != nil { - log.Fatal(0, "Failed to backup current 'custom': %v", err) - } - } - if err = os.Rename(path.Join(archivePath, "custom"), setting.CustomPath); err != nil { - log.Fatal(0, "Failed to import 'custom': %v", err) - } - } - - // Data files - if !c.Bool("database-only") { - os.MkdirAll(setting.AppDataPath, os.ModePerm) - for _, dir := range []string{"attachments", "avatars", "repo-avatars"} { - // Skip if backup archive does not have corresponding data - srcPath := path.Join(archivePath, "data", dir) - if !com.IsDir(srcPath) { - continue - } - - dirPath := path.Join(setting.AppDataPath, dir) - if com.IsExist(dirPath) { - if err = os.Rename(dirPath, dirPath+".bak"); err != nil { - log.Fatal(0, "Failed to backup current 'data': %v", err) - } - } - if err = os.Rename(srcPath, dirPath); err != nil { - log.Fatal(0, "Failed to import 'data': %v", err) - } - } - } - - // Repositories - reposPath := path.Join(archivePath, "repositories.zip") - if !c.Bool("exclude-repos") && !c.Bool("database-only") && com.IsExist(reposPath) { - if err := zip.ExtractTo(reposPath, path.Dir(setting.RepoRootPath)); err != nil { - log.Fatal(0, "Failed to extract 'repositories.zip': %v", err) - } - } - - log.Info("Restore succeed!") - log.Shutdown() - return nil -} diff --git a/cmd/serv.go b/cmd/serv.go deleted file mode 100644 index c767634e..00000000 --- a/cmd/serv.go +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright 2014 The Gogs Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" - "time" - - "github.com/unknwon/com" - "github.com/urfave/cli" - log "gopkg.in/clog.v1" - - "gogs.io/gogs/models" - "gogs.io/gogs/models/errors" - "gogs.io/gogs/pkg/setting" -) - -const ( - _ACCESS_DENIED_MESSAGE = "Repository does not exist or you do not have access" -) - -var Serv = cli.Command{ - Name: "serv", - Usage: "This command should only be called by SSH shell", - Description: `Serv provide access auth for repositories`, - Action: runServ, - Flags: []cli.Flag{ - stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"), - }, -} - -func fail(userMessage, logMessage string, args ...interface{}) { - fmt.Fprintln(os.Stderr, "Gogs:", userMessage) - - if len(logMessage) > 0 { - if !setting.ProdMode { - fmt.Fprintf(os.Stderr, logMessage+"\n", args...) - } - log.Fatal(3, logMessage, args...) - } - - os.Exit(1) -} - -func setup(c *cli.Context, logPath string, connectDB bool) { - if c.IsSet("config") { - setting.CustomConf = c.String("config") - } else if c.GlobalIsSet("config") { - setting.CustomConf = c.GlobalString("config") - } - - setting.NewContext() - - level := log.TRACE - if setting.ProdMode { - level = log.ERROR - } - log.New(log.FILE, log.FileConfig{ - Level: level, - Filename: filepath.Join(setting.LogRootPath, logPath), - FileRotationConfig: log.FileRotationConfig{ - Rotate: true, - Daily: true, - MaxDays: 3, - }, - }) - log.Delete(log.CONSOLE) // Remove primary logger - - if !connectDB { - return - } - - models.LoadConfigs() - - if setting.UseSQLite3 { - workDir, _ := setting.WorkDir() - os.Chdir(workDir) - } - - if err := models.SetEngine(); err != nil { - fail("Internal error", "SetEngine: %v", err) - } -} - -func parseSSHCmd(cmd string) (string, string) { - ss := strings.SplitN(cmd, " ", 2) - if len(ss) != 2 { - return "", "" - } - return ss[0], strings.Replace(ss[1], "'/", "'", 1) -} - -func checkDeployKey(key *models.PublicKey, repo *models.Repository) { - // Check if this deploy key belongs to current repository. - if !models.HasDeployKey(key.ID, repo.ID) { - fail("Key access denied", "Deploy key access denied: [key_id: %d, repo_id: %d]", key.ID, repo.ID) - } - - // Update deploy key activity. - deployKey, err := models.GetDeployKeyByRepo(key.ID, repo.ID) - if err != nil { - fail("Internal error", "GetDeployKey: %v", err) - } - - deployKey.Updated = time.Now() - if err = models.UpdateDeployKey(deployKey); err != nil { - fail("Internal error", "UpdateDeployKey: %v", err) - } -} - -var ( - allowedCommands = map[string]models.AccessMode{ - "git-upload-pack": models.ACCESS_MODE_READ, - "git-upload-archive": models.ACCESS_MODE_READ, - "git-receive-pack": models.ACCESS_MODE_WRITE, - } -) - -func runServ(c *cli.Context) error { - setup(c, "serv.log", true) - - if setting.SSH.Disabled { - println("Gogs: SSH has been disabled") - return nil - } - - if len(c.Args()) < 1 { - fail("Not enough arguments", "Not enough arguments") - } - - sshCmd := os.Getenv("SSH_ORIGINAL_COMMAND") - if len(sshCmd) == 0 { - println("Hi there, You've successfully authenticated, but Gogs does not provide shell access.") - println("If this is unexpected, please log in with password and setup Gogs under another user.") - return nil - } - - verb, args := parseSSHCmd(sshCmd) - repoFullName := strings.ToLower(strings.Trim(args, "'")) - repoFields := strings.SplitN(repoFullName, "/", 2) - if len(repoFields) != 2 { - fail("Invalid repository path", "Invalid repository path: %v", args) - } - ownerName := strings.ToLower(repoFields[0]) - repoName := strings.TrimSuffix(strings.ToLower(repoFields[1]), ".git") - repoName = strings.TrimSuffix(repoName, ".wiki") - - owner, err := models.GetUserByName(ownerName) - if err != nil { - if errors.IsUserNotExist(err) { - fail("Repository owner does not exist", "Unregistered owner: %s", ownerName) - } - fail("Internal error", "Fail to get repository owner '%s': %v", ownerName, err) - } - - repo, err := models.GetRepositoryByName(owner.ID, repoName) - if err != nil { - if errors.IsRepoNotExist(err) { - fail(_ACCESS_DENIED_MESSAGE, "Repository does not exist: %s/%s", owner.Name, repoName) - } - fail("Internal error", "Fail to get repository: %v", err) - } - repo.Owner = owner - - requestMode, ok := allowedCommands[verb] - if !ok { - fail("Unknown git command", "Unknown git command '%s'", verb) - } - - // Prohibit push to mirror repositories. - if requestMode > models.ACCESS_MODE_READ && repo.IsMirror { - fail("Mirror repository is read-only", "") - } - - // Allow anonymous (user is nil) clone for public repositories. - var user *models.User - - key, err := models.GetPublicKeyByID(com.StrTo(strings.TrimPrefix(c.Args()[0], "key-")).MustInt64()) - if err != nil { - fail("Invalid key ID", "Invalid key ID '%s': %v", c.Args()[0], err) - } - - if requestMode == models.ACCESS_MODE_WRITE || repo.IsPrivate { - // Check deploy key or user key. - if key.IsDeployKey() { - if key.Mode < requestMode { - fail("Key permission denied", "Cannot push with deployment key: %d", key.ID) - } - checkDeployKey(key, repo) - } else { - user, err = models.GetUserByKeyID(key.ID) - if err != nil { - fail("Internal error", "Fail to get user by key ID '%d': %v", key.ID, err) - } - - mode, err := models.UserAccessMode(user.ID, repo) - if err != nil { - fail("Internal error", "Fail to check access: %v", err) - } - - if mode < requestMode { - clientMessage := _ACCESS_DENIED_MESSAGE - if mode >= models.ACCESS_MODE_READ { - clientMessage = "You do not have sufficient authorization for this action" - } - fail(clientMessage, - "User '%s' does not have level '%v' access to repository '%s'", - user.Name, requestMode, repoFullName) - } - } - } else { - setting.NewService() - // Check if the key can access to the repository in case of it is a deploy key (a deploy keys != user key). - // A deploy key doesn't represent a signed in user, so in a site with Service.RequireSignInView activated - // we should give read access only in repositories where this deploy key is in use. In other case, a server - // or system using an active deploy key can get read access to all the repositories in a Gogs service. - if key.IsDeployKey() && setting.Service.RequireSignInView { - checkDeployKey(key, repo) - } - } - - // Update user key activity. - if key.ID > 0 { - key, err := models.GetPublicKeyByID(key.ID) - if err != nil { - fail("Internal error", "GetPublicKeyByID: %v", err) - } - - key.Updated = time.Now() - if err = models.UpdatePublicKey(key); err != nil { - fail("Internal error", "UpdatePublicKey: %v", err) - } - } - - // Special handle for Windows. - if setting.IsWindows { - verb = strings.Replace(verb, "-", " ", 1) - } - - var gitCmd *exec.Cmd - verbs := strings.Split(verb, " ") - if len(verbs) == 2 { - gitCmd = exec.Command(verbs[0], verbs[1], repoFullName) - } else { - gitCmd = exec.Command(verb, repoFullName) - } - if requestMode == models.ACCESS_MODE_WRITE { - gitCmd.Env = append(os.Environ(), models.ComposeHookEnvs(models.ComposeHookEnvsOptions{ - AuthUser: user, - OwnerName: owner.Name, - OwnerSalt: owner.Salt, - RepoID: repo.ID, - RepoName: repo.Name, - RepoPath: repo.RepoPath(), - })...) - } - gitCmd.Dir = setting.RepoRootPath - gitCmd.Stdout = os.Stdout - gitCmd.Stdin = os.Stdin - gitCmd.Stderr = os.Stderr - if err = gitCmd.Run(); err != nil { - fail("Internal error", "Fail to execute git command: %v", err) - } - - return nil -} diff --git a/cmd/web.go b/cmd/web.go deleted file mode 100644 index 66a24aee..00000000 --- a/cmd/web.go +++ /dev/null @@ -1,757 +0,0 @@ -// Copyright 2014 The Gogs Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "crypto/tls" - "fmt" - "io/ioutil" - "net" - "net/http" - "net/http/fcgi" - "os" - "path" - "strings" - - "github.com/unknwon/com" - "github.com/go-macaron/binding" - "github.com/go-macaron/cache" - "github.com/go-macaron/captcha" - "github.com/go-macaron/csrf" - "github.com/go-macaron/gzip" - "github.com/go-macaron/i18n" - "github.com/go-macaron/session" - "github.com/go-macaron/toolbox" - "github.com/mcuadros/go-version" - "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/urfave/cli" - log "gopkg.in/clog.v1" - "gopkg.in/macaron.v1" - - "gogs.io/gogs/models" - "gogs.io/gogs/pkg/bindata" - "gogs.io/gogs/pkg/context" - "gogs.io/gogs/pkg/form" - "gogs.io/gogs/pkg/mailer" - "gogs.io/gogs/pkg/setting" - "gogs.io/gogs/pkg/template" - "gogs.io/gogs/routes" - "gogs.io/gogs/routes/admin" - apiv1 "gogs.io/gogs/routes/api/v1" - "gogs.io/gogs/routes/dev" - "gogs.io/gogs/routes/org" - "gogs.io/gogs/routes/repo" - "gogs.io/gogs/routes/user" -) - -var Web = cli.Command{ - Name: "web", - Usage: "Start web server", - Description: `Gogs web server is the only thing you need to run, -and it takes care of all the other things for you`, - Action: runWeb, - Flags: []cli.Flag{ - stringFlag("port, p", "3000", "Temporary port number to prevent conflict"), - stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"), - }, -} - -// checkVersion checks if binary matches the version of templates files. -func checkVersion() { - // Templates. - data, err := ioutil.ReadFile(setting.StaticRootPath + "/templates/.VERSION") - if err != nil { - log.Fatal(2, "Fail to read 'templates/.VERSION': %v", err) - } - tplVer := strings.TrimSpace(string(data)) - if tplVer != setting.AppVer { - if version.Compare(tplVer, setting.AppVer, ">") { - log.Fatal(2, "Binary version is lower than template file version, did you forget to recompile Gogs?") - } else { - log.Fatal(2, "Binary version is higher than template file version, did you forget to update template files?") - } - } -} - -// newMacaron initializes Macaron instance. -func newMacaron() *macaron.Macaron { - m := macaron.New() - if !setting.DisableRouterLog { - m.Use(macaron.Logger()) - } - m.Use(macaron.Recovery()) - if setting.EnableGzip { - m.Use(gzip.Gziper()) - } - if setting.Protocol == setting.SCHEME_FCGI { - m.SetURLPrefix(setting.AppSubURL) - } - m.Use(macaron.Static( - path.Join(setting.StaticRootPath, "public"), - macaron.StaticOptions{ - SkipLogging: setting.DisableRouterLog, - }, - )) - m.Use(macaron.Static( - setting.AvatarUploadPath, - macaron.StaticOptions{ - Prefix: models.USER_AVATAR_URL_PREFIX, - SkipLogging: setting.DisableRouterLog, - }, - )) - m.Use(macaron.Static( - setting.RepositoryAvatarUploadPath, - macaron.StaticOptions{ - Prefix: models.REPO_AVATAR_URL_PREFIX, - SkipLogging: setting.DisableRouterLog, - }, - )) - - funcMap := template.NewFuncMap() - m.Use(macaron.Renderer(macaron.RenderOptions{ - Directory: path.Join(setting.StaticRootPath, "templates"), - AppendDirectories: []string{path.Join(setting.CustomPath, "templates")}, - Funcs: funcMap, - IndentJSON: macaron.Env != macaron.PROD, - })) - mailer.InitMailRender(path.Join(setting.StaticRootPath, "templates/mail"), - path.Join(setting.CustomPath, "templates/mail"), funcMap) - - localeNames, err := bindata.AssetDir("conf/locale") - if err != nil { - log.Fatal(4, "Fail to list locale files: %v", err) - } - localFiles := make(map[string][]byte) - for _, name := range localeNames { - localFiles[name] = bindata.MustAsset("conf/locale/" + name) - } - m.Use(i18n.I18n(i18n.Options{ - SubURL: setting.AppSubURL, - Files: localFiles, - CustomDirectory: path.Join(setting.CustomPath, "conf/locale"), - Langs: setting.Langs, - Names: setting.Names, - DefaultLang: "en-US", - Redirect: true, - })) - m.Use(cache.Cacher(cache.Options{ - Adapter: setting.CacheAdapter, - AdapterConfig: setting.CacheConn, - Interval: setting.CacheInterval, - })) - m.Use(captcha.Captchaer(captcha.Options{ - SubURL: setting.AppSubURL, - })) - m.Use(session.Sessioner(setting.SessionConfig)) - m.Use(csrf.Csrfer(csrf.Options{ - Secret: setting.SecretKey, - Cookie: setting.CSRFCookieName, - SetCookie: true, - Header: "X-Csrf-Token", - CookiePath: setting.AppSubURL, - })) - m.Use(toolbox.Toolboxer(m, toolbox.Options{ - HealthCheckFuncs: []*toolbox.HealthCheckFuncDesc{ - &toolbox.HealthCheckFuncDesc{ - Desc: "Database connection", - Func: models.Ping, - }, - }, - })) - m.Use(context.Contexter()) - return m -} - -func runWeb(c *cli.Context) error { - if c.IsSet("config") { - setting.CustomConf = c.String("config") - } - routes.GlobalInit() - checkVersion() - - m := newMacaron() - - reqSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: true}) - ignSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: setting.Service.RequireSignInView}) - ignSignInAndCsrf := context.Toggle(&context.ToggleOptions{DisableCSRF: true}) - reqSignOut := context.Toggle(&context.ToggleOptions{SignOutRequired: true}) - - bindIgnErr := binding.BindIgnErr - - m.SetAutoHead(true) - - // FIXME: not all routes need go through same middlewares. - // Especially some AJAX requests, we can reduce middleware number to improve performance. - // Routers. - m.Get("/", ignSignIn, routes.Home) - m.Group("/explore", func() { - m.Get("", func(c *context.Context) { - c.Redirect(setting.AppSubURL + "/explore/repos") - }) - m.Get("/repos", routes.ExploreRepos) - m.Get("/users", routes.ExploreUsers) - m.Get("/organizations", routes.ExploreOrganizations) - }, ignSignIn) - m.Combo("/install", routes.InstallInit).Get(routes.Install). - Post(bindIgnErr(form.Install{}), routes.InstallPost) - m.Get("/^:type(issues|pulls)$", reqSignIn, user.Issues) - - // ***** START: User ***** - m.Group("/user", func() { - m.Group("/login", func() { - m.Combo("").Get(user.Login). - Post(bindIgnErr(form.SignIn{}), user.LoginPost) - m.Combo("/two_factor").Get(user.LoginTwoFactor).Post(user.LoginTwoFactorPost) - m.Combo("/two_factor_recovery_code").Get(user.LoginTwoFactorRecoveryCode).Post(user.LoginTwoFactorRecoveryCodePost) - }) - - m.Get("/sign_up", user.SignUp) - m.Post("/sign_up", bindIgnErr(form.Register{}), user.SignUpPost) - m.Get("/reset_password", user.ResetPasswd) - m.Post("/reset_password", user.ResetPasswdPost) - }, reqSignOut) - - m.Group("/user/settings", func() { - m.Get("", user.Settings) - m.Post("", bindIgnErr(form.UpdateProfile{}), user.SettingsPost) - m.Combo("/avatar").Get(user.SettingsAvatar). - Post(binding.MultipartForm(form.Avatar{}), user.SettingsAvatarPost) - m.Post("/avatar/delete", user.SettingsDeleteAvatar) - m.Combo("/email").Get(user.SettingsEmails). - Post(bindIgnErr(form.AddEmail{}), user.SettingsEmailPost) - m.Post("/email/delete", user.DeleteEmail) - m.Get("/password", user.SettingsPassword) - m.Post("/password", bindIgnErr(form.ChangePassword{}), user.SettingsPasswordPost) - m.Combo("/ssh").Get(user.SettingsSSHKeys). - Post(bindIgnErr(form.AddSSHKey{}), user.SettingsSSHKeysPost) - m.Post("/ssh/delete", user.DeleteSSHKey) - m.Group("/security", func() { - m.Get("", user.SettingsSecurity) - m.Combo("/two_factor_enable").Get(user.SettingsTwoFactorEnable). - Post(user.SettingsTwoFactorEnablePost) - m.Combo("/two_factor_recovery_codes").Get(user.SettingsTwoFactorRecoveryCodes). - Post(user.SettingsTwoFactorRecoveryCodesPost) - m.Post("/two_factor_disable", user.SettingsTwoFactorDisable) - }) - m.Group("/repositories", func() { - m.Get("", user.SettingsRepos) - m.Post("/leave", user.SettingsLeaveRepo) - }) - m.Group("/organizations", func() { - m.Get("", user.SettingsOrganizations) - m.Post("/leave", user.SettingsLeaveOrganization) - }) - m.Combo("/applications").Get(user.SettingsApplications). - Post(bindIgnErr(form.NewAccessToken{}), user.SettingsApplicationsPost) - m.Post("/applications/delete", user.SettingsDeleteApplication) - m.Route("/delete", "GET,POST", user.SettingsDelete) - }, reqSignIn, func(c *context.Context) { - c.Data["PageIsUserSettings"] = true - }) - - m.Group("/user", func() { - m.Any("/activate", user.Activate) - m.Any("/activate_email", user.ActivateEmail) - m.Get("/email2user", user.Email2User) - m.Get("/forget_password", user.ForgotPasswd) - m.Post("/forget_password", user.ForgotPasswdPost) - m.Post("/logout", user.SignOut) - }) - // ***** END: User ***** - - reqAdmin := context.Toggle(&context.ToggleOptions{SignInRequired: true, AdminRequired: true}) - - // ***** START: Admin ***** - m.Group("/admin", func() { - m.Get("", admin.Dashboard) - m.Get("/config", admin.Config) - m.Post("/config/test_mail", admin.SendTestMail) - m.Get("/monitor", admin.Monitor) - - m.Group("/users", func() { - m.Get("", admin.Users) - m.Combo("/new").Get(admin.NewUser).Post(bindIgnErr(form.AdminCrateUser{}), admin.NewUserPost) - m.Combo("/:userid").Get(admin.EditUser).Post(bindIgnErr(form.AdminEditUser{}), admin.EditUserPost) - m.Post("/:userid/delete", admin.DeleteUser) - }) - - m.Group("/orgs", func() { - m.Get("", admin.Organizations) - }) - - m.Group("/repos", func() { - m.Get("", admin.Repos) - m.Post("/delete", admin.DeleteRepo) - }) - - m.Group("/auths", func() { - m.Get("", admin.Authentications) - m.Combo("/new").Get(admin.NewAuthSource).Post(bindIgnErr(form.Authentication{}), admin.NewAuthSourcePost) - m.Combo("/:authid").Get(admin.EditAuthSource). - Post(bindIgnErr(form.Authentication{}), admin.EditAuthSourcePost) - m.Post("/:authid/delete", admin.DeleteAuthSource) - }) - - m.Group("/notices", func() { - m.Get("", admin.Notices) - m.Post("/delete", admin.DeleteNotices) - m.Get("/empty", admin.EmptyNotices) - }) - }, reqAdmin) - // ***** END: Admin ***** - - m.Group("", func() { - m.Group("/:username", func() { - m.Get("", user.Profile) - m.Get("/followers", user.Followers) - m.Get("/following", user.Following) - m.Get("/stars", user.Stars) - }, context.InjectParamsUser()) - - m.Get("/attachments/:uuid", func(c *context.Context) { - attach, err := models.GetAttachmentByUUID(c.Params(":uuid")) - if err != nil { - c.NotFoundOrServerError("GetAttachmentByUUID", models.IsErrAttachmentNotExist, err) - return - } else if !com.IsFile(attach.LocalPath()) { - c.NotFound() - return - } - - fr, err := os.Open(attach.LocalPath()) - if err != nil { - c.Handle(500, "Open", err) - return - } - defer fr.Close() - - c.Header().Set("Cache-Control", "public,max-age=86400") - fmt.Println("attach.Name:", attach.Name) - c.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, attach.Name)) - if err = repo.ServeData(c, attach.Name, fr); err != nil { - c.Handle(500, "ServeData", err) - return - } - }) - m.Post("/issues/attachments", repo.UploadIssueAttachment) - m.Post("/releases/attachments", repo.UploadReleaseAttachment) - }, ignSignIn) - - m.Group("/:username", func() { - m.Post("/action/:action", user.Action) - }, reqSignIn, context.InjectParamsUser()) - - if macaron.Env == macaron.DEV { - m.Get("/template/*", dev.TemplatePreview) - } - - reqRepoAdmin := context.RequireRepoAdmin() - reqRepoWriter := context.RequireRepoWriter() - - // ***** START: Organization ***** - m.Group("/org", func() { - m.Group("", func() { - m.Get("/create", org.Create) - m.Post("/create", bindIgnErr(form.CreateOrg{}), org.CreatePost) - }, func(c *context.Context) { - if !c.User.CanCreateOrganization() { - c.NotFound() - } - }) - - m.Group("/:org", func() { - m.Get("/dashboard", user.Dashboard) - m.Get("/^:type(issues|pulls)$", user.Issues) - m.Get("/members", org.Members) - m.Get("/members/action/:action", org.MembersAction) - - m.Get("/teams", org.Teams) - }, context.OrgAssignment(true)) - - m.Group("/:org", func() { - m.Get("/teams/:team", org.TeamMembers) - m.Get("/teams/:team/repositories", org.TeamRepositories) - m.Route("/teams/:team/action/:action", "GET,POST", org.TeamsAction) - m.Route("/teams/:team/action/repo/:action", "GET,POST", org.TeamsRepoAction) - }, context.OrgAssignment(true, false, true)) - - m.Group("/:org", func() { - m.Get("/teams/new", org.NewTeam) - m.Post("/teams/new", bindIgnErr(form.CreateTeam{}), org.NewTeamPost) - m.Get("/teams/:team/edit", org.EditTeam) - m.Post("/teams/:team/edit", bindIgnErr(form.CreateTeam{}), org.EditTeamPost) - m.Post("/teams/:team/delete", org.DeleteTeam) - - m.Group("/settings", func() { - m.Combo("").Get(org.Settings). - Post(bindIgnErr(form.UpdateOrgSetting{}), org.SettingsPost) - m.Post("/avatar", binding.MultipartForm(form.Avatar{}), org.SettingsAvatar) - m.Post("/avatar/delete", org.SettingsDeleteAvatar) - - m.Group("/hooks", func() { - m.Get("", org.Webhooks) - m.Post("/delete", org.DeleteWebhook) - m.Get("/:type/new", repo.WebhooksNew) - m.Post("/gogs/new", bindIgnErr(form.NewWebhook{}), repo.WebHooksNewPost) - m.Post("/slack/new", bindIgnErr(form.NewSlackHook{}), repo.SlackHooksNewPost) - m.Post("/discord/new", bindIgnErr(form.NewDiscordHook{}), repo.DiscordHooksNewPost) - m.Post("/dingtalk/new", bindIgnErr(form.NewDingtalkHook{}), repo.DingtalkHooksNewPost) - m.Get("/:id", repo.WebHooksEdit) - m.Post("/gogs/:id", bindIgnErr(form.NewWebhook{}), repo.WebHooksEditPost) - m.Post("/slack/:id", bindIgnErr(form.NewSlackHook{}), repo.SlackHooksEditPost) - m.Post("/discord/:id", bindIgnErr(form.NewDiscordHook{}), repo.DiscordHooksEditPost) - m.Post("/dingtalk/:id", bindIgnErr(form.NewDingtalkHook{}), repo.DingtalkHooksEditPost) - }) - - m.Route("/delete", "GET,POST", org.SettingsDelete) - }) - - m.Route("/invitations/new", "GET,POST", org.Invitation) - }, context.OrgAssignment(true, true)) - }, reqSignIn) - // ***** END: Organization ***** - - // ***** START: Repository ***** - m.Group("/repo", func() { - m.Get("/create", repo.Create) - m.Post("/create", bindIgnErr(form.CreateRepo{}), repo.CreatePost) - m.Get("/migrate", repo.Migrate) - m.Post("/migrate", bindIgnErr(form.MigrateRepo{}), repo.MigratePost) - m.Combo("/fork/:repoid").Get(repo.Fork). - Post(bindIgnErr(form.CreateRepo{}), repo.ForkPost) - }, reqSignIn) - - m.Group("/:username/:reponame", func() { - m.Group("/settings", func() { - m.Combo("").Get(repo.Settings). - Post(bindIgnErr(form.RepoSetting{}), repo.SettingsPost) - m.Combo("/avatar").Get(repo.SettingsAvatar). - Post(binding.MultipartForm(form.Avatar{}), repo.SettingsAvatarPost) - m.Post("/avatar/delete", repo.SettingsDeleteAvatar) - m.Group("/collaboration", func() { - m.Combo("").Get(repo.SettingsCollaboration).Post(repo.SettingsCollaborationPost) - m.Post("/access_mode", repo.ChangeCollaborationAccessMode) - m.Post("/delete", repo.DeleteCollaboration) - }) - m.Group("/branches", func() { - m.Get("", repo.SettingsBranches) - m.Post("/default_branch", repo.UpdateDefaultBranch) - m.Combo("/*").Get(repo.SettingsProtectedBranch). - Post(bindIgnErr(form.ProtectBranch{}), repo.SettingsProtectedBranchPost) - }, func(c *context.Context) { - if c.Repo.Repository.IsMirror { - c.NotFound() - return - } - }) - - m.Group("/hooks", func() { - m.Get("", repo.Webhooks) - m.Post("/delete", repo.DeleteWebhook) - m.Get("/:type/new", repo.WebhooksNew) - m.Post("/gogs/new", bindIgnErr(form.NewWebhook{}), repo.WebHooksNewPost) - m.Post("/slack/new", bindIgnErr(form.NewSlackHook{}), repo.SlackHooksNewPost) - m.Post("/discord/new", bindIgnErr(form.NewDiscordHook{}), repo.DiscordHooksNewPost) - m.Post("/dingtalk/new", bindIgnErr(form.NewDingtalkHook{}), repo.DingtalkHooksNewPost) - m.Post("/gogs/:id", bindIgnErr(form.NewWebhook{}), repo.WebHooksEditPost) - m.Post("/slack/:id", bindIgnErr(form.NewSlackHook{}), repo.SlackHooksEditPost) - m.Post("/discord/:id", bindIgnErr(form.NewDiscordHook{}), repo.DiscordHooksEditPost) - m.Post("/dingtalk/:id", bindIgnErr(form.NewDingtalkHook{}), repo.DingtalkHooksEditPost) - - m.Group("/:id", func() { - m.Get("", repo.WebHooksEdit) - m.Post("/test", repo.TestWebhook) - m.Post("/redelivery", repo.RedeliveryWebhook) - }) - - m.Group("/git", func() { - m.Get("", repo.SettingsGitHooks) - m.Combo("/:name").Get(repo.SettingsGitHooksEdit). - Post(repo.SettingsGitHooksEditPost) - }, context.GitHookService()) - }) - - m.Group("/keys", func() { - m.Combo("").Get(repo.SettingsDeployKeys). - Post(bindIgnErr(form.AddSSHKey{}), repo.SettingsDeployKeysPost) - m.Post("/delete", repo.DeleteDeployKey) - }) - - }, func(c *context.Context) { - c.Data["PageIsSettings"] = true - }) - }, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.RepoRef()) - - m.Post("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), repo.Action) - m.Group("/:username/:reponame", func() { - m.Get("/issues", repo.RetrieveLabels, repo.Issues) - m.Get("/issues/:index", repo.ViewIssue) - m.Get("/labels/", repo.RetrieveLabels, repo.Labels) - m.Get("/milestones", repo.Milestones) - }, ignSignIn, context.RepoAssignment(true)) - m.Group("/:username/:reponame", func() { - // FIXME: should use different URLs but mostly same logic for comments of issue and pull reuqest. - // So they can apply their own enable/disable logic on routers. - m.Group("/issues", func() { - m.Combo("/new", repo.MustEnableIssues).Get(context.RepoRef(), repo.NewIssue). - Post(bindIgnErr(form.NewIssue{}), repo.NewIssuePost) - - m.Group("/:index", func() { - m.Post("/title", repo.UpdateIssueTitle) - m.Post("/content", repo.UpdateIssueContent) - m.Combo("/comments").Post(bindIgnErr(form.CreateComment{}), repo.NewComment) - }) - }) - m.Group("/comments/:id", func() { - m.Post("", repo.UpdateCommentContent) - m.Post("/delete", repo.DeleteComment) - }) - }, reqSignIn, context.RepoAssignment(true)) - m.Group("/:username/:reponame", func() { - m.Group("/wiki", func() { - m.Get("/?:page", repo.Wiki) - m.Get("/_pages", repo.WikiPages) - }, repo.MustEnableWiki, context.RepoRef()) - }, ignSignIn, context.RepoAssignment(false, true)) - - m.Group("/:username/:reponame", func() { - // FIXME: should use different URLs but mostly same logic for comments of issue and pull reuqest. - // So they can apply their own enable/disable logic on routers. - m.Group("/issues", func() { - m.Group("/:index", func() { - m.Post("/label", repo.UpdateIssueLabel) - m.Post("/milestone", repo.UpdateIssueMilestone) - m.Post("/assignee", repo.UpdateIssueAssignee) - }, reqRepoWriter) - }) - m.Group("/labels", func() { - m.Post("/new", bindIgnErr(form.CreateLabel{}), repo.NewLabel) - m.Post("/edit", bindIgnErr(form.CreateLabel{}), repo.UpdateLabel) - m.Post("/delete", repo.DeleteLabel) - m.Post("/initialize", bindIgnErr(form.InitializeLabels{}), repo.InitializeLabels) - }, reqRepoWriter, context.RepoRef()) - m.Group("/milestones", func() { - m.Combo("/new").Get(repo.NewMilestone). - Post(bindIgnErr(form.CreateMilestone{}), repo.NewMilestonePost) - m.Get("/:id/edit", repo.EditMilestone) - m.Post("/:id/edit", bindIgnErr(form.CreateMilestone{}), repo.EditMilestonePost) - m.Get("/:id/:action", repo.ChangeMilestonStatus) - m.Post("/delete", repo.DeleteMilestone) - }, reqRepoWriter, context.RepoRef()) - - m.Group("/releases", func() { - m.Get("/new", repo.NewRelease) - m.Post("/new", bindIgnErr(form.NewRelease{}), repo.NewReleasePost) - m.Post("/delete", repo.DeleteRelease) - m.Get("/edit/*", repo.EditRelease) - m.Post("/edit/*", bindIgnErr(form.EditRelease{}), repo.EditReleasePost) - }, repo.MustBeNotBare, reqRepoWriter, func(c *context.Context) { - c.Data["PageIsViewFiles"] = true - }) - - // FIXME: Should use c.Repo.PullRequest to unify template, currently we have inconsistent URL - // for PR in same repository. After select branch on the page, the URL contains redundant head user name. - // e.g. /org1/test-repo/compare/master...org1:develop - // which should be /org1/test-repo/compare/master...develop - m.Combo("/compare/*", repo.MustAllowPulls).Get(repo.CompareAndPullRequest). - Post(bindIgnErr(form.NewIssue{}), repo.CompareAndPullRequestPost) - - m.Group("", func() { - m.Combo("/_edit/*").Get(repo.EditFile). - Post(bindIgnErr(form.EditRepoFile{}), repo.EditFilePost) - m.Combo("/_new/*").Get(repo.NewFile). - Post(bindIgnErr(form.EditRepoFile{}), repo.NewFilePost) - m.Post("/_preview/*", bindIgnErr(form.EditPreviewDiff{}), repo.DiffPreviewPost) - m.Combo("/_delete/*").Get(repo.DeleteFile). - Post(bindIgnErr(form.DeleteRepoFile{}), repo.DeleteFilePost) - - m.Group("", func() { - m.Combo("/_upload/*").Get(repo.UploadFile). - Post(bindIgnErr(form.UploadRepoFile{}), repo.UploadFilePost) - m.Post("/upload-file", repo.UploadFileToServer) - m.Post("/upload-remove", bindIgnErr(form.RemoveUploadFile{}), repo.RemoveUploadFileFromServer) - }, func(c *context.Context) { - if !setting.Repository.Upload.Enabled { - c.NotFound() - return - } - }) - }, repo.MustBeNotBare, reqRepoWriter, context.RepoRef(), func(c *context.Context) { - if !c.Repo.CanEnableEditor() { - c.NotFound() - return - } - - c.Data["PageIsViewFiles"] = true - }) - }, reqSignIn, context.RepoAssignment()) - - m.Group("/:username/:reponame", func() { - m.Group("", func() { - m.Get("/releases", repo.MustBeNotBare, repo.Releases) - m.Get("/pulls", repo.RetrieveLabels, repo.Pulls) - m.Get("/pulls/:index", repo.ViewPull) - }, context.RepoRef()) - - m.Group("/branches", func() { - m.Get("", repo.Branches) - m.Get("/all", repo.AllBranches) - m.Post("/delete/*", reqSignIn, reqRepoWriter, repo.DeleteBranchPost) - }, repo.MustBeNotBare, func(c *context.Context) { - c.Data["PageIsViewFiles"] = true - }) - - m.Group("/wiki", func() { - m.Group("", func() { - m.Combo("/_new").Get(repo.NewWiki). - Post(bindIgnErr(form.NewWiki{}), repo.NewWikiPost) - m.Combo("/:page/_edit").Get(repo.EditWiki). - Post(bindIgnErr(form.NewWiki{}), repo.EditWikiPost) - m.Post("/:page/delete", repo.DeleteWikiPagePost) - }, reqSignIn, reqRepoWriter) - }, repo.MustEnableWiki, context.RepoRef()) - - m.Get("/archive/*", repo.MustBeNotBare, repo.Download) - - m.Group("/pulls/:index", func() { - m.Get("/commits", context.RepoRef(), repo.ViewPullCommits) - m.Get("/files", context.RepoRef(), repo.ViewPullFiles) - m.Post("/merge", reqRepoWriter, repo.MergePullRequest) - }, repo.MustAllowPulls) - - m.Group("", func() { - m.Get("/src/*", repo.Home) - m.Get("/raw/*", repo.SingleDownload) - m.Get("/commits/*", repo.RefCommits) - m.Get("/commit/:sha([a-f0-9]{7,40})$", repo.Diff) - m.Get("/forks", repo.Forks) - }, repo.MustBeNotBare, context.RepoRef()) - m.Get("/commit/:sha([a-f0-9]{7,40})\\.:ext(patch|diff)", repo.MustBeNotBare, repo.RawDiff) - - m.Get("/compare/:before([a-z0-9]{40})\\.\\.\\.:after([a-z0-9]{40})", repo.MustBeNotBare, context.RepoRef(), repo.CompareDiff) - }, ignSignIn, context.RepoAssignment()) - m.Group("/:username/:reponame", func() { - m.Get("/stars", repo.Stars) - m.Get("/watchers", repo.Watchers) - }, ignSignIn, context.RepoAssignment(), context.RepoRef()) - - m.Group("/:username", func() { - m.Get("/:reponame", ignSignIn, context.RepoAssignment(), context.RepoRef(), repo.Home) - - m.Group("/:reponame", func() { - m.Head("/tasks/trigger", repo.TriggerTask) - }) - // Use the regexp to match the repository name - // Duplicated routes to enable different ways of accessing same set of URLs, - // e.g. with or without ".git" suffix. - m.Group("/:reponame([\\d\\w-_\\.]+\\.git$)", func() { - m.Get("", ignSignIn, context.RepoAssignment(), context.RepoRef(), repo.Home) - m.Options("/*", ignSignInAndCsrf, repo.HTTPContexter(), repo.HTTP) - m.Route("/*", "GET,POST", ignSignInAndCsrf, repo.HTTPContexter(), repo.HTTP) - }) - m.Options("/:reponame/*", ignSignInAndCsrf, repo.HTTPContexter(), repo.HTTP) - m.Route("/:reponame/*", "GET,POST", ignSignInAndCsrf, repo.HTTPContexter(), repo.HTTP) - }) - // ***** END: Repository ***** - - m.Group("/api", func() { - apiv1.RegisterRoutes(m) - }, ignSignIn) - - m.Group("/-", func() { - if setting.Prometheus.Enabled { - m.Get("/metrics", func(c *context.Context) { - if !setting.Prometheus.EnableBasicAuth { - return - } - - c.RequireBasicAuth(setting.Prometheus.BasicAuthUsername, setting.Prometheus.BasicAuthPassword) - }, promhttp.Handler()) - } - }) - - // robots.txt - m.Get("/robots.txt", func(c *context.Context) { - if setting.HasRobotsTxt { - c.ServeFileContent(path.Join(setting.CustomPath, "robots.txt")) - } else { - c.NotFound() - } - }) - - // Not found handler. - m.NotFound(routes.NotFound) - - // Flag for port number in case first time run conflict. - if c.IsSet("port") { - setting.AppURL = strings.Replace(setting.AppURL, setting.HTTPPort, c.String("port"), 1) - setting.HTTPPort = c.String("port") - } - - var listenAddr string - if setting.Protocol == setting.SCHEME_UNIX_SOCKET { - listenAddr = fmt.Sprintf("%s", setting.HTTPAddr) - } else { - listenAddr = fmt.Sprintf("%s:%s", setting.HTTPAddr, setting.HTTPPort) - } - log.Info("Listen: %v://%s%s", setting.Protocol, listenAddr, setting.AppSubURL) - - var err error - switch setting.Protocol { - case setting.SCHEME_HTTP: - err = http.ListenAndServe(listenAddr, m) - case setting.SCHEME_HTTPS: - var tlsMinVersion uint16 - switch setting.TLSMinVersion { - case "SSL30": - tlsMinVersion = tls.VersionSSL30 - case "TLS12": - tlsMinVersion = tls.VersionTLS12 - case "TLS11": - tlsMinVersion = tls.VersionTLS11 - case "TLS10": - fallthrough - default: - tlsMinVersion = tls.VersionTLS10 - } - server := &http.Server{Addr: listenAddr, TLSConfig: &tls.Config{ - MinVersion: tlsMinVersion, - CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256}, - PreferServerCipherSuites: true, - CipherSuites: []uint16{ - tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, // Required for HTTP/2 support. - tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - tls.TLS_RSA_WITH_AES_256_CBC_SHA, - }, - }, Handler: m} - err = server.ListenAndServeTLS(setting.CertFile, setting.KeyFile) - case setting.SCHEME_FCGI: - err = fcgi.Serve(nil, m) - case setting.SCHEME_UNIX_SOCKET: - os.Remove(listenAddr) - - var listener *net.UnixListener - listener, err = net.ListenUnix("unix", &net.UnixAddr{listenAddr, "unix"}) - if err != nil { - break // Handle error after switch - } - - // FIXME: add proper implementation of signal capture on all protocols - // execute this on SIGTERM or SIGINT: listener.Close() - if err = os.Chmod(listenAddr, os.FileMode(setting.UnixSocketPermission)); err != nil { - log.Fatal(4, "Failed to set permission of unix socket: %v", err) - } - err = http.Serve(listener, m) - default: - log.Fatal(4, "Invalid protocol: %s", setting.Protocol) - } - - if err != nil { - log.Fatal(4, "Failed to start server: %v", err) - } - - return nil -} |