2024-01-05 13:58:13 +00:00
|
|
|
package metadata
|
|
|
|
|
2024-03-01 05:18:07 +00:00
|
|
|
import (
|
2024-03-01 06:24:20 +00:00
|
|
|
"bytes"
|
|
|
|
"crypto/ed25519"
|
2024-03-01 05:18:07 +00:00
|
|
|
"errors"
|
2024-03-01 06:24:20 +00:00
|
|
|
"git.lumeweb.com/LumeWeb/libs5-go/encoding"
|
2024-03-01 05:18:07 +00:00
|
|
|
"git.lumeweb.com/LumeWeb/libs5-go/serialize"
|
|
|
|
"git.lumeweb.com/LumeWeb/libs5-go/types"
|
2024-03-01 06:24:20 +00:00
|
|
|
"git.lumeweb.com/LumeWeb/libs5-go/utils"
|
2024-03-01 05:18:07 +00:00
|
|
|
"github.com/vmihailenco/msgpack/v5"
|
2024-03-01 06:24:20 +00:00
|
|
|
"io"
|
|
|
|
"lukechampine.com/blake3"
|
|
|
|
_ "lukechampine.com/blake3"
|
2024-03-01 05:18:07 +00:00
|
|
|
)
|
|
|
|
|
2024-01-09 13:16:14 +00:00
|
|
|
var (
|
2024-03-01 05:18:07 +00:00
|
|
|
_ Metadata = (*MediaMetadata)(nil)
|
|
|
|
_ msgpack.CustomDecoder = (*MediaMetadata)(nil)
|
|
|
|
_ msgpack.CustomEncoder = (*MediaMetadata)(nil)
|
|
|
|
_ msgpack.CustomDecoder = (*mediaMap)(nil)
|
2024-01-09 13:16:14 +00:00
|
|
|
)
|
|
|
|
|
2024-03-01 05:18:07 +00:00
|
|
|
type mediaMap map[string][]MediaFormat
|
|
|
|
|
2024-01-05 13:58:13 +00:00
|
|
|
type MediaMetadata struct {
|
|
|
|
Name string
|
2024-03-01 05:18:07 +00:00
|
|
|
MediaTypes mediaMap
|
2024-01-05 13:58:13 +00:00
|
|
|
Parents []MetadataParentLink
|
|
|
|
Details MediaMetadataDetails
|
|
|
|
Links *MediaMetadataLinks
|
|
|
|
ExtraMetadata ExtraMetadata
|
2024-03-01 06:24:20 +00:00
|
|
|
provenPubKeys []*encoding.Multihash
|
2024-01-09 13:16:14 +00:00
|
|
|
BaseMetadata
|
2024-01-05 13:58:13 +00:00
|
|
|
}
|
|
|
|
|
2024-03-01 06:24:20 +00:00
|
|
|
func (m *MediaMetadata) ProvenPubKeys() []*encoding.Multihash {
|
|
|
|
return m.provenPubKeys
|
|
|
|
}
|
|
|
|
|
2024-01-05 13:58:13 +00:00
|
|
|
func NewMediaMetadata(name string, details MediaMetadataDetails, parents []MetadataParentLink, mediaTypes map[string][]MediaFormat, links *MediaMetadataLinks, extraMetadata ExtraMetadata) *MediaMetadata {
|
|
|
|
return &MediaMetadata{
|
|
|
|
Name: name,
|
|
|
|
Details: details,
|
|
|
|
Parents: parents,
|
|
|
|
MediaTypes: mediaTypes,
|
|
|
|
Links: links,
|
|
|
|
ExtraMetadata: extraMetadata,
|
|
|
|
}
|
|
|
|
}
|
2024-01-09 13:16:42 +00:00
|
|
|
func NewEmptyMediaMetadata() *MediaMetadata {
|
|
|
|
return &MediaMetadata{}
|
|
|
|
}
|
2024-03-01 05:18:07 +00:00
|
|
|
|
|
|
|
func (m *MediaMetadata) EncodeMsgpack(enc *msgpack.Encoder) error {
|
|
|
|
return errors.New("Not implemented")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *MediaMetadata) DecodeMsgpack(dec *msgpack.Decoder) error {
|
|
|
|
kind, err := serialize.InitUnmarshaller(dec, types.MetadataTypeProof, types.MetadataTypeMedia)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
switch kind {
|
|
|
|
case types.MetadataTypeProof:
|
|
|
|
return m.decodeProof(dec)
|
|
|
|
case types.MetadataTypeMedia:
|
|
|
|
return m.decodeMedia(dec)
|
|
|
|
default:
|
|
|
|
return errors.New("Invalid metadata type")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *MediaMetadata) decodeProof(dec *msgpack.Decoder) error {
|
2024-03-01 06:24:20 +00:00
|
|
|
all, err := io.ReadAll(dec.Buffered())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
proofSectionLength := utils.DecodeEndian(all[0:2])
|
|
|
|
|
2024-03-01 07:24:20 +00:00
|
|
|
all = all[2:]
|
|
|
|
|
|
|
|
bodyBytes := all[proofSectionLength:]
|
2024-03-01 06:24:20 +00:00
|
|
|
|
|
|
|
if proofSectionLength == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-03-01 07:24:20 +00:00
|
|
|
childDec := msgpack.NewDecoder(bytes.NewReader(all[:proofSectionLength]))
|
2024-03-01 06:24:20 +00:00
|
|
|
|
2024-03-01 07:36:11 +00:00
|
|
|
hash := blake3.Sum256(bodyBytes)
|
|
|
|
b3hash := append([]byte{byte(types.HashTypeBlake3)}, hash[:]...)
|
2024-03-01 06:24:20 +00:00
|
|
|
|
|
|
|
arrayLen, err := childDec.DecodeArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
provenPubKeys := make([]*encoding.Multihash, 0)
|
|
|
|
|
|
|
|
for i := 0; i < arrayLen; i++ {
|
|
|
|
proofData, err := childDec.DecodeSlice()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-03-01 06:41:15 +00:00
|
|
|
var hashType int8
|
|
|
|
var pubkey []byte
|
|
|
|
var signature []byte
|
|
|
|
|
2024-03-01 07:08:54 +00:00
|
|
|
if len(proofData) != 4 {
|
|
|
|
return errors.New("Invalid proof data length")
|
|
|
|
}
|
|
|
|
|
2024-03-01 06:24:20 +00:00
|
|
|
for j := 0; j < len(proofData); j++ {
|
|
|
|
|
|
|
|
switch j {
|
|
|
|
case 0:
|
2024-03-01 06:31:22 +00:00
|
|
|
sigType := proofData[j].(int8)
|
2024-03-01 06:24:20 +00:00
|
|
|
if types.MetadataProofType(sigType) != types.MetadataProofTypeSignature {
|
|
|
|
return errors.New("Invalid proof type")
|
|
|
|
}
|
|
|
|
case 1:
|
2024-03-01 06:36:18 +00:00
|
|
|
hashType = proofData[j].(int8)
|
|
|
|
if types.HashType(hashType) != types.HashTypeBlake3 {
|
2024-03-01 06:24:20 +00:00
|
|
|
return errors.New("Invalid hash type")
|
|
|
|
}
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
pubkey = proofData[j].([]byte)
|
2024-03-01 06:35:54 +00:00
|
|
|
if types.HashType(pubkey[0]) != types.HashTypeEd25519 {
|
2024-03-01 06:24:20 +00:00
|
|
|
return errors.New("Invalid public key type")
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(pubkey) != 33 {
|
|
|
|
return errors.New("Invalid public key length")
|
|
|
|
}
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
signature = proofData[j].([]byte)
|
|
|
|
|
2024-03-01 06:49:00 +00:00
|
|
|
if valid := ed25519.Verify(pubkey[1:], b3hash[:], signature); !valid {
|
2024-03-01 06:24:20 +00:00
|
|
|
return errors.New("Invalid signature")
|
|
|
|
}
|
|
|
|
|
|
|
|
provenPubKeys = append(provenPubKeys, encoding.NewMultihash(pubkey))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m.provenPubKeys = provenPubKeys
|
|
|
|
|
2024-03-01 07:46:10 +00:00
|
|
|
mediaDec := msgpack.NewDecoder(bytes.NewReader(bodyBytes))
|
|
|
|
|
|
|
|
mediaByte, err := mediaDec.DecodeUint8()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if types.MetadataType(mediaByte) != types.MetadataTypeMedia {
|
|
|
|
return errors.New("Invalid metadata type")
|
|
|
|
}
|
|
|
|
|
|
|
|
return m.decodeMedia(mediaDec)
|
2024-03-01 05:18:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m *MediaMetadata) decodeMedia(dec *msgpack.Decoder) error {
|
|
|
|
_, err := dec.DecodeArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = dec.Decode(&m.Name)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = dec.Decode(&m.Details)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-03-01 06:24:20 +00:00
|
|
|
arrLen, err := dec.DecodeArrayLen()
|
2024-03-01 05:18:07 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-03-01 06:24:20 +00:00
|
|
|
parents := make([]MetadataParentLink, arrLen)
|
|
|
|
for i := 0; i < arrLen; i++ {
|
|
|
|
parents[i].SetParent(m)
|
|
|
|
err = dec.Decode(&parents[i])
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-01 05:18:07 +00:00
|
|
|
err = dec.Decode(&m.MediaTypes)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = dec.Decode(&m.Links)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = dec.Decode(&m.ExtraMetadata)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *mediaMap) DecodeMsgpack(dec *msgpack.Decoder) error {
|
|
|
|
mapLen, err := dec.DecodeMapLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-03-01 08:17:03 +00:00
|
|
|
*m = make(map[string][]MediaFormat, mapLen)
|
|
|
|
|
2024-03-01 05:18:07 +00:00
|
|
|
for i := 0; i < mapLen; i++ {
|
|
|
|
typ, err := dec.DecodeString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var formats []MediaFormat
|
|
|
|
|
|
|
|
err = dec.Decode(&formats)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
(*m)[typ] = formats
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|