util.go

  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.
 15package util
 16
 17import (
 18	"encoding/json"
 19	"errors"
 20	"io"
 21	"os"
 22	"os/user"
 23	"path/filepath"
 24	"runtime"
 25	"strings"
 26)
 27
 28const configFileName = "certificate_config.json"
 29
 30// EnterpriseCertificateConfig contains parameters for initializing signer.
 31type EnterpriseCertificateConfig struct {
 32	Libs Libs `json:"libs"`
 33}
 34
 35// Libs specifies the locations of helper libraries.
 36type 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.
 42var ErrConfigUnavailable = errors.New("Config is unavailable")
 43
 44// LoadSignerBinaryPath retrieves the path of the signer binary from the config file.
 45func 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
 73func 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
 85func 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.
 93func GetDefaultConfigFilePath() (path string) {
 94	return filepath.Join(getDefaultConfigFileDirectory(), configFileName)
 95}
 96
 97// GetConfigFilePathFromEnv returns the path associated with environment variable GOOGLE_API_CERTIFICATE_CONFIG
 98func GetConfigFilePathFromEnv() (path string) {
 99	return os.Getenv("GOOGLE_API_CERTIFICATE_CONFIG")
100}