khatru/blossom: blossom ext updates.
see https://github.com/fiatjaf/khatru/pull/59
This commit is contained in:
@@ -7,7 +7,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"mime"
|
"mime"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -130,13 +129,17 @@ func (bs BlossomServer) handleUpload(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
hash := sha256.Sum256(b)
|
hash := sha256.Sum256(b)
|
||||||
hhash := hex.EncodeToString(hash[:])
|
hhash := hex.EncodeToString(hash[:])
|
||||||
|
mimeType := mime.TypeByExtension(ext)
|
||||||
|
if mimeType == "" {
|
||||||
|
mimeType = "application/octet-stream"
|
||||||
|
}
|
||||||
|
|
||||||
// keep track of the blob descriptor
|
// keep track of the blob descriptor
|
||||||
bd := BlobDescriptor{
|
bd := BlobDescriptor{
|
||||||
URL: bs.ServiceURL + "/" + hhash + ext,
|
URL: bs.ServiceURL + "/" + hhash + ext,
|
||||||
SHA256: hhash,
|
SHA256: hhash,
|
||||||
Size: len(b),
|
Size: len(b),
|
||||||
Type: mime.TypeByExtension(ext),
|
Type: mimeType,
|
||||||
Uploaded: nostr.Now(),
|
Uploaded: nostr.Now(),
|
||||||
}
|
}
|
||||||
if err := bs.Store.Keep(r.Context(), bd, auth.PubKey); err != nil {
|
if err := bs.Store.Keep(r.Context(), bd, auth.PubKey); err != nil {
|
||||||
@@ -146,7 +149,7 @@ func (bs BlossomServer) handleUpload(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
// save actual blob
|
// save actual blob
|
||||||
if nil != bs.StoreBlob {
|
if nil != bs.StoreBlob {
|
||||||
if err := bs.StoreBlob(r.Context(), hhash, b); err != nil {
|
if err := bs.StoreBlob(r.Context(), hhash, ext, b); err != nil {
|
||||||
blossomError(w, "failed to save: "+err.Error(), 500)
|
blossomError(w, "failed to save: "+err.Error(), 500)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -187,21 +190,27 @@ func (bs BlossomServer) handleGetBlob(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ext string
|
||||||
|
bd, err := bs.Store.Get(r.Context(), hhash)
|
||||||
|
if err != nil {
|
||||||
|
// can't find the BlobDescriptor, try to get the extension from the URL
|
||||||
|
if len(spl) == 2 {
|
||||||
|
ext = spl[1]
|
||||||
|
}
|
||||||
|
} else if bd != nil {
|
||||||
|
ext = getExtension(bd.Type)
|
||||||
|
}
|
||||||
|
|
||||||
if nil != bs.RejectGet {
|
if nil != bs.RejectGet {
|
||||||
reject, reason, code := bs.RejectGet(r.Context(), auth, hhash)
|
reject, reason, code := bs.RejectGet(r.Context(), auth, hhash, ext)
|
||||||
if reject {
|
if reject {
|
||||||
blossomError(w, reason, code)
|
blossomError(w, reason, code)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var ext string
|
|
||||||
if len(spl) == 2 {
|
|
||||||
ext = "." + spl[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
if bs.LoadBlob != nil {
|
if bs.LoadBlob != nil {
|
||||||
reader, redirectURL, err := bs.LoadBlob(r.Context(), hhash)
|
reader, redirectURL, err := bs.LoadBlob(r.Context(), hhash, ext)
|
||||||
if err == nil && redirectURL != nil {
|
if err == nil && redirectURL != nil {
|
||||||
// check that the redirectURL contains the hash of the file
|
// check that the redirectURL contains the hash of the file
|
||||||
if ok, _ := regexp.MatchString(`\b`+hhash+`\b`, redirectURL.String()); !ok {
|
if ok, _ := regexp.MatchString(`\b`+hhash+`\b`, redirectURL.String()); !ok {
|
||||||
@@ -329,9 +338,20 @@ func (bs BlossomServer) handleDelete(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ext string
|
||||||
|
bd, err := bs.Store.Get(r.Context(), hhash)
|
||||||
|
if err != nil {
|
||||||
|
// can't find the BlobDescriptor, try to get the extension from the URL
|
||||||
|
if len(spl) == 2 {
|
||||||
|
ext = spl[1]
|
||||||
|
}
|
||||||
|
} else if bd != nil {
|
||||||
|
ext = getExtension(bd.Type)
|
||||||
|
}
|
||||||
|
|
||||||
// should we accept this delete?
|
// should we accept this delete?
|
||||||
if nil != bs.RejectDelete {
|
if nil != bs.RejectDelete {
|
||||||
reject, reason, code := bs.RejectDelete(r.Context(), auth, hhash)
|
reject, reason, code := bs.RejectDelete(r.Context(), auth, hhash, ext)
|
||||||
if reject {
|
if reject {
|
||||||
blossomError(w, reason, code)
|
blossomError(w, reason, code)
|
||||||
return
|
return
|
||||||
@@ -347,7 +367,7 @@ func (bs BlossomServer) handleDelete(w http.ResponseWriter, r *http.Request) {
|
|||||||
// we will actually only delete the file if no one else owns it
|
// we will actually only delete the file if no one else owns it
|
||||||
if bd, err := bs.Store.Get(r.Context(), hhash); err == nil && bd == nil {
|
if bd, err := bs.Store.Get(r.Context(), hhash); err == nil && bd == nil {
|
||||||
if nil != bs.DeleteBlob {
|
if nil != bs.DeleteBlob {
|
||||||
if err := bs.DeleteBlob(r.Context(), hhash); err != nil {
|
if err := bs.DeleteBlob(r.Context(), hhash, ext); err != nil {
|
||||||
blossomError(w, "failed to delete blob: "+err.Error(), 500)
|
blossomError(w, "failed to delete blob: "+err.Error(), 500)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -415,7 +435,6 @@ func (bs BlossomServer) handleMirror(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
blossomError(w, "failed to read response body: "+err.Error(), 503)
|
blossomError(w, "failed to read response body: "+err.Error(), 503)
|
||||||
@@ -437,9 +456,10 @@ func (bs BlossomServer) handleMirror(w http.ResponseWriter, r *http.Request) {
|
|||||||
contentType := resp.Header.Get("Content-Type")
|
contentType := resp.Header.Get("Content-Type")
|
||||||
if contentType != "" {
|
if contentType != "" {
|
||||||
ext = getExtension(contentType)
|
ext = getExtension(contentType)
|
||||||
} else {
|
} else if ft, _ := magic.Lookup(body); ft != nil {
|
||||||
// try to detect from url
|
ext = "." + ft.Extension
|
||||||
ext = filepath.Ext(req.URL)
|
} else if idx := strings.LastIndex(req.URL, "."); idx != -1 {
|
||||||
|
ext = req.URL[idx:]
|
||||||
}
|
}
|
||||||
|
|
||||||
// run reject hook if defined
|
// run reject hook if defined
|
||||||
@@ -466,7 +486,7 @@ func (bs BlossomServer) handleMirror(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
// save actual blob
|
// save actual blob
|
||||||
if bs.StoreBlob != nil {
|
if bs.StoreBlob != nil {
|
||||||
if err := bs.StoreBlob(r.Context(), hhash, body); err != nil {
|
if err := bs.StoreBlob(r.Context(), hhash, ext, body); err != nil {
|
||||||
blossomError(w, "failed to save: "+err.Error(), 500)
|
blossomError(w, "failed to save: "+err.Error(), 500)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,15 +15,15 @@ type BlossomServer struct {
|
|||||||
ServiceURL string
|
ServiceURL string
|
||||||
Store BlobIndex
|
Store BlobIndex
|
||||||
|
|
||||||
StoreBlob func(ctx context.Context, sha256 string, body []byte) error
|
StoreBlob func(ctx context.Context, sha256 string, ext string, body []byte) error
|
||||||
LoadBlob func(ctx context.Context, sha256 string) (io.ReadSeeker, *url.URL, error)
|
LoadBlob func(ctx context.Context, sha256 string, ext string) (io.ReadSeeker, *url.URL, error)
|
||||||
DeleteBlob func(ctx context.Context, sha256 string) error
|
DeleteBlob func(ctx context.Context, sha256 string, ext string) error
|
||||||
ReceiveReport func(ctx context.Context, reportEvt nostr.Event) error
|
ReceiveReport func(ctx context.Context, reportEvt nostr.Event) error
|
||||||
|
|
||||||
RejectUpload func(ctx context.Context, auth *nostr.Event, size int, ext string) (bool, string, int)
|
RejectUpload func(ctx context.Context, auth *nostr.Event, size int, ext string) (bool, string, int)
|
||||||
RejectGet func(ctx context.Context, auth *nostr.Event, sha256 string) (bool, string, int)
|
RejectGet func(ctx context.Context, auth *nostr.Event, sha256 string, ext string) (bool, string, int)
|
||||||
RejectList func(ctx context.Context, auth *nostr.Event, pubkey nostr.PubKey) (bool, string, int)
|
RejectList func(ctx context.Context, auth *nostr.Event, pubkey nostr.PubKey) (bool, string, int)
|
||||||
RejectDelete func(ctx context.Context, auth *nostr.Event, sha256 string) (bool, string, int)
|
RejectDelete func(ctx context.Context, auth *nostr.Event, sha256 string, ext string) (bool, string, int)
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(rl *khatru.Relay, serviceURL string) *BlossomServer {
|
func New(rl *khatru.Relay, serviceURL string) *BlossomServer {
|
||||||
|
|||||||
@@ -22,15 +22,15 @@ func main() {
|
|||||||
bl.Store = blossom.EventStoreBlobIndexWrapper{Store: blobdb, ServiceURL: bl.ServiceURL}
|
bl.Store = blossom.EventStoreBlobIndexWrapper{Store: blobdb, ServiceURL: bl.ServiceURL}
|
||||||
|
|
||||||
// implement the required storage functions
|
// implement the required storage functions
|
||||||
bl.StoreBlob = func(ctx context.Context, sha256 string, body []byte) error {
|
bl.StoreBlob = func(ctx context.Context, sha256 string, ext string, body []byte) error {
|
||||||
// store the blob data somewhere
|
// store the blob data somewhere
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
bl.LoadBlob = func(ctx context.Context, sha256 string) (io.ReadSeeker, *url.URL, error) {
|
bl.LoadBlob = func(ctx context.Context, sha256 string, ext string) (io.ReadSeeker, *url.URL, error) {
|
||||||
// load and return the blob data, or a redirect URL
|
// load and return the blob data, or a redirect URL
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
bl.DeleteBlob = func(ctx context.Context, sha256 string) error {
|
bl.DeleteBlob = func(ctx context.Context, sha256 string, ext string) error {
|
||||||
// delete the blob data
|
// delete the blob data
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,11 +29,11 @@ func main() {
|
|||||||
}
|
}
|
||||||
bl := blossom.New(relay, "http://localhost:3334")
|
bl := blossom.New(relay, "http://localhost:3334")
|
||||||
bl.Store = blossom.EventStoreBlobIndexWrapper{Store: bdb, ServiceURL: bl.ServiceURL}
|
bl.Store = blossom.EventStoreBlobIndexWrapper{Store: bdb, ServiceURL: bl.ServiceURL}
|
||||||
bl.StoreBlob = func(ctx context.Context, sha256 string, body []byte) error {
|
bl.StoreBlob = func(ctx context.Context, sha256 string, ext string, body []byte) error {
|
||||||
fmt.Println("storing", sha256, len(body))
|
fmt.Println("storing", sha256, len(body))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
bl.LoadBlob = func(ctx context.Context, sha256 string) (io.ReadSeeker, *url.URL, error) {
|
bl.LoadBlob = func(ctx context.Context, sha256 string, ext string) (io.ReadSeeker, *url.URL, error) {
|
||||||
fmt.Println("loading", sha256)
|
fmt.Println("loading", sha256)
|
||||||
blob := strings.NewReader("aaaaa")
|
blob := strings.NewReader("aaaaa")
|
||||||
return blob, nil, nil
|
return blob, nil, nil
|
||||||
|
|||||||
Reference in New Issue
Block a user