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}