package main import ( "bufio" "context" "encoding/json" "fmt" "log" "net/http" "net/url" "sort" "strings" s3 "github.com/minio/minio-go/v7" ) func router(w http.ResponseWriter, r *http.Request) { path := strings.TrimPrefix(r.URL.Path, "/v1/providers/") parts := strings.Split(path, "/") if len(parts) == 3 && parts[2] == "versions" { listVersions(w, parts[0], parts[1]) return } if len(parts) == 6 && parts[3] == "download" { downloadVersion(w, parts[0], parts[1], parts[2], parts[4], parts[5]) return } http.Error(w, "Not Found", http.StatusNotFound) } func listVersions(w http.ResponseWriter, namespace, pType string) { prefix := fmt.Sprintf("%s/%s/%s/", s3Prefix, namespace, pType) versions := []Version{} seenVersions := map[string]*Version{} objectCh := s3Client.ListObjects(context.Background(), bucketName, s3.ListObjectsOptions{ Prefix: prefix, Recursive: true, }) for object := range objectCh { if object.Err != nil { continue } parts := strings.Split(object.Key, "/") if len(parts) < 5 { continue } verStr := parts[3] fileName := parts[4] if _, ok := seenVersions[verStr]; !ok { seenVersions[verStr] = &Version{ Version: verStr, Protocols: []string{"5.0"}, Platforms: []Platform{}, } } if strings.Contains(fileName, "_darwin_amd64.zip") { seenVersions[verStr].Platforms = append(seenVersions[verStr].Platforms, Platform{OS: "darwin", Arch: "amd64"}) } if strings.Contains(fileName, "_linux_amd64.zip") { seenVersions[verStr].Platforms = append(seenVersions[verStr].Platforms, Platform{OS: "linux", Arch: "amd64"}) } if strings.Contains(fileName, "_windows_amd64.zip") { seenVersions[verStr].Platforms = append(seenVersions[verStr].Platforms, Platform{OS: "windows", Arch: "amd64"}) } } for _, v := range seenVersions { versions = append(versions, *v) } sort.Slice(versions, func(i, j int) bool { return versions[i].Version < versions[j].Version }) resp := VersionList{ ID: fmt.Sprintf("%s/%s", namespace, pType), Versions: versions, } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(resp) } func downloadVersion(w http.ResponseWriter, namespace, pType, version, osType, arch string) { basePath := fmt.Sprintf("%s/%s/%s/%s", s3Prefix, namespace, pType, version) filename := fmt.Sprintf("terraform-provider-%s_%s_%s_%s.zip", pType, version, osType, arch) fullKey := fmt.Sprintf("%s/%s", basePath, filename) shasumsKey := fmt.Sprintf("%s/terraform-provider-%s_%s_SHA256SUMS", basePath, pType, version) sigKey := fmt.Sprintf("%s/terraform-provider-%s_%s_SHA256SUMS.sig", basePath, pType, version) var shasumValue string shasumsObj, err := s3Client.GetObject(context.Background(), bucketName, shasumsKey, s3.GetObjectOptions{}) if err == nil { defer shasumsObj.Close() scanner := bufio.NewScanner(shasumsObj) for scanner.Scan() { line := scanner.Text() if strings.Contains(line, filename) { fields := strings.Fields(line) if len(fields) >= 1 { shasumValue = fields[0] } break } } if err := scanner.Err(); err != nil { log.Printf("Error scanning SHA256SUMS: %v", err) } } baseURL := "https://" + hostname downloadLink := fmt.Sprintf("%s/v1/proxy?bucket=%s&key=%s", baseURL, bucketName, url.QueryEscape(fullKey)) shasumsLink := fmt.Sprintf("%s/v1/proxy?bucket=%s&key=%s", baseURL, bucketName, url.QueryEscape(shasumsKey)) sigLink := fmt.Sprintf("%s/v1/proxy?bucket=%s&key=%s", baseURL, bucketName, url.QueryEscape(sigKey)) resp := DownloadResponse{ Protocols: []string{"5.0"}, OS: osType, Arch: arch, Filename: filename, DownloadURL: downloadLink, ShasumsURL: shasumsLink, ShasumsSignatureURL: sigLink, Shasum: shasumValue, SigningKeys: SigningKeys{ GPGPublicKeys: []GPGPublicKey{gpgPrimaryKey, gpgLegacyKey}, }, } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(resp) }