go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/resources/macos/preferences.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package macos 5 6 import ( 7 "bytes" 8 "fmt" 9 "io" 10 "strings" 11 12 "go.mondoo.com/cnquery/providers/os/connection/shared" 13 "howett.net/plist" 14 ) 15 16 const ( 17 currentHostDomains = "defaults -currentHost domains" 18 currentHostDomainPreferences = "defaults -currentHost export %s -" 19 userDomains = "defaults domains" 20 userDomainPreferences = "defaults export %s -" 21 ) 22 23 func NewPreferences(c shared.Connection) *Preferences { 24 return &Preferences{ 25 connection: c, 26 } 27 } 28 29 type Preferences struct { 30 connection shared.Connection 31 } 32 33 func (p *Preferences) UserPreferences() (map[string]map[string]interface{}, error) { 34 return p.preferences(userDomains, userDomainPreferences) 35 } 36 37 func (p *Preferences) UserHostPreferences() (map[string]map[string]interface{}, error) { 38 return p.preferences(currentHostDomains, currentHostDomainPreferences) 39 } 40 41 func (p *Preferences) preferences(domainCmd string, preferencesCmd string) (map[string]map[string]interface{}, error) { 42 c, err := p.connection.RunCommand(domainCmd) 43 if err != nil { 44 return nil, err 45 } 46 47 domains, err := ParseDomains(c.Stdout) 48 if err != nil { 49 return nil, err 50 } 51 52 res := map[string]map[string]interface{}{} 53 54 for i := range domains { 55 domain := domains[i] 56 57 c, err := p.connection.RunCommand(fmt.Sprintf(preferencesCmd, domain)) 58 if err != nil { 59 return nil, err 60 } 61 62 data, err := ParsePreferences(c.Stdout) 63 if err != nil { 64 return nil, err 65 } 66 67 res[domain] = data 68 } 69 70 return res, nil 71 } 72 73 func ParseDomains(r io.Reader) ([]string, error) { 74 data, err := io.ReadAll(r) 75 if err != nil { 76 return nil, err 77 } 78 79 res := strings.Split(string(data), ",") 80 81 for i := range res { 82 res[i] = strings.TrimSpace(res[i]) 83 } 84 return res, nil 85 } 86 87 func ParsePreferences(input io.Reader) (map[string]interface{}, error) { 88 var r io.ReadSeeker 89 r, ok := input.(io.ReadSeeker) 90 if !ok { 91 data, err := io.ReadAll(input) 92 if err != nil { 93 return nil, err 94 } 95 r = bytes.NewReader(data) 96 } 97 98 var data map[string]interface{} 99 decoder := plist.NewDecoder(r) 100 err := decoder.Decode(&data) 101 if err != nil { 102 return nil, err 103 } 104 return data, nil 105 }