entities.go 3.61 KB
Newer Older
Lukas Matt's avatar
Lukas Matt committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
package federation
//
// GangGo Diaspora Federation Library
// Copyright (C) 2017 Lukas Matt <lukas@zauberstuhl.de>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

20 21
import (
  "errors"
Lukas Matt's avatar
Lukas Matt committed
22 23
  "github.com/Zauberstuhl/go-xml"
  "encoding/base64"
24
  "time"
25
)
Lukas Matt's avatar
Lukas Matt committed
26

27
type Message struct {
Lukas Matt's avatar
Lukas Matt committed
28
  XMLName xml.Name `xml:"me:env"`
29 30
  Me string `xml:"me,attr"`
  Data struct {
Lukas Matt's avatar
Lukas Matt committed
31
    XMLName xml.Name `xml:"me:data"`
32 33
    Type string `xml:"type,attr"`
    Data string `xml:",chardata"`
Lukas Matt's avatar
Lukas Matt committed
34
  }
Lukas Matt's avatar
Lukas Matt committed
35 36
  Encoding string `xml:"me:encoding"`
  Alg string `xml:"me:alg"`
37
  Sig struct {
Lukas Matt's avatar
Lukas Matt committed
38
    XMLName xml.Name `xml:"me:sig"`
39 40
    Sig string `xml:",chardata"`
    KeyId string `xml:"key_id,attr,omitempty"`
Lukas Matt's avatar
Lukas Matt committed
41 42 43 44
  }
}

type Entity struct {
45 46 47 48
  XMLName xml.Name
  // Use custom unmarshaler for xml fetch XMLName
  // and decide which entity to use
  Type string `xml:"-"`
49
  SignatureOrder string `xml:"-"`
50 51 52
  Data interface{} `xml:"-"`
}

53 54 55 56
type Time string

func (m Message) Signature() string {
  return m.Sig.Sig
57 58
}

59
func (m Message) SignatureText(order string) []string {
Lukas Matt's avatar
Lukas Matt committed
60 61 62 63 64 65 66 67
  return []string{
    m.Data.Data,
    base64.StdEncoding.EncodeToString([]byte(m.Data.Type)),
    base64.StdEncoding.EncodeToString([]byte(m.Encoding)),
    base64.StdEncoding.EncodeToString([]byte(m.Alg)),
  }
}

68 69 70
func (t *Time) New(newTime time.Time) *Time {
  *t = Time(newTime.UTC().Format(TIME_FORMAT))
  return t
71 72
}

73 74 75 76 77 78
func (t Time) Time() (time.Time, error) {
  return time.Parse(TIME_FORMAT, string(t))
}

func (t Time) String() string {
  return string(t)
79 80
}

81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
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)
  // we have to decode on every single step
  switch local := start.Name.Local; local {
  case Retraction:
    content := EntityRetraction{}
    if err := d.DecodeElement(&content, &start); err != nil {
      return err
    }
    (*e).Type = local
    (*e).Data = content
  case Profile:
    content := EntityProfile{}
    if err := d.DecodeElement(&content, &start); err != nil {
      return err
    }
    (*e).Type = local
    (*e).Data = content
  case StatusMessage:
    content := EntityStatusMessage{}
    if err := d.DecodeElement(&content, &start); err != nil {
      return err
    }
    (*e).Type = local
    (*e).Data = content
107 108 109 110 111 112 113
  case Reshare:
    content := EntityReshare{}
    if err := d.DecodeElement(&content, &start); err != nil {
      return err
    }
    (*e).Type = local
    (*e).Data = content
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
  case Comment:
    content := EntityComment{}
    if err := d.DecodeElement(&content, &start); err != nil {
      return err
    }
    (*e).Type = local
    (*e).Data = content
  case Like:
    content := EntityLike{}
    if err := d.DecodeElement(&content, &start); err != nil {
      return err
    }
    (*e).Type = local
    (*e).Data = content
  case Contact:
    content := EntityContact{}
    if err := d.DecodeElement(&content, &start); err != nil {
      return err
    }
    (*e).Type = local
    (*e).Data = content
  default:
    return errors.New("Entity '" + local + "' not known!")
  }
  return nil
Lukas Matt's avatar
Lukas Matt committed
139
}