Commit 9abcf5ee authored by Lukas Matt's avatar Lukas Matt Committed by GitHub

Merge pull request #10 from ganggo/recoverable

HTTP clean-up and Message parse separated functionality 
parents 5c90e6d6 cd180efd
......@@ -22,6 +22,7 @@ import (
"github.com/Zauberstuhl/go-xml"
"encoding/base64"
"time"
"strings"
)
type Message struct {
......@@ -65,6 +66,49 @@ func (m Message) SignatureText(order string) []string {
}
}
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
}
func (t *Time) New(newTime time.Time) *Time {
*t = Time(newTime.UTC().Format(TIME_FORMAT))
return t
......
......@@ -32,6 +32,7 @@ const (
PROTO_HTTPS = "https://"
CONTENT_TYPE_ENVELOPE = "application/magic-envelope+xml"
CONTENT_TYPE_JSON = "application/json"
USER_AGENT = "GangGo/v0 (Federation library)"
)
var timeout = time.Duration(10 * time.Second)
......@@ -49,7 +50,8 @@ func push(host, endpoint, proto, contentType string, body io.Reader) error {
if err != nil {
return err
}
req.Header.Add("Content-Type", contentType)
req.Header.Set("User-Agent", USER_AGENT)
req.Header.Set("Content-Type", contentType)
client := &http.Client{Timeout: timeout}
resp, err := client.Do(req)
......@@ -69,63 +71,26 @@ func push(host, endpoint, proto, contentType string, body io.Reader) error {
}
func FetchJson(method, url string, body io.Reader, result interface{}) error {
var proto string
if !strings.HasPrefix(url, "http") {
proto = "https://"
}
req, err := http.NewRequest(method, proto + url, body)
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{
Timeout: timeout,
}
resp, err := client.Do(req)
if err != nil {
if !strings.HasPrefix(url, "http") {
return FetchJson(method, "http://" + url, body, result)
}
return err
}
err = json.NewDecoder(resp.Body).Decode(result)
resp, err := fetch(method, url, "application/json", body)
if err != nil {
return err
}
return nil
return json.NewDecoder(resp.Body).Decode(result)
}
func FetchXml(method, url string, body io.Reader, result interface{}) error {
var proto string
if !strings.HasPrefix(url, "http") {
proto = "https://"
}
req, err := http.NewRequest(method, proto + url, body)
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/xrd+xml")
client := &http.Client{
Timeout: timeout,
}
resp, err := client.Do(req)
if err != nil {
if !strings.HasPrefix(url, "http") {
return FetchXml(method, "http://" + url, body, result)
}
return err
}
err = xml.NewDecoder(resp.Body).Decode(result)
resp, err := fetch(method, url, "application/xrd+xml", body)
if err != nil {
return err
}
return nil
return xml.NewDecoder(resp.Body).Decode(result)
}
func FetchHtml(method, url string, body io.Reader) (resp *http.Response, err error) {
return fetch(method, url, "text/html", body)
}
func fetch(method, url, contentType string, body io.Reader) (*http.Response, error) {
var proto string
if !strings.HasPrefix(url, "http") {
proto = "https://"
......@@ -134,17 +99,16 @@ func FetchHtml(method, url string, body io.Reader) (resp *http.Response, err err
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/xrd+xml")
req.Header.Set("User-Agent", USER_AGENT)
req.Header.Set("Content-Type", contentType)
client := &http.Client{
Timeout: timeout,
}
resp, err = client.Do(req)
client := &http.Client{Timeout: timeout}
resp, err := client.Do(req)
if err != nil {
if !strings.HasPrefix(url, "http") {
return FetchHtml(method, "http://" + url, body)
return fetch(method, "http://" + url, contentType, body)
}
return nil, err
}
return
return resp, nil
}
......@@ -20,8 +20,6 @@ package federation
import (
"crypto/rsa"
"github.com/Zauberstuhl/go-xml"
"encoding/base64"
"strings"
)
func ParseDecryptedRequest(entityXML []byte) (message Message, entity Entity, err error) {
......@@ -30,44 +28,7 @@ func ParseDecryptedRequest(entityXML []byte) (message Message, entity Entity, er
logger.Error(err)
return
}
if !strings.EqualFold(message.Encoding, BASE64_URL) {
logger.Error(err)
return
}
if !strings.EqualFold(message.Alg, RSA_SHA256) {
logger.Error(err)
return
}
keyId, err := base64.StdEncoding.DecodeString(message.Sig.KeyId)
if err != nil {
logger.Error(err)
return
}
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(err)
return
}
logger.Info("Entity raw", string(data))
entity.SignatureOrder, err = FetchEntityOrder(data)
if err != nil {
logger.Error(err)
return
}
logger.Info("Entity order", entity.SignatureOrder)
err = xml.Unmarshal(data, &entity)
if err != nil {
logger.Error(err)
return
}
entity, err = message.Parse()
return
}
......
......@@ -17,23 +17,37 @@ package federation
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
import "testing"
import (
"testing"
"fmt"
)
func TestParseDecryptedRequest(t *testing.T) {
var xml = []byte(`<?xml version="1.0" encoding="UTF-8"?><me:env xmlns:me="http://salmon-protocol.org/ns/magic-env"><me:data type="application/xml">PHN0YXR1c19tZXNzYWdlPgogIDxhdXRob3I-ZGlhc3BvcmFfMm5kQGxvY2FsaG9zdDozMDAxPC9hdXRob3I-CiAgPGd1aWQ-ZmUyZDJhODA1MzQ4MDEzNWQwOGY1Mjk2ZjJlNzQ0N2I8L2d1aWQ-CiAgPGNyZWF0ZWRfYXQ-MjAxNy0wNy0yNVQwOToyNDozM1o8L2NyZWF0ZWRfYXQ-CiAgPHByb3ZpZGVyX2Rpc3BsYXlfbmFtZS8-CiAgPHRleHQ-cGluZzwvdGV4dD4KICA8cHVibGljPmZhbHNlPC9wdWJsaWM-Cjwvc3RhdHVzX21lc3NhZ2U-</me:data><me:encoding>base64url</me:encoding><me:alg>RSA-SHA256</me:alg><me:sig key_id="ZGlhc3BvcmFfMm5kQGxvY2FsaG9zdDozMDAx">NbuD4kERZzXPFRORH4NOcr7EAij-dWKTCG0eBBGZObN3Aic0lMAZ_rLU7o6PLOH9Q6p6dyneYjUjSu07vtI5Jy_N2XQpKUni3fUWxfDNgfMo26XKmxdJ5S2Gp1ux1ToO3FY9RByTZw5HZRpOBAfRSgttTgiY5_Yu5D-BLcEm_94R6FMWRniQXrMAt8hU9qCNSuVQlUKtuuy8qJXu6Z21VhI9lAT7wIALlR9UwIgz0e6UG9S9sU95f_38co0ibD1KbQpBd8c_lu5vCVIqlEe_Fa_xYZupMLaU8De-wzoBpBgqR65mRtUQTu2jP-Qxa3aXrANHxweIbnYfpZ5QcNA50hfyVJJSolczDSlDljTunEmHmWNaS3J7waEQsIDFATPFy6H5leRPpSzebXYca4T-EiapPP-mn41Vs3VKIdUXOHus_HcTPWRVT-Vr-yt7byFYEanb5b5lQ_IHcI0oyqX7RrVJid6UsBtwxwkX0FSc1cZgLhBQUgxBsUh5MNte-WZJv_6c9rHyNsH3rn9YEZp431P9GCe8gNdLY9bFQ1pYS9BxOAS2enu3yVpWpWRechiR7D__HC4-Hw2MHfSSmBQTxq5oO01_efEHB8XxWF85XYNT6_icXf3ZsTxkURT9HlHapkFwL7TlO5gPUZZVJt9f6kn9HoGQ56MX2n46KdKKid8=</me:sig></me:env>`)
var msgData = `PHN0YXR1c19tZXNzYWdlPgogIDxhdXRob3I-ZGlhc3BvcmFfMm5kQGxvY2FsaG9zdDozMDAxPC9hdXRob3I-CiAgPGd1aWQ-ZmUyZDJhODA1MzQ4MDEzNWQwOGY1Mjk2ZjJlNzQ0N2I8L2d1aWQ-CiAgPGNyZWF0ZWRfYXQ-MjAxNy0wNy0yNVQwOToyNDozM1o8L2NyZWF0ZWRfYXQ-CiAgPHByb3ZpZGVyX2Rpc3BsYXlfbmFtZS8-CiAgPHRleHQ-cGluZzwvdGV4dD4KICA8cHVibGljPmZhbHNlPC9wdWJsaWM-Cjwvc3RhdHVzX21lc3NhZ2U-`
var tmpl = `<?xml version="1.0" encoding="UTF-8"?><me:env xmlns:me="http://salmon-protocol.org/ns/magic-env"><me:data type="application/xml">%s</me:data><me:encoding>%s</me:encoding><me:alg>%s</me:alg><me:sig key_id="%s">NbuD4kERZzXPFRORH4NOcr7EAij-dWKTCG0eBBGZObN3Aic0lMAZ_rLU7o6PLOH9Q6p6dyneYjUjSu07vtI5Jy_N2XQpKUni3fUWxfDNgfMo26XKmxdJ5S2Gp1ux1ToO3FY9RByTZw5HZRpOBAfRSgttTgiY5_Yu5D-BLcEm_94R6FMWRniQXrMAt8hU9qCNSuVQlUKtuuy8qJXu6Z21VhI9lAT7wIALlR9UwIgz0e6UG9S9sU95f_38co0ibD1KbQpBd8c_lu5vCVIqlEe_Fa_xYZupMLaU8De-wzoBpBgqR65mRtUQTu2jP-Qxa3aXrANHxweIbnYfpZ5QcNA50hfyVJJSolczDSlDljTunEmHmWNaS3J7waEQsIDFATPFy6H5leRPpSzebXYca4T-EiapPP-mn41Vs3VKIdUXOHus_HcTPWRVT-Vr-yt7byFYEanb5b5lQ_IHcI0oyqX7RrVJid6UsBtwxwkX0FSc1cZgLhBQUgxBsUh5MNte-WZJv_6c9rHyNsH3rn9YEZp431P9GCe8gNdLY9bFQ1pYS9BxOAS2enu3yVpWpWRechiR7D__HC4-Hw2MHfSSmBQTxq5oO01_efEHB8XxWF85XYNT6_icXf3ZsTxkURT9HlHapkFwL7TlO5gPUZZVJt9f6kn9HoGQ56MX2n46KdKKid8=</me:sig></me:env>`
tests := [][]string{
[]string{msgData, "base32url", "RSA-SHA256", "ZGlhc3BvcmFfMm5kQGxvY2FsaG9zdDozMDAx"},
[]string{msgData, "base64url", "RSA-SHA128", "ZGlhc3BvcmFfMm5kQGxvY2FsaG9zdDozMDAx"},
[]string{msgData, "base64url", "RSA-SHA256", "not valid at all"},
[]string{"not valid", "base64url", "RSA-SHA256", "ZGlhc3BvcmFfMm5kQGxvY2FsaG9zdDozMDAx"},
}
_, entity, err := ParseDecryptedRequest([]byte(""))
if err == nil {
t.Errorf("Expected to be an error, got nil")
for i, test := range tests {
_, entity, err := ParseDecryptedRequest([]byte(fmt.Sprintf(
tmpl, test[0], test[1], test[2], test[3],
))); if err == nil {
t.Errorf("#%d: Expected to be an error, got %+v, with %+v", i, entity, test)
}
}
_, entity, err = ParseDecryptedRequest([]byte("<broken></broken"))
_, _, err := ParseDecryptedRequest([]byte("<broken></broken"))
if err == nil {
t.Errorf("Expected to be an error, got nil")
}
message, entity, err := ParseDecryptedRequest(xml)
if err != nil {
message, entity, err := ParseDecryptedRequest([]byte(fmt.Sprintf(
tmpl, msgData, "base64url", "RSA-SHA256", "ZGlhc3BvcmFfMm5kQGxvY2FsaG9zdDozMDAx",
))); if err != nil {
t.Errorf("Some error occured while parsing: %v", err)
}
......
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