Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NIP-96 sign payload, content field for file caption #148

Merged
merged 2 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions nip94/nip94.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type FileMetadata struct {
TorrentInfoHash string
Blurhash string
Thumb string
Content string
}

func (fm FileMetadata) IsVideo() bool { return strings.Split(fm.M, "/")[0] == "video" }
Expand Down
16 changes: 13 additions & 3 deletions nip96/nip96.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ package nip96
import (
"bytes"
"context"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"hash"
"io"
"mime/multipart"
"net/http"
Expand All @@ -26,14 +29,15 @@ func Upload(ctx context.Context, req UploadRequest) (*UploadResponse, error) {
}

var requestBody bytes.Buffer
fileHash := sha256.New()
writer := multipart.NewWriter(&requestBody)
{
// Add the file
fileWriter, err := writer.CreateFormFile("file", req.Filename)
if err != nil {
return nil, fmt.Errorf("multipartWriter.CreateFormFile: %w", err)
}
if _, err := io.Copy(fileWriter, req.File); err != nil {
if _, err := io.Copy(fileWriter, io.TeeReader(req.File, fileHash)); err != nil {
return nil, fmt.Errorf("io.Copy: %w", err)
}

Expand Down Expand Up @@ -61,7 +65,10 @@ func Upload(ctx context.Context, req UploadRequest) (*UploadResponse, error) {
uploadReq.Header.Set("Content-Type", writer.FormDataContentType())

if req.SK != "" {
auth, err := generateAuthHeader(req.SK, req.Host)
if !req.SignPayload {
fileHash = nil
}
auth, err := generateAuthHeader(req.SK, req.Host, fileHash)
if err != nil {
return nil, fmt.Errorf("generateAuthHeader: %w", err)
}
Expand Down Expand Up @@ -99,7 +106,7 @@ func Upload(ctx context.Context, req UploadRequest) (*UploadResponse, error) {
}
}

func generateAuthHeader(sk, host string) (string, error) {
func generateAuthHeader(sk, host string, fileHash hash.Hash) (string, error) {
pk, err := nostr.GetPublicKey(sk)
if err != nil {
return "", fmt.Errorf("nostr.GetPublicKey: %w", err)
Expand All @@ -114,6 +121,9 @@ func generateAuthHeader(sk, host string) (string, error) {
nostr.Tag{"method", "POST"},
},
}
if fileHash != nil {
event.Tags = append(event.Tags, nostr.Tag{"payload", hex.EncodeToString(fileHash.Sum(nil))})
}
event.Sign(sk)

b, err := json.Marshal(event)
Expand Down
1 change: 1 addition & 0 deletions nip96/nip96_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func TestUpload(t *testing.T) {
//Host: "https://nostrcheck.me/api/v2/media",
//Host: "https://nostrage.com/api/v2/media",
SK: nostr.GeneratePrivateKey(),
SignPayload: true,
File: img,
Filename: "ostrich.png",
Caption: "nostr ostrich",
Expand Down
6 changes: 5 additions & 1 deletion nip96/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ type UploadRequest struct {
// SK is a private key used to sign the NIP-98 Auth header. If not set
// the auth header will not be included in the upload.
SK string
// Optional signing of payload (file) as described in NIP-98, if enabled
// includes `payload` tag with file's sha256 in signed event / auth header.
SignPayload bool

// File is the file to upload.
File io.Reader
Expand Down Expand Up @@ -64,6 +67,7 @@ type UploadResponse struct {
Message string `json:"message"`
ProcessingURL string `json:"processing_url"`
Nip94Event struct {
Tags nostr.Tags `json:"tags"`
Tags nostr.Tags `json:"tags"`
Content string `json:"content"`
} `json:"nip94_event"`
}
Loading