metafeed

package module
v1.1.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 11, 2023 License: MIT Imports: 16 Imported by: 0

README

go-metafeeds

This Go module implements the bendy butt specification to encode and verify feed entries in that format and offers utility functions for creating and verifiying signed content entries as required by the meta feed spec.

This repository also offers JSON test vectors to assist in testing implementations in other languages.

Usage

See the Go Reference for an exhaustive list of all the APIs this package offers.

The metamngmt Package offers helper types and functions to create the necessary types to manage the subfeeds of a metafeed.

To get the complete picture, read internal/vectors/gen_good_test.go which creates the testvector-metafeed-managment.json and goes through all the steps of creating feed entries and signing subfeeds.

Generating Vectors

Test vector generation is facilitated through Go's testing system.

To regenerate the vectors (e.g. after having changed vector generation ./internal/vectors), run the go test command:

cd internal/vectors/
go test

(Alternatively: stand in the root of the repo and run go test ./internal/vectors/)

License

The code is licenses under MIT.

The test vectors are licensed under Creative Commons Attribution Share Alike 4.0.

REUSE status

Documentation

Overview

Package metafeed implements the SSB metafeed spec to enable partial replication.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func SetNow

func SetNow(fn func() time.Time)

SetNow can be used to create arbitrary timestamps on a message. Mostly used for testing.

func SubSignContent

func SubSignContent(pk ed25519.PrivateKey, content bencode.Marshaler) (bencode.RawMessage, error)

SubSignContent uses the passed private key to sign the passed content after it was encoded. It then packs both fields as an array [content, signature]. TODO: add hmac signing

func VerifySubSignedContent

func VerifySubSignedContent(rawMessage []byte, content bencode.Unmarshaler) error

VerifySubSignedContent expects an array of [content, signature] where 'content' needs to contain a 'subfeed' field which contains the tfk encoded publickey to verify the signature. TODO: add hmac signing

Types

type Encoder

type Encoder struct {
	// contains filtered or unexported fields
}

Encoder exposes two control options for timestamps and the hmac key and the Encode() function which creates new signed messages.

func NewEncoder

func NewEncoder(author ed25519.PrivateKey) *Encoder

NewEncoder creates an encoding facility which uses the passed author to sign new messages

func (*Encoder) Encode

func (e *Encoder) Encode(sequence int32, prev refs.MessageRef, val interface{}) (*Message, refs.MessageRef, error)

Encode uses the passed sequence and previous message reference to create a signed messages over the passed value.

func (*Encoder) WithHMAC

func (e *Encoder) WithHMAC(in []byte) error

WithHMAC update the HMAC signing secret

func (*Encoder) WithNowTimestamps

func (e *Encoder) WithNowTimestamps(yes bool)

WithNowTimestamps controls wether timestamps should be used to create new messages

type Message

type Message struct {
	Data bencode.RawMessage

	Signature []byte
	// contains filtered or unexported fields
}

Message is used to create the (un)marshal a message to and from bencode while also acting as refs.Message for the rest of the ssb system.

func (*Message) Author

func (msg *Message) Author() refs.FeedRef

Author returns the author who signed the message

func (*Message) Claimed

func (msg *Message) Claimed() time.Time

Claimed returns the time the message claims as it's timestamp

func (*Message) ContentBytes

func (msg *Message) ContentBytes() []byte

ContentBytes returns the pure bencoded content portion of the message

func (*Message) Key

func (msg *Message) Key() refs.MessageRef

Key returns the hash reference of the message

func (*Message) MarshalBencode

func (msg *Message) MarshalBencode() ([]byte, error)

MarshalBencode turns data and signature into an bencode array [content, signature]

func (*Message) MarshalBinary

func (msg *Message) MarshalBinary() ([]byte, error)

MarshalBinary for now, calls the bencode versions (performance profiling pending)

func (*Message) Payload

func (msg *Message) Payload() (Payload, error)

Payload returns the message payload inside the data portion of the Message object.

func (*Message) Previous

func (msg *Message) Previous() *refs.MessageRef

Previous return nil for the first message and otherwise the hash reference of the previous message

func (*Message) Received

func (msg *Message) Received() time.Time

Received needs to be repalced by the database (this spoofs it as the calimed timestamp)

func (*Message) Seq

func (msg *Message) Seq() int64

Seq returns the sequence of th message

func (*Message) UnmarshalBencode

func (msg *Message) UnmarshalBencode(input []byte) error

UnmarshalBencode expects a benocded array of [content, signature]

func (*Message) UnmarshalBinary

func (msg *Message) UnmarshalBinary(input []byte) error

UnmarshalBinary for now, calls the bencode versions (performance profiling pending)

func (*Message) ValueContent

func (msg *Message) ValueContent() *refs.Value

ValueContent returns a ssb.Value that can be represented as JSON. Note that it's signature is useless for verification in this form. Get the whole Message message and use msg.Verify()

func (*Message) ValueContentJSON

func (msg *Message) ValueContentJSON() json.RawMessage

ValueContentJSON encodes the Message into JSON like a normal SSB message.

func (*Message) Verify

func (msg *Message) Verify(hmacKey *[32]byte) bool

Verify returns true if the Message was signed by the author specified by the meta portion of the message

type Payload

type Payload struct {
	Author    refs.FeedRef
	Sequence  int
	Previous  *refs.MessageRef
	Timestamp time.Time
	Content   bencode.RawMessage
}

Payload represents a single Payload on a metafeed.

Example
package main

import (
	"bytes"
	"encoding/hex"
	"fmt"
	"io"
	"os"
	"time"

	refs "github.com/ssbc/go-ssb-refs"
	"github.com/ssbc/go-ssb-refs/tfk"
	"github.com/zeebo/bencode"

	metafeed "github.com/ssbc/go-metafeed"
)

func check(err error) {
	if err != nil {
		panic(err)
	}
}

func createTestEntry(author refs.FeedRef) metafeed.Payload {

	return metafeed.Payload{
		Author:    author,
		Sequence:  1,
		Previous:  nil,
		Timestamp: time.Unix(10, 0),
		Content:   bencode.RawMessage("12:hello, world"),
	}
}

func main() {
	pubKey := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}
	exAuthor, err := refs.NewFeedRefFromBytes(pubKey, refs.RefAlgoFeedBendyButt)
	check(err)

	exampleFile, err := os.OpenFile("example-feed-entry.bendybutt", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0600)
	check(err)
	defer exampleFile.Close()

	var (
		buf    bytes.Buffer
		dumper = hex.Dumper(os.Stdout)
		w      = io.MultiWriter(&buf, dumper, exampleFile)

		entry = createTestEntry(exAuthor)
	)

	encoded, err := entry.MarshalBencode()
	check(err)

	_, err = w.Write(encoded)
	check(err)

	var decodedEntry []interface{}
	err = bencode.NewDecoder(&buf).Decode(&decodedEntry)
	check(err)

	authorAsString := decodedEntry[0].(string)
	var decodedAuthor tfk.Feed
	err = decodedAuthor.UnmarshalBinary([]byte(authorAsString))
	check(err)

	decodedAuthorRef, err := decodedAuthor.Feed()
	check(err)

	if !decodedAuthorRef.Equal(exAuthor) {
		fmt.Println("wrong author")
	}

}
Output:

00000000  6c 33 34 3a 00 03 01 02  03 04 05 06 07 08 09 0a  |l34:............|
00000010  0b 0c 0d 0e 0f 10 11 12  13 14 15 16 17 18 19 1a  |................|
00000020  1b 1c 1d 1e 1f 20 69 31  65 32 3a 06 02 69 31 30  |..... i1e2:..i10|
00000030  65 31 32 3a 68 65 6c 6c  6f 2c 20 77 6f 72 6c 64  |e12:hello, world|
00000040  65

func (*Payload) MarshalBencode

func (p *Payload) MarshalBencode() ([]byte, error)

MarshalBencode turns the payload into an array of 5 elements: author as tfk, sequence, previous as tfk, timestamp as unix ts and content as a bencode entity (usually object or byte string for box2)

func (*Payload) UnmarshalBencode

func (p *Payload) UnmarshalBencode(input []byte) error

UnmarshalBencode does the reverse of MarshalBencode. It expects the input to be a bencoded array of 5 entries.

Directories

Path Synopsis
internal
bencodeext
Package bencodeext defines some extenstions for bencode to work better with the existing JavaScript type system.
Package bencodeext defines some extenstions for bencode to work better with the existing JavaScript type system.
sign
Package sign implements the signature creation and verification used in bendybutt powered metafeeds.
Package sign implements the signature creation and verification used in bendybutt powered metafeeds.
vectors
Package vectors sists in internal because it also contains code to produce bad/invalid messages.
Package vectors sists in internal because it also contains code to produce bad/invalid messages.
Package metamngmt contains all the managment types that one needs to have in order to work with metafeeds.
Package metamngmt contains all the managment types that one needs to have in order to work with metafeeds.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL