gostorage

package module
v0.0.3-alpha2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 16, 2021 License: MIT Imports: 17 Imported by: 0

README

Go Storage

Provide simple storage abstraction for easily working with file object using different storage mechanism.

Storage Implementation:

Usage

Install (go 1.15+)

go get -u github.com/commonlib-dev/go-storage

Implementation

Local Storage

If you're using local storage you need to provide root or base path where you would store files for public or private usage.

Then create endpoints to serve those public or private files using your http library of choice.

In order to serve private files you can create a signed request to temporarily give access to URL.

Configuration Example using go gin:

The complete sample source code here

  1. Create function to generate HMAC signature for a particular resource URI
const secret = "this-is-your-hmac-secret"

func generateHmac(expireAt string, requestURI string) (string, error) {
	data, err := json.Marshal(map[string]interface{} {
		"expireAt": expireAt,
		"requestURI": requestURI,
	})
	if err != nil {
		return "", err
	}

	h := hmac.New(sha512.New, []byte(secret))
	h.Write(data)
	return base64.RawURLEncoding.EncodeToString(h.Sum(nil)), nil
}
  1. Create gin middleware to check for signed URL
func signedURLMiddleware(context *gin.Context) {
	expireAt := context.Query("expireAt")
	expire, err := strconv.ParseInt(expireAt, 10, 64)
	if err != nil {
		context.AbortWithStatusJSON(400, "Invalid expiration arg")
		return
	}

	if time.Now().Unix() > expire {
		context.AbortWithStatusJSON(400, "URL expired")
		return
	}

	u := context.Request.URL
	q := u.Query()

	signature := q.Get("signature")
	q.Del("signature")
	u.RawQuery = q.Encode()

	generatedSignature, err := generateHmac(expireAt, u.RequestURI())

	if generatedSignature != signature {
		context.AbortWithStatusJSON(403, "No Access Sorry Bre 🤚 ⛔")
		return
	}
}
  1. Create signed URL builder function to be provided to local storage constructor, it is used by local storage implementation to generate a download signed URL for particular private file object
func signedURLBuilder(absoluteFilePath string, objectPath string, expireIn time.Duration) (string, error) {
	u, err := url.Parse("http://localhost:8000/private/files")
	if err != nil {
		return "", err
	}

	expireAt := fmt.Sprintf("%d", time.Now().Add(expireIn).Unix())

	q := u.Query()
	q.Add("expireAt", expireAt)

	u.Path = path.Join(u.Path, objectPath)
	u.RawQuery = q.Encode()

	signature, err := generateHmac(expireAt, u.RequestURI())
	if err != nil {
		return "", err
	}

	q.Add("signature", signature)
	u.RawQuery = q.Encode()

	return u.String(), nil
}
  1. Instantiate storage and serve public/private files using gin router with StaticFS() route function.
func main() {
	c := gin.Default()

	// Serve public files
	c.StaticFS("/files", http.Dir("storage/public"))

	// Serve private files
	c.Use(signedURLMiddleware).StaticFS("/private/files", http.Dir("storage/private"))

	storage := gostorage.NewLocalStorage(
		"storage/private",
		"storage/public",
		"http://localhost:8000/files",
		signedURLBuilder)

	dataSource := strings.NewReader("Hello, this is content 😊 😅 updated")
	_ = storage.Put("user-files/sample.txt", dataSource, gostorage.ObjectPublicRead)

	// will generate: http://localhost:8000/files/user-files/sample.txt
	publicURL, _ := storage.URL("user-files/sample.txt")
	
	// will generate: http://localhost:8000/private/files/user-files/sample.txt?expireAt=1619449697&signature=JB9d6dFOPhVLzp83EIkws2UGWMQqvnTnMGXDVY9HTZKb92TpI7K2UeocO4xgxQyhBtgeFfVMfz-NCjBB3Aeuxw
	singedURL, _ = storage.TemporaryURL("user-files/sample.txt", time.Minute)
}
AWS S3

TODO

Alibaba OSS

TODO

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type LocalStorageSignedURLBuilder

type LocalStorageSignedURLBuilder func(absoluteFilePath string, objectPath string, expireIn time.Duration) (string, error)

LocalStorageSignedURLBuilder is used to serve file temporarily in private directory mode

type ObjectVisibility

type ObjectVisibility string
const (
	ObjectPrivate         ObjectVisibility = "private"
	ObjectPublicReadWrite ObjectVisibility = "public-read-write"
	ObjectPublicRead      ObjectVisibility = "public-read"
)

type Storage

type Storage interface {
	// Read return reader to stream data from source
	Read(objectPath string) (io.ReadCloser, error)

	// Put store source stream into
	Put(objectPath string, source io.Reader, visibility ObjectVisibility) error

	// Delete object by objectPath
	Delete(objectPaths ...string) error

	// URL return object url
	URL(objectPath string) (string, error)

	// TemporaryURL give temporary access to an object using returned signed url
	TemporaryURL(objectPath string, expireIn time.Duration) (string, error)

	// Copy source to destination
	Copy(srcObjectPath string, dstObjectPath string) error

	// Size return object size
	Size(objectPath string) (int64, error)

	// LastModified 	return last modified time of object
	LastModified(objectPath string) (time.Time, error)

	// Exist check whether object exists
	Exist(objectPath string) (bool, error)

	// SetVisibility update object visibility for a given object path
	SetVisibility(objectPath string, visibility ObjectVisibility) error

	// GetVisibility return object visibility for a given object path
	GetVisibility(objectPath string) (ObjectVisibility, error)
}

Storage is an abstraction for persistence storage mechanism, remember that all object path used here should be specified relative to the root location configured for each implementation

func NewAWSS3Storage

func NewAWSS3Storage(
	bucketName string,
	region string,
	accessKeyID string,
	secretAccessKey string,
	sessionToken string) Storage

NewAWSS3Storage create new storage backed by AWS S3

func NewAlibabaOSSStorage

func NewAlibabaOSSStorage(
	bucketName string,
	endpoint string,
	accessID string,
	accessSecret string) Storage

NewAlibabaOSSStorage create storage backed by alibaba oss

func NewLocalStorage

func NewLocalStorage(
	baseDir string,
	publicBaseDir string,
	publicBaseURL string,
	signedURLBuilder LocalStorageSignedURLBuilder) Storage

NewLocalStorage create local file storage with given params baseDir: base directory where a private file is stored (conventionally directory should not publicly serve over http) publicBaseDir: base directory where a public file reside, the file actually a link from baseDir, directory should be publicly serve over http publicBaseURL: base URL where to be concatenated with objectPath to build full file download URL signedURLBuilder: used to generate temporary download URL for serving private files if needed (provide nil will always return error)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL