0222623be9
* Explicitly disable Git credential helper
If the user running Gitea has configured a credential helper, Git
credentials might leak out of Gitea.
There are two problems with credential helpers when combined with Gitea:
1. Credentials entered by a user when doing a migration or setting up a
mirror will end up in the credential store. In the worst case, this
is the plain text file ~/.git-credentials.
2. Credentials in the credential store will be used for migrations and
mirrors by all users. For example, if user A sets up a mirror, their
credentials will be stored. If user B later sets up a mirror from the
same host and does not enter any credentials, user A's credentials
will be used.
This PR prepends -c credential.helper= to all Git commands to clear the
list of helpers. This requires at least Git version 2.9, as previous
versions will try to load an empty helper instead. For more details, see
24321375cd
* Update git module
137 lines
3.7 KiB
Go
137 lines
3.7 KiB
Go
// 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 git
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"os/exec"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
// GlobalCommandArgs global command args for external package setting
|
|
GlobalCommandArgs []string
|
|
|
|
// DefaultCommandExecutionTimeout default command execution timeout duration
|
|
DefaultCommandExecutionTimeout = 60 * time.Second
|
|
)
|
|
|
|
// Command represents a command with its subcommands or arguments.
|
|
type Command struct {
|
|
name string
|
|
args []string
|
|
}
|
|
|
|
func (c *Command) String() string {
|
|
if len(c.args) == 0 {
|
|
return c.name
|
|
}
|
|
return fmt.Sprintf("%s %s", c.name, strings.Join(c.args, " "))
|
|
}
|
|
|
|
// NewCommand creates and returns a new Git Command based on given command and arguments.
|
|
func NewCommand(args ...string) *Command {
|
|
// Make an explicit copy of GlobalCommandArgs, otherwise append might overwrite it
|
|
cargs := make([]string, len(GlobalCommandArgs))
|
|
copy(cargs, GlobalCommandArgs)
|
|
return &Command{
|
|
name: "git",
|
|
args: append(cargs, args...),
|
|
}
|
|
}
|
|
|
|
// AddArguments adds new argument(s) to the command.
|
|
func (c *Command) AddArguments(args ...string) *Command {
|
|
c.args = append(c.args, args...)
|
|
return c
|
|
}
|
|
|
|
// RunInDirTimeoutPipeline executes the command in given directory with given timeout,
|
|
// it pipes stdout and stderr to given io.Writer.
|
|
func (c *Command) RunInDirTimeoutPipeline(timeout time.Duration, dir string, stdout, stderr io.Writer) error {
|
|
if timeout == -1 {
|
|
timeout = DefaultCommandExecutionTimeout
|
|
}
|
|
|
|
if len(dir) == 0 {
|
|
log(c.String())
|
|
} else {
|
|
log("%s: %v", dir, c)
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
|
defer cancel()
|
|
|
|
cmd := exec.CommandContext(ctx, c.name, c.args...)
|
|
cmd.Dir = dir
|
|
cmd.Stdout = stdout
|
|
cmd.Stderr = stderr
|
|
if err := cmd.Start(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := cmd.Wait(); err != nil {
|
|
return err
|
|
}
|
|
|
|
return ctx.Err()
|
|
}
|
|
|
|
// RunInDirTimeout executes the command in given directory with given timeout,
|
|
// and returns stdout in []byte and error (combined with stderr).
|
|
func (c *Command) RunInDirTimeout(timeout time.Duration, dir string) ([]byte, error) {
|
|
stdout := new(bytes.Buffer)
|
|
stderr := new(bytes.Buffer)
|
|
if err := c.RunInDirTimeoutPipeline(timeout, dir, stdout, stderr); err != nil {
|
|
return nil, concatenateError(err, stderr.String())
|
|
}
|
|
|
|
if stdout.Len() > 0 {
|
|
log("stdout:\n%s", stdout.Bytes()[:1024])
|
|
}
|
|
return stdout.Bytes(), nil
|
|
}
|
|
|
|
// RunInDirPipeline executes the command in given directory,
|
|
// it pipes stdout and stderr to given io.Writer.
|
|
func (c *Command) RunInDirPipeline(dir string, stdout, stderr io.Writer) error {
|
|
return c.RunInDirTimeoutPipeline(-1, dir, stdout, stderr)
|
|
}
|
|
|
|
// RunInDirBytes executes the command in given directory
|
|
// and returns stdout in []byte and error (combined with stderr).
|
|
func (c *Command) RunInDirBytes(dir string) ([]byte, error) {
|
|
return c.RunInDirTimeout(-1, dir)
|
|
}
|
|
|
|
// RunInDir executes the command in given directory
|
|
// and returns stdout in string and error (combined with stderr).
|
|
func (c *Command) RunInDir(dir string) (string, error) {
|
|
stdout, err := c.RunInDirTimeout(-1, dir)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return string(stdout), nil
|
|
}
|
|
|
|
// RunTimeout executes the command in defualt working directory with given timeout,
|
|
// and returns stdout in string and error (combined with stderr).
|
|
func (c *Command) RunTimeout(timeout time.Duration) (string, error) {
|
|
stdout, err := c.RunInDirTimeout(timeout, "")
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return string(stdout), nil
|
|
}
|
|
|
|
// Run executes the command in defualt working directory
|
|
// and returns stdout in string and error (combined with stderr).
|
|
func (c *Command) Run() (string, error) {
|
|
return c.RunTimeout(-1)
|
|
}
|