Commit 4a77bf4e authored by Lukas Matt's avatar Lukas Matt

Refactor Dispatcher/Receiver jobs

* Add custom time xml encoder/decoder
* Add reshare entity to post class
* Fix unit tests for recent changes
* Fix struct tag test
* Add unit test for custom xml coder

related to ganggo/ganggo@4383093ce34acb5335081ecbfdacbc53d3b83525
parent 5972d854
......@@ -18,6 +18,7 @@ package federation
//
const (
TIME_FORMAT = "2006-01-02T15:04:05Z"
XMLNS = "https://joindiaspora.com/protocol"
XMLNS_ME = "http://salmon-protocol.org/ns/magic-env"
APPLICATION_XML = "application/xml"
......@@ -36,8 +37,4 @@ const (
// webfinger
WebFingerOstatus = "http://ostatus.org/schema/1.0/subscribe"
WebFingerHcard = "http://microformats.org/profile/hcard"
// signature types
AuthorSignatureType = iota
ParentAuthorSignatureType
)
......@@ -78,6 +78,8 @@ func AuthorSignature(data interface{}, order string, privKey []byte) (string, er
if tag == o {
value := v.Field(i).Interface()
switch v := value.(type) {
case Time:
text += v.Format(TIME_FORMAT) + ";"
case string:
text += v + ";"
case bool:
......
......@@ -20,6 +20,7 @@ package federation
import (
"errors"
"encoding/xml"
"time"
)
type Message struct {
......@@ -49,6 +50,26 @@ type Entity struct {
Data interface{} `xml:"-"`
}
type Time struct {
time.Time
}
func (t *Time) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
e.EncodeElement(t.Format(TIME_FORMAT), start)
return nil
}
func (t *Time) UnmarshalXML(decoder *xml.Decoder, start xml.StartElement) error {
var value string
decoder.DecodeElement(&value, &start)
parse, err := time.Parse(TIME_FORMAT, value)
if err != nil {
return err
}
*t = Time{parse}
return nil
}
func (e *Entity) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
// NOTE since the encoder ignores the interface type
// (see https://golang.org/src/encoding/xml/read.go#L377)
......@@ -69,14 +90,19 @@ func (e *Entity) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
(*e).Type = local
(*e).Data = content
case StatusMessage:
fallthrough
case Reshare:
content := EntityStatusMessage{}
if err := d.DecodeElement(&content, &start); err != nil {
return err
}
(*e).Type = local
(*e).Data = content
case Reshare:
content := EntityReshare{}
if err := d.DecodeElement(&content, &start); err != nil {
return err
}
(*e).Type = local
(*e).Data = content
case Comment:
content := EntityComment{}
if err := d.DecodeElement(&content, &start); err != nil {
......
......@@ -28,7 +28,7 @@ func TestEntitiesUnmarshalXML(t *testing.T) {
var retractionRaw = []byte(`<retraction></retraction>`)
var profileRaw = []byte(`<profile></profile>`)
var statusMessageRaw = []byte(`<status_message></status_message>`)
//var reshareRaw = []byte(`<reshare></reshare>`)
var reshareRaw = []byte(`<reshare></reshare>`)
var commentRaw = []byte(`<comment></comment>`)
var likeRaw = []byte(`<like></like>`)
var contactRaw = []byte(`<contact></contact>`)
......@@ -41,6 +41,10 @@ func TestEntitiesUnmarshalXML(t *testing.T) {
if data, ok := entity.Data.(EntityRetraction); !ok {
t.Errorf("Expected to be 'like', got %v", data)
}
err = xml.Unmarshal(retractionRaw[:len(retractionRaw)-1], &entity)
if err == nil {
t.Errorf("Expected an error, got nil")
}
err = xml.Unmarshal(profileRaw, &entity)
if err != nil {
......@@ -49,6 +53,10 @@ func TestEntitiesUnmarshalXML(t *testing.T) {
if data, ok := entity.Data.(EntityProfile); !ok {
t.Errorf("Expected to be 'profile', got %v", data)
}
err = xml.Unmarshal(profileRaw[:len(profileRaw)-1], &entity)
if err == nil {
t.Errorf("Expected an error, got nil")
}
err = xml.Unmarshal(statusMessageRaw, &entity)
if err != nil {
......@@ -57,14 +65,22 @@ func TestEntitiesUnmarshalXML(t *testing.T) {
if data, ok := entity.Data.(EntityStatusMessage); !ok {
t.Errorf("Expected to be 'status_message', got %v", data)
}
err = xml.Unmarshal(statusMessageRaw[:len(statusMessageRaw)-1], &entity)
if err == nil {
t.Errorf("Expected an error, got nil")
}
//err = xml.Unmarshal(reshareRaw, &entity)
//if err != nil {
// t.Errorf("Some error occured while parsing: %v", err)
//}
//if data, ok := entity.Data.(EntityStatusMessage); !ok {
// t.Errorf("Expected to be 'reshare', got %v", data)
//}
err = xml.Unmarshal(reshareRaw, &entity)
if err != nil {
t.Errorf("Some error occured while parsing: %v", err)
}
if data, ok := entity.Data.(EntityReshare); !ok {
t.Errorf("Expected to be 'reshare', got %v", data)
}
err = xml.Unmarshal(reshareRaw[:len(reshareRaw)-1], &entity)
if err == nil {
t.Errorf("Expected an error, got nil")
}
err = xml.Unmarshal(commentRaw, &entity)
if err != nil {
......@@ -73,6 +89,10 @@ func TestEntitiesUnmarshalXML(t *testing.T) {
if data, ok := entity.Data.(EntityComment); !ok {
t.Errorf("Expected to be 'comment', got %v", data)
}
err = xml.Unmarshal(commentRaw[:len(commentRaw)-1], &entity)
if err == nil {
t.Errorf("Expected an error, got nil")
}
err = xml.Unmarshal(likeRaw, &entity)
if err != nil {
......@@ -81,6 +101,10 @@ func TestEntitiesUnmarshalXML(t *testing.T) {
if data, ok := entity.Data.(EntityLike); !ok {
t.Errorf("Expected to be 'like', got %v", data)
}
err = xml.Unmarshal(likeRaw[:len(likeRaw)-1], &entity)
if err == nil {
t.Errorf("Expected an error, got nil")
}
err = xml.Unmarshal(contactRaw, &entity)
if err != nil {
......@@ -89,9 +113,46 @@ func TestEntitiesUnmarshalXML(t *testing.T) {
if data, ok := entity.Data.(EntityContact); !ok {
t.Errorf("Expected to be 'contact', got %v", data)
}
err = xml.Unmarshal(contactRaw[:len(contactRaw)-1], &entity)
if err == nil {
t.Errorf("Expected an error, got nil")
}
err = xml.Unmarshal(notSupportedRaw, &entity)
if err == nil {
t.Errorf("Expected an error, got nil")
}
}
func TestEntitiesTimeMarshalAndUnmarshal(t *testing.T) {
// federation time format
// 2006-01-02T15:04:05Z
var time = "2018-01-19T01:32:23Z"
var rawXml = "<time><CreatedAt>"+time+"</CreatedAt></time>";
var origTime = struct {
XMLName xml.Name `xml:"time"`
CreatedAt Time
}{}
err := xml.Unmarshal([]byte(rawXml), &origTime)
if err != nil {
t.Errorf("Some error occured while parsing: %v", err)
}
if origTime.CreatedAt.Time.Format(TIME_FORMAT) != time {
t.Errorf("Expected to be '%s', got '%s'",
origTime.CreatedAt.Time.Format(TIME_FORMAT))
}
result, err := xml.Marshal(origTime)
if err != nil {
t.Errorf("Some error occured while parsing: %v", err)
}
if string(result) != rawXml {
t.Errorf("Expected to be '%s', got '%s'", result, rawXml)
}
err = xml.Unmarshal([]byte("<time><CreatedAt></CreatedAt></time>"), &origTime)
if err == nil {
t.Errorf("Expected an error, got nil")
}
}
......@@ -17,38 +17,28 @@ package federation
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
import (
"encoding/xml"
"errors"
)
import "encoding/xml"
type EntityComment struct {
XMLName xml.Name `xml:"comment"`
Author string `xml:"author"`
CreatedAt string `xml:"created_at"`
CreatedAt Time `xml:"created_at"`
Guid string `xml:"guid"`
ParentGuid string `xml:"parent_guid"`
Text string `xml:"text"`
AuthorSignature string `xml:"author_signature"`
ParentAuthorSignature string `xml:"parent_author_signature"`
}
func (e *EntityComment) SignatureOrder() string {
return "author created_at guid parent_guid text"
}
func (e *EntityComment) AppendSignature(privKey []byte, order string, typ int) error {
func (e *EntityComment) AppendSignature(privKey []byte, order string) error {
signature, err := AuthorSignature(*e, order, privKey)
if err != nil {
return err
}
(*e).AuthorSignature = signature
if AuthorSignatureType == typ {
(*e).AuthorSignature = signature
} else if ParentAuthorSignatureType == typ {
(*e).ParentAuthorSignature = signature
} else {
return errors.New("Unsupported author signature type!")
}
return nil
}
......@@ -17,7 +17,10 @@ package federation
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
import "testing"
import (
"testing"
"time"
)
func TestCommentSignatureOrder(t *testing.T) {
var comment EntityComment
......@@ -31,8 +34,8 @@ func TestCommentSignatureOrder(t *testing.T) {
func TestCommentAppendSignature(t *testing.T) {
comment := EntityComment{
Author: "author@localhost",
CreatedAt: "01.01.1970",
Guid: "1234",
CreatedAt: Time{time.Now()},
ParentGuid: "4321",
Text: "hello world",
}
......@@ -41,12 +44,7 @@ func TestCommentAppendSignature(t *testing.T) {
t.Errorf("Expected to be empty, got %s", comment.AuthorSignature)
}
if comment.ParentAuthorSignature != "" {
t.Errorf("Expected to be empty, got %s", comment.AuthorSignature)
}
err := comment.AppendSignature(TEST_PRIV_KEY,
comment.SignatureOrder(), AuthorSignatureType)
err := comment.AppendSignature(TEST_PRIV_KEY, comment.SignatureOrder())
if err != nil {
t.Errorf("Some error occured while parsing: %v", err)
}
......@@ -55,13 +53,8 @@ func TestCommentAppendSignature(t *testing.T) {
t.Errorf("Expected signature, was empty")
}
err = comment.AppendSignature(TEST_PRIV_KEY,
comment.SignatureOrder(), ParentAuthorSignatureType)
err = comment.AppendSignature(TEST_PRIV_KEY, comment.SignatureOrder())
if err != nil {
t.Errorf("Some error occured while parsing: %v", err)
}
if comment.ParentAuthorSignature == "" {
t.Errorf("Expected signature, was empty")
}
}
......@@ -17,38 +17,28 @@ package federation
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
import (
"encoding/xml"
"errors"
)
import "encoding/xml"
type EntityLike struct {
XMLName xml.Name `xml:"like"`
Positive bool `xml:"positive"`
Guid string `xml:"guid"`
ParentGuid string `xml:"parent_guid"`
TargetType string `xml:"parent_type"`
ParentType string `xml:"parent_type"`
Author string `xml:"author"`
AuthorSignature string `xml:"author_signature"`
ParentAuthorSignature string `xml:"parent_author_signature"`
}
func (e *EntityLike) SignatureOrder() string {
return "positive guid parent_guid target_type author"
return "positive guid parent_guid parent_type author"
}
func (e *EntityLike) AppendSignature(privKey []byte, order string, typ int) error {
func (e *EntityLike) AppendSignature(privKey []byte, order string) error {
signature, err := AuthorSignature(*e, order, privKey)
if err != nil {
return err
}
(*e).AuthorSignature = signature
if AuthorSignatureType == typ {
(*e).AuthorSignature = signature
} else if ParentAuthorSignatureType == typ {
(*e).ParentAuthorSignature = signature
} else {
return errors.New("Unsupported author signature type!")
}
return nil
}
......@@ -23,7 +23,7 @@ import "testing"
func TestLikeSignatureOrder(t *testing.T) {
var like EntityLike
expected := "positive guid parent_guid target_type author"
expected := "positive guid parent_guid parent_type author"
if expected != like.SignatureOrder() {
t.Errorf("Expected to be %s, got %s", expected, like.SignatureOrder())
}
......@@ -34,7 +34,7 @@ func TestLikeAppendSignature(t *testing.T) {
Positive: true,
Guid: "1234",
ParentGuid: "4321",
TargetType: "Post",
ParentType: "Post",
Author: "author@localhost",
}
......@@ -42,12 +42,7 @@ func TestLikeAppendSignature(t *testing.T) {
t.Errorf("Expected to be empty, got %s", like.AuthorSignature)
}
if like.ParentAuthorSignature != "" {
t.Errorf("Expected to be empty, got %s", like.AuthorSignature)
}
err := like.AppendSignature(TEST_PRIV_KEY,
like.SignatureOrder(), AuthorSignatureType)
err := like.AppendSignature(TEST_PRIV_KEY, like.SignatureOrder())
if err != nil {
t.Errorf("Some error occured while parsing: %v", err)
}
......@@ -56,13 +51,8 @@ func TestLikeAppendSignature(t *testing.T) {
t.Errorf("Expected signature, was empty")
}
err = like.AppendSignature(TEST_PRIV_KEY,
like.SignatureOrder(), ParentAuthorSignatureType)
err = like.AppendSignature(TEST_PRIV_KEY, like.SignatureOrder())
if err != nil {
t.Errorf("Some error occured while parsing: %v", err)
}
if like.ParentAuthorSignature == "" {
t.Errorf("Expected signature, was empty")
}
}
......@@ -17,32 +17,36 @@ package federation
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
import (
"time"
"encoding/xml"
)
import "encoding/xml"
type EntityStatusMessage struct {
XMLName xml.Name `xml:"status_message"`
Author string `xml:"author"`
Guid string `xml:"guid"`
CreatedAt time.Time `xml:"created_at"`
CreatedAt Time `xml:"created_at"`
ProviderName string `xml:"provider_display_name"`
Text string `xml:"text,omitempty"`
Photo *EntityPhotos `xml:"photo,omitempty"`
Location *EntityLocation `xml:"location,omitempty"`
Poll *EntityPoll `xml:"poll,omitempty"`
Public bool `xml:"public"`
// on reshare
RootHandle string `xml:"root_diaspora_id,omitempty"`
RootGuid string `xml:"root_guid,omitempty"`
Event *EntityEvent `xml:"event,omitempty"`
}
type EntityReshare struct {
XMLName xml.Name `xml:"reshare"`
Author string `xml:"author"`
Guid string `xml:"guid"`
CreatedAt Time `xml:"created_at"`
RootAuthor string `xml:"root_author"`
RootGuid string `xml:"root_guid"`
}
type EntityPhoto struct {
Guid string `xml:"guid"`
Author string `xml:"author"`
Public bool `xml:"public"`
CreatedAt time.Time `xml:"created_at"`
CreatedAt Time `xml:"created_at"`
RemotePhotoPath string `xml:"remote_photo_path"`
RemotePhotoName string `xml:"remote_photo_name"`
Text string `xml:"text"`
......@@ -70,6 +74,14 @@ type EntityPollAnswer struct {
Answer string `xml:"answer"`
}
type PollParticipation struct {
PollAnswerGuid string `xml:"poll_answer_guid"`
type EntityEvent struct {
Author string `xml:"author"`
Guid string `xml:"guid"`
Summary string `xml:"summary"`
Start Time `xml:"start"`
End Time `xml:"end"`
AllDay bool `xml:"all_day"`
Timezone string `xml:"timezone"`
Description string `xml:"description"`
Location *EntityLocation `xml:"location,omitempty"`
}
......@@ -27,9 +27,9 @@ import (
)
type Test struct {
XMLName xml.Name `xml:"AB";json:"-"`
A string `xml:"A";json:"A"`
B string `xml:"B";json:"B"`
XMLName xml.Name `xml:"AB" json:"-"`
A string `xml:"A" json:"A"`
B string `xml:"B" json:"B"`
}
func TestPushToPrivate(t *testing.T) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment