From 81187655c0df41e71f7e6ff6f7ee2641032b1b49 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 15 Jun 2021 15:04:48 +0300 Subject: [PATCH] Add some tests and fix bugs in matrix: URI parsing --- id/matrixuri.go | 21 +++--- id/matrixuri_test.go | 174 +++++++++++++++++++++++++++++++++++++++++++ id/userid_test.go | 2 +- 3 files changed, 184 insertions(+), 13 deletions(-) create mode 100644 id/matrixuri_test.go diff --git a/id/matrixuri.go b/id/matrixuri.go index c6bf9679..1742d457 100644 --- a/id/matrixuri.go +++ b/id/matrixuri.go @@ -81,23 +81,16 @@ func (uri *MatrixURI) String() string { // MatrixToURL converts to parsed matrix: URI into a matrix.to URL func (uri *MatrixURI) MatrixToURL() string { - rawFragment := fmt.Sprintf("#/%s", uri.PrimaryIdentifier()) fragment := fmt.Sprintf("#/%s", url.QueryEscape(uri.PrimaryIdentifier())) if uri.Sigil2 != 0 { - rawFragment = fmt.Sprintf("%s/%s", rawFragment, uri.SecondaryIdentifier()) - fragment = fmt.Sprintf("%s/%s", rawFragment, url.QueryEscape(uri.SecondaryIdentifier())) + fragment = fmt.Sprintf("%s/%s", fragment, url.QueryEscape(uri.SecondaryIdentifier())) } query := uri.getQuery().Encode() if len(query) > 0 { - rawFragment = fmt.Sprintf("%s?%s", rawFragment, query) fragment = fmt.Sprintf("%s?%s", fragment, query) } - return (&url.URL{ - Scheme: "https", - Host: "matrix.to", - Fragment: fragment, - RawFragment: rawFragment, - }).String() + // It would be nice to use URL{...}.String() here, but figuring out the Fragment vs RawFragment stuff is a pain + return fmt.Sprintf("https://matrix.to/%s", fragment) } // PrimaryIdentifier returns the first Matrix identifier in the URI. @@ -211,7 +204,7 @@ func ProcessMatrixURI(uri *url.URL) (*MatrixURI, error) { parsed.MXID1 = parts[1] // Step 6: if the first part is a room and the URI has 4 segments, construct a second level identifier - if (parsed.Sigil1 == '!' || parsed.Sigil1 == '@') && len(parts) == 4 { + if (parsed.Sigil1 == '!' || parsed.Sigil1 == '#') && len(parts) == 4 { // a: find the sigil from the third segment switch parts[2] { case "e", "event": @@ -255,7 +248,11 @@ func ProcessMatrixToURL(uri *url.URL) (*MatrixURI, error) { return nil, ErrNotMatrixTo } - parts := strings.Split(uri.Fragment, "/") + initialSplit := strings.SplitN(uri.Fragment, "?", 2) + parts := strings.Split(initialSplit[0], "/") + if len(initialSplit) > 1 { + uri.RawQuery = initialSplit[1] + } if len(parts) < 2 || len(parts) > 3 { return nil, ErrInvalidMatrixToPartCount diff --git a/id/matrixuri_test.go b/id/matrixuri_test.go new file mode 100644 index 00000000..5b9d91e8 --- /dev/null +++ b/id/matrixuri_test.go @@ -0,0 +1,174 @@ +// Copyright (c) 2021 Tulir Asokan +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package id_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "maunium.net/go/mautrix/id" +) + +var ( + roomIDLink = id.MatrixURI{Sigil1: '!', MXID1: "7NdBVvkd4aLSbgKt9RXl:example.org"} + roomIDViaLink = id.MatrixURI{Sigil1: '!', MXID1: "7NdBVvkd4aLSbgKt9RXl:example.org", Via: []string{"maunium.net", "matrix.org"}} + roomAliasLink = id.MatrixURI{Sigil1: '#', MXID1: "someroom:example.org"} + roomIDEventLink = id.MatrixURI{Sigil1: '!', MXID1: "7NdBVvkd4aLSbgKt9RXl:example.org", Sigil2: '$', MXID2: "uOH4C9cK4HhMeFWkUXMbdF_dtndJ0j9je-kIK3XpV1s"} + roomAliasEventLink = id.MatrixURI{Sigil1: '#', MXID1: "someroom:example.org", Sigil2: '$', MXID2: "uOH4C9cK4HhMeFWkUXMbdF_dtndJ0j9je-kIK3XpV1s"} + userLink = id.MatrixURI{Sigil1: '@', MXID1: "user:example.org"} +) + +func TestMatrixURI_MatrixToURL(t *testing.T) { + assert.Equal(t, "https://matrix.to/#/%217NdBVvkd4aLSbgKt9RXl%3Aexample.org", roomIDLink.MatrixToURL()) + assert.Equal(t, "https://matrix.to/#/%217NdBVvkd4aLSbgKt9RXl%3Aexample.org?via=maunium.net&via=matrix.org", roomIDViaLink.MatrixToURL()) + assert.Equal(t, "https://matrix.to/#/%23someroom%3Aexample.org", roomAliasLink.MatrixToURL()) + assert.Equal(t, "https://matrix.to/#/%217NdBVvkd4aLSbgKt9RXl%3Aexample.org/%24uOH4C9cK4HhMeFWkUXMbdF_dtndJ0j9je-kIK3XpV1s", roomIDEventLink.MatrixToURL()) + assert.Equal(t, "https://matrix.to/#/%23someroom%3Aexample.org/%24uOH4C9cK4HhMeFWkUXMbdF_dtndJ0j9je-kIK3XpV1s", roomAliasEventLink.MatrixToURL()) + assert.Equal(t, "https://matrix.to/#/%40user%3Aexample.org", userLink.MatrixToURL()) +} + +func TestMatrixURI_String(t *testing.T) { + assert.Equal(t, "matrix:roomid/7NdBVvkd4aLSbgKt9RXl:example.org", roomIDLink.String()) + assert.Equal(t, "matrix:roomid/7NdBVvkd4aLSbgKt9RXl:example.org?via=maunium.net&via=matrix.org", roomIDViaLink.String()) + assert.Equal(t, "matrix:r/someroom:example.org", roomAliasLink.String()) + assert.Equal(t, "matrix:roomid/7NdBVvkd4aLSbgKt9RXl:example.org/e/uOH4C9cK4HhMeFWkUXMbdF_dtndJ0j9je-kIK3XpV1s", roomIDEventLink.String()) + assert.Equal(t, "matrix:r/someroom:example.org/e/uOH4C9cK4HhMeFWkUXMbdF_dtndJ0j9je-kIK3XpV1s", roomAliasEventLink.String()) + assert.Equal(t, "matrix:u/user:example.org", userLink.String()) +} + +func TestParseMatrixURIOrMatrixToURL(t *testing.T) { + const inputURI = "matrix:u/user:example.org" + const inputMatrixToURL = "https://matrix.to/#/%40user%3Aexample.org" + parsed1, err := id.ParseMatrixURIOrMatrixToURL(inputURI) + require.NoError(t, err) + require.NotNil(t, parsed1) + parsed2, err := id.ParseMatrixURIOrMatrixToURL(inputMatrixToURL) + require.NoError(t, err) + require.NotNil(t, parsed2) + + assert.Equal(t, parsed1, parsed2) + assert.Equal(t, inputURI, parsed2.String()) + assert.Equal(t, inputMatrixToURL, parsed1.MatrixToURL()) +} + +func TestParseMatrixURI_RoomAlias(t *testing.T) { + parsed1, err := id.ParseMatrixURI("matrix:r/someroom:example.org") + require.NoError(t, err) + require.NotNil(t, parsed1) + parsed2, err := id.ParseMatrixURI("matrix:room/someroom:example.org") + require.NoError(t, err) + require.NotNil(t, parsed2) + + assert.Equal(t, roomAliasLink, *parsed1) + assert.Equal(t, roomAliasLink, *parsed2) +} + +func TestParseMatrixURI_RoomID(t *testing.T) { + parsed, err := id.ParseMatrixURI("matrix:roomid/7NdBVvkd4aLSbgKt9RXl:example.org") + require.NoError(t, err) + require.NotNil(t, parsed) + parsedVia, err := id.ParseMatrixURI("matrix:roomid/7NdBVvkd4aLSbgKt9RXl:example.org?via=maunium.net&via=matrix.org") + require.NoError(t, err) + require.NotNil(t, parsedVia) + + assert.Equal(t, roomIDLink, *parsed) + assert.Equal(t, roomIDViaLink, *parsedVia) +} + +func TestParseMatrixURI_UserID(t *testing.T) { + parsed1, err := id.ParseMatrixURI("matrix:u/user:example.org") + require.NoError(t, err) + require.NotNil(t, parsed1) + parsed2, err := id.ParseMatrixURI("matrix:user/user:example.org") + require.NoError(t, err) + require.NotNil(t, parsed2) + + assert.Equal(t, userLink, *parsed1) + assert.Equal(t, userLink, *parsed2) +} + +func TestParseMatrixURI_EventID(t *testing.T) { + parsed1, err := id.ParseMatrixURI("matrix:r/someroom:example.org/e/uOH4C9cK4HhMeFWkUXMbdF_dtndJ0j9je-kIK3XpV1s") + require.NoError(t, err) + require.NotNil(t, parsed1) + parsed2, err := id.ParseMatrixURI("matrix:room/someroom:example.org/e/uOH4C9cK4HhMeFWkUXMbdF_dtndJ0j9je-kIK3XpV1s") + require.NoError(t, err) + require.NotNil(t, parsed2) + parsed3, err := id.ParseMatrixURI("matrix:roomid/7NdBVvkd4aLSbgKt9RXl:example.org/e/uOH4C9cK4HhMeFWkUXMbdF_dtndJ0j9je-kIK3XpV1s") + require.NoError(t, err) + require.NotNil(t, parsed3) + + assert.Equal(t, roomAliasEventLink, *parsed1) + assert.Equal(t, roomAliasEventLink, *parsed2) + assert.Equal(t, roomIDEventLink, *parsed3) +} + +func TestParseMatrixToURL_RoomAlias(t *testing.T) { + parsed, err := id.ParseMatrixToURL("https://matrix.to/#/#someroom:example.org") + require.NoError(t, err) + require.NotNil(t, parsed) + parsedEncoded, err := id.ParseMatrixToURL("https://matrix.to/#/%23someroom%3Aexample.org") + require.NoError(t, err) + require.NotNil(t, parsedEncoded) + + assert.Equal(t, roomAliasLink, *parsed) + assert.Equal(t, roomAliasLink, *parsedEncoded) +} + +func TestParseMatrixToURL_RoomID(t *testing.T) { + parsed, err := id.ParseMatrixToURL("https://matrix.to/#/!7NdBVvkd4aLSbgKt9RXl:example.org") + require.NoError(t, err) + require.NotNil(t, parsed) + parsedEncoded, err := id.ParseMatrixToURL("https://matrix.to/#/%217NdBVvkd4aLSbgKt9RXl%3Aexample.org") + require.NoError(t, err) + require.NotNil(t, parsedEncoded) + parsedVia, err := id.ParseMatrixToURL("https://matrix.to/#/!7NdBVvkd4aLSbgKt9RXl:example.org?via=maunium.net&via=matrix.org") + require.NoError(t, err) + require.NotNil(t, parsedVia) + parsedViaEncoded, err := id.ParseMatrixToURL("https://matrix.to/#/%217NdBVvkd4aLSbgKt9RXl%3Aexample.org?via=maunium.net&via=matrix.org") + require.NoError(t, err) + require.NotNil(t, parsedViaEncoded) + + assert.Equal(t, roomIDLink, *parsed) + assert.Equal(t, roomIDLink, *parsedEncoded) + assert.Equal(t, roomIDViaLink, *parsedVia) + assert.Equal(t, roomIDViaLink, *parsedViaEncoded) +} + +func TestParseMatrixToURL_UserID(t *testing.T) { + parsed, err := id.ParseMatrixToURL("https://matrix.to/#/@user:example.org") + require.NoError(t, err) + require.NotNil(t, parsed) + parsedEncoded, err := id.ParseMatrixToURL("https://matrix.to/#/%40user%3Aexample.org") + require.NoError(t, err) + require.NotNil(t, parsedEncoded) + + assert.Equal(t, userLink, *parsed) + assert.Equal(t, userLink, *parsedEncoded) +} + +func TestParseMatrixToURL_EventID(t *testing.T) { + parsed1, err := id.ParseMatrixToURL("https://matrix.to/#/#someroom:example.org/$uOH4C9cK4HhMeFWkUXMbdF_dtndJ0j9je-kIK3XpV1s") + require.NoError(t, err) + require.NotNil(t, parsed1) + parsed2, err := id.ParseMatrixToURL("https://matrix.to/#/!7NdBVvkd4aLSbgKt9RXl:example.org/$uOH4C9cK4HhMeFWkUXMbdF_dtndJ0j9je-kIK3XpV1s") + require.NoError(t, err) + require.NotNil(t, parsed2) + parsed1Encoded, err := id.ParseMatrixToURL("https://matrix.to/#/%23someroom:example.org/%24uOH4C9cK4HhMeFWkUXMbdF_dtndJ0j9je-kIK3XpV1s") + require.NoError(t, err) + require.NotNil(t, parsed1) + parsed2Encoded, err := id.ParseMatrixToURL("https://matrix.to/#/%217NdBVvkd4aLSbgKt9RXl:example.org/%24uOH4C9cK4HhMeFWkUXMbdF_dtndJ0j9je-kIK3XpV1s") + require.NoError(t, err) + require.NotNil(t, parsed2) + + assert.Equal(t, roomAliasEventLink, *parsed1) + assert.Equal(t, roomAliasEventLink, *parsed1Encoded) + assert.Equal(t, roomIDEventLink, *parsed2) + assert.Equal(t, roomIDEventLink, *parsed2Encoded) +} diff --git a/id/userid_test.go b/id/userid_test.go index fdbf240a..1ab33dae 100644 --- a/id/userid_test.go +++ b/id/userid_test.go @@ -23,7 +23,7 @@ func TestUserID_Parse(t *testing.T) { assert.Equal(t, "maunium.net", parsedServerName) } -func TestUserID_Parse_Emtpty(t *testing.T) { +func TestUserID_Parse_Empty(t *testing.T) { const inputUserID = "@:ponies.im" parsedLocalpart, parsedServerName, err := id.UserID(inputUserID).Parse() assert.NoError(t, err)