diff --git a/.gitignore b/.gitignore index f84b9fc..2e814ef 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ **/.envrc **/.DS_Store +**/coverage.out /msgs /dist diff --git a/cmd/salty-chat/chat.go b/cmd/salty-chat/chat.go index 3a25e2e..d3368ed 100644 --- a/cmd/salty-chat/chat.go +++ b/cmd/salty-chat/chat.go @@ -47,7 +47,7 @@ func init() { } func chat(me *saltyim.Addr, identity, user string) { - cli, err := saltyim.NewClient(me, saltyim.IdentityPath(identity)) + cli, err := saltyim.NewClient(me, saltyim.WithIdentityPath(identity)) if err != nil { fmt.Fprintf(os.Stderr, "error initializing client: %s\n", err) os.Exit(2) diff --git a/cmd/salty-chat/makeuser.go b/cmd/salty-chat/makeuser.go index 3d40f62..9964e4a 100644 --- a/cmd/salty-chat/makeuser.go +++ b/cmd/salty-chat/makeuser.go @@ -96,7 +96,7 @@ func makeuser(me *saltyim.Addr, identity, endpoint string) { } ulid := saltyim.MustGenerateULID() if strings.HasSuffix(u.Path, "/") { - u.Path += fmt.Sprintf("%s", ulid) + u.Path += ulid } else { u.Path += fmt.Sprintf("/%s", ulid) } @@ -107,12 +107,12 @@ func makeuser(me *saltyim.Addr, identity, endpoint string) { os.Exit(2) } - if _, err := saltyim.CreateIdentity(saltyim.IdentityPath(identity), saltyim.IdentityAddr(me)); err != nil { + if _, err := saltyim.CreateIdentity(saltyim.WithIdentityPath(identity), saltyim.WithIdentityAddr(me)); err != nil { fmt.Fprintf(os.Stderr, "error creating identity %q for %s: %s\n", identity, me, err) os.Exit(2) } - ident, err := saltyim.GetIdentity(saltyim.IdentityPath(identity)) + ident, err := saltyim.GetIdentity(saltyim.WithIdentityPath(identity)) if err != nil { fmt.Fprintf(os.Stderr, "error reading identity %s for %s: %s\n", identity, me, err) os.Exit(2) diff --git a/cmd/salty-chat/read.go b/cmd/salty-chat/read.go index fb288d0..fc3e822 100644 --- a/cmd/salty-chat/read.go +++ b/cmd/salty-chat/read.go @@ -74,7 +74,7 @@ func init() { } func read(me *saltyim.Addr, identity string, prehook, posthook string, args ...string) { - cli, err := saltyim.NewClient(me, saltyim.IdentityPath(identity)) + cli, err := saltyim.NewClient(me, saltyim.WithIdentityPath(identity)) if err != nil { fmt.Fprintf(os.Stderr, "error initializing client: %s\n", err) os.Exit(2) diff --git a/cmd/salty-chat/register.go b/cmd/salty-chat/register.go index 173aaea..6de1230 100644 --- a/cmd/salty-chat/register.go +++ b/cmd/salty-chat/register.go @@ -50,7 +50,7 @@ func init() { } func register(me *saltyim.Addr, identity string) { - cli, err := saltyim.NewClient(me, saltyim.IdentityPath(identity)) + cli, err := saltyim.NewClient(me, saltyim.WithIdentityPath(identity)) if err != nil { fmt.Fprintf(os.Stderr, "error initializing client: %s\n", err) os.Exit(2) diff --git a/cmd/salty-chat/send.go b/cmd/salty-chat/send.go index 9cfdf2f..a6071c3 100644 --- a/cmd/salty-chat/send.go +++ b/cmd/salty-chat/send.go @@ -67,7 +67,7 @@ func send(me *saltyim.Addr, identity, user string, args ...string) { os.Exit(2) } - cli, err := saltyim.NewClient(me, saltyim.IdentityPath(identity)) + cli, err := saltyim.NewClient(me, saltyim.WithIdentityPath(identity)) if err != nil { fmt.Fprintf(os.Stderr, "error initializing client: %s\n", err) os.Exit(2) diff --git a/format_test.go b/format_test.go new file mode 100644 index 0000000..a210e78 --- /dev/null +++ b/format_test.go @@ -0,0 +1,32 @@ +package saltyim + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.yarn.social/lextwt" +) + +func TestPackMessage(t *testing.T) { + assert := assert.New(t) + require := require.New(t) + + addr, err := ParseAddr("alice@example.com") + require.NoError(err) + assert.Equal("alice", addr.User) + assert.Equal("example.com", addr.Domain) + + msg := "Hello World!" + packed := PackMessage(addr, msg) + require.NotNil(packed) + + s, err := lextwt.ParseSalty(string(packed)) + require.NoError(err) + + st, ok := s.(*lextwt.SaltyText) + require.Equal(true, ok) + + assert.Equal("alice@example.com", st.User.String()) + assert.Equal("Hello World!", st.LiteralText()) +} diff --git a/go.mod b/go.mod index ae6ed90..78333e2 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,9 @@ require ( github.com/sirupsen/logrus v1.8.1 github.com/spf13/cobra v1.4.0 github.com/spf13/viper v1.10.1 + github.com/stretchr/testify v1.7.0 go.mills.io/salty v0.0.0-20220322161301-ce2b9f6573fa + golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 ) require ( @@ -41,6 +43,7 @@ require ( github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/plar/go-adaptive-radix-tree v1.0.4 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.12.1 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect @@ -54,7 +57,6 @@ require ( github.com/vmihailenco/msgpack/v4 v4.3.12 // indirect github.com/vmihailenco/tagparser v0.1.2 // indirect github.com/writeas/go-strip-markdown/v2 v2.1.1 // indirect - golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 // indirect golang.org/x/exp v0.0.0-20220321173239-a90fa8a75705 // indirect golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect @@ -63,6 +65,7 @@ require ( google.golang.org/protobuf v1.28.0 // indirect gopkg.in/ini.v1 v1.66.4 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) require ( diff --git a/identity.go b/identity.go index 275df93..2c82da2 100644 --- a/identity.go +++ b/identity.go @@ -37,15 +37,8 @@ func DefaultIdentity() string { return os.ExpandEnv("$HOME/.config/salty/$USER.key") } -// DefaultEndpoint returns a default inbox file (if one exists) otherwise -// returns an empty string -func DefaultEndpoint() string { - return os.ExpandEnv("https://msgbus.mills.io/$USER") -} - // CreateIdentity ... func CreateIdentity(options ...IdentityOption) (*Identity, error) { - ident := &Identity{} for _, option := range options { option(ident) @@ -57,7 +50,8 @@ func CreateIdentity(options ...IdentityOption) (*Identity, error) { buf := &bytes.Buffer{} - salty.GenerateKeys(buf) + key, _ := salty.GenerateKeys(buf) + ident.key = key buf.Write([]byte(fmt.Sprintf("# user: %s\n", ident.addr.String()))) @@ -92,7 +86,6 @@ func CreateIdentity(options ...IdentityOption) (*Identity, error) { // GetIdentity ... func GetIdentity(options ...IdentityOption) (*Identity, error) { - ident := &Identity{} for _, option := range options { option(ident) @@ -134,10 +127,13 @@ func GetIdentity(options ...IdentityOption) (*Identity, error) { type Identity struct { // path where identity is read or written to path string + // contents where identity is read from or stored contents []byte + // key is the identity key key *keys.EdX25519Key + // addr is the user / endpoint addr *Addr } @@ -164,17 +160,17 @@ func (i *Identity) Addr() *Addr { // IdentityOption represents functional options for various identity operations type IdentityOption func(*Identity) -// IdentityAddr sets the identity Addr option -func IdentityAddr(addr *Addr) IdentityOption { +// WithIdentityAddr sets the identity Addr option +func WithIdentityAddr(addr *Addr) IdentityOption { return func(i *Identity) { i.addr = addr } } -// IdentityPath indicates that an identity should be read / written from a file path -func IdentityPath(path string) IdentityOption { +// WithIdentityPath indicates that an identity should be read / written from a file path +func WithIdentityPath(path string) IdentityOption { return func(i *Identity) { i.path = path } } -// IdentityContents indicates that the identity should be read from a byte array -func IdentityContents(contents []byte) IdentityOption { +// WithIdentityBytes indicates that the identity should be read from a byte array +func WithIdentityBytes(contents []byte) IdentityOption { return func(i *Identity) { i.contents = contents } } diff --git a/identity_test.go b/identity_test.go new file mode 100644 index 0000000..af4a6f4 --- /dev/null +++ b/identity_test.go @@ -0,0 +1,33 @@ +package saltyim + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const ( + testAddr = "alice@example.com" + testIdentityPath = "alice.key" +) + +func TestIdentity(t *testing.T) { + assert := assert.New(t) + require := require.New(t) + + dir, err := ioutil.TempDir("", "salty") + require.NoError(err) + defer os.RemoveAll(dir) + + addr, err := ParseAddr(testAddr) + require.NoError(err) + + fn := filepath.Join(dir, testIdentityPath) + ident, err := CreateIdentity(WithIdentityAddr(addr), WithIdentityPath(fn)) + require.NoError(err) + assert.NotNil(ident.Key()) +} diff --git a/lookup_test.go b/lookup_test.go new file mode 100644 index 0000000..635a44f --- /dev/null +++ b/lookup_test.go @@ -0,0 +1,18 @@ +package saltyim + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestParseAddr(t *testing.T) { + assert := assert.New(t) + require := require.New(t) + + addr, err := ParseAddr("alice@example.com") + require.NoError(err) + assert.Equal("alice", addr.User) + assert.Equal("example.com", addr.Domain) +} diff --git a/utils_test.go b/utils_test.go new file mode 100644 index 0000000..efa90c9 --- /dev/null +++ b/utils_test.go @@ -0,0 +1,17 @@ +package saltyim + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestGenerateULID(t *testing.T) { + assert := assert.New(t) + require := require.New(t) + + ulid, err := GenerateULID() + require.NoError(err) + assert.NotEmpty(ulid) +} diff --git a/version_test.go b/version_test.go new file mode 100644 index 0000000..675d32f --- /dev/null +++ b/version_test.go @@ -0,0 +1,15 @@ +package saltyim + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestFullVersion(t *testing.T) { + assert := assert.New(t) + + expected := fmt.Sprintf("%s@%s", Version, Commit) + assert.Equal(expected, FullVersion()) +}