Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes/cleanups for SSH key/systemd unit local file embedding #441

Merged
merged 7 commits into from
Mar 14, 2023
14 changes: 14 additions & 0 deletions base/util/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package util

import (
"os"
"path/filepath"
"strings"

Expand All @@ -36,6 +37,19 @@ func EnsurePathWithinFilesDir(path, filesDir string) error {
return nil
}

func ReadLocalFile(configPath, filesDir string) ([]byte, error) {
if filesDir == "" {
// a files dir isn't configured; refuse to read anything
return nil, common.ErrNoFilesDir
}
// calculate file path within FilesDir and check for path traversal
filePath := filepath.Join(filesDir, filepath.FromSlash(configPath))
if err := EnsurePathWithinFilesDir(filePath, filesDir); err != nil {
return nil, err
}
return os.ReadFile(filePath)
}

// CheckForDecimalMode fails if the specified mode appears to have been
// incorrectly specified in decimal instead of octal.
func CheckForDecimalMode(mode int, directory bool) error {
Expand Down
17 changes: 1 addition & 16 deletions base/v0_2/translate.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,26 +118,11 @@ func translateResource(from Resource, options common.TranslateOptions) (to types

if from.Local != nil {
c := path.New("yaml", "local")

if options.FilesDir == "" {
r.AddOnError(c, common.ErrNoFilesDir)
return
}

// calculate file path within FilesDir and check for
// path traversal
filePath := filepath.Join(options.FilesDir, filepath.FromSlash(*from.Local))
if err := baseutil.EnsurePathWithinFilesDir(filePath, options.FilesDir); err != nil {
r.AddOnError(c, err)
return
}

contents, err := os.ReadFile(filePath)
contents, err := baseutil.ReadLocalFile(*from.Local, options.FilesDir)
if err != nil {
r.AddOnError(c, err)
return
}

src, compression, err := baseutil.MakeDataURL(contents, to.Compression, !options.NoResourceAutoCompression)
if err != nil {
r.AddOnError(c, err)
Expand Down
17 changes: 1 addition & 16 deletions base/v0_3/translate.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,26 +125,11 @@ func translateResource(from Resource, options common.TranslateOptions) (to types

if from.Local != nil {
c := path.New("yaml", "local")

if options.FilesDir == "" {
r.AddOnError(c, common.ErrNoFilesDir)
return
}

// calculate file path within FilesDir and check for
// path traversal
filePath := filepath.Join(options.FilesDir, filepath.FromSlash(*from.Local))
if err := baseutil.EnsurePathWithinFilesDir(filePath, options.FilesDir); err != nil {
r.AddOnError(c, err)
return
}

contents, err := os.ReadFile(filePath)
contents, err := baseutil.ReadLocalFile(*from.Local, options.FilesDir)
if err != nil {
r.AddOnError(c, err)
return
}

src, compression, err := baseutil.MakeDataURL(contents, to.Compression, !options.NoResourceAutoCompression)
if err != nil {
r.AddOnError(c, err)
Expand Down
17 changes: 1 addition & 16 deletions base/v0_4/translate.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,26 +140,11 @@ func translateResource(from Resource, options common.TranslateOptions) (to types

if from.Local != nil {
c := path.New("yaml", "local")

if options.FilesDir == "" {
r.AddOnError(c, common.ErrNoFilesDir)
return
}

// calculate file path within FilesDir and check for
// path traversal
filePath := filepath.Join(options.FilesDir, filepath.FromSlash(*from.Local))
if err := baseutil.EnsurePathWithinFilesDir(filePath, options.FilesDir); err != nil {
r.AddOnError(c, err)
return
}

contents, err := os.ReadFile(filePath)
contents, err := baseutil.ReadLocalFile(*from.Local, options.FilesDir)
if err != nil {
r.AddOnError(c, err)
return
}

src, compression, err := baseutil.MakeDataURL(contents, to.Compression, !options.NoResourceAutoCompression)
if err != nil {
r.AddOnError(c, err)
Expand Down
84 changes: 15 additions & 69 deletions base/v0_5_exp/translate.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,26 +143,11 @@ func translateResource(from Resource, options common.TranslateOptions) (to types

if from.Local != nil {
c := path.New("yaml", "local")

if options.FilesDir == "" {
r.AddOnError(c, common.ErrNoFilesDir)
return
}

// calculate file path within FilesDir and check for
// path traversal
filePath := filepath.Join(options.FilesDir, filepath.FromSlash(*from.Local))
if err := baseutil.EnsurePathWithinFilesDir(filePath, options.FilesDir); err != nil {
r.AddOnError(c, err)
return
}

contents, err := os.ReadFile(filePath)
contents, err := baseutil.ReadLocalFile(*from.Local, options.FilesDir)
if err != nil {
r.AddOnError(c, err)
return
}

src, compression, err := baseutil.MakeDataURL(contents, to.Compression, !options.NoResourceAutoCompression)
if err != nil {
r.AddOnError(c, err)
Expand Down Expand Up @@ -241,17 +226,17 @@ func translatePasswdUser(from PasswdUser, options common.TranslateOptions) (to t
return
}

for _, sshKeyFile := range from.SSHAuthorizedKeysLocal {
sshKeys, err := readSshKeyFile(options.FilesDir, sshKeyFile)
for keyFileIndex, sshKeyFile := range from.SSHAuthorizedKeysLocal {
sshKeys, err := baseutil.ReadLocalFile(sshKeyFile, options.FilesDir)
if err != nil {
r.AddOnError(c, err)
r.AddOnError(c.Append(keyFileIndex), err)
continue
}

// offset for TranslationSets when both ssh_authorized_keys and ssh_authorized_keys_local are available
offset := len(to.SSHAuthorizedKeys)
for i, line := range regexp.MustCompile("\r?\n").Split(sshKeys, -1) {
tm.AddTranslation(c, path.New("json", "sshAuthorizedKeys", i+offset))
for _, line := range regexp.MustCompile("\r?\n").Split(string(sshKeys), -1) {
if line == "" {
continue
}
tm.AddTranslation(c.Append(keyFileIndex), path.New("json", "sshAuthorizedKeys", len(to.SSHAuthorizedKeys)))
to.SSHAuthorizedKeys = append(to.SSHAuthorizedKeys, types.SSHAuthorizedKey(line))
}
}
Expand All @@ -260,22 +245,9 @@ func translatePasswdUser(from PasswdUser, options common.TranslateOptions) (to t
return
}

func readSshKeyFile(filesDir string, sshKeyFile string) (string, error) {
// calculate file path within FilesDir and check for path traversal
filePath := filepath.Join(filesDir, sshKeyFile)
if err := baseutil.EnsurePathWithinFilesDir(filePath, filesDir); err != nil {
return "", err
}
contents, err := os.ReadFile(filePath)
if err != nil {
return "", err
}
return string(contents), nil
}

func translateUnit(from Unit, options common.TranslateOptions) (to types.Unit, tm translate.TranslationSet, r report.Report) {
tr := translate.NewTranslator("yaml", "json", options)
tr.AddCustomTranslator(translateUnitDropIn)
tr.AddCustomTranslator(translateDropin)
tm, r = translate.Prefixed(tr, "contents", &from.Contents, &to.Contents)
translate.MergeP(tr, tm, &r, "dropins", &from.Dropins, &to.Dropins)
translate.MergeP(tr, tm, &r, "enabled", &from.Enabled, &to.Enabled)
Expand All @@ -284,19 +256,7 @@ func translateUnit(from Unit, options common.TranslateOptions) (to types.Unit, t

if util.NotEmpty(from.ContentsLocal) {
c := path.New("yaml", "contents_local")
if options.FilesDir == "" {
r.AddOnError(c, common.ErrNoFilesDir)
return
}

// calculate file path within FilesDir and check for
// path traversal
filePath := filepath.Join(options.FilesDir, *from.ContentsLocal)
if err := baseutil.EnsurePathWithinFilesDir(filePath, options.FilesDir); err != nil {
r.AddOnError(c, err)
return
}
contents, err := os.ReadFile(filePath)
contents, err := baseutil.ReadLocalFile(*from.ContentsLocal, options.FilesDir)
if err != nil {
r.AddOnError(c, err)
return
Expand All @@ -308,34 +268,20 @@ func translateUnit(from Unit, options common.TranslateOptions) (to types.Unit, t
return
}

func translateUnitDropIn(from Dropin, options common.TranslateOptions) (to types.Dropin, tm translate.TranslationSet, r report.Report) {
func translateDropin(from Dropin, options common.TranslateOptions) (to types.Dropin, tm translate.TranslationSet, r report.Report) {
tr := translate.NewTranslator("yaml", "json", options)
tm, r = translate.Prefixed(tr, "contents", &from.Contents, &to.Contents)
translate.MergeP(tr, tm, &r, "name", &from.Name, &to.Name)

if util.NotEmpty(from.ContentsLocal) {
c := path.New("yaml", "contents_local")
tm.AddTranslation(c, path.New("json", "contents"))

if options.FilesDir == "" {
r.AddOnError(c, common.ErrNoFilesDir)
return
}

// calculate file path within FilesDir and check for
// path traversal
filePath := filepath.Join(options.FilesDir, *from.ContentsLocal)
if err := baseutil.EnsurePathWithinFilesDir(filePath, options.FilesDir); err != nil {
r.AddOnError(c, err)
return
}
contents, err := os.ReadFile(filePath)
contents, err := baseutil.ReadLocalFile(*from.ContentsLocal, options.FilesDir)
if err != nil {
r.AddOnError(c, err)
return
}
stringContents := string(contents)
to.Contents = util.StrToPtr(stringContents)
tm.AddTranslation(c, path.New("json", "contents"))
to.Contents = util.StrToPtr(string(contents))
}

return
Expand Down
Loading