mirror of
https://github.com/safedep/vet.git
synced 2025-12-10 00:22:08 -06:00
357 lines
8.3 KiB
Go
357 lines
8.3 KiB
Go
package auth
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"time"
|
|
|
|
"gopkg.in/yaml.v2"
|
|
)
|
|
|
|
const (
|
|
apiUrlEnvKey = "VET_INSIGHTS_API_URL"
|
|
apiV2UrlEnvKey = "VET_INSIGHTS_API_V2_URL" // gitleaks:allow
|
|
communityServicesApiUrlEnvKey = "VET_COMMUNITY_SERVICES_API_URL"
|
|
syncUrlEnvKey = "VET_SYNC_API_URL"
|
|
controlPlaneUrlEnvKey = "VET_CONTROL_PLANE_API_URL"
|
|
dataPlaneUrlEnvKey = "VET_DATA_PLANE_API_URL"
|
|
apiKeyEnvKey = "VET_API_KEY"
|
|
apiKeyAlternateEnvKey = "VET_INSIGHTS_API_KEY"
|
|
communityModeEnvKey = "VET_COMMUNITY_MODE"
|
|
controlTowerTenantEnvKey = "VET_CONTROL_TOWER_TENANT_ID"
|
|
|
|
defaultSafeDepApiKeyEnvKey = "SAFEDEP_API_KEY"
|
|
defaultSafeDepTenantIdEnvKey = "SAFEDEP_TENANT_ID"
|
|
|
|
defaultApiUrl = "https://api.safedep.io/insights/v1"
|
|
defaultCommunityApiUrl = "https://api.safedep.io/insights-community/v1"
|
|
|
|
// gRPC service base URL.
|
|
defaultDataPlaneApiUrl = "https://api.safedep.io"
|
|
defaultSyncApiUrl = "https://api.safedep.io"
|
|
defaultInsightsApiV2Url = "https://api.safedep.io"
|
|
defaultControlPlaneApiUrl = "https://cloud.safedep.io"
|
|
|
|
// Community services is a new unauthenticated endpoint through
|
|
// which we can serve the community features without authentication.
|
|
defaultCommunityServicesApiUrl = "https://community-api.safedep.io"
|
|
|
|
homeRelativeConfigPath = ".safedep/vet-auth.yml"
|
|
|
|
cloudIdentityServiceClientId = "QtXHUN3hOdbJbCiGU8FiNCnC2KtuROCu" // gitleaks:allow
|
|
cloudIdentityServiceAudience = "https://cloud.safedep.io"
|
|
cloudIdentityServiceBaseUrl = "https://auth.safedep.io"
|
|
cloudIdentityServiceDeviceCodeUrl = "https://auth.safedep.io/oauth/device/code"
|
|
cloudIdentityServiceTokenUrl = "https://auth.safedep.io/oauth/token"
|
|
)
|
|
|
|
type Config struct {
|
|
ApiUrl string `yaml:"api_url"`
|
|
ApiKey string `yaml:"api_key"`
|
|
Community bool `yaml:"community"`
|
|
DataPlaneApiUrl string `yaml:"data_plane_api_url"`
|
|
ControlPlaneApiUrl string `yaml:"control_api_url"`
|
|
SyncApiUrl string `yaml:"sync_api_url"`
|
|
InsightsApiV2Url string `yaml:"insights_api_v2_url"`
|
|
CommunityServicesApiUrl string `yaml:"community_services_api_url"`
|
|
TenantDomain string `yaml:"tenant_domain"`
|
|
CloudAccessToken string `yaml:"cloud_access_token"`
|
|
CloudRefreshToken string `yaml:"cloud_refresh_token"`
|
|
CloudAccessTokenUpdatedAt time.Time `yaml:"cloud_access_token_updated_at"`
|
|
}
|
|
|
|
// Global config to be used during runtime
|
|
var globalConfig *Config
|
|
|
|
func init() {
|
|
_ = loadConfiguration()
|
|
}
|
|
|
|
func DefaultConfig() Config {
|
|
return Config{
|
|
ApiUrl: defaultApiUrl,
|
|
Community: false,
|
|
DataPlaneApiUrl: defaultDataPlaneApiUrl,
|
|
ControlPlaneApiUrl: defaultControlPlaneApiUrl,
|
|
SyncApiUrl: defaultSyncApiUrl,
|
|
InsightsApiV2Url: defaultInsightsApiV2Url,
|
|
CommunityServicesApiUrl: defaultCommunityServicesApiUrl,
|
|
}
|
|
}
|
|
|
|
func PersistApiKey(key, domain string) error {
|
|
if globalConfig == nil {
|
|
c := DefaultConfig()
|
|
globalConfig = &c
|
|
}
|
|
|
|
if domain != "" {
|
|
globalConfig.TenantDomain = domain
|
|
}
|
|
|
|
globalConfig.ApiUrl = defaultApiUrl
|
|
globalConfig.ApiKey = key
|
|
|
|
return persistConfiguration()
|
|
}
|
|
|
|
func PersistCloudTokens(accessToken, refreshToken, domain string) error {
|
|
if globalConfig == nil {
|
|
c := DefaultConfig()
|
|
globalConfig = &c
|
|
}
|
|
|
|
// We are explicitly check for empty string for domain
|
|
// because we do not want to overwrite the domain if it is
|
|
// not provided.
|
|
if domain != "" {
|
|
globalConfig.TenantDomain = domain
|
|
}
|
|
|
|
globalConfig.CloudAccessToken = accessToken
|
|
globalConfig.CloudRefreshToken = refreshToken
|
|
globalConfig.CloudAccessTokenUpdatedAt = time.Now()
|
|
|
|
return persistConfiguration()
|
|
}
|
|
|
|
func PersistTenantDomain(domain string) error {
|
|
if globalConfig == nil {
|
|
c := DefaultConfig()
|
|
globalConfig = &c
|
|
}
|
|
|
|
globalConfig.TenantDomain = domain
|
|
return persistConfiguration()
|
|
}
|
|
|
|
func DefaultApiUrl() string {
|
|
return defaultApiUrl
|
|
}
|
|
|
|
func DefaultCommunityApiUrl() string {
|
|
return defaultCommunityApiUrl
|
|
}
|
|
|
|
func CloudIdentityServiceClientId() string {
|
|
return cloudIdentityServiceClientId
|
|
}
|
|
|
|
func CloudIdentityServiceBaseUrl() string {
|
|
return cloudIdentityServiceBaseUrl
|
|
}
|
|
|
|
func CloudIdentityServiceDeviceCodeUrl() string {
|
|
return cloudIdentityServiceDeviceCodeUrl
|
|
}
|
|
|
|
func CloudIdentityServiceAudience() string {
|
|
return cloudIdentityServiceAudience
|
|
}
|
|
|
|
func CloudIdentityServiceTokenUrl() string {
|
|
return cloudIdentityServiceTokenUrl
|
|
}
|
|
|
|
func CloudAccessToken() string {
|
|
if globalConfig != nil {
|
|
return globalConfig.CloudAccessToken
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
func CloudRefreshToken() string {
|
|
if globalConfig != nil {
|
|
return globalConfig.CloudRefreshToken
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
func DataPlaneUrl() string {
|
|
envOverride := os.Getenv(dataPlaneUrlEnvKey)
|
|
if envOverride != "" {
|
|
return envOverride
|
|
}
|
|
|
|
if (globalConfig != nil) && (globalConfig.DataPlaneApiUrl != "") {
|
|
return globalConfig.DataPlaneApiUrl
|
|
}
|
|
|
|
return defaultDataPlaneApiUrl
|
|
}
|
|
|
|
func SyncApiUrl() string {
|
|
envOverride := os.Getenv(syncUrlEnvKey)
|
|
if envOverride != "" {
|
|
return envOverride
|
|
}
|
|
|
|
if (globalConfig != nil) && (globalConfig.SyncApiUrl != "") {
|
|
return globalConfig.SyncApiUrl
|
|
}
|
|
|
|
return defaultSyncApiUrl
|
|
}
|
|
|
|
func ControlTowerUrl() string {
|
|
envOverride := os.Getenv(controlPlaneUrlEnvKey)
|
|
if envOverride != "" {
|
|
return envOverride
|
|
}
|
|
|
|
if (globalConfig != nil) && (globalConfig.ControlPlaneApiUrl != "") {
|
|
return globalConfig.ControlPlaneApiUrl
|
|
}
|
|
|
|
return defaultControlPlaneApiUrl
|
|
}
|
|
|
|
func InsightsApiV2Url() string {
|
|
envOverride := os.Getenv(apiV2UrlEnvKey)
|
|
if envOverride != "" {
|
|
return envOverride
|
|
}
|
|
|
|
if (globalConfig != nil) && (globalConfig.InsightsApiV2Url != "") {
|
|
return globalConfig.InsightsApiV2Url
|
|
}
|
|
|
|
return defaultInsightsApiV2Url
|
|
}
|
|
|
|
func CommunityServicesApiUrl() string {
|
|
envOverride := os.Getenv(communityServicesApiUrlEnvKey)
|
|
if envOverride != "" {
|
|
return envOverride
|
|
}
|
|
|
|
if (globalConfig != nil) && (globalConfig.CommunityServicesApiUrl != "") {
|
|
return globalConfig.CommunityServicesApiUrl
|
|
}
|
|
|
|
return defaultCommunityServicesApiUrl
|
|
}
|
|
|
|
func TenantDomain() string {
|
|
if tenantFromEnv, ok := os.LookupEnv(controlTowerTenantEnvKey); ok && tenantFromEnv != "" {
|
|
return tenantFromEnv
|
|
}
|
|
|
|
if tenantFromEnv, ok := os.LookupEnv(defaultSafeDepTenantIdEnvKey); ok && tenantFromEnv != "" {
|
|
return tenantFromEnv
|
|
}
|
|
|
|
if globalConfig != nil {
|
|
return globalConfig.TenantDomain
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
func ApiUrl() string {
|
|
if url, ok := os.LookupEnv(apiUrlEnvKey); ok {
|
|
return url
|
|
}
|
|
|
|
if CommunityMode() {
|
|
return defaultCommunityApiUrl
|
|
}
|
|
|
|
if globalConfig != nil {
|
|
return globalConfig.ApiUrl
|
|
}
|
|
|
|
return defaultApiUrl
|
|
}
|
|
|
|
func ApiKey() string {
|
|
if key, ok := os.LookupEnv(apiKeyEnvKey); ok {
|
|
return key
|
|
}
|
|
|
|
if key, ok := os.LookupEnv(apiKeyAlternateEnvKey); ok {
|
|
return key
|
|
}
|
|
|
|
if key, ok := os.LookupEnv(defaultSafeDepApiKeyEnvKey); ok {
|
|
return key
|
|
}
|
|
|
|
if globalConfig != nil {
|
|
return globalConfig.ApiKey
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
func CommunityMode() bool {
|
|
bRet, err := strconv.ParseBool(os.Getenv(communityModeEnvKey))
|
|
if (err == nil) && bRet {
|
|
return true
|
|
}
|
|
|
|
if globalConfig != nil {
|
|
return globalConfig.Community
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// SetRuntimeCommunityMode sets the runtime mode to community without
|
|
// persisting it to the configuration file.
|
|
func SetRuntimeCommunityMode() {
|
|
os.Setenv(communityModeEnvKey, "true")
|
|
}
|
|
|
|
func SetRuntimeCloudTenant(domain string) {
|
|
os.Setenv(controlTowerTenantEnvKey, domain)
|
|
}
|
|
|
|
func SetRuntimeApiKey(key string) {
|
|
os.Setenv(apiKeyEnvKey, key)
|
|
}
|
|
|
|
func loadConfiguration() error {
|
|
path, err := os.UserHomeDir()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
path = filepath.Join(path, homeRelativeConfigPath)
|
|
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var config Config
|
|
err = yaml.Unmarshal(data, &config)
|
|
if err != nil {
|
|
return fmt.Errorf("config deserialization failed: %w", err)
|
|
}
|
|
|
|
globalConfig = &config
|
|
return nil
|
|
}
|
|
|
|
func persistConfiguration() error {
|
|
data, err := yaml.Marshal(globalConfig)
|
|
if err != nil {
|
|
return fmt.Errorf("config serialization failed: %w", err)
|
|
}
|
|
|
|
path, err := os.UserHomeDir()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
path = filepath.Join(path, homeRelativeConfigPath)
|
|
|
|
_ = os.MkdirAll(filepath.Dir(path), os.ModePerm)
|
|
return os.WriteFile(path, data, 0o600)
|
|
}
|