util.go raw

   1  // Copyright 2022 Google LLC.
   2  // Licensed under the Apache License, Version 2.0 (the "License");
   3  // you may not use this file except in compliance with the License.
   4  // You may obtain a copy of the License at
   5  //
   6  //     https://www.apache.org/licenses/LICENSE-2.0
   7  //
   8  // Unless required by applicable law or agreed to in writing, software
   9  // distributed under the License is distributed on an "AS IS" BASIS,
  10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11  // See the License for the specific language governing permissions and
  12  // limitations under the License.
  13  
  14  // Package util provides helper functions for the client.
  15  package util
  16  
  17  import (
  18  	"encoding/json"
  19  	"errors"
  20  	"io"
  21  	"os"
  22  	"os/user"
  23  	"path/filepath"
  24  	"runtime"
  25  	"strings"
  26  )
  27  
  28  const configFileName = "certificate_config.json"
  29  
  30  // EnterpriseCertificateConfig contains parameters for initializing signer.
  31  type EnterpriseCertificateConfig struct {
  32  	Libs Libs `json:"libs"`
  33  }
  34  
  35  // Libs specifies the locations of helper libraries.
  36  type Libs struct {
  37  	ECP string `json:"ecp"`
  38  }
  39  
  40  // ErrConfigUnavailable is a sentinel error that indicates ECP config is unavailable,
  41  // possibly due to entire config missing or missing binary path.
  42  var ErrConfigUnavailable = errors.New("Config is unavailable")
  43  
  44  // LoadSignerBinaryPath retrieves the path of the signer binary from the config file.
  45  func LoadSignerBinaryPath(configFilePath string) (path string, err error) {
  46  	jsonFile, err := os.Open(configFilePath)
  47  	if err != nil {
  48  		if errors.Is(err, os.ErrNotExist) {
  49  			return "", ErrConfigUnavailable
  50  		}
  51  		return "", err
  52  	}
  53  
  54  	byteValue, err := io.ReadAll(jsonFile)
  55  	if err != nil {
  56  		return "", err
  57  	}
  58  	var config EnterpriseCertificateConfig
  59  	err = json.Unmarshal(byteValue, &config)
  60  	if err != nil {
  61  		return "", err
  62  	}
  63  	signerBinaryPath := config.Libs.ECP
  64  	if signerBinaryPath == "" {
  65  		return "", ErrConfigUnavailable
  66  	}
  67  
  68  	signerBinaryPath = strings.ReplaceAll(signerBinaryPath, "~", guessHomeDir())
  69  	signerBinaryPath = strings.ReplaceAll(signerBinaryPath, "$HOME", guessHomeDir())
  70  	return signerBinaryPath, nil
  71  }
  72  
  73  func guessHomeDir() string {
  74  	// Prefer $HOME over user.Current due to glibc bug: golang.org/issue/13470
  75  	if v := os.Getenv("HOME"); v != "" {
  76  		return v
  77  	}
  78  	// Else, fall back to user.Current:
  79  	if u, err := user.Current(); err == nil {
  80  		return u.HomeDir
  81  	}
  82  	return ""
  83  }
  84  
  85  func getDefaultConfigFileDirectory() (directory string) {
  86  	if runtime.GOOS == "windows" {
  87  		return filepath.Join(os.Getenv("APPDATA"), "gcloud")
  88  	}
  89  	return filepath.Join(guessHomeDir(), ".config/gcloud")
  90  }
  91  
  92  // GetDefaultConfigFilePath returns the default path of the enterprise certificate config file created by gCloud.
  93  func GetDefaultConfigFilePath() (path string) {
  94  	return filepath.Join(getDefaultConfigFileDirectory(), configFileName)
  95  }
  96  
  97  // GetConfigFilePathFromEnv returns the path associated with environment variable GOOGLE_API_CERTIFICATE_CONFIG
  98  func GetConfigFilePathFromEnv() (path string) {
  99  	return os.Getenv("GOOGLE_API_CERTIFICATE_CONFIG")
 100  }
 101