package server_test
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"testing"
"github.com/keys-pub/keys"
"github.com/stretchr/testify/require"
)
func TestUserSearch(t *testing.T) {
env := newEnv(t)
srv := newTestServer(t, env)
req, err := http.NewRequest("GET", "/user/search", nil)
require.NoError(t, err)
code, _, body := srv.Serve(req)
require.Equal(t, http.StatusOK, code)
require.Equal(t, `{"users":[]}`, body)
alice := keys.NewEdX25519KeyFromSeed(keys.Bytes32(bytes.Repeat([]byte{0x01}, 32)))
st := userMock(t, alice, "alice", "github", env.client, env.clock)
b, err := st.Bytes()
require.NoError(t, err)
req, err = http.NewRequest("PUT", fmt.Sprintf("/sigchain/%s/1", alice.ID()), bytes.NewReader(b))
require.NoError(t, err)
code, _, body = srv.Serve(req)
require.Equal(t, http.StatusOK, code)
require.Equal(t, "{}", body)
req, err = http.NewRequest("GET", "/user/search", nil)
require.NoError(t, err)
code, _, body = srv.Serve(req)
require.Equal(t, http.StatusOK, code)
expected := `{
"users": [
{
"id": "alice@github",
"name": "alice",
"kid": "kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077",
"seq": 1,
"service": "github",
"url": "https://gist.github.com/alice/6769746875622f61",
"status": "ok",
"statement": "BEGIN MESSAGE.\nY24cziOYlfrf5Jo StDTUuPnS6LKuhx awYPRXyhwwlRHUA c0pXakmOZjgjMzs8DCAifCEdAkZfEU VDk6hs3Z2OGTCKq 6Xr2MZHgg4UNRDb Zy2loGoGN3Mvxd4r7FIwpZOJPE1JEq D2gGjkgLByR9CFG 2aCgRgZZwl5UAa4 6bmBzjEOhmsiW0KTDXulMpC51JXgyc 1MliDDv03o9DXy5 mbXLLP0PDrc9ziK lQqXFL3j737xB4VyAwvIctTRYqHeOH X5y51pUcCb2s5VI uU0x96I37FiTbk8 BW9SG90C6ST.\nEND MESSAGE.",
"verifiedAt": 1234567890004,
"ts": 1234567890004
}
]
}`
require.Equal(t, expected, pretty(t, body))
req, err = http.NewRequest("GET", "/user/search?q=alice", nil)
require.NoError(t, err)
code, _, body = srv.Serve(req)
require.Equal(t, http.StatusOK, code)
expected = `{
"users": [
{
"id": "alice@github",
"name": "alice",
"kid": "kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077",
"seq": 1,
"service": "github",
"url": "https://gist.github.com/alice/6769746875622f61",
"status": "ok",
"statement": "BEGIN MESSAGE.\nY24cziOYlfrf5Jo StDTUuPnS6LKuhx awYPRXyhwwlRHUA c0pXakmOZjgjMzs8DCAifCEdAkZfEU VDk6hs3Z2OGTCKq 6Xr2MZHgg4UNRDb Zy2loGoGN3Mvxd4r7FIwpZOJPE1JEq D2gGjkgLByR9CFG 2aCgRgZZwl5UAa4 6bmBzjEOhmsiW0KTDXulMpC51JXgyc 1MliDDv03o9DXy5 mbXLLP0PDrc9ziK lQqXFL3j737xB4VyAwvIctTRYqHeOH X5y51pUcCb2s5VI uU0x96I37FiTbk8 BW9SG90C6ST.\nEND MESSAGE.",
"verifiedAt": 1234567890004,
"ts": 1234567890004
}
]
}`
require.Equal(t, expected, pretty(t, body))
req, err = http.NewRequest("GET", "/user/search?q=kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077", nil)
require.NoError(t, err)
code, _, body = srv.Serve(req)
require.Equal(t, http.StatusOK, code)
expected = `{
"users": [
{
"id": "alice@github",
"name": "alice",
"kid": "kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077",
"seq": 1,
"service": "github",
"url": "https://gist.github.com/alice/6769746875622f61",
"status": "ok",
"statement": "BEGIN MESSAGE.\nY24cziOYlfrf5Jo StDTUuPnS6LKuhx awYPRXyhwwlRHUA c0pXakmOZjgjMzs8DCAifCEdAkZfEU VDk6hs3Z2OGTCKq 6Xr2MZHgg4UNRDb Zy2loGoGN3Mvxd4r7FIwpZOJPE1JEq D2gGjkgLByR9CFG 2aCgRgZZwl5UAa4 6bmBzjEOhmsiW0KTDXulMpC51JXgyc 1MliDDv03o9DXy5 mbXLLP0PDrc9ziK lQqXFL3j737xB4VyAwvIctTRYqHeOH X5y51pUcCb2s5VI uU0x96I37FiTbk8 BW9SG90C6ST.\nEND MESSAGE.",
"verifiedAt": 1234567890004,
"ts": 1234567890004,
"mf": "kid"
}
]
}`
require.Equal(t, expected, pretty(t, body))
req, err = http.NewRequest("GET", "/user/search?q=kbx1rvd43h2sag2tvrdp0duse5p82nvhpjd6hpjwhv7q7vqklega8atshec5ws", nil)
require.NoError(t, err)
code, _, body = srv.Serve(req)
require.Equal(t, http.StatusOK, code)
expected = `{
"users": [
{
"id": "alice@github",
"name": "alice",
"kid": "kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077",
"seq": 1,
"service": "github",
"url": "https://gist.github.com/alice/6769746875622f61",
"status": "ok",
"statement": "BEGIN MESSAGE.\nY24cziOYlfrf5Jo StDTUuPnS6LKuhx awYPRXyhwwlRHUA c0pXakmOZjgjMzs8DCAifCEdAkZfEU VDk6hs3Z2OGTCKq 6Xr2MZHgg4UNRDb Zy2loGoGN3Mvxd4r7FIwpZOJPE1JEq D2gGjkgLByR9CFG 2aCgRgZZwl5UAa4 6bmBzjEOhmsiW0KTDXulMpC51JXgyc 1MliDDv03o9DXy5 mbXLLP0PDrc9ziK lQqXFL3j737xB4VyAwvIctTRYqHeOH X5y51pUcCb2s5VI uU0x96I37FiTbk8 BW9SG90C6ST.\nEND MESSAGE.",
"verifiedAt": 1234567890004,
"ts": 1234567890004,
"mf": "kid"
}
]
}`
require.Equal(t, expected, pretty(t, body))
req, err = http.NewRequest("GET", "/user/search?q=unknown", nil)
require.NoError(t, err)
code, _, body = srv.Serve(req)
require.Equal(t, http.StatusOK, code)
require.Equal(t, `{"users":[]}`, body)
}
func pretty(t *testing.T, s string) string {
var pretty bytes.Buffer
err := json.Indent(&pretty, []byte(s), "", " ")
require.NoError(t, err)
return pretty.String()
}
func TestUserGet(t *testing.T) {
env := newEnv(t)
srv := newTestServer(t, env)
alice := keys.NewEdX25519KeyFromSeed(keys.Bytes32(bytes.Repeat([]byte{0x01}, 32)))
st := userMock(t, alice, "alice", "github", env.client, env.clock)
b, err := st.Bytes()
require.NoError(t, err)
req, err := http.NewRequest("PUT", fmt.Sprintf("/sigchain/%s/1", alice.ID()), bytes.NewReader(b))
require.NoError(t, err)
code, _, body := srv.Serve(req)
require.Equal(t, http.StatusOK, code)
require.Equal(t, "{}", body)
req, err = http.NewRequest("GET", "/user/kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077", nil)
require.NoError(t, err)
code, _, body = srv.Serve(req)
require.Equal(t, http.StatusOK, code)
expected := `{
"user": {
"id": "alice@github",
"name": "alice",
"kid": "kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077",
"seq": 1,
"service": "github",
"url": "https://gist.github.com/alice/6769746875622f61",
"status": "ok",
"statement": "BEGIN MESSAGE.\nY24cziOYlfrf5Jo StDTUuPnS6LKuhx awYPRXyhwwlRHUA c0pXakmOZjgjMzs8DCAifCEdAkZfEU VDk6hs3Z2OGTCKq 6Xr2MZHgg4UNRDb Zy2loGoGN3Mvxd4r7FIwpZOJPE1JEq D2gGjkgLByR9CFG 2aCgRgZZwl5UAa4 6bmBzjEOhmsiW0KTDXulMpC51JXgyc 1MliDDv03o9DXy5 mbXLLP0PDrc9ziK lQqXFL3j737xB4VyAwvIctTRYqHeOH X5y51pUcCb2s5VI uU0x96I37FiTbk8 BW9SG90C6ST.\nEND MESSAGE.",
"verifiedAt": 1234567890004,
"ts": 1234567890004
}
}`
require.Equal(t, expected, pretty(t, body))
key := keys.GenerateEdX25519Key()
req, err = http.NewRequest("GET", "/user/"+key.ID().String(), nil)
require.NoError(t, err)
code, _, body = srv.Serve(req)
require.Equal(t, http.StatusNotFound, code)
require.Equal(t, `{"error":{"code":404,"message":"user not found"}}`, body)
req, err = http.NewRequest("GET", "/user/search?q=alice@github", nil)
require.NoError(t, err)
code, _, body = srv.Serve(req)
require.Equal(t, http.StatusOK, code)
expected = `{
"users": [
{
"id": "alice@github",
"name": "alice",
"kid": "kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077",
"seq": 1,
"service": "github",
"url": "https://gist.github.com/alice/6769746875622f61",
"status": "ok",
"statement": "BEGIN MESSAGE.\nY24cziOYlfrf5Jo StDTUuPnS6LKuhx awYPRXyhwwlRHUA c0pXakmOZjgjMzs8DCAifCEdAkZfEU VDk6hs3Z2OGTCKq 6Xr2MZHgg4UNRDb Zy2loGoGN3Mvxd4r7FIwpZOJPE1JEq D2gGjkgLByR9CFG 2aCgRgZZwl5UAa4 6bmBzjEOhmsiW0KTDXulMpC51JXgyc 1MliDDv03o9DXy5 mbXLLP0PDrc9ziK lQqXFL3j737xB4VyAwvIctTRYqHeOH X5y51pUcCb2s5VI uU0x96I37FiTbk8 BW9SG90C6ST.\nEND MESSAGE.",
"verifiedAt": 1234567890004,
"ts": 1234567890004
}
]
}`
require.Equal(t, expected, pretty(t, body))
req, err = http.NewRequest("GET", "/user/bob@github", nil)
require.NoError(t, err)
code, _, body = srv.Serve(req)
require.Equal(t, http.StatusNotFound, code)
require.Equal(t, `{"error":{"code":404,"message":"user not found"}}`, body)
req, err = http.NewRequest("GET", "/user/kbx1rvd43h2sag2tvrdp0duse5p82nvhpjd6hpjwhv7q7vqklega8atshec5ws", nil)
require.NoError(t, err)
code, _, body = srv.Serve(req)
require.Equal(t, http.StatusOK, code)
expected = `{
"user": {
"id": "alice@github",
"name": "alice",
"kid": "kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077",
"seq": 1,
"service": "github",
"url": "https://gist.github.com/alice/6769746875622f61",
"status": "ok",
"statement": "BEGIN MESSAGE.\nY24cziOYlfrf5Jo StDTUuPnS6LKuhx awYPRXyhwwlRHUA c0pXakmOZjgjMzs8DCAifCEdAkZfEU VDk6hs3Z2OGTCKq 6Xr2MZHgg4UNRDb Zy2loGoGN3Mvxd4r7FIwpZOJPE1JEq D2gGjkgLByR9CFG 2aCgRgZZwl5UAa4 6bmBzjEOhmsiW0KTDXulMpC51JXgyc 1MliDDv03o9DXy5 mbXLLP0PDrc9ziK lQqXFL3j737xB4VyAwvIctTRYqHeOH X5y51pUcCb2s5VI uU0x96I37FiTbk8 BW9SG90C6ST.\nEND MESSAGE.",
"verifiedAt": 1234567890004,
"ts": 1234567890004
}
}`
require.Equal(t, expected, pretty(t, body))
req, err = http.NewRequest("GET", "/user/kbx1rvd43h2sag2tvrdp0duse5p82nvhpjd6hpjwhv7q7vqklega8atshec5ws", nil)
require.NoError(t, err)
code, _, body = srv.Serve(req)
require.Equal(t, http.StatusOK, code)
expected = `{
"user": {
"id": "alice@github",
"name": "alice",
"kid": "kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077",
"seq": 1,
"service": "github",
"url": "https://gist.github.com/alice/6769746875622f61",
"status": "ok",
"statement": "BEGIN MESSAGE.\nY24cziOYlfrf5Jo StDTUuPnS6LKuhx awYPRXyhwwlRHUA c0pXakmOZjgjMzs8DCAifCEdAkZfEU VDk6hs3Z2OGTCKq 6Xr2MZHgg4UNRDb Zy2loGoGN3Mvxd4r7FIwpZOJPE1JEq D2gGjkgLByR9CFG 2aCgRgZZwl5UAa4 6bmBzjEOhmsiW0KTDXulMpC51JXgyc 1MliDDv03o9DXy5 mbXLLP0PDrc9ziK lQqXFL3j737xB4VyAwvIctTRYqHeOH X5y51pUcCb2s5VI uU0x96I37FiTbk8 BW9SG90C6ST.\nEND MESSAGE.",
"verifiedAt": 1234567890004,
"ts": 1234567890004
}
}`
require.Equal(t, expected, pretty(t, body))
}
func TestUserDuplicate(t *testing.T) {
env := newEnv(t)
srv := newTestServer(t, env)
alice := keys.NewEdX25519KeyFromSeed(keys.Bytes32(bytes.Repeat([]byte{0x01}, 32)))
alice2 := keys.NewEdX25519KeyFromSeed(keys.Bytes32(bytes.Repeat([]byte{0x08}, 32)))
st := userMock(t, alice, "alice", "github", env.client, env.clock)
b, err := st.Bytes()
require.NoError(t, err)
req, err := http.NewRequest("PUT", fmt.Sprintf("/sigchain/%s/1", alice.ID()), bytes.NewReader(b))
require.NoError(t, err)
code, _, body := srv.Serve(req)
require.Equal(t, http.StatusOK, code)
require.Equal(t, "{}", body)
req, err = http.NewRequest("GET", "/user/search", nil)
require.NoError(t, err)
code, _, body = srv.Serve(req)
require.Equal(t, http.StatusOK, code)
expected := `{
"users": [
{
"id": "alice@github",
"name": "alice",
"kid": "kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077",
"seq": 1,
"service": "github",
"url": "https://gist.github.com/alice/6769746875622f61",
"status": "ok",
"statement": "BEGIN MESSAGE.\nY24cziOYlfrf5Jo StDTUuPnS6LKuhx awYPRXyhwwlRHUA c0pXakmOZjgjMzs8DCAifCEdAkZfEU VDk6hs3Z2OGTCKq 6Xr2MZHgg4UNRDb Zy2loGoGN3Mvxd4r7FIwpZOJPE1JEq D2gGjkgLByR9CFG 2aCgRgZZwl5UAa4 6bmBzjEOhmsiW0KTDXulMpC51JXgyc 1MliDDv03o9DXy5 mbXLLP0PDrc9ziK lQqXFL3j737xB4VyAwvIctTRYqHeOH X5y51pUcCb2s5VI uU0x96I37FiTbk8 BW9SG90C6ST.\nEND MESSAGE.",
"verifiedAt": 1234567890004,
"ts": 1234567890004
}
]
}`
require.Equal(t, expected, pretty(t, body))
st2 := userMock(t, alice2, "alice", "github", env.client, env.clock)
b2, err := st2.Bytes()
require.NoError(t, err)
req, err = http.NewRequest("PUT", fmt.Sprintf("/sigchain/%s/1", alice2.ID()), bytes.NewReader(b2))
require.NoError(t, err)
code, _, body = srv.Serve(req)
require.Equal(t, http.StatusConflict, code)
require.Equal(t, `{"error":{"code":409,"message":"user already exists with key kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077, if you removed or revoked the previous statement you may need to wait briefly for search to update"}}`, body)
}