Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions link/echo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package link

import (
"net/url"
"strings"

"github.com/pkg/errors"
)

type echo struct{}

// Echo service (for testing).
var Echo = &echo{}

func (s *echo) ID() string {
return "echo"
}

func (s *echo) NormalizeURLString(name string, urs string) (string, error) {
return basicURLString(urs)
}

func (s *echo) ValidateURLString(name string, urs string) (string, error) {
u, err := url.Parse(urs)
if err != nil {
return "", err
}
if u.Scheme != "test" {
return "", errors.Errorf("invalid scheme for url %s", u)
}
if u.Host != "echo" {
return "", errors.Errorf("invalid host for url %s", u)
}
path := u.Path
path = strings.TrimPrefix(path, "/")
paths := strings.Split(path, "/")
if len(paths) == 0 {
return "", errors.Errorf("path invalid %s for url %s", paths, u)
}
if paths[0] != name {
return "", errors.Errorf("path invalid (name mismatch) %s != %s", paths[0], name)
}
return u.String(), nil
}

func (s *echo) NormalizeName(name string) string {
name = strings.ToLower(name)
return name
}

func (s *echo) ValidateName(name string) error {
ok := isAlphaNumericWithDashUnderscore(name)
if !ok {
return errors.Errorf("name has an invalid character")
}

if len(name) > 39 {
return errors.Errorf("test name is too long, it must be less than 40 characters")
}

return nil
}

func (s *echo) CheckContent(name string, b []byte) ([]byte, error) {
return b, nil
}
57 changes: 57 additions & 0 deletions link/echo_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package link_test

import (
"testing"

"github.com/keys-pub/keys/link"
"github.com/stretchr/testify/require"
)

func TestEchoNormalizeName(t *testing.T) {
name := link.Echo.NormalizeName("Gabriel")
require.Equal(t, "gabriel", name)
}

func TestEchoValidateName(t *testing.T) {
err := link.Echo.ValidateName("gabriel01")
require.NoError(t, err)

err = link.Echo.ValidateName("gabriel-01")
require.NoError(t, err)

err = link.Echo.ValidateName("gabriel_01")
require.NoError(t, err)

err = link.Echo.ValidateName("Gabriel")
require.EqualError(t, err, "name has an invalid character")

err = link.Echo.ValidateName("Gabriel++")
require.EqualError(t, err, "name has an invalid character")

err = link.Echo.ValidateName("reallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongname")
require.EqualError(t, err, "test name is too long, it must be less than 40 characters")
}

func TestEchoNormalizeURL(t *testing.T) {
testNormalizeURL(t, link.Echo,
"gabriel",
"test://echo/gabriel?",
"test://echo/gabriel")
}

func TestEchoValidateURL(t *testing.T) {
testValidateURL(t, link.Echo,
"gabriel",
"test://echo/gabriel",
"test://echo/gabriel")

testValidateURLErr(t, link.Echo,
"gabriel",
"test://ech/gabriel",
"invalid host for url test://ech/gabriel")

testValidateURLErr(t, link.Echo,
"gabriel",
"test://echo/gabrie",
"path invalid (name mismatch) gabrie != gabriel")
}
2 changes: 2 additions & 0 deletions link/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ func NewService(service string) (Service, error) {
return Reddit, nil
case HTTPS.ID():
return HTTPS, nil
case Echo.ID():
return Echo, nil
default:
return nil, errors.Errorf("invalid service %s", service)
}
Expand Down
10 changes: 5 additions & 5 deletions testdata/kid.spew
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/kid/kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077 {"kid":"kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077"}
/kid/kex1a4yj333g68pvd6hfqvufqkv4vy54jfe6t33ljd3kc9rpfty8xlgs2u3qxr {"kid":"kex1a4yj333g68pvd6hfqvufqkv4vy54jfe6t33ljd3kc9rpfty8xlgs2u3qxr","result":{"status":"ok","ts":1234567890052,"user":{"k":"kex1a4yj333g68pvd6hfqvufqkv4vy54jfe6t33ljd3kc9rpfty8xlgs2u3qxr","n":"alice","sq":1,"sr":"twitter","u":"https://twitter.com/alice/status/1"},"vts":1234567890052}}
/kid/kex1a4yj333g68pvd6hfqvufqkv4vy54jfe6t33ljd3kc9rpfty8xlgs2u3qxr {"kid":"kex1a4yj333g68pvd6hfqvufqkv4vy54jfe6t33ljd3kc9rpfty8xlgs2u3qxr","result":{"status":"ok","ts":1234567890066,"user":{"k":"kex1a4yj333g68pvd6hfqvufqkv4vy54jfe6t33ljd3kc9rpfty8xlgs2u3qxr","n":"alice","sq":1,"sr":"twitter","u":"https://twitter.com/alice/status/1"},"vts":1234567890066}}
/kid/kex1gwnjuu2yq9mzmantdrpxm77ly6p24myly36wefrp8epy5ra6l57qj97xgz {"kid":"kex1gwnjuu2yq9mzmantdrpxm77ly6p24myly36wefrp8epy5ra6l57qj97xgz","result":{"status":"ok","ts":1234567890007,"user":{"k":"kex1gwnjuu2yq9mzmantdrpxm77ly6p24myly36wefrp8epy5ra6l57qj97xgz","n":"name10","sq":1,"sr":"github","u":"https://gist.github.com/name10/1"},"vts":1234567890007}}
/kid/kex1jx3g5zm58q2e8fxeg62hjgyfy6hu3tvzezpekajyxkdeaw56fvaq46atcz {"kid":"kex1jx3g5zm58q2e8fxeg62hjgyfy6hu3tvzezpekajyxkdeaw56fvaq46atcz","result":{"status":"ok","ts":1234567890025,"user":{"k":"kex1jx3g5zm58q2e8fxeg62hjgyfy6hu3tvzezpekajyxkdeaw56fvaq46atcz","n":"name13","sq":1,"sr":"github","u":"https://gist.github.com/name13/1"},"vts":1234567890025}}
/kid/kex1p0h0t20x08n28cf5lcncx7llxtrukh6agn4qn09su4pt444ycrxq2x9f8c {"kid":"kex1p0h0t20x08n28cf5lcncx7llxtrukh6agn4qn09su4pt444ycrxq2x9f8c","result":{"status":"ok","ts":1234567890031,"user":{"k":"kex1p0h0t20x08n28cf5lcncx7llxtrukh6agn4qn09su4pt444ycrxq2x9f8c","n":"name14","sq":1,"sr":"github","u":"https://gist.github.com/name14/1"},"vts":1234567890031}}
/kid/kex1pdgn4kd5jfqptjsfqtks0yzy6wk9m0kzxphsd9yvzrdgadhrnuksyklezm {"kid":"kex1pdgn4kd5jfqptjsfqtks0yzy6wk9m0kzxphsd9yvzrdgadhrnuksyklezm","result":{"status":"ok","ts":1234567890019,"user":{"k":"kex1pdgn4kd5jfqptjsfqtks0yzy6wk9m0kzxphsd9yvzrdgadhrnuksyklezm","n":"name12","sq":1,"sr":"github","u":"https://gist.github.com/name12/1"},"vts":1234567890019}}
/kid/kex1v6l8uvev0fznxv4an5987lds2h6utmc6q6k6vmvckw0mdqgvguaq4850kc {"kid":"kex1v6l8uvev0fznxv4an5987lds2h6utmc6q6k6vmvckw0mdqgvguaq4850kc","result":{"status":"ok","ts":1234567890013,"user":{"k":"kex1v6l8uvev0fznxv4an5987lds2h6utmc6q6k6vmvckw0mdqgvguaq4850kc","n":"name11","sq":1,"sr":"github","u":"https://gist.github.com/name11/1"},"vts":1234567890013}}
/kid/kex1jx3g5zm58q2e8fxeg62hjgyfy6hu3tvzezpekajyxkdeaw56fvaq46atcz {"kid":"kex1jx3g5zm58q2e8fxeg62hjgyfy6hu3tvzezpekajyxkdeaw56fvaq46atcz","result":{"status":"ok","ts":1234567890031,"user":{"k":"kex1jx3g5zm58q2e8fxeg62hjgyfy6hu3tvzezpekajyxkdeaw56fvaq46atcz","n":"name13","sq":1,"sr":"github","u":"https://gist.github.com/name13/1"},"vts":1234567890031}}
/kid/kex1p0h0t20x08n28cf5lcncx7llxtrukh6agn4qn09su4pt444ycrxq2x9f8c {"kid":"kex1p0h0t20x08n28cf5lcncx7llxtrukh6agn4qn09su4pt444ycrxq2x9f8c","result":{"status":"ok","ts":1234567890039,"user":{"k":"kex1p0h0t20x08n28cf5lcncx7llxtrukh6agn4qn09su4pt444ycrxq2x9f8c","n":"name14","sq":1,"sr":"github","u":"https://gist.github.com/name14/1"},"vts":1234567890039}}
/kid/kex1pdgn4kd5jfqptjsfqtks0yzy6wk9m0kzxphsd9yvzrdgadhrnuksyklezm {"kid":"kex1pdgn4kd5jfqptjsfqtks0yzy6wk9m0kzxphsd9yvzrdgadhrnuksyklezm","result":{"status":"ok","ts":1234567890023,"user":{"k":"kex1pdgn4kd5jfqptjsfqtks0yzy6wk9m0kzxphsd9yvzrdgadhrnuksyklezm","n":"name12","sq":1,"sr":"github","u":"https://gist.github.com/name12/1"},"vts":1234567890023}}
/kid/kex1v6l8uvev0fznxv4an5987lds2h6utmc6q6k6vmvckw0mdqgvguaq4850kc {"kid":"kex1v6l8uvev0fznxv4an5987lds2h6utmc6q6k6vmvckw0mdqgvguaq4850kc","result":{"status":"ok","ts":1234567890015,"user":{"k":"kex1v6l8uvev0fznxv4an5987lds2h6utmc6q6k6vmvckw0mdqgvguaq4850kc","n":"name11","sq":1,"sr":"github","u":"https://gist.github.com/name11/1"},"vts":1234567890015}}
2 changes: 1 addition & 1 deletion testdata/kid2.spew
Original file line number Diff line number Diff line change
@@ -1 +1 @@
/kid/kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077 {"kid":"kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077","result":{"err":"http error 404","status":"resource-not-found","ts":1234567890010,"user":{"k":"kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077","n":"alice","sq":1,"sr":"github","u":"https://gist.github.com/alice/1"},"vts":1234567890004}}
/kid/kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077 {"kid":"kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077","result":{"err":"http error 404","status":"resource-not-found","ts":1234567890014,"user":{"k":"kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077","n":"alice","sq":1,"sr":"github","u":"https://gist.github.com/alice/1"},"vts":1234567890004}}
10 changes: 5 additions & 5 deletions testdata/user.spew
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/user/alice@twitter {"kid":"kex1a4yj333g68pvd6hfqvufqkv4vy54jfe6t33ljd3kc9rpfty8xlgs2u3qxr","result":{"status":"ok","ts":1234567890052,"user":{"k":"kex1a4yj333g68pvd6hfqvufqkv4vy54jfe6t33ljd3kc9rpfty8xlgs2u3qxr","n":"alice","sq":1,"sr":"twitter","u":"https://twitter.com/alice/status/1"},"vts":1234567890052}}
/user/alice@twitter {"kid":"kex1a4yj333g68pvd6hfqvufqkv4vy54jfe6t33ljd3kc9rpfty8xlgs2u3qxr","result":{"status":"ok","ts":1234567890066,"user":{"k":"kex1a4yj333g68pvd6hfqvufqkv4vy54jfe6t33ljd3kc9rpfty8xlgs2u3qxr","n":"alice","sq":1,"sr":"twitter","u":"https://twitter.com/alice/status/1"},"vts":1234567890066}}
/user/name10@github {"kid":"kex1gwnjuu2yq9mzmantdrpxm77ly6p24myly36wefrp8epy5ra6l57qj97xgz","result":{"status":"ok","ts":1234567890007,"user":{"k":"kex1gwnjuu2yq9mzmantdrpxm77ly6p24myly36wefrp8epy5ra6l57qj97xgz","n":"name10","sq":1,"sr":"github","u":"https://gist.github.com/name10/1"},"vts":1234567890007}}
/user/name11@github {"kid":"kex1v6l8uvev0fznxv4an5987lds2h6utmc6q6k6vmvckw0mdqgvguaq4850kc","result":{"status":"ok","ts":1234567890013,"user":{"k":"kex1v6l8uvev0fznxv4an5987lds2h6utmc6q6k6vmvckw0mdqgvguaq4850kc","n":"name11","sq":1,"sr":"github","u":"https://gist.github.com/name11/1"},"vts":1234567890013}}
/user/name12@github {"kid":"kex1pdgn4kd5jfqptjsfqtks0yzy6wk9m0kzxphsd9yvzrdgadhrnuksyklezm","result":{"status":"ok","ts":1234567890019,"user":{"k":"kex1pdgn4kd5jfqptjsfqtks0yzy6wk9m0kzxphsd9yvzrdgadhrnuksyklezm","n":"name12","sq":1,"sr":"github","u":"https://gist.github.com/name12/1"},"vts":1234567890019}}
/user/name13@github {"kid":"kex1jx3g5zm58q2e8fxeg62hjgyfy6hu3tvzezpekajyxkdeaw56fvaq46atcz","result":{"status":"ok","ts":1234567890025,"user":{"k":"kex1jx3g5zm58q2e8fxeg62hjgyfy6hu3tvzezpekajyxkdeaw56fvaq46atcz","n":"name13","sq":1,"sr":"github","u":"https://gist.github.com/name13/1"},"vts":1234567890025}}
/user/name14@github {"kid":"kex1p0h0t20x08n28cf5lcncx7llxtrukh6agn4qn09su4pt444ycrxq2x9f8c","result":{"status":"ok","ts":1234567890031,"user":{"k":"kex1p0h0t20x08n28cf5lcncx7llxtrukh6agn4qn09su4pt444ycrxq2x9f8c","n":"name14","sq":1,"sr":"github","u":"https://gist.github.com/name14/1"},"vts":1234567890031}}
/user/name11@github {"kid":"kex1v6l8uvev0fznxv4an5987lds2h6utmc6q6k6vmvckw0mdqgvguaq4850kc","result":{"status":"ok","ts":1234567890015,"user":{"k":"kex1v6l8uvev0fznxv4an5987lds2h6utmc6q6k6vmvckw0mdqgvguaq4850kc","n":"name11","sq":1,"sr":"github","u":"https://gist.github.com/name11/1"},"vts":1234567890015}}
/user/name12@github {"kid":"kex1pdgn4kd5jfqptjsfqtks0yzy6wk9m0kzxphsd9yvzrdgadhrnuksyklezm","result":{"status":"ok","ts":1234567890023,"user":{"k":"kex1pdgn4kd5jfqptjsfqtks0yzy6wk9m0kzxphsd9yvzrdgadhrnuksyklezm","n":"name12","sq":1,"sr":"github","u":"https://gist.github.com/name12/1"},"vts":1234567890023}}
/user/name13@github {"kid":"kex1jx3g5zm58q2e8fxeg62hjgyfy6hu3tvzezpekajyxkdeaw56fvaq46atcz","result":{"status":"ok","ts":1234567890031,"user":{"k":"kex1jx3g5zm58q2e8fxeg62hjgyfy6hu3tvzezpekajyxkdeaw56fvaq46atcz","n":"name13","sq":1,"sr":"github","u":"https://gist.github.com/name13/1"},"vts":1234567890031}}
/user/name14@github {"kid":"kex1p0h0t20x08n28cf5lcncx7llxtrukh6agn4qn09su4pt444ycrxq2x9f8c","result":{"status":"ok","ts":1234567890039,"user":{"k":"kex1p0h0t20x08n28cf5lcncx7llxtrukh6agn4qn09su4pt444ycrxq2x9f8c","n":"name14","sq":1,"sr":"github","u":"https://gist.github.com/name14/1"},"vts":1234567890039}}
49 changes: 49 additions & 0 deletions user/echo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package user

import (
"net/url"
"strings"

"github.com/keys-pub/keys"
"github.com/pkg/errors"
)

func echoRequest(ur *url.URL) ([]byte, error) {
if ur.Scheme != "test" {
return nil, errors.Errorf("invalid scheme for echo")
}
if ur.Host != "echo" {
return nil, errors.Errorf("invalid host for echo")
}

path := ur.Path
path = strings.TrimPrefix(path, "/")
paths := strings.Split(path, "/")
if len(paths) != 3 {
return nil, errors.Errorf("path invalid %s", path)
}
username := paths[0]
kid, err := keys.ParseID(paths[1])
if err != nil {
return nil, err
}
msg := paths[2]
un, err := url.QueryUnescape(msg)
if err != nil {
return nil, err
}
msg = un

usr := &User{
Service: "echo",
KID: kid,
Name: username,
}

if err := Verify(msg, usr); err != nil {
return nil, err
}

return []byte(msg), nil

}
111 changes: 111 additions & 0 deletions user/echo_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package user_test

import (
"context"
"net/url"
"strings"
"testing"

"github.com/keys-pub/keys"
"github.com/keys-pub/keys/docs"
"github.com/keys-pub/keys/link"
"github.com/keys-pub/keys/request"
"github.com/keys-pub/keys/tsutil"
"github.com/keys-pub/keys/user"
"github.com/stretchr/testify/require"
)

func TestResultEcho(t *testing.T) {
sk := keys.NewEdX25519KeyFromSeed(testSeed(0x01))

clock := tsutil.NewTestClock()
req := request.NewMockRequestor()
ds := docs.NewMem()
scs := keys.NewSigchains(ds)
users := user.NewUsers(ds, scs, req, clock)

usr, err := user.NewForSigning(sk.ID(), "echo", "alice")
require.NoError(t, err)
msg, err := usr.Sign(sk)
require.NoError(t, err)
err = user.Verify(msg, usr)
require.NoError(t, err)

urs := "test://echo/alice/" + sk.ID().String() + "/" + url.QueryEscape(strings.ReplaceAll(msg, "\n", " "))
expected := `test://echo/alice/kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077/BEGIN+MESSAGE.+c0ypzQnuMjHRspp+4e0pl3TYCllN7ZG+MfKStJEnWVz5Uxt+lHFJtaTmEjPdy43+aOvtlDN9ZKwtQqS+WzHAKQB7RxKTCKq+6Xr2MZHgg4UNRDb+Zy2loGoGN3Mvxd4+r7FIwpZOJPE1JEq+D2gGjkgLByR9CFG+2aCgRgZZwl5UAa4+6bmBzjE1RqUnMN5+RDaVlacMSHyIP0d+IbCHwBmy0ZnY9pb+T0X.+END+MESSAGE.`
require.Equal(t, expected, urs)

sc := keys.NewSigchain(sk.ID())
stu, err := user.New(sk.ID(), "echo", "alice", urs, sc.LastSeq()+1)
require.NoError(t, err)
st, err := user.NewSigchainStatement(sc, stu, sk, clock.Now())
require.NoError(t, err)
err = sc.Add(st)
require.NoError(t, err)
err = scs.Save(sc)
require.NoError(t, err)

result, err := users.Update(context.TODO(), sk.ID())
require.NoError(t, err)
require.NotNil(t, result)
t.Logf("Result: %+v", result)
require.Equal(t, user.StatusOK, result.Status)
require.Equal(t, "echo", result.User.Service)
require.Equal(t, "alice", result.User.Name)
require.Equal(t, int64(1234567890002), result.VerifiedAt)
require.Equal(t, int64(1234567890002), result.Timestamp)

result, err = users.Get(context.TODO(), sk.ID())
require.NoError(t, err)
require.NotNil(t, result)
require.Equal(t, "echo", result.User.Service)
require.Equal(t, "alice", result.User.Name)

result, err = users.User(context.TODO(), "alice@echo")
require.NoError(t, err)
require.NotNil(t, result)
require.Equal(t, "echo", result.User.Service)
require.Equal(t, "alice", result.User.Name)

kids, err := users.KIDs(context.TODO())
require.NoError(t, err)
require.Equal(t, 1, len(kids))
require.Equal(t, keys.ID("kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077"), kids[0])

// TODO: When we flip indexUser to indexSearch, uncomment this...
// res, err := users.Search(context.TODO(), &user.SearchRequest{Query: "alice@echo"})
// require.NoError(t, err)
// require.Equal(t, 0, len(res))
}

func TestRequestVerifyEcho(t *testing.T) {
sk := keys.NewEdX25519KeyFromSeed(testSeed(0x01))

clock := tsutil.NewTestClock()
req := request.NewMockRequestor()
ds := docs.NewMem()
scs := keys.NewSigchains(ds)
users := user.NewUsers(ds, scs, req, clock)

usrSign, err := user.NewForSigning(sk.ID(), "echo", "alice")
require.NoError(t, err)
msg, err := usrSign.Sign(sk)
require.NoError(t, err)
msg = url.QueryEscape(strings.ReplaceAll(msg, "\n", " "))

urs := "test://echo/alice/" + sk.ID().String() + "/" + msg

norm, err := link.Echo.NormalizeURLString("alice", urs)
require.NoError(t, err)

usr := &user.User{
KID: sk.ID(),
Name: "alice",
Service: "echo",
URL: norm,
}

result := users.RequestVerify(context.TODO(), usr)
t.Logf("result: %+v", result)
require.Equal(t, user.StatusOK, result.Status)
}
Loading