diff --git a/ma.go b/ma.go index 442b400..b52df6d 100644 --- a/ma.go +++ b/ma.go @@ -1,7 +1,5 @@ package ma -import "time" - const ( // Just our name @@ -16,27 +14,19 @@ const ( // The rendezvous string used for peer discovery in libp2p. RENDEZVOUS = "/" + NAME + "/" + VERSION - // The topic prefix used in pubsub. It is the same as the rendezvous string. - // But we keep it separate for future flexibility. - TOPIC_PREFIX = RENDEZVOUS - // BLAKE3 label for symmetric key generation. HASH_ALGORITHM_MULTICODEC_STRING = "blake3" BLAKE3_LABEL = NAME BLAKE3_SUM_SIZE = 32 // 256 bits - // MIME types - - // A MIME type for a message. Just to implement it for future proofing. - MESSAGE_MIME_TYPE = "application/x-ma-message; version=" + VERSION - ENVELOPE_MIME_TYPE = "application/x-ma-envelope; version=" + VERSION + // Message constants + MESSAGE_TYPE = "/ma/message/" + VERSION + ENVELOPE_MESSAGE_TYPE = "/ma/message/envelope/" + VERSION + BROADCAST_MESSAGE_TYPE = "/ma/message/broadcast/" + VERSION - // Broadcasts - BROADCAST_MIME_TYPE = "application/x-ma-broadcast; version=" + VERSION - BROADCAST_TOPIC = "/" + NAME + "/broadcast/" + VERSION + BROADCAST_TOPIC = BROADCAST_MESSAGE_TYPE MESSAGE_DEFAULT_CONTENT_TYPE = "text/plain" - MESSAGE_DEFAULT_TTL = time.Hour * 24 // API DEFAULT_IPFS_API_MULTIADDR = "/ip4/127.0.0.1/tcp/45005" // Default to Brave browser, Kubo is /ip4/127.0.0.1/tcp/5001 diff --git a/msg/broadcast.go b/msg/broadcast.go index 43387ae..f0ccf95 100644 --- a/msg/broadcast.go +++ b/msg/broadcast.go @@ -26,9 +26,8 @@ func NewBroadcast( m := &Message{ // Message meta data - ID: id, - MimeType: ma.BROADCAST_MIME_TYPE, - Version: ma.VERSION, + Id: id, + Type: ma.BROADCAST_MESSAGE_TYPE, // Recipients From: from, // Body @@ -72,7 +71,7 @@ func (m *Message) Broadcast(ctx context.Context, t *pubsub.Topic) error { } func (m *Message) verifyBroadcast(t *pubsub.Topic) error { - if m.MimeType != ma.BROADCAST_MIME_TYPE { + if m.Type != ma.BROADCAST_MESSAGE_TYPE { return ErrMessageInvalidType } diff --git a/msg/errors.go b/msg/errors.go index 01665b3..74df8fa 100644 --- a/msg/errors.go +++ b/msg/errors.go @@ -10,7 +10,7 @@ import ( var ( ErrBroadcastHasRecipient = errors.New("broadcast message must not have a recipient") ErrBroadcastInvalidTopic = fmt.Errorf("broadcast topic must be %s", ma.BROADCAST_TOPIC) - ErrBroadcastInvalidType = fmt.Errorf("broadcast message must not %s", ma.BROADCAST_MIME_TYPE) + ErrBroadcastInvalidType = fmt.Errorf("broadcast message must not %s", ma.BROADCAST_MESSAGE_TYPE) ErrEmptyID = errors.New("id must be non-empty") ErrInvalidID = errors.New("invalid message id") ErrFetchDoc = errors.New("failed to fetch entity document") @@ -18,6 +18,7 @@ var ( ErrInvalidSender = errors.New("invalid sender") ErrInvalidRecipient = errors.New("invalid recipient") ErrMissingContentType = errors.New("empty ContentType") + ErrMissingContent = errors.New("empty ContentType") ErrMissingFrom = errors.New("mmissing From sender") ErrMissinSignature = errors.New("mmissing signature") ErrNilMessage = errors.New("nil Message provided") diff --git a/msg/headers.go b/msg/headers.go index d679d84..6a697a5 100644 --- a/msg/headers.go +++ b/msg/headers.go @@ -1,7 +1,6 @@ package msg import ( - semver "github.com/blang/semver/v4" cbor "github.com/fxamacker/cbor/v2" ) @@ -10,11 +9,9 @@ import ( // NB! Content is *not* a part of the headers type Headers struct { // Version of the message format - Version string - // Unique identifier of the message - ID string `cbor:"id"` + Id string `cbor:"id"` // MIME type of the message - MimeType string `cbor:"mimeType"` + Type string `cbor:"type"` // Sender of the message From string `cbor:"from"` // Recipient of the message @@ -29,9 +26,8 @@ func (m *Message) unsignedHeaders() Headers { return Headers{ // Message Headers - ID: m.ID, - MimeType: m.MimeType, - Version: m.Version, + Id: m.Id, + Type: m.Type, From: m.From, To: m.To, ContentType: m.ContentType, @@ -54,7 +50,3 @@ func (m *Message) Headers() Headers { func (m *Message) marshalHeadersToCBOR() ([]byte, error) { return cbor.Marshal(m.Headers()) } - -func (h *Headers) semVersion() (semver.Version, error) { - return semver.Make(h.Version) -} diff --git a/msg/message.go b/msg/message.go index 1dc60a9..43d23a5 100644 --- a/msg/message.go +++ b/msg/message.go @@ -11,21 +11,13 @@ import ( nanoid "github.com/matoous/go-nanoid/v2" ) -const ( - - // Messages which are older than a day should be ignored - MESSAGE_TTL = ma.MESSAGE_DEFAULT_TTL -) - // This struct mimicks the Message format, but it's *not* Message. // It should enable using Message later, if that's a good idea. type Message struct { - // Version of the message format - Version string `cbor:"version"` // Unique identifier of the message - ID string `cbor:"id"` + Id string `cbor:"id"` // MIME type of the message - MimeType string `cbor:"mimeType"` + Type string `cbor:"mimeType"` // Sender of the message From string `cbor:"from"` // Recipient of the message @@ -54,9 +46,8 @@ func New( m := &Message{ // Message meta data - ID: id, - MimeType: ma.MESSAGE_MIME_TYPE, - Version: ma.VERSION, + Id: id, + Type: ma.MESSAGE_TYPE, // Recipient From: from, To: to, @@ -66,6 +57,11 @@ func New( Content: content, } + err = verifyContent(content) + if err != nil { + return nil, err + } + err = m.Sign(priv_key) if err != nil { return nil, fmt.Errorf("msg_new: failed to sign message: %w", err) @@ -81,14 +77,13 @@ func newFromHeaders(h *Headers) (*Message, error) { err := h.validate() if err != nil { - return nil, fmt.Errorf("msg_new_from_headers: failed to validate headers: %w", err) + return nil, fmt.Errorf("newFromHeaders: %w", err) } m := &Message{ // Message meta data - ID: h.ID, - MimeType: h.MimeType, - Version: h.Version, + Id: h.Id, + Type: h.Type, // Recipient From: h.From, To: h.To, @@ -97,6 +92,7 @@ func newFromHeaders(h *Headers) (*Message, error) { // Signature Signature: h.Signature, } + return m, nil } diff --git a/msg/validate.go b/msg/validate.go index 932a85b..35ee528 100644 --- a/msg/validate.go +++ b/msg/validate.go @@ -2,6 +2,7 @@ package msg import ( "fmt" + "strings" "github.com/bahner/go-ma" "github.com/bahner/go-ma/did" @@ -18,29 +19,30 @@ func (h *Headers) validate() error { return ErrNilMessage } - if h.MimeType != ma.MESSAGE_MIME_TYPE && h.MimeType != ma.BROADCAST_MIME_TYPE { - return ErrMessageInvalidType + // Verify ID + err = verifyID(h.Id) + if err != nil { + return err } - // Check that message body headers are valid - if h.ContentType == "" { - return ErrMissingContentType + err = verifyType(h.Type) + if err != nil { + return err } - // Verify ID - err = h.verifyID() + // Message version check. Check the type first + err = verifyMessageVersion(h.Type) if err != nil { return err } - // Verify actors - err = h.verifyActors() + err = verifyContentType(h.ContentType) if err != nil { return err } - // Message version check - err = h.verifyMessageVersion() + // Verify actors + err = h.verifyActors() if err != nil { return err } @@ -49,9 +51,14 @@ func (h *Headers) validate() error { } // Compare messageVersion. Return nil if ok else an error -func (h *Headers) verifyMessageVersion() error { +// Takes the type string as input +func verifyMessageVersion(t string) error { + + // Split the string on "/" + parts := strings.Split(t, "/") - messageSemver, err := h.semVersion() + // Make a semver version from the last element + messageSemver, err := semver.Make(parts[len(parts)-1]) if err != nil { return err } @@ -89,7 +96,7 @@ func (h *Headers) verifyActors() error { return err } - if h.ContentType == ma.BROADCAST_MIME_TYPE { + if h.ContentType == ma.BROADCAST_MESSAGE_TYPE { if h.To != "" { return ErrBroadcastHasRecipient } @@ -110,14 +117,46 @@ func (h *Headers) verifyActors() error { } // Check that ID is valid -func (h *Headers) verifyID() error { - if h.ID == "" { +func verifyID(id string) error { + if id == "" { return ErrEmptyID } - if !internal.IsValidNanoID(h.ID) { + if !internal.IsValidNanoID(id) { return ErrInvalidID } return nil } + +func verifyType(t string) error { + + if t == ma.MESSAGE_TYPE || t == ma.BROADCAST_MESSAGE_TYPE { + return nil + } + + return ErrMessageInvalidType + +} + +// We don't want to parse this. That's up to the receiver +// But we do want to check that it is there. +func verifyContentType(ct string) error { + + if ct == "" { + return ErrMissingContentType + } + + return nil +} + +// We don't want to parse this. That's up to the receiver +// But we do want to check that it is there. +func verifyContent(c []byte) error { + + if c == nil { + return ErrMissingContent + } + + return nil +}