Skip to content

Commit 830e4d2

Browse files
authored
Cherry pick security tickets (#2519)
1 parent 9be7faa commit 830e4d2

File tree

6 files changed

+180
-9
lines changed

6 files changed

+180
-9
lines changed

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ require (
88
github.com/buildpacks/pack v0.36.4
99
github.com/docker/cli v27.5.1+incompatible
1010
github.com/docker/docker v27.5.1+incompatible
11-
github.com/gboddin/go-www-authenticate-parser v0.0.0-20230926203616-ec0b649bb077
1211
github.com/go-test/deep v1.1.1
1312
github.com/google/go-containerregistry v0.20.3
1413
github.com/itchyny/gojq v0.12.17

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,6 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
160160
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
161161
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
162162
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
163-
github.com/gboddin/go-www-authenticate-parser v0.0.0-20230926203616-ec0b649bb077 h1:JvEO7eltd2aCHF+ABLquTUziO7hzC6G7H3tgENYkDBc=
164-
github.com/gboddin/go-www-authenticate-parser v0.0.0-20230926203616-ec0b649bb077/go.mod h1:RlYuEjNYq/NkhOCSkZGPKxP3dgZOBH94UwsQraDng8s=
165163
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
166164
github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw=
167165
github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo=

internal/btp/cis/auth.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// Copied from:
2+
// https://github.com/gboddin/go-www-authenticate-parser/commit/ec0b649bb07701564d8bf002d0262a7bc4c13fe8
3+
4+
package cis
5+
6+
import (
7+
"bytes"
8+
"encoding/json"
9+
)
10+
11+
type wwwAuthenticateSettings struct {
12+
state func() error
13+
digestBuffer *bytes.Buffer
14+
buffer string
15+
currentParam string
16+
quoteOpened bool
17+
AuthType string
18+
Params map[string]string
19+
}
20+
21+
func ParseAuthSettings(digestBuffer string) wwwAuthenticateSettings {
22+
digest := wwwAuthenticateSettings{
23+
digestBuffer: bytes.NewBufferString(digestBuffer),
24+
buffer: "",
25+
AuthType: "",
26+
Params: make(map[string]string),
27+
}
28+
digest.state = digest.ParseType
29+
for {
30+
if err := digest.state(); err != nil {
31+
break
32+
}
33+
}
34+
return digest
35+
}
36+
37+
func (d *wwwAuthenticateSettings) ParseType() error {
38+
currentByte, err := d.digestBuffer.ReadByte()
39+
if err != nil {
40+
return err
41+
}
42+
if currentByte != ' ' && currentByte != '\n' {
43+
d.buffer += string(currentByte)
44+
return nil
45+
}
46+
d.AuthType = d.buffer
47+
d.buffer = ""
48+
d.state = d.ParseParamKey
49+
return nil
50+
}
51+
52+
func (d *wwwAuthenticateSettings) ParseParamKey() error {
53+
currentByte, err := d.digestBuffer.ReadByte()
54+
if err != nil {
55+
return err
56+
}
57+
switch currentByte {
58+
case '=':
59+
d.currentParam = d.buffer
60+
d.buffer = ""
61+
d.state = d.ParseParamValue
62+
return nil
63+
case ' ':
64+
if len(d.buffer) > 0 {
65+
d.Params[d.buffer] = "true"
66+
d.currentParam = ""
67+
d.buffer = ""
68+
d.state = d.ParseParamKey
69+
}
70+
return nil
71+
case ',':
72+
if len(d.buffer) > 0 {
73+
d.Params[d.buffer] = "true"
74+
}
75+
d.currentParam = ""
76+
d.buffer = ""
77+
d.state = d.ParseParamKey
78+
return nil
79+
}
80+
d.buffer += string(currentByte)
81+
return nil
82+
}
83+
84+
func (d *wwwAuthenticateSettings) ParseParamValue() error {
85+
currentByte, err := d.digestBuffer.ReadByte()
86+
if err != nil {
87+
return err
88+
}
89+
switch currentByte {
90+
case '\\':
91+
nextByte, err := d.digestBuffer.ReadByte()
92+
if err != nil {
93+
return err
94+
}
95+
var unquoted string
96+
err = json.Unmarshal([]byte("\""+string(currentByte)+string(nextByte)+"\""), &unquoted)
97+
if err != nil {
98+
return err
99+
}
100+
d.buffer += unquoted
101+
return nil
102+
case '"':
103+
if d.quoteOpened {
104+
d.quoteOpened = false
105+
d.Params[d.currentParam] = d.buffer
106+
d.currentParam = ""
107+
d.buffer = ""
108+
// Read until the next ','
109+
_, err = d.digestBuffer.ReadString(',')
110+
if err != nil {
111+
return err
112+
}
113+
d.state = d.ParseParamKey
114+
return nil
115+
}
116+
if !d.quoteOpened {
117+
d.quoteOpened = true
118+
return nil
119+
}
120+
case ',':
121+
if !d.quoteOpened {
122+
d.quoteOpened = false
123+
d.Params[d.currentParam] = d.buffer
124+
d.currentParam = ""
125+
d.buffer = ""
126+
d.state = d.ParseParamKey
127+
return nil
128+
}
129+
}
130+
131+
d.buffer += string(currentByte)
132+
return nil
133+
}

internal/btp/cis/client.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"io"
88
"net/http"
99

10-
wwwAuthParser "github.com/gboddin/go-www-authenticate-parser"
1110
"github.com/kyma-project/cli.v3/internal/btp/auth"
1211
)
1312

@@ -127,6 +126,6 @@ func (c *httpClient) buildErrorFromHeaders(response *http.Response) error {
127126
return fmt.Errorf("failed to parse http error for status: %s", response.Status)
128127
}
129128

130-
wwwAuthHeader := wwwAuthParser.Parse(wwwAuthHeaderString)
129+
wwwAuthHeader := ParseAuthSettings(wwwAuthHeaderString)
131130
return fmt.Errorf("%s: %s", wwwAuthHeader.Params["error"], wwwAuthHeader.Params["error_description"])
132131
}

internal/cmd/alpha/function/init.go

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package function
22

33
import (
4+
"bufio"
45
"fmt"
56
"io"
67
"os"
@@ -56,7 +57,7 @@ func NewInitCmd(kymaConfig *cmdcommon.KymaConfig, cmdConfig interface{}) (*cobra
5657
clierror.Check(cfg.validate())
5758
},
5859
Run: func(cmd *cobra.Command, _ []string) {
59-
clierror.Check(runInit(cfg, cmd.OutOrStdout()))
60+
clierror.Check(runInit(cfg, cmd.InOrStdin(), cmd.OutOrStdout()))
6061
},
6162
}
6263

@@ -87,6 +88,16 @@ func parseExtensionConfig(cmdConfig interface{}) (*extensionConfig, error) {
8788
return nil, errors.New("unexpected extension error, empty config data")
8889
}
8990

91+
for runtimeName, runtimeCfg := range extCfg.Runtimes {
92+
if !filepath.IsLocal(runtimeCfg.DepsFilename) {
93+
return nil, errors.New(fmt.Sprintf("deps filename %s for runtime %s is not a single file name", runtimeCfg.DepsFilename, runtimeName))
94+
}
95+
96+
if !filepath.IsLocal(runtimeCfg.HandlerFilename) {
97+
return nil, errors.New(fmt.Sprintf("handler filename %s for runtime %s is not a single file name", runtimeCfg.HandlerFilename, runtimeName))
98+
}
99+
}
100+
90101
return &extCfg, nil
91102
}
92103

@@ -101,9 +112,17 @@ func (c *initConfig) validate() clierror.Error {
101112
return nil
102113
}
103114

104-
func runInit(cfg *initConfig, out io.Writer) clierror.Error {
115+
func runInit(cfg *initConfig, in io.Reader, out io.Writer) clierror.Error {
105116
runtimeCfg := cfg.extensionConfig.Runtimes[cfg.runtime]
106117

118+
if !filepath.IsLocal(cfg.dir) {
119+
// output dir is not a local path, ask user for confirmation
120+
clierr := getUserAcceptance(in, out, cfg.dir)
121+
if clierr != nil {
122+
return clierr
123+
}
124+
}
125+
107126
handlerPath := path.Join(cfg.dir, runtimeCfg.HandlerFilename)
108127
err := os.WriteFile(handlerPath, []byte(runtimeCfg.HandlerData), os.ModePerm)
109128
if err != nil {
@@ -139,3 +158,26 @@ func sortedRuntimesString(m map[string]runtimeConfig) string {
139158
sort.Strings(sort.StringSlice(keys))
140159
return strings.Join(keys, ", ")
141160
}
161+
162+
func getUserAcceptance(in io.Reader, out io.Writer, path string) clierror.Error {
163+
fmt.Fprintf(out, "The output path ( %s ) seems to be outside of the current working directory.\n", path)
164+
fmt.Fprint(out, "Do you want to proceed? (y/n): ")
165+
166+
input, err := bufio.NewReader(in).ReadString('\n') // wait for user to press enter
167+
fmt.Fprintln(out)
168+
169+
if err != nil {
170+
return clierror.Wrap(err, clierror.New("failed to read user input"))
171+
}
172+
173+
lowerInput := strings.ToLower(input)
174+
if lowerInput == "y\n" || lowerInput == "yes\n" {
175+
// user accepted, continue
176+
return nil
177+
}
178+
179+
return clierror.New(
180+
"function init aborted",
181+
"you must provide a local path for the output directory or accept the default one by typing 'y' and pressing enter",
182+
)
183+
}

internal/cmd/alpha/registry/config/config.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func runConfig(cfg *cfgConfig) clierror.Error {
5454
}
5555

5656
if cfg.externalurl && cfg.output != "" {
57-
writeErr := os.WriteFile(cfg.output, []byte(registryConfig.SecretData.PushRegAddr), os.ModePerm)
57+
writeErr := os.WriteFile(cfg.output, []byte(registryConfig.SecretData.PushRegAddr), 0600)
5858
if writeErr != nil {
5959
return clierror.New("failed to write docker config to file")
6060
}
@@ -64,7 +64,7 @@ func runConfig(cfg *cfgConfig) clierror.Error {
6464
if cfg.output == "" {
6565
fmt.Print(registryConfig.SecretData.DockerConfigJSON)
6666
} else {
67-
writeErr := os.WriteFile(cfg.output, []byte(registryConfig.SecretData.DockerConfigJSON), os.ModePerm)
67+
writeErr := os.WriteFile(cfg.output, []byte(registryConfig.SecretData.DockerConfigJSON), 0600)
6868
if writeErr != nil {
6969
return clierror.New("failed to write docker config to file")
7070
}

0 commit comments

Comments
 (0)