Skip to content

Instantly share code, notes, and snippets.

@nohe427
Created February 4, 2025 17:14
Show Gist options
  • Save nohe427/59eb70bf511d6e942c0ccc45bff2dfe2 to your computer and use it in GitHub Desktop.
Save nohe427/59eb70bf511d6e942c0ccc45bff2dfe2 to your computer and use it in GitHub Desktop.
A go file for generating signed urls
package hello
import (
"context"
"encoding/json"
"fmt"
"net/http"
"path/filepath"
"time"
"cloud.google.com/go/compute/metadata"
"cloud.google.com/go/logging"
"cloud.google.com/go/storage"
"github.com/GoogleCloudPlatform/functions-framework-go/functions"
"github.com/google/uuid"
)
func init() {
functions.HTTP("UploadImgTrip", GenerateUploadURL)
}
var (
projectId string = "projectId" // Only if you are not using metadata service
folder string = "srt"
folderPrefix string = "" //"object"
folderOfInterest string = folder // filepath.Join(folderPrefix, folder)
bucketName string = "PROJECTID.appspot.com"
)
func initLogger() *logging.Client {
ctx := context.Background()
client, err := logging.NewClient(ctx, logging.DetectProjectID)
if err != nil {
return nil
}
return client
}
// HelloHTTP is an HTTP Cloud Function with a request parameter.
func GenerateUploadURL(w http.ResponseWriter, r *http.Request) {
type o struct {
Uploadlocation string `json:"uploadLocation"`
DownloadLocation string `json:"downloadLocation"`
}
id := uuid.New()
outputName := filepath.Join(folder, id.String())
mimeType := r.Header.Get("mime")
v, err := generateV4PutObjectSignedURL(bucketName, outputName, mimeType)
if err != nil {
fmt.Printf("Could not sign object %s", err)
fmt.Fprintf(w, "Could not generate URL")
return
}
d, _ := generateV4GetObjectSignedURL(bucketName, outputName)
O := o{Uploadlocation: v, DownloadLocation: d}
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "*")
w.Header().Set("Access-Control-Allow-Headers", "*")
w.Header().Set("Content-Type", "application/json")
encoder := json.NewEncoder(w)
encoder.SetEscapeHTML(false)
encoder.Encode(O)
}
// generateV4GetObjectSignedURL generates object signed URL with GET method.
func generateV4GetObjectSignedURL(bucket, object string) (string, error) {
ctx := context.Background()
client, err := storage.NewClient(ctx)
if err != nil {
return "", fmt.Errorf("storage.NewClient: %w", err)
}
defer client.Close()
// Signing a URL requires credentials authorized to sign a URL. You can pass
// these in through SignedURLOptions with one of the following options:
// a. a Google service account private key, obtainable from the Google Developers Console
// b. a Google Access ID with iam.serviceAccounts.signBlob permissions
// c. a SignBytes function implementing custom signing.
// In this example, none of these options are used, which means the SignedURL
// function attempts to use the same authentication that was used to instantiate
// the Storage client. This authentication must include a private key or have
// iam.serviceAccounts.signBlob permissions.
opts := &storage.SignedURLOptions{
Scheme: storage.SigningSchemeV4,
Method: "GET",
Expires: time.Now().Add(15 * time.Minute),
}
u, err := client.Bucket(bucket).SignedURL(object, opts)
if err != nil {
return "", fmt.Errorf("Bucket(%q).SignedURL: %w", bucket, err)
}
fmt.Println("Generated GET signed URL:")
fmt.Printf("%q\n", u)
fmt.Println("You can use this URL with any user agent, for example:")
fmt.Printf("curl %q\n", u)
return u, nil
}
// generateV4GetObjectSignedURL generates object signed URL with PUT method.
func generateV4PutObjectSignedURL(bucket, object, mimeType string) (string, error) {
if mimeType == "" {
mimeType = "application/octet-stream"
}
ctx := context.Background()
client, err := storage.NewClient(ctx)
if err != nil {
return "", fmt.Errorf("storage.NewClient: %w", err)
}
defer client.Close()
// Signing a URL requires credentials authorized to sign a URL. You can pass
// these in through SignedURLOptions with one of the following options:
// a. a Google service account private key, obtainable from the Google Developers Console
// b. a Google Access ID with iam.serviceAccounts.signBlob permissions
// c. a SignBytes function implementing custom signing.
// In this example, none of these options are used, which means the SignedURL
// function attempts to use the same authentication that was used to instantiate
// the Storage client. This authentication must include a private key or have
// iam.serviceAccounts.signBlob permissions.
opts := &storage.SignedURLOptions{
Scheme: storage.SigningSchemeV4,
Method: "PUT",
Headers: []string{
fmt.Sprintf("Content-Type:%s", mimeType),
},
Expires: time.Now().Add(15 * time.Minute),
}
u, err := client.Bucket(bucket).SignedURL(object, opts)
if err != nil {
return "", fmt.Errorf("Bucket(%q).SignedURL: %w", bucket, err)
}
return u, nil
}
func fetchProjId() string {
id, err := metadata.ProjectID()
if err != nil {
fmt.Printf("Error getting metadata project id : %v", err)
id = projectId
}
return id
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment