entities.go 4.92 KB
Newer Older
zauberstuhl's avatar
zauberstuhl 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"
zauberstuhl's avatar
zauberstuhl committed
22 23
  "github.com/Zauberstuhl/go-xml"
  "encoding/base64"
24
  "time"
25
  "strings"
26
)
zauberstuhl's avatar
zauberstuhl committed
27

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

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

54 55 56 57
type Time string

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

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

69 70 71 72 73 74 75 76 77 78 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 107 108 109 110 111
func (message *Message) Parse() (entity Entity, err error) {
  if !strings.EqualFold(message.Encoding, BASE64_URL) {
    logger.Error("Encoding doesn't match",
      "message", message.Encoding, "lib", BASE64_URL)
    return entity, errors.New("Encoding doesn't match")
  }

  if !strings.EqualFold(message.Alg, RSA_SHA256) {
    logger.Error("Algorithm doesn't match",
      "message", message.Alg, "lib", RSA_SHA256)
    return entity, errors.New("Algorithm doesn't match")
  }

  keyId, err := base64.StdEncoding.DecodeString(message.Sig.KeyId)
  if err != nil {
    logger.Error("Cannot decode signature key ID", "err", err)
    return entity, err
  }
  message.Sig.KeyId = string(keyId)
  logger.Info("Entity sender", message.Sig.KeyId)

  data, err := base64.URLEncoding.DecodeString(message.Data.Data)
  if err != nil {
    logger.Error("Cannot decode message data", "err", err)
    return entity, err
  }
  logger.Info("Entity raw", string(data))

  entity.SignatureOrder, err = FetchEntityOrder(data)
  if err != nil {
    logger.Error("Cannot fetch entity order", "err", err)
    return entity, err
  }
  logger.Info("Entity order", entity.SignatureOrder)

  err = xml.Unmarshal(data, &entity)
  if err != nil {
    logger.Error("Cannot unmarshal data", "err", err)
    return entity, err
  }
  return entity, nil
}

112 113 114
func (t *Time) New(newTime time.Time) *Time {
  *t = Time(newTime.UTC().Format(TIME_FORMAT))
  return t
115 116
}

117 118 119 120 121 122
func (t Time) Time() (time.Time, error) {
  return time.Parse(TIME_FORMAT, string(t))
}

func (t Time) String() string {
  return string(t)
123 124
}

125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
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
151 152 153 154 155 156 157
  case Reshare:
    content := EntityReshare{}
    if err := d.DecodeElement(&content, &start); err != nil {
      return err
    }
    (*e).Type = local
    (*e).Data = content
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
  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
zauberstuhl's avatar
zauberstuhl committed
183
}