diff --git a/cmd/aa/main.go b/cmd/aa/main.go index d5bc10d5..9f407015 100644 --- a/cmd/aa/main.go +++ b/cmd/aa/main.go @@ -13,7 +13,6 @@ import ( "github.com/roddhjav/apparmor.d/pkg/aa" "github.com/roddhjav/apparmor.d/pkg/logging" "github.com/roddhjav/apparmor.d/pkg/paths" - "github.com/roddhjav/apparmor.d/pkg/util" ) const usage = `aa [-h] [--lint | --format | --tree] [-s] [-F file] [profiles...] diff --git a/pkg/aa/apparmor_test.go b/pkg/aa/apparmor_test.go index 19cfd5a4..0cc74d43 100644 --- a/pkg/aa/apparmor_test.go +++ b/pkg/aa/apparmor_test.go @@ -10,7 +10,6 @@ import ( "testing" "github.com/roddhjav/apparmor.d/pkg/paths" - "github.com/roddhjav/apparmor.d/pkg/util" ) var ( @@ -21,7 +20,7 @@ var ( // mustReadProfileFile read a file and return its content as a slice of string. // It panics if an error occurs. It removes the last comment line. func mustReadProfileFile(path *paths.Path) string { - res := strings.Split(util.MustReadFile(path), "\n") + res := strings.Split(path.MustReadFileAsString(), "\n") return strings.Join(res[:len(res)-2], "\n") } @@ -108,7 +107,7 @@ func TestAppArmorProfileFile_String(t *testing.T) { }, }}, }, - want: util.MustReadFile(testData.Join("string.aa")), + want: testData.Join("string.aa").MustReadFileAsString(), }, } for _, tt := range tests { diff --git a/pkg/aa/parse_test.go b/pkg/aa/parse_test.go index 8b54487f..71607fd3 100644 --- a/pkg/aa/parse_test.go +++ b/pkg/aa/parse_test.go @@ -8,8 +8,6 @@ import ( "reflect" "strings" "testing" - - "github.com/roddhjav/apparmor.d/pkg/util" ) func Test_tokenizeRule(t *testing.T) { @@ -919,7 +917,7 @@ var ( }, { name: "string.aa", - raw: util.MustReadFile(testData.Join("string.aa")), + raw: testData.Join("string.aa").MustReadFileAsString(), apparmor: &AppArmorProfileFile{ Preamble: Rules{ &Comment{Base: Base{Comment: " Simple test profile for the AppArmorProfileFile.String() method", IsLineRule: true}}, @@ -1017,7 +1015,7 @@ var ( }, { name: "full.aa", - raw: util.MustReadFile(testData.Join("full.aa")), + raw: testData.Join("full.aa").MustReadFileAsString(), apparmor: &AppArmorProfileFile{ Preamble: Rules{ &Comment{Base: Base{IsLineRule: true, Comment: " Simple test profile with all rules used"}}, diff --git a/pkg/aa/resolve.go b/pkg/aa/resolve.go index 26a03691..6ce768bc 100644 --- a/pkg/aa/resolve.go +++ b/pkg/aa/resolve.go @@ -10,7 +10,6 @@ import ( "strings" "github.com/roddhjav/apparmor.d/pkg/paths" - "github.com/roddhjav/apparmor.d/pkg/util" ) var ( @@ -149,7 +148,7 @@ func (f *AppArmorProfileFile) resolveInclude(include *Include) error { iFile := &AppArmorProfileFile{} for _, file := range files { - raw, err := util.ReadFile(file) + raw, err := file.ReadFileAsString() if err != nil { return err } diff --git a/pkg/paths/paths.go b/pkg/paths/paths.go index b77adfa6..feb1e21c 100644 --- a/pkg/paths/paths.go +++ b/pkg/paths/paths.go @@ -35,9 +35,12 @@ import ( "io/fs" "os" "path/filepath" + "slices" "strings" "syscall" "time" + + "github.com/roddhjav/apparmor.d/pkg/util" ) // Path represents a path @@ -360,6 +363,31 @@ func (p *Path) CopyTo(dst *Path) error { return nil } +// CopyTo recursivelly copy all files from a source path to a destination path. +func CopyTo(src *Path, dst *Path) error { + files, err := src.ReadDirRecursiveFiltered(nil, + FilterOutDirectories(), + FilterOutNames("README.md"), + ) + if err != nil { + return err + } + for _, file := range files { + destination, err := file.RelFrom(src) + if err != nil { + return err + } + destination = dst.JoinPath(destination) + if err := destination.Parent().MkdirAll(); err != nil { + return err + } + if err := file.CopyTo(destination); err != nil { + return err + } + } + return nil +} + // CopyDirTo recursively copies the directory denoted by the current path to // the destination path. The source directory must exist and the destination // directory must NOT exist (no implicit destination name allowed). @@ -460,6 +488,24 @@ func WriteToTempFile(data []byte, dir *Path, prefix string) (res *Path, err erro return New(f.Name()), nil } +// ReadFileAsString read a file and return its content as a string. +func (p *Path) ReadFileAsString() (string, error) { + content, err := p.ReadFile() + if err != nil { + return "", err + } + return string(content), nil +} + +// MustReadFileAsString read a file and return its content as a string. Panic if an error occurs. +func (p *Path) MustReadFileAsString() string { + content, err := p.ReadFile() + if err != nil { + panic(err) + } + return string(content) +} + // ReadFileAsLines reads the file named by filename and returns it as an // array of lines. This function takes care of the newline encoding // differences between different OS @@ -473,6 +519,33 @@ func (p *Path) ReadFileAsLines() ([]string, error) { return strings.Split(txt, "\n"), nil } +// MustReadFileAsLines read a file and return its content as a slice of string. Panic if an error occurs. +func (p *Path) MustReadFileAsLines() []string { + lines, err := p.ReadFileAsLines() + if err != nil { + panic(err) + } + return lines +} + +// MustReadFilteredFileAsLines read a file and return its content as a slice of string. +// It filter out comments and empty lines. Panic if an error occurs. +func (p *Path) MustReadFilteredFileAsLines() []string { + data, err := p.ReadFile() + if err != nil { + panic(err) + } + txt := string(data) + txt = strings.Replace(txt, "\r\n", "\n", -1) + txt = util.Filter(txt) + res := strings.Split(txt, "\n") + if slices.Contains(res, "") { + idx := slices.Index(res, "") + res = slices.Delete(res, idx, idx+1) + } + return res +} + // Truncate create an empty file named by path or if the file already // exist it truncates it (delete all contents) func (p *Path) Truncate() error { diff --git a/pkg/prebuild/cli/cli.go b/pkg/prebuild/cli/cli.go index 7c91d828..932851d0 100644 --- a/pkg/prebuild/cli/cli.go +++ b/pkg/prebuild/cli/cli.go @@ -15,7 +15,6 @@ import ( "github.com/roddhjav/apparmor.d/pkg/prebuild/builder" "github.com/roddhjav/apparmor.d/pkg/prebuild/directive" "github.com/roddhjav/apparmor.d/pkg/prebuild/prepare" - "github.com/roddhjav/apparmor.d/pkg/util" ) const ( @@ -138,7 +137,7 @@ func Build() error { if !file.Exist() { continue } - profile, err := util.ReadFile(file) + profile, err := file.ReadFileAsString() if err != nil { return err } diff --git a/pkg/prebuild/directive/exec.go b/pkg/prebuild/directive/exec.go index c856b726..5aee7374 100644 --- a/pkg/prebuild/directive/exec.go +++ b/pkg/prebuild/directive/exec.go @@ -13,7 +13,6 @@ import ( "github.com/roddhjav/apparmor.d/pkg/aa" "github.com/roddhjav/apparmor.d/pkg/prebuild" - "github.com/roddhjav/apparmor.d/pkg/util" ) type Exec struct { @@ -44,7 +43,7 @@ func (d Exec) Apply(opt *Option, profileRaw string) (string, error) { rules := aa.Rules{} for name := range opt.ArgMap { - profiletoTransition := util.MustReadFile(prebuild.RootApparmord.Join(name)) + profiletoTransition := prebuild.RootApparmord.Join(name).MustReadFileAsString() dstProfile := aa.DefaultTunables() if _, err := dstProfile.Parse(profiletoTransition); err != nil { return "", err diff --git a/pkg/prebuild/directive/stack.go b/pkg/prebuild/directive/stack.go index 70740536..03dd826e 100644 --- a/pkg/prebuild/directive/stack.go +++ b/pkg/prebuild/directive/stack.go @@ -55,7 +55,7 @@ func (s Stack) Apply(opt *Option, profile string) (string, error) { res := "" for name := range opt.ArgMap { - stackedProfile := util.MustReadFile(prebuild.RootApparmord.Join(name)) + stackedProfile := prebuild.RootApparmord.Join(name).MustReadFileAsString() m := regRules.FindStringSubmatch(stackedProfile) if len(m) < 2 { return "", fmt.Errorf("No profile found in %s", name) diff --git a/pkg/prebuild/files.go b/pkg/prebuild/files.go index d275c916..c1473096 100644 --- a/pkg/prebuild/files.go +++ b/pkg/prebuild/files.go @@ -8,7 +8,6 @@ import ( "strings" "github.com/roddhjav/apparmor.d/pkg/paths" - "github.com/roddhjav/apparmor.d/pkg/util" ) // Default content of debian/apparmor.d.hide. Whonix has special addition. @@ -29,7 +28,7 @@ func (f Flagger) Read(name string) map[string][]string { return res } - lines := util.MustReadFileAsLines(path) + lines := path.MustReadFilteredFileAsLines() for _, line := range lines { manifest := strings.Split(line, " ") profile := manifest[0] @@ -49,7 +48,7 @@ func (i Ignorer) Read(name string) []string { if !path.Exist() { return []string{} } - return util.MustReadFileAsLines(path) + return path.MustReadFilteredFileAsLines() } type DebianHider struct { diff --git a/pkg/prebuild/prepare/flags.go b/pkg/prebuild/prepare/flags.go index 23998d4d..5a851cbe 100644 --- a/pkg/prebuild/prepare/flags.go +++ b/pkg/prebuild/prepare/flags.go @@ -10,7 +10,6 @@ import ( "strings" "github.com/roddhjav/apparmor.d/pkg/prebuild" - "github.com/roddhjav/apparmor.d/pkg/util" ) var ( @@ -44,7 +43,7 @@ func (p SetFlags) Apply() ([]string, error) { // Overwrite profile flags if len(flags) > 0 { flagsStr := " flags=(" + strings.Join(flags, ",") + ") {\n" - out, err := util.ReadFile(file) + out, err := file.ReadFileAsString() if err != nil { return res, err } diff --git a/pkg/prebuild/prepare/fsp.go b/pkg/prebuild/prepare/fsp.go index af57ed9d..b40030d2 100644 --- a/pkg/prebuild/prepare/fsp.go +++ b/pkg/prebuild/prepare/fsp.go @@ -35,7 +35,7 @@ func (p FullSystemPolicy) Apply() ([]string, error) { // Set systemd profile name path := prebuild.RootApparmord.Join("tunables/multiarch.d/system") - out, err := util.ReadFile(path) + out, err := path.ReadFileAsString() if err != nil { return res, err } @@ -47,7 +47,7 @@ func (p FullSystemPolicy) Apply() ([]string, error) { // Fix conflicting x modifiers in abstractions - FIXME: Temporary solution path = prebuild.RootApparmord.Join("abstractions/gstreamer") - out, err = util.ReadFile(path) + out, err = path.ReadFileAsString() if err != nil { return res, err } diff --git a/pkg/prebuild/prepare/overwrite.go b/pkg/prebuild/prepare/overwrite.go index 209e8dc8..6f895116 100644 --- a/pkg/prebuild/prepare/overwrite.go +++ b/pkg/prebuild/prepare/overwrite.go @@ -9,7 +9,6 @@ import ( "os" "github.com/roddhjav/apparmor.d/pkg/prebuild" - "github.com/roddhjav/apparmor.d/pkg/util" ) const ext = ".apparmor.d" @@ -44,7 +43,7 @@ func (p Overwrite) Apply() ([]string, error) { if !path.Exist() { return res, fmt.Errorf("%s not found", path) } - for _, name := range util.MustReadFileAsLines(path) { + for _, name := range path.MustReadFilteredFileAsLines() { origin := prebuild.RootApparmord.Join(name) dest := prebuild.RootApparmord.Join(name + ext) if !dest.Exist() && p.OneFile { diff --git a/pkg/util/tools.go b/pkg/util/tools.go index 0d3372fc..749a97e6 100644 --- a/pkg/util/tools.go +++ b/pkg/util/tools.go @@ -7,10 +7,6 @@ package util import ( "encoding/hex" "regexp" - "slices" - "strings" - - "github.com/roddhjav/apparmor.d/pkg/paths" ) var ( @@ -67,61 +63,7 @@ func DecodeHexInString(str string) string { return str } -// CopyTo recursivelly copy all files from a source path to a destination path. -func CopyTo(src *paths.Path, dst *paths.Path) error { - files, err := src.ReadDirRecursiveFiltered(nil, - paths.FilterOutDirectories(), - paths.FilterOutNames("README.md"), - ) - if err != nil { - return err - } - for _, file := range files { - destination, err := file.RelFrom(src) - if err != nil { - return err - } - destination = dst.JoinPath(destination) - if err := destination.Parent().MkdirAll(); err != nil { - return err - } - if err := file.CopyTo(destination); err != nil { - return err - } - } - return nil -} - // Filter out comments and empty line from a string func Filter(src string) string { return regFilter.Replace(src) } - -// ReadFile read a file and return its content as a string. -func ReadFile(path *paths.Path) (string, error) { - content, err := path.ReadFile() - if err != nil { - return "", err - } - return string(content), nil -} - -// MustReadFile read a file and return its content as a string. Panic if an error occurs. -func MustReadFile(path *paths.Path) string { - content, err := path.ReadFile() - if err != nil { - panic(err) - } - return string(content) -} - -// MustReadFileAsLines read a file and return its content as a slice of string. -// It panics if an error occurs and filter out comments and empty lines. -func MustReadFileAsLines(path *paths.Path) []string { - res := strings.Split(Filter(MustReadFile(path)), "\n") - if slices.Contains(res, "") { - idx := slices.Index(res, "") - res = slices.Delete(res, idx, idx+1) - } - return res -}