mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-07-23 19:49:40 +02:00
- When specifying push options, tooling like [git-repo-go](https://github.com/alibaba/git-repo-go) encodes pushoption values if they contain newlines or non-ASCII characters as they cannot be easily specified via the CLI otherwise. - Recognize such base64 encoded values in the pushoptions (those that have the `{base64}` prefix), if the base64 decoding fails we return the original value. - Resolves forgejo/forgejo#8161 <!--start release-notes-assistant--> ## Release notes <!--URL:https://codeberg.org/forgejo/forgejo--> - Features - [PR](https://codeberg.org/forgejo/forgejo/pulls/8479): <!--number 8479 --><!--line 0 --><!--description QUdpdCBwdXNoIG9wdGlvbnMgc3RhcnRpbmcgd2l0aCBge2Jhc2U2NH1gIGFyZSBkZWNvZGVk-->AGit push options starting with `{base64}` are decoded<!--description--> <!--end release-notes-assistant--> Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/8479 Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org> Co-authored-by: Gusted <postmaster@gusted.xyz> Co-committed-by: Gusted <postmaster@gusted.xyz>
131 lines
2.5 KiB
Go
131 lines
2.5 KiB
Go
// Copyright twenty-panda <twenty-panda@posteo.com>
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package pushoptions
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type Key string
|
|
|
|
const (
|
|
RepoPrivate = Key("repo.private")
|
|
RepoTemplate = Key("repo.template")
|
|
AgitTopic = Key("topic")
|
|
AgitForcePush = Key("force-push")
|
|
AgitTitle = Key("title")
|
|
AgitDescription = Key("description")
|
|
|
|
envPrefix = "GIT_PUSH_OPTION"
|
|
EnvCount = envPrefix + "_COUNT"
|
|
EnvFormat = envPrefix + "_%d"
|
|
)
|
|
|
|
type Interface interface {
|
|
ReadEnv() Interface
|
|
Parse(string) bool
|
|
Map() map[string]string
|
|
|
|
ChangeRepoSettings() bool
|
|
|
|
Empty() bool
|
|
|
|
GetBool(key Key, def bool) bool
|
|
GetString(key Key) (val string, ok bool)
|
|
}
|
|
|
|
type gitPushOptions map[string]string
|
|
|
|
func New() Interface {
|
|
pushOptions := gitPushOptions(make(map[string]string))
|
|
return &pushOptions
|
|
}
|
|
|
|
func NewFromMap(o *map[string]string) Interface {
|
|
return (*gitPushOptions)(o)
|
|
}
|
|
|
|
func (o *gitPushOptions) ReadEnv() Interface {
|
|
if pushCount, err := strconv.Atoi(os.Getenv(EnvCount)); err == nil {
|
|
for idx := 0; idx < pushCount; idx++ {
|
|
_ = o.Parse(os.Getenv(fmt.Sprintf(EnvFormat, idx)))
|
|
}
|
|
}
|
|
return o
|
|
}
|
|
|
|
func (o *gitPushOptions) Parse(data string) bool {
|
|
key, value, found := strings.Cut(data, "=")
|
|
if !found {
|
|
value = "true"
|
|
}
|
|
switch Key(key) {
|
|
case RepoPrivate:
|
|
case RepoTemplate:
|
|
case AgitTopic:
|
|
case AgitForcePush:
|
|
case AgitTitle:
|
|
case AgitDescription:
|
|
default:
|
|
return false
|
|
}
|
|
(*o)[key] = value
|
|
return true
|
|
}
|
|
|
|
func (o gitPushOptions) Map() map[string]string {
|
|
return o
|
|
}
|
|
|
|
func (o gitPushOptions) ChangeRepoSettings() bool {
|
|
if o.Empty() {
|
|
return false
|
|
}
|
|
for _, key := range []Key{RepoPrivate, RepoTemplate} {
|
|
_, ok := o[string(key)]
|
|
if ok {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (o gitPushOptions) Empty() bool {
|
|
return len(o) == 0
|
|
}
|
|
|
|
func (o gitPushOptions) GetBool(key Key, def bool) bool {
|
|
if val, ok := o[string(key)]; ok {
|
|
if b, err := strconv.ParseBool(val); err == nil {
|
|
return b
|
|
}
|
|
}
|
|
return def
|
|
}
|
|
|
|
func (o gitPushOptions) GetString(key Key) (string, bool) {
|
|
val, ok := o[string(key)]
|
|
if !ok {
|
|
return "", false
|
|
}
|
|
|
|
// If the value is prefixed with `{base64}` then everything after that is very
|
|
// likely to be encoded via base64.
|
|
base64Value, found := strings.CutPrefix(val, "{base64}")
|
|
if !found {
|
|
return val, true
|
|
}
|
|
|
|
value, err := base64.StdEncoding.DecodeString(base64Value)
|
|
if err != nil {
|
|
// Not valid base64? Return the original value.
|
|
return val, true
|
|
}
|
|
|
|
return string(value), true
|
|
}
|