mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2026-05-12 22:10:25 +00:00
fix: store pull mirror creds encrypted with keying (#11909)
Fixes #9629. New pull mirrors have credentials stored encrypted in the database, the same as push mirrors, rather than in the repository's `config` file. `git fetch` on the pull mirror is updated to use the credential store. Pull mirrors will have their credentials migrated to the encrypted storage in the database as they're synced or otherwise accessed via the web UI. ## Checklist The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. All work and communication must conform to Forgejo's [AI Agreement](https://codeberg.org/forgejo/governance/src/branch/main/AIAgreement.md). There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org). ### Tests for Go changes - I added test coverage for Go changes... - [ ] in their respective `*_test.go` for unit tests. - [x] in the `tests/integration` directory if it involves interactions with a live Forgejo server. - I ran... - [x] `make pr-go` before pushing ### Documentation - [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change. - [x] I did not document these changes and I do not expect someone else to do it. ### Release notes - [x] This change will be noticed by a Forgejo user or admin (feature, bug fix, performance, etc.). I suggest to include a release note for this change. - [ ] This change is not visible to a Forgejo user or admin (refactor, dependency upgrade, etc.). I think there is no need to add a release note for this change. Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11909 Reviewed-by: Gusted <gusted@noreply.codeberg.org> Reviewed-by: Andreas Ahlenstorf <aahlenst@noreply.codeberg.org> Co-authored-by: Mathieu Fenniak <mathieu@fenniak.net> Co-committed-by: Mathieu Fenniak <mathieu@fenniak.net>
This commit is contained in:
parent
e4bd84b574
commit
6a99b6b0c1
12 changed files with 774 additions and 182 deletions
|
|
@ -10,6 +10,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime/trace"
|
||||
|
|
@ -446,6 +447,54 @@ func (c *Command) RunStdBytes(opts *RunOpts) (stdout, stderr []byte, runErr RunS
|
|||
return stdoutBuf.Bytes(), stderr, nil
|
||||
}
|
||||
|
||||
// If `remoteURL` is a URL with a password in it, add parameters to the git command that will read that password from a
|
||||
// credential store file, and return the URL that should be used in the command instead of the original, and a cleanup
|
||||
// function to call to remove the credential file. If `remoteURL` doesn't have a password, then it is returned as-is.
|
||||
// This function must be invoked on the the git command before the git sub-command -- eg. before the `clone` or `fetch`
|
||||
// parameter is added to the command's args.
|
||||
func (c *Command) AddAuthCredentialHelperForRemote(remoteURL string) (commandURL string, cleanup func(), err error) {
|
||||
parsedFromURL, _ := url.Parse(remoteURL)
|
||||
|
||||
// If the clone URL has credentials, build a credential file for usage by git-credential-store
|
||||
// to prevent credential leak in the process list.
|
||||
// https://git-scm.com/docs/git-credential-store#_storage_format
|
||||
// credential.helper adjustment must be set before the git subcommand
|
||||
if strings.Contains(remoteURL, "://") && strings.Contains(remoteURL, "@") && parsedFromURL != nil {
|
||||
credentialsFile, err := os.CreateTemp("", "forgejo-clone-credentials-")
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
credentialsPath := credentialsFile.Name()
|
||||
|
||||
cleanup := func() {
|
||||
_ = credentialsFile.Close()
|
||||
if err := util.Remove(credentialsPath); err != nil {
|
||||
log.Warn("Unable to remove temporary file %q: %v", credentialsPath, err)
|
||||
}
|
||||
}
|
||||
_, err = credentialsFile.Write([]byte(parsedFromURL.String()))
|
||||
if err != nil {
|
||||
cleanup()
|
||||
return "", nil, err
|
||||
}
|
||||
err = credentialsFile.Close()
|
||||
if err != nil {
|
||||
cleanup()
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
c.AddArguments("-c").AddDynamicArguments("credential.helper=store --file=" + credentialsPath)
|
||||
|
||||
// remove the password from the URL argument
|
||||
parsedFromURL.User = url.User(parsedFromURL.User.Username())
|
||||
commandURL = parsedFromURL.String()
|
||||
|
||||
return commandURL, cleanup, nil
|
||||
}
|
||||
|
||||
return remoteURL, func() {}, nil
|
||||
}
|
||||
|
||||
// AllowLFSFiltersArgs return globalCommandArgs with lfs filter, it should only be used for tests
|
||||
func AllowLFSFiltersArgs() TrustedCmdArgs {
|
||||
// Now here we should explicitly allow lfs filters to run
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"forgejo.org/modules/log"
|
||||
"forgejo.org/modules/proxy"
|
||||
"forgejo.org/modules/setting"
|
||||
"forgejo.org/modules/util"
|
||||
|
|
@ -141,44 +140,13 @@ func CloneWithArgs(ctx context.Context, args TrustedCmdArgs, from, to string, op
|
|||
envs = proxy.EnvWithProxy(parsedFromURL)
|
||||
}
|
||||
|
||||
fromURL := from
|
||||
sanitizedFrom := from
|
||||
sanitizedFrom := util.SanitizeCredentialURLs(from)
|
||||
|
||||
// If the clone URL has credentials, build a credential file for usage by git-credential-store
|
||||
// to prevent credential leak in the process list.
|
||||
// https://git-scm.com/docs/git-credential-store#_storage_format
|
||||
// credential.helper adjustment must be set before the git subcommand
|
||||
if strings.Contains(from, "://") && strings.Contains(from, "@") {
|
||||
sanitizedFrom = util.SanitizeCredentialURLs(from)
|
||||
if parsedFromURL != nil {
|
||||
credentialsFile, err := os.CreateTemp("", "forgejo-clone-credentials-")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
credentialsPath := credentialsFile.Name()
|
||||
|
||||
defer func() {
|
||||
_ = credentialsFile.Close()
|
||||
if err := util.Remove(credentialsPath); err != nil {
|
||||
log.Warn("Unable to remove temporary file %q: %v", credentialsPath, err)
|
||||
}
|
||||
}()
|
||||
_, err = credentialsFile.Write([]byte(parsedFromURL.String()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = credentialsFile.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd.AddArguments("-c").AddDynamicArguments("credential.helper=store --file=" + credentialsPath)
|
||||
|
||||
// remove the password from the URL argument
|
||||
parsedFromURL.User = url.User(parsedFromURL.User.Username())
|
||||
fromURL = parsedFromURL.String()
|
||||
}
|
||||
fromURL, cleanup, err := cmd.AddAuthCredentialHelperForRemote(from)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cleanup()
|
||||
|
||||
cmd.AddArguments("clone")
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue