From 25be0637b3c6fc771ae1fb043f7eee98e49302b7 Mon Sep 17 00:00:00 2001 From: David Imola Date: Wed, 25 May 2022 16:49:21 -0600 Subject: [PATCH] Snap Config overrider --- overrider/snapconfig/snapconfig.go | 82 ++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 overrider/snapconfig/snapconfig.go diff --git a/overrider/snapconfig/snapconfig.go b/overrider/snapconfig/snapconfig.go new file mode 100644 index 0000000..5f865e8 --- /dev/null +++ b/overrider/snapconfig/snapconfig.go @@ -0,0 +1,82 @@ +package snapconfig + +import ( + "encoding/json" + "errors" + "fmt" + "os" + + "github.com/snapcore/snapd/client" + "github.com/snapcore/snapd/dirs" +) + +var ( + ErrSnapctl = errors.New("snapctl system call failed") + ErrJSONUnmarshal = errors.New("couldn't unmarhsal json") +) + +// This variable copied from +// Vogt, Michael, et al. “Snapd.” Github.com, 2.54.4, Snapcore, 25 Nov. 2020, +// https://github.com/snapcore/snapd/blob/67901c9dd5c22f4ece95b53f43fb0acc73e81a23/cmd/snapctl/main.go. +// Accessed 8 Mar. 2022 +var clientConfig = client.Config{ + // snapctl should not try to read $HOME/.snap/auth.json, this will + // result in apparmor denials and configure task failures + // (LP: #1660941) + DisableAuth: true, + + // we need the less privileged snap socket in snapctl + Socket: dirs.SnapSocket, +} + +// This function modified from +// Vogt, Michael, et al. “Snapd.” Github.com, 2.54.4, Snapcore, 25 Nov. 2020, +// https://github.com/snapcore/snapd/blob/67901c9dd5c22f4ece95b53f43fb0acc73e81a23/cmd/snapctl/main.go. +// Accessed 8 Mar. 2022. +func runSnapCtl(args []string) (stdout []byte, stderr []byte, err error) { + cli := client.New(&clientConfig) + cookie := os.Getenv("SNAP_COOKIE") + // for compatibility, if re-exec is not enabled and facing older snapd. + if cookie == "" { + cookie = os.Getenv("SNAP_CONTEXT") + } + + return cli.RunSnapctl(&client.SnapCtlOptions{ + ContextID: cookie, + Args: args, + }, nil) +} + +func get(key string) (string, error) { + stdout, _, err := runSnapCtl([]string{"get", "-d", key}) + if err != nil { + return "", fmt.Errorf("%w for %s: %v", ErrSnapctl, key, err) + } + var result map[string]string + if err = json.Unmarshal(stdout, &result); err != nil { + return "", fmt.Errorf("%w for %s: %v", ErrJSONUnmarshal, key, err) + } + if len(result) == 0 { + return "", nil + } + return result[key], nil +} + +type snapConfigOverrider struct { + ErrHandler func(error) +} + +func (o *snapConfigOverrider) Get(lowerCaseKey string) (string, bool) { + result, err := get(lowerCaseKey) + if err != nil { + o.ErrHandler(err) + } + return result, err == nil && len(result) > 0 +} + +//nolint:revive // we dont want to give access to snapConfigOverrider type without constructor +func Overrider(errHandler func(error)) *snapConfigOverrider { + return &snapConfigOverrider{ + ErrHandler: errHandler, + } +}