# 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/abdularis/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
- 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
}
- 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
}
}
- 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
}
- 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
# Packages
No description provided by the author
# Functions
NewAlibabaOSSStorage create storage backed by alibaba oss.
NewAWSS3Storage create new storage backed by AWS S3.
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).
# Constants
No description provided by the author
No description provided by the author
No description provided by the author
# Interfaces
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.
# Type aliases
LocalStorageSignedURLBuilder is used to serve file temporarily in private directory mode.
No description provided by the author