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  }