package rootaws import ( "bytes" "fmt" "strings" "github.com/aws/aws-sdk-go-v2/aws" ) const MaxCredentialsSize = 64 << 10 // ParseStaticCredentials accepts only one default profile with literal keys. // Errors never include credential values or executable configuration text. func ParseStaticCredentials(body []byte) (aws.Credentials, error) { var empty aws.Credentials if len(body) > MaxCredentialsSize || bytes.IndexByte(body, 0) >= 0 { return empty, fmt.Errorf("invalid credentials size or encoding") } profile := false values := make(map[string]string) for _, line := range strings.Split(string(body), "\n") { line = strings.TrimSpace(line) if line == "" || strings.HasPrefix(line, "#") || strings.HasPrefix(line, ";") { continue } if strings.HasPrefix(line, "[") { if line != "[default]" || profile { return empty, fmt.Errorf("credentials require one default profile") } profile = true continue } // Same order as the SDK: cut the inline comment, then trim, then // remove one matching pair of quotes. key, value, found := strings.Cut(trimInlineComment(line), "=") key, value = strings.TrimSpace(key), unquote(strings.TrimSpace(value)) if !profile || !found || value == "" { return empty, fmt.Errorf("invalid static credentials entry") } switch key { case "aws_access_key_id", "aws_secret_access_key", "aws_session_token": default: return empty, fmt.Errorf("unsupported credentials key") } if _, exists := values[key]; exists || strings.ContainsAny(value, "\r\t ") { return empty, fmt.Errorf("duplicate or invalid static credentials entry") } values[key] = value } if values["aws_access_key_id"] == "" || values["aws_secret_access_key"] == "" { return empty, fmt.Errorf("credentials require access and secret keys") } return aws.Credentials{AccessKeyID: values["aws_access_key_id"], SecretAccessKey: values["aws_secret_access_key"], SessionToken: values["aws_session_token"], Source: "CarlosStaticCredentials"}, nil } // trimInlineComment matches the SDK's property comments: only a # or ; after // a space or tab starts one, so values may contain either character. func trimInlineComment(s string) string { for _, marker := range []string{" #", " ;", "\t#", "\t;"} { s, _, _ = strings.Cut(s, marker) } return s } func unquote(s string) string { if len(s) >= 2 && (s[0] == '"' && s[len(s)-1] == '"' || s[0] == '\'' && s[len(s)-1] == '\'') { return s[1 : len(s)-1] } return s }