From 6d183d2b59f219cab429a11d7e48b183d115fa31 Mon Sep 17 00:00:00 2001 From: N Date: Fri, 2 Sep 2022 12:07:21 +0200 Subject: [PATCH] Review1 --- asymcrypt.go | 22 ++-- asymcrypt_test.go | 37 ++++++- doc/protocol.tex | 66 ++++++------ endtoend_test.go | 34 +++++-- go.mod | 3 +- go.sum | 5 + https.go | 33 ------ id.enc | 243 ++++++++++++++++++++++++++++++++++++++++++++ id.json | 1 + identity.go | 12 +-- identity_test.go | 17 +--- invitation.png | Bin 0 -> 530 bytes messages.pb.go | 94 ++++++++++------- network.go | 7 -- pb/messages.proto | 15 ++- pb/protogen.bat | 4 + peer.go | 70 +++++++------ test | 2 + test.id | 51 ++++++++++ usermessage.go | 60 ----------- usermessage_test.go | 37 ------- 21 files changed, 524 insertions(+), 289 deletions(-) delete mode 100644 https.go create mode 100644 id.enc create mode 100644 id.json create mode 100644 invitation.png delete mode 100644 network.go create mode 100644 pb/protogen.bat create mode 100644 test create mode 100644 test.id delete mode 100644 usermessage.go delete mode 100644 usermessage_test.go diff --git a/asymcrypt.go b/asymcrypt.go index 0728f6e..e39790f 100644 --- a/asymcrypt.go +++ b/asymcrypt.go @@ -66,41 +66,41 @@ func Decrypt(privateKey string, data []byte) ([]byte, error) { if err != nil { log.Error().Msg("Message decryption b64 failed") } - decrypted, err := helper.DecryptBinaryMessageArmored(string(priv), []byte(""), string(data)) + decrypted, err := helper.DecryptBinaryMessageArmored(string(priv), nil, string(data)) if err != nil { log.Error().Msg("Message decryption failed") } return []byte(decrypted), err } -func EncryptAndSign(publicKey string, privateKey string, data []byte) ([]byte, []byte, error) { - pub, err := base64.StdEncoding.DecodeString(publicKey) +func EncryptAndSign(publicEncKey string, privateSignKey string, data []byte) ([]byte, []byte, error) { + pub, err := base64.StdEncoding.DecodeString(publicEncKey) if err != nil { log.Error().Msg("Message encryption and sign b64 failed") } - priv, err := base64.StdEncoding.DecodeString(privateKey) + priv, err := base64.StdEncoding.DecodeString(privateSignKey) if err != nil { log.Error().Msg("Message encryption and sign b64 failed") } - armor, signature, err := helper.EncryptSignBinaryDetached(string(pub), string(priv), []byte(""), data) + encrypted, signature, err := helper.EncryptSignBinaryDetached(string(pub), string(priv), nil, data) if err != nil { log.Error().Msg("Message encryption and sign failed") } - return []byte(armor), []byte(signature), err + return []byte(encrypted), []byte(signature), err } -func DecryptAndSign(publicKey string, privateKey string, data []byte, signature []byte) ([]byte, error) { - pub, err := base64.StdEncoding.DecodeString(publicKey) +func DecryptAndCheck(MyPrivateEncryptionKey string, peerContactPublicKey string, data []byte, signature []byte) (DecryptedMessage []byte, err error) { + pub, err := base64.StdEncoding.DecodeString(MyPrivateEncryptionKey) if err != nil { log.Error().Msg("Message decryption and sign b64 failed") } - priv, err := base64.StdEncoding.DecodeString(privateKey) + priv, err := base64.StdEncoding.DecodeString(peerContactPublicKey) if err != nil { log.Error().Msg("Message decryption and sign b64 failed") } - decrypted, err := helper.DecryptVerifyBinaryDetached(string(pub), string(priv), []byte(""), data, string(signature)) + DecryptedMessage, err = helper.DecryptVerifyBinaryDetached(string(pub), string(priv), nil, data, string(signature)) if err != nil { log.Error().Msg("Message decryption and sign failed") } - return decrypted, err + return DecryptedMessage, err } diff --git a/asymcrypt_test.go b/asymcrypt_test.go index 8c407f2..d2c00f9 100644 --- a/asymcrypt_test.go +++ b/asymcrypt_test.go @@ -5,6 +5,8 @@ import ( "fmt" "log" "testing" + + "github.com/stretchr/testify/assert" ) func TestNewKeyPair(t *testing.T) { @@ -21,7 +23,36 @@ func TestGetKey(t *testing.T) { // fmt.Println(key.Armor()) Armpubkey, _ := key.GetArmoredPublicKey() pubkey := base64.StdEncoding.EncodeToString([]byte(Armpubkey)) - if kp.Public != pubkey { - log.Fatal("error in public key") - } + assert.Equal(t, kp.Public, pubkey, "The two public keys should be the same.") + //if kp.Public != pubkey { + // log.Fatal("error in public key") + //} +} + +func TestEncryptDecrypt(t *testing.T) { + kp := NewKeyPair() + foo := "totoaimelesfrites!" + encMess, err := Encrypt(kp.Public, []byte(foo)) + if err != nil { + log.Println(err.Error()) + } + decMess, err2 := Decrypt(kp.Private, encMess) + if err2 != nil { + log.Println(err2.Error()) + } + assert.Equal(t, foo, decMess, "The two messages should be the same.") +} + +func TestEncryptDecryptSigned(t *testing.T) { + kp := NewKeyPair() + foo := "totoaimelesfrites!" + encMess, sign, err := EncryptAndSign(kp.Public, kp.Private, []byte(foo)) + if err != nil { + log.Println(err.Error()) + } + decMess, err2 := DecryptAndCheck(kp.Private, kp.Public, encMess, sign) + if err2 != nil { + log.Println(err2.Error()) + } + assert.Equal(t, foo, string(decMess), "The two messages should be the same.") } diff --git a/doc/protocol.tex b/doc/protocol.tex index f7ea59b..5392d9e 100644 --- a/doc/protocol.tex +++ b/doc/protocol.tex @@ -35,12 +35,12 @@ No phone number or email check will be performed, unlike main instant messaging \subsubsection{Trustable server based communication} Like most widely available messaging softwares, (Whatsapp, Signal, Viber, Telegram...), \textffm{Meow} provides a simple server based messaging. -The main difference is that allows to explicitly choose which server you want to use. +The main difference is it allows to explicitly choose which server you want to use. The server code being open source, we strongly encourage you to run your own server at home or in your company. The server requires very few ressources and will run on any low cost single board computer. \subsubsection{Anonymized message transfer} -\textffm{Meow} also provides an anonymizing transfer services very similar to the Tor Onion protocol, we called it the Matriochka protocol. +\textffm{Meow} also provides an anonymizing transfer services very similar to the Tor Onion protocol, we call it the Matriochka protocol. Any server can be used for building the transfer chain. Some of them might be marked as trusted. It is strongly advised to use trusted servers as your first node and message server (the one that holds your incoming messages). @@ -51,16 +51,16 @@ The presence protocol is simply activated by setting a flag in the message poll If that flag is set, your encrypted IP will be published on the server, allowing your only your peer(s) to decrypt it and directly communicate with your terminal. \subsubsection{Peer based privacy settings} -You might define specific communication privacy preferences for each of your contacts : +You might define specific communication privacy preferences for each of your contacts: \begin{itemize} \item simple server based communication allowed for Joe, - \item direct communication prefered with Julian, fallback to my own server, - \item matriochka protocol required for Edward, first node is one of my trusted servers, my message node is my own server, randomly switch from trusted server lists for others. + \item preferred direct communication with Julian, fallback to my own server, + \item required matriochka protocol for Edward, first node is one of my trusted servers, my message node is my own server, randomly switch from trusted server lists for others. \item ... \end{itemize} \subsection{Multiple devices support} \textffm{Meow} allows you to be connected from multiple devices and offers chat synchronization capability. -A device might be revoqued anytime from an other any one. Proof of your identity (password or other) shall be provided in order to grant device revocation. +A device might be revoqued anytime from any other one. Proof of your identity (password or other) shall be provided in order to grant device revocation. \subsection{Adding contacts} If you want to add a new contact, keys and uuids will be generated, then a rendez-vous card will be created. @@ -68,8 +68,8 @@ That rendez-vous card might be sent by any trustable communication means, or pre In return your contact will provide the exact same data, encrypted with your public key and delivered to the address specified in the initial rendez-vous card. \subsection{Contacts forwarding} -Using the \textffm{Meow} protocol a user won't be able to forward your contact information without your consent. -Each user knows you as a different identity, thus forwarding a known identity to another user is meaningless. Any message to that identity signed by another user thna you would be discarded. +By using the \textffm{Meow} protocol a user won't be able to forward your contact information without your consent. +Each user knows you as a different identity, thus forwarding a known identity to another user is meaningless. Any message to that identity signed by another user than you would be discarded. \subsection{Group conversation} @@ -81,18 +81,18 @@ A local (server based) emergency broadcast service will be provided. It will pro \subsection{Public networks shortage resilience} -\textffm{Meow} may run without Internet connection, either on an isolated wifi access point, either on a meshed network of wifi routers or even via serial IOT transport layers (LoRa,...) +\textffm{Meow} may run without Internet connection, either on an isolated wifi access point, or on a meshed network of wifi routers or even via serial IOT transport layers (LoRa,...) \subsection{User directory service} -This service allows to restore a lost functionality of Internet historic chat services (like ICQ). You could simply set a "Free for chat" status that allowed other people to contact you, either randomly or based on a short description that you might provide. +This service allows to restore a lost functionality of Internet historic chat services (like ICQ). You could simply set a "Free for chat" status that would allow other people to contact you, either randomly or based on a short description that you might provide. Why providing that service while the internet is suffocating due to the abundance of social networks ?\\ -Well, that option offered a few advantages : +Well, that option offers a few advantages : \begin{itemize} - \item you're still an anonymous user chatting with other anonymous users. - \item no social network algorithm will select people that think/behave/vote/eat... just like you. Diversity makes a better world. - \item a smaller community of users, skilled enough to operate a \textffm{Meow} chat app... that might provide a first filter. + \item you are still an anonymous user chatting with other anonymous users; + \item no social network algorithm will select people that think/behave/vote/eat... just like you. Diversity makes a better world; + \item a smaller community of users, skilled enough to operate a \textffm{Meow} chat app... that might provide a first filter; It's a bit like in the old times, when people had to be able to start a win98 computer, connect it to internet, then download and install ICQ... If you lost some time in social networks, and experienced ICQ in the 2000's, you know what I mean. \end{itemize} @@ -104,45 +104,43 @@ Each \textffm{Meow} user has a unique identity. That identity is strictly privat Let's call that one the User Key Pair (Ukp) \subsection{Contact identity} -Each of your contacts will know you as a different identity, we'll call that one the Contact Key Pair (Ckp) -That contact Key Pair will not change once it's agreed between the two peerr : An initial key will be exchanged as part of the peer invitation process. -As other people myth have seen your key -This means that : +Each of your contacts will know you under a different identity, we'll call that one the Contact Key Pair (Ckp) +That contact Key Pair will not change once it's agreed between both peers: an initial key will be exchanged as part of the peer invitation process. +As other people might have seen your key, this means that : \begin{itemize} - \item none of your contacts will be able to forward your id to another person without your consent - \item any message to that Ckp, not signed by the user associated to it, will be discarded. + \item none of your contacts will be able to forward your id to another person without your consent; + \item any message to that Ckp, not signed by its associated user, will be discarded. \end{itemize} \subsection{Conversation encryption} -Each conversation with one of your contacts will be encrypted using an encryption keypair (Ekp) +Each conversation with one of your contacts will be encrypted using an encryption keypair (Ekp) allowing cyphering your conversation. The Ekp might be changed anytime by its owner and the new public key will be sent along the last message. -The Ekp is used to cypher your conversation. \subsection{Conversation lookup} A contact conversation Lookup Key Pair(Lkp) is also associated with your conversation. The Lkp public key is used to identify your conversation on a server. -the private key allows you to sign your request and prove the server that you are the legitimate recipient for a message. -This Lkp can be changed anytime by it's owner and the new public key will be sent along the last message. -The Lkp and the Ekp are only changed, once the change has beeen acknowledged by your contact. +The private key allows you to sign your request and prove the server that you are the legitimate recipient for a message. +This Lkp can be changed anytime by its owner and the new public key will be sent along the last message. +The Lkp and the Ekp are only changed once the change has beeen acknowledged by your contact. \subsection{Server identity} Each server has a Server key (Skp). That key allows you to cypher the messages that you're sending to the server. \subsection{Device identity} -Each device is identified by a key (Dkp), that device key allows you to perform secured exchanges between your devices for synchronization/revocation purposes. -Communication between devices is achieved using the same principle as the user to user communication. A device might be considered as any another user. The messages content are based on a synchronization protocol. +Each device is identified by a device key (Dkp) that allows you to perform secured exchanges between your devices for synchronization/revocation purposes. +Communication between devices is achieved using the same principle as the user to user communication. A device might be considered as any another user. The messages content is based on a synchronization protocol. \section{Contact management} \subsection{Adding a contact} Rendez-vous card, containing : \begin{itemize} - \item Your public key for that contact - \item An initial conversation public key for getting encrypted messages from that contact - \item An initial conversation uuid that you'll use to lookup for incoming messages on the servers - \item A list of your prefered message servers - \item A signature to prevent transmission of tampered data + \item Your public key for that contact; + \item An initial conversation public key for getting encrypted messages from that contact; + \item An initial conversation uuid that you'll use to lookup for incoming messages on the servers; + \item A list of your preferred message servers; + \item A signature to prevent transmission of tampered data. \end{itemize} \subsection{Sharing a contact} -If a user wants to forward one of his contacts to you, that will be handled as a double request : +If a user wants to forward one of his contacts to you, it will be handled as a double request: \begin{enumerate} \item I'm receiving a contact name, without any key \item @@ -164,7 +162,7 @@ TODO \section{Transport protocols} \subsection{URLs} Server urls do define the protocol used for communicating with the server. -Some of the protocols will be described hereafter, but that list is not exhaustive, and might be extended in the future.\\ +Some of the protocols will be described hereafter, but that list is not exhaustive and might be extended in the future.\\ Examples of a valid url: \begin{verbatim} http://myserver.com diff --git a/endtoend_test.go b/endtoend_test.go index 30ca649..c554b68 100644 --- a/endtoend_test.go +++ b/endtoend_test.go @@ -12,7 +12,7 @@ func TestEndToEnd(t *testing.T) { // Create my own identity // fmt.Println("Trying to load identity from file.") - me, err := LoadIdentity("test.id") + me, err := LoadIdentity("id.enc") if err != nil { fmt.Println("Failed : creating New identity...") me = CreateIdentity("myname") @@ -36,6 +36,8 @@ func TestEndToEnd(t *testing.T) { // Simulate peer invitation response : generate the friend's keypair fmt.Println("Simulating first friend answer...") var receivedContact ContactCard + + // Friend simulated invitation firstFriendContactKp := NewKeyPair() firstFriendEncryptionKp := NewKeyPair() firstFriendLookupKp := NewKeyPair() @@ -45,9 +47,12 @@ func TestEndToEnd(t *testing.T) { receivedContact.LookupPublicKey = firstFriendLookupKp.Public var friendsMessageServers ServerList friendsMessageServers.AddUrls([]string{"http://myfriend.org/meow/"}) + // end Friend simulated invitation + for _, srv := range friendsMessageServers.Servers { receivedContact.PullServers = append(receivedContact.PullServers, srv.ServerData) } + // End simulating contact invitation response // @@ -55,7 +60,7 @@ func TestEndToEnd(t *testing.T) { // Finalize the contact with the invitation response // me.FinalizeInvitation(myFirstFriend, &receivedContact) - err = me.Save("test.id") + err = me.Save("id.enc") if err != nil { fmt.Println(err.Error()) } @@ -63,10 +68,27 @@ func TestEndToEnd(t *testing.T) { a, _ = json.Marshal(me) ioutil.WriteFile("id.json", a, 0644) fmt.Println(string(a)) - } - // go me.CheckMessages() - //myFirstFriend.SetComMethod() - //msg := myFirstFriend.SendText() + // create message to simulated friend + sentmessage := "Hello friend!" + lookupK, EncMsg, MsgSignature, Servers, err := myFirstFriend.CreateMessage([]byte(sentmessage)) + if err != nil { + fmt.Println(err.Error()) + } + fmt.Println(lookupK) + fmt.Println(len(Servers)) + // simulated friend decoding the message + //ReadMessage + + // simulates if peer can decrypt my message + //Message := "toto" + //Signature := "test" + decMess, err2 := DecryptAndCheck(myFirstFriend.EncryptionKp.Private, myFirstFriend.Contact.EncryptionPublicKey, []byte(EncMsg), MsgSignature) + if err2 != nil { + fmt.Println(err2.Error()) + } + fmt.Println(decMess) + // + } } diff --git a/go.mod b/go.mod index f07383c..cda29ec 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,10 @@ go 1.16 require ( github.com/ProtonMail/gopenpgp/v2 v2.2.4 github.com/go-resty/resty/v2 v2.6.0 + github.com/golang/protobuf v1.5.2 // indirect github.com/google/uuid v1.3.0 github.com/makiuchi-d/gozxing v0.1.1 github.com/rs/zerolog v1.25.0 github.com/stretchr/testify v1.4.0 - google.golang.org/protobuf v1.27.1 + google.golang.org/protobuf v1.28.1 ) diff --git a/go.sum b/go.sum index a2a9892..57516f1 100644 --- a/go.sum +++ b/go.sum @@ -13,6 +13,8 @@ github.com/go-resty/resty/v2 v2.6.0 h1:joIR5PNLM2EFqqESUjCMGXrWmXNHEU9CEiK813oKY github.com/go-resty/resty/v2 v2.6.0/go.mod h1:PwvJS6hvaPkjtjNg9ph+VrSD92bi5Zq73w/BIH7cC3Q= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= @@ -82,8 +84,11 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= diff --git a/https.go b/https.go deleted file mode 100644 index c3aabff..0000000 --- a/https.go +++ /dev/null @@ -1,33 +0,0 @@ -package meowlib - -import ( - "crypto/tls" - - "github.com/go-resty/resty/v2" - "github.com/rs/zerolog/log" -) - -type Https struct { - url string -} - -func (https *Https) Send(msg []byte) ([]byte, error) { - client := resty.New().SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}) - - resp, err := client.R(). - SetHeader("Content-Type", "application/json"). - SetBody(msg). - Post(https.url + "/message/add/") - if err != nil { - log.Error().Msg(err.Error()) - } - return resp.Body(), err -} - -func (https *Https) Start(callback *func() []InternalMessage) { - -} - -func (https *Https) Stop() { - -} diff --git a/id.enc b/id.enc new file mode 100644 index 0000000..cfa00d5 --- /dev/null +++ b/id.enc @@ -0,0 +1,243 @@ +-----BEGIN PGP MESSAGE----- +Comment: https://gopenpgp.org +Version: GopenPGP 2.2.4 + +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 +=zCs9 +-----END PGP MESSAGE----- \ No newline at end of file diff --git a/id.json b/id.json new file mode 100644 index 0000000..cee582d --- /dev/null +++ b/id.json @@ -0,0 +1 @@ +{"nickname":"myname","public_key":"LS0tLS1CRUdJTiBQR1AgUFVCTElDIEtFWSBCTE9DSy0tLS0tClZlcnNpb246IEdvcGVuUEdQIDIuMi40CkNvbW1lbnQ6IGh0dHBzOi8vZ29wZW5wZ3Aub3JnCgp4ak1FWXc0VmR4WUpLd1lCQkFIYVJ3OEJBUWRBT0hkU1JiS1RNZFJlbHJGNjJTL2dISmZkamVMbEhIL1hDWEpDCmNJYjJQOHZOQzI1aGJXVWdQRzFoYVd3K3dvd0VFeFlJQUQ0RkFtTU9GWGNKa08wNnJra09obE9jRnFFRWpydHIKbGwvbVplRlJjMEo3N1RxdVNRNkdVNXdDR3dNQ0hnRUNHUUVEQ3drSEFoVUlBeFlBQWdJaUFRQUFMYVVCQUtscgozWm5zUFczVVlIM0g2ZHg5K0hsWGVkMmZXRWVpNFNTWnFGMElLd05oQVA5Mm1XcHIxYjY4ajF1VUpwNksrZFllCldITzlsWlJCSHFSKzZDTGRYQU1WRHM0NEJHTU9GWGNTQ2lzR0FRUUJsMVVCQlFFQkIwRDNXbTF3N0lWZXhwa2gKdXhkUWxaYW9OUHNzbUovWk4yUG1hZXY4aGV5UVZRTUJDZ25DZUFRWUZnZ0FLZ1VDWXc0VmR3bVE3VHF1U1E2RwpVNXdXb1FTT3UydVdYK1psNFZGelFudnRPcTVKRG9aVG5BSWJEQUFBZUxrQSt3ZGkxb3o4c0xqbHBXOGI0eXdOCm9ZVmwxV0lPQUFVK2lveVhoUTlZbXFkMEFQOTVIREVpbVVqYXdnWUJ1YmsreGlTTmRWc1hMNDYxK1ZWM2hGcksKR005SEJnPT0KPVFKeTUKLS0tLS1FTkQgUEdQIFBVQkxJQyBLRVkgQkxPQ0stLS0tLQ==","private_key":"LS0tLS1CRUdJTiBQR1AgUFJJVkFURSBLRVkgQkxPQ0stLS0tLQpWZXJzaW9uOiBHb3BlblBHUCAyLjIuNApDb21tZW50OiBodHRwczovL2dvcGVucGdwLm9yZwoKeFZnRVl3NFZkeFlKS3dZQkJBSGFSdzhCQVFkQU9IZFNSYktUTWRSZWxyRjYyUy9nSEpmZGplTGxISC9YQ1hKQwpjSWIyUDhzQUFQOXRuOTFabEd1UVVxYWNOVkFYYW9jQzRtd3BuaUsyKzlsVmxlRS9aUFphN0JGZXpRdHVZVzFsCklEeHRZV2xzUHNLTUJCTVdDQUErQlFKakRoVjNDWkR0T3E1SkRvWlRuQmFoQkk2N2E1WmY1bVhoVVhOQ2UrMDYKcmtrT2hsT2NBaHNEQWg0QkFoa0JBd3NKQndJVkNBTVdBQUlDSWdFQUFDMmxBUUNwYTkyWjdEMXQxR0I5eCtuYwpmZmg1VjNuZG4xaEhvdUVrbWFoZENDc0RZUUQvZHBscWE5Vyt2STlibENhZWl2bldIbGh6dlpXVVFSNmtmdWdpCjNWd0RGUTdIWFFSakRoVjNFZ29yQmdFRUFaZFZBUVVCQVFkQTkxcHRjT3lGWHNhWklic1hVSldXcURUN0xKaWYKMlRkajVtbnIvSVhza0ZVREFRb0pBQUQvZXFZc3VvdE9taE9TeFpUNlFOTGxacjd6SlN2MUVuQjhzVXNVaFhDbQp4d0FSTThKNEJCZ1dDQUFxQlFKakRoVjNDWkR0T3E1SkRvWlRuQmFoQkk2N2E1WmY1bVhoVVhOQ2UrMDZya2tPCmhsT2NBaHNNQUFCNHVRRDdCMkxXalB5d3VPV2xieHZqTEEyaGhXWFZZZzRBQlQ2S2pKZUZEMWlhcDNRQS8za2MKTVNLWlNOckNCZ0c1dVQ3R0pJMTFXeGN2anJYNVZYZUVXc29ZejBjRwo9MG1QdQotLS0tLUVORCBQR1AgUFJJVkFURSBLRVkgQkxPQ0stLS0tLQ==","peers":[{"name":"myfirstfriend","me":{"public":"LS0tLS1CRUdJTiBQR1AgUFVCTElDIEtFWSBCTE9DSy0tLS0tClZlcnNpb246IEdvcGVuUEdQIDIuMi40CkNvbW1lbnQ6IGh0dHBzOi8vZ29wZW5wZ3Aub3JnCgp4ak1FWXc0VmR4WUpLd1lCQkFIYVJ3OEJBUWRBTlVMTWVnRmk0Z1BMVmdubXp6cWtHYkhGZEtnTzA3RzIzWUVzCjdzOEdOa3ZOQzI1aGJXVWdQRzFoYVd3K3dvd0VFeFlJQUQ0RkFtTU9GWGNKa0lZQUN2dnZ0eHlCRnFFRTZVWmMKdDlyRlVRdHdzMUZDaGdBSysrKzNISUVDR3dNQ0hnRUNHUUVEQ3drSEFoVUlBeFlBQWdJaUFRQUF6SlVBL1JaRApiRTgyZnZBNDlnVnVnOWEydzQyQWFQeTlyVjlkdnZQNDNqV3RQRllYQVA5SHdwY2ZWYlBNOFR6ZGV0cm03L29PCjV1SUdaRTJpb1ArN29tS0x3Nlg4Q000NEJHTU9GWGNTQ2lzR0FRUUJsMVVCQlFFQkIwRDZ4WlJvclpmbmwrYjAKc2IxOVlrWTQrOXhPL2diZG8xa0VQcjJkbXFaOFBnTUJDZ25DZUFRWUZnZ0FLZ1VDWXc0VmR3bVFoZ0FLKysrMwpISUVXb1FUcFJseTMyc1ZSQzNDelVVS0dBQXI3NzdjY2dRSWJEQUFBY2EwQkFLSGh5UklBejhFZjlkVzhOUjRWCkpaci9YREZuTks5Rkp0T3pwSDZxN0FXUEFRRG4yblR6WjR3TjhYaWorMDdpU08xYVBtVkY3K0xlUmxmK1hsTTYKaFZOWkN3PT0KPXNaVzcKLS0tLS1FTkQgUEdQIFBVQkxJQyBLRVkgQkxPQ0stLS0tLQ==","private":"LS0tLS1CRUdJTiBQR1AgUFJJVkFURSBLRVkgQkxPQ0stLS0tLQpWZXJzaW9uOiBHb3BlblBHUCAyLjIuNApDb21tZW50OiBodHRwczovL2dvcGVucGdwLm9yZwoKeFZnRVl3NFZkeFlKS3dZQkJBSGFSdzhCQVFkQU5VTE1lZ0ZpNGdQTFZnbm16enFrR2JIRmRLZ08wN0cyM1lFcwo3czhHTmtzQUFRQ0N6dlcvM3RIeWRwTXQxTzFMMXQwaXN6c3JHVHIyL1ZkWVI5S0lzUkUrc3hJZnpRdHVZVzFsCklEeHRZV2xzUHNLTUJCTVdDQUErQlFKakRoVjNDWkNHQUFyNzc3Y2NnUmFoQk9sR1hMZmF4VkVMY0xOUlFvWUEKQ3Z2dnR4eUJBaHNEQWg0QkFoa0JBd3NKQndJVkNBTVdBQUlDSWdFQUFNeVZBUDBXUTJ4UE5uN3dPUFlGYm9QVwp0c09OZ0dqOHZhMWZYYjd6K040MXJUeFdGd0QvUjhLWEgxV3p6UEU4M1hyYTV1LzZEdWJpQm1STm9xRC91NkppCmk4T2wvQWpIWFFSakRoVjNFZ29yQmdFRUFaZFZBUVVCQVFkQStzV1VhSzJYNTVmbTlMRzlmV0pHT1B2Y1R2NEcKM2FOWkJENjluWnFtZkQ0REFRb0pBQUQvWW9IZ2RvSFY0aERacFRDamtoSjdBQ2VKOG9PQkc5OWl2Y1BML25Jbgowd0FScDhKNEJCZ1dDQUFxQlFKakRoVjNDWkNHQUFyNzc3Y2NnUmFoQk9sR1hMZmF4VkVMY0xOUlFvWUFDdnZ2CnR4eUJBaHNNQUFCeHJRRUFvZUhKRWdEUHdSLzExYncxSGhVbG12OWNNV2MwcjBVbTA3T2tmcXJzQlk4QkFPZmEKZFBObmpBM3hlS1A3VHVKSTdWbytaVVh2NHQ1R1YvNWVVenFGVTFrTAo9SHRSMwotLS0tLUVORCBQR1AgUFJJVkFURSBLRVkgQkxPQ0stLS0tLQ==","generated":"2022-08-30T15:49:43.9615543+02:00"},"contact":{"name":"I'm the friend","contact_public_key":"LS0tLS1CRUdJTiBQR1AgUFVCTElDIEtFWSBCTE9DSy0tLS0tClZlcnNpb246IEdvcGVuUEdQIDIuMi40CkNvbW1lbnQ6IGh0dHBzOi8vZ29wZW5wZ3Aub3JnCgp4ak1FWXc0VmR4WUpLd1lCQkFIYVJ3OEJBUWRBSEtFeEtUWUh1Q1FHUUR6bkNwTHJvcm1FOUROeUN4cXEwM3lpCmxQbkVvemZOQzI1aGJXVWdQRzFoYVd3K3dvd0VFeFlJQUQ0RkFtTU9GWGNKa0NNZndzQXN0dTdnRnFFRWdzVEIKL1VPWmZlRmVJNE1wSXgvQ3dDeTI3dUFDR3dNQ0hnRUNHUUVEQ3drSEFoVUlBeFlBQWdJaUFRQUFJZE1CQUpDcApXWU1wVEVNNk5LQk02VWgzQlNudGpxajk1NmtyR1lCOW5xd1VmSTNlQVFEMytsR2txdDlxRDJaMnI3VzRNSHA0CjYyVjc5ejY2d3czb25YWUZxT1JkQ2M0NEJHTU9GWGNTQ2lzR0FRUUJsMVVCQlFFQkIwQnZoN3VZMEJiWEk4N2kKNXFJdGZyMDA5T0VFWThlRjBGNXZ6Vk85UjFNbU13TUJDZ25DZUFRWUZnZ0FLZ1VDWXc0VmR3bVFJeC9Dd0N5Mgo3dUFXb1FTQ3hNSDlRNWw5NFY0amd5a2pIOExBTExidTRBSWJEQUFBaHlFQS9pemxOMEJVUGFSOGZhRTlwdFlvClR4SnhYdGp0MFlLNm5qT0x3NnZ4dGVDMkFRRHlhQUtiRk5zK3Y2YWx0UVBjMk5yZXMwSmsvOTBTWVpLV2t4VkwKd1lVQUF3PT0KPU1EK0wKLS0tLS1FTkQgUEdQIFBVQkxJQyBLRVkgQkxPQ0stLS0tLQ==","encryption_public_key":"LS0tLS1CRUdJTiBQR1AgUFVCTElDIEtFWSBCTE9DSy0tLS0tClZlcnNpb246IEdvcGVuUEdQIDIuMi40CkNvbW1lbnQ6IGh0dHBzOi8vZ29wZW5wZ3Aub3JnCgp4ak1FWXc0VmR4WUpLd1lCQkFIYVJ3OEJBUWRBMEFERXNKV1RnbEFqQ3RMRnpVaU5PaFcvcFc3c0lKMWV3S0J2ClN2N0RmZkROQzI1aGJXVWdQRzFoYVd3K3dvd0VFeFlJQUQ0RkFtTU9GWGNKa082UzdHRmpjd0xORnFFRVVQUVgKUC9BTndqQUlwK292N3BMc1lXTnpBczBDR3dNQ0hnRUNHUUVEQ3drSEFoVUlBeFlBQWdJaUFRQUFCVFVCQUpldgo0UHMxd3RGdVhwU3RidDdGKzVYelNwNU44Q2IyeXowNlRLakZIV3BLQVFELytOQzRaWit4YW84clRESG9nWTJlCjRCYlplTzBwcnBvSkdocktuTkhRQzg0NEJHTU9GWGNTQ2lzR0FRUUJsMVVCQlFFQkIwQ2RVTU9oTFYxeWVaSjcKRFIzOXdYU2FhaDY4TE80aytSdW9tTVN0SnFydEZBTUJDZ25DZUFRWUZnZ0FLZ1VDWXc0VmR3bVE3cExzWVdOegpBczBXb1FSUTlCYy84QTNDTUFpbjZpL3VrdXhoWTNNQ3pRSWJEQUFBUTlnQkFMd1lCb3RpU2hXR3lacHB6TWExCko4T0FRd3ZETWRhUjRmM280YTFxOFYwVUFQOXIwdXEwTDBqRm5QVHJOaER5bUZGRkJEdlhuSTg1ZGpVWnZ5aEMKV1AwYUF3PT0KPTlEOEgKLS0tLS1FTkQgUEdQIFBVQkxJQyBLRVkgQkxPQ0stLS0tLQ==","lookup_public_key":"LS0tLS1CRUdJTiBQR1AgUFVCTElDIEtFWSBCTE9DSy0tLS0tClZlcnNpb246IEdvcGVuUEdQIDIuMi40CkNvbW1lbnQ6IGh0dHBzOi8vZ29wZW5wZ3Aub3JnCgp4ak1FWXc0VmR4WUpLd1lCQkFIYVJ3OEJBUWRBajdBcVM5ck1BUzdQVEVZS05NUWtHTlpVM1ROZ0U2bVhLRXRxClV4dDl0cEhOQzI1aGJXVWdQRzFoYVd3K3dvd0VFeFlJQUQ0RkFtTU9GWGNKa1BZQzlVc2pneSs0RnFFRTF4WkMKb1hRNThJVkJST0tyOWdMMVN5T0RMN2dDR3dNQ0hnRUNHUUVEQ3drSEFoVUlBeFlBQWdJaUFRQUF6WFFCQVB3TQp1ZmtJZnZZMkIxVUhGMDVSZzNrWkY0VXZWSkxyajV1eTBUWUxrSklkQVFETFNBZ0ZJcExRT1o2a25LK1o3cEs5Ckh4Q0l2elIrWEV1em43K2VDT3ZyQ2M0NEJHTU9GWGNTQ2lzR0FRUUJsMVVCQlFFQkIwQloxTzVFaWVYZC85bVkKWlA3bjR6Tmg1TWRGSk1pU0tCWmlaeDM2UzFROFl3TUJDZ25DZUFRWUZnZ0FLZ1VDWXc0VmR3bVE5Z0wxU3lPRApMN2dXb1FUWEZrS2hkRG53aFVGRTRxdjJBdlZMSTRNdnVBSWJEQUFBM29jQkFNOUgzclV4OVdsV3JJMEo5UHZjCm1vSmJtMFA4L0lLeE4rbGZjUHpQdWllNEFRQ0dsemM4T3ZQK0oxSjZORnV2NDlyQ3Q4QVNvSys4cWRHOGdZYm4KZFJSYUR3PT0KPUpIUUcKLS0tLS1FTkQgUEdQIFBVQkxJQyBLRVkgQkxPQ0stLS0tLQ==","pull_servers":[{"Url":"http://myfriend.org/meow/"}]},"last_message":"0001-01-01T00:00:00Z","conversation_kp":{"public":"LS0tLS1CRUdJTiBQR1AgUFVCTElDIEtFWSBCTE9DSy0tLS0tClZlcnNpb246IEdvcGVuUEdQIDIuMi40CkNvbW1lbnQ6IGh0dHBzOi8vZ29wZW5wZ3Aub3JnCgp4ak1FWXc0VmR4WUpLd1lCQkFIYVJ3OEJBUWRBZlRvNnBSbVhPSTBFUTZ6UGZWeExxNDI3YThTVzhNMS9WLzdVCm9Oa3B2MmZOQzI1aGJXVWdQRzFoYVd3K3dvd0VFeFlJQUQ0RkFtTU9GWGNKa0hNcG9TQm0rbG1RRnFFRVNHTFMKQkloRzFiVmRMWFkxY3ltaElHYjZXWkFDR3dNQ0hnRUNHUUVEQ3drSEFoVUlBeFlBQWdJaUFRQUEwN2NBLzExZwp4ZXR5dUtnNXdGV1p1cEtoZmhMV2MvaGdyQ1R6bk9SN3BvUXBoTkQwQVB3S1JrVldQSEFrYUtMbzJ4NVVVVVJ6CnM4SG4ra2ZiNjhWT2R4M3RDckp3QTg0NEJHTU9GWGNTQ2lzR0FRUUJsMVVCQlFFQkIwQXB6bmZxYUMzMWVEd04KbHN4c2dYL0lNQW1McTJZeFZqOGRlK2VMb1J1SFBRTUJDZ25DZUFRWUZnZ0FLZ1VDWXc0VmR3bVFjeW1oSUdiNgpXWkFXb1FSSVl0SUVpRWJWdFYwdGRqVnpLYUVnWnZwWmtBSWJEQUFBeUNrQS8zeEszZ1RGU1VmcW1RVVcrN1RNCkkwcFVFR3BsNU81elF1NDZ5RDZ0cW1YNkFQd0xGK2NpQ2V4Z1JPOG5HeFYwQWlibkRoMkNRSHV0bXpxSU1iY1UKcklIdkN3PT0KPUlWVzkKLS0tLS1FTkQgUEdQIFBVQkxJQyBLRVkgQkxPQ0stLS0tLQ==","private":"LS0tLS1CRUdJTiBQR1AgUFJJVkFURSBLRVkgQkxPQ0stLS0tLQpWZXJzaW9uOiBHb3BlblBHUCAyLjIuNApDb21tZW50OiBodHRwczovL2dvcGVucGdwLm9yZwoKeFZnRVl3NFZkeFlKS3dZQkJBSGFSdzhCQVFkQWZUbzZwUm1YT0kwRVE2elBmVnhMcTQyN2E4U1c4TTEvVi83VQpvTmtwdjJjQUFRRGFmZ2ovWlZCck8yNXM1bkNWRzVQenhuMzJUclhQYVN3SWhmN05FaUZNc2hCS3pRdHVZVzFsCklEeHRZV2xzUHNLTUJCTVdDQUErQlFKakRoVjNDWkJ6S2FFZ1p2cFprQmFoQkVoaTBnU0lSdFcxWFMxMk5YTXAKb1NCbStsbVFBaHNEQWg0QkFoa0JBd3NKQndJVkNBTVdBQUlDSWdFQUFOTzNBUDlkWU1YcmNyaW9PY0JWbWJxUwpvWDRTMW5QNFlLd2s4NXprZTZhRUtZVFE5QUQ4Q2taRlZqeHdKR2lpNk5zZVZGRkVjN1BCNS9wSDIrdkZUbmNkCjdRcXljQVBIWFFSakRoVjNFZ29yQmdFRUFaZFZBUVVCQVFkQUtjNTM2bWd0OVhnOERaYk1iSUYveURBSmk2dG0KTVZZL0hYdm5pNkViaHowREFRb0pBQUQvVG1iU2xBUDV1eTYxckJ0dTNpL1ozWkRqS2dDOWlCZXVsRmZWcjBKMwpVZ0FRek1KNEJCZ1dDQUFxQlFKakRoVjNDWkJ6S2FFZ1p2cFprQmFoQkVoaTBnU0lSdFcxWFMxMk5YTXBvU0JtCitsbVFBaHNNQUFESUtRRC9mRXJlQk1WSlIrcVpCUmI3dE13alNsUVFhbVhrN25OQzdqcklQcTJxWmZvQS9Bc1gKNXlJSjdHQkU3eWNiRlhRQ0p1Y09IWUpBZTYyYk9vZ3h0eFNzZ2U4TAo9enFsbQotLS0tLUVORCBQR1AgUFJJVkFURSBLRVkgQkxPQ0stLS0tLQ==","generated":"2022-08-30T15:49:43.9620978+02:00"},"lookup_kp":{"public":"LS0tLS1CRUdJTiBQR1AgUFVCTElDIEtFWSBCTE9DSy0tLS0tClZlcnNpb246IEdvcGVuUEdQIDIuMi40CkNvbW1lbnQ6IGh0dHBzOi8vZ29wZW5wZ3Aub3JnCgp4ak1FWXc0VmR4WUpLd1lCQkFIYVJ3OEJBUWRBYXIwWmUrT3NpSk50cDd2d1RHQ3BIZ0tIaEVhRDF5bW9tUXFDCkNGTmc2OHpOQzI1aGJXVWdQRzFoYVd3K3dvd0VFeFlJQUQ0RkFtTU9GWGNKa05SUzJUUVkwanJQRnFFRS8ydFIKemllc0RJZEJNOWtBMUZMWk5CalNPczhDR3dNQ0hnRUNHUUVEQ3drSEFoVUlBeFlBQWdJaUFRQUFPSWdBLzNVTwpQL1djL2VSTmhnMXJCb2xEU3VBckEyeTF0NUR0K1BEMlR2U010M2Q5QVFDQ2hJQVRNVDJyUkZueDJ4VlJ0bkQyCk50cWdFVE1jS0dPQ0Q5Wjk4bmRXQ000NEJHTU9GWGNTQ2lzR0FRUUJsMVVCQlFFQkIwRGg3UnBQMC9LQ2VlaUUKaVFIT1hlQzVoclhmYXFlck00b2lENFA4K2IyOEhBTUJDZ25DZUFRWUZnZ0FLZ1VDWXc0VmR3bVExRkxaTkJqUwpPczhXb1FUL2ExSE9KNndNaDBFejJRRFVVdGswR05JNnp3SWJEQUFBcWJRQkFKdjV5U0c4VDVEZUdCMWxMV0d1CkRDTFpjNDRRODFMSmxrT1AvSkhQc0s5SEFQOWVqK3dsTnZXVU5MVWFicWNGUDFtV3FwNDBTUVBtWWs3R010QTQKZHdIREFnPT0KPUcyWFAKLS0tLS1FTkQgUEdQIFBVQkxJQyBLRVkgQkxPQ0stLS0tLQ==","private":"LS0tLS1CRUdJTiBQR1AgUFJJVkFURSBLRVkgQkxPQ0stLS0tLQpWZXJzaW9uOiBHb3BlblBHUCAyLjIuNApDb21tZW50OiBodHRwczovL2dvcGVucGdwLm9yZwoKeFZnRVl3NFZkeFlKS3dZQkJBSGFSdzhCQVFkQWFyMFplK09zaUpOdHA3dndUR0NwSGdLSGhFYUQxeW1vbVFxQwpDRk5nNjh3QUFRRFhyMllFZTkxTWJHRTRHRFRPSnk2dWFGbTFlczRPdzBCeld3OWNTWU1zV0EwUHpRdHVZVzFsCklEeHRZV2xzUHNLTUJCTVdDQUErQlFKakRoVjNDWkRVVXRrMEdOSTZ6eGFoQlA5clVjNG5yQXlIUVRQWkFOUlMKMlRRWTBqclBBaHNEQWg0QkFoa0JBd3NKQndJVkNBTVdBQUlDSWdFQUFEaUlBUDkxRGovMW5QM2tUWVlOYXdhSgpRMHJnS3dOc3RiZVE3Zmp3OWs3MGpMZDNmUUVBZ29TQUV6RTlxMFJaOGRzVlViWnc5amJhb0JFekhDaGpnZy9XCmZmSjNWZ2pIWFFSakRoVjNFZ29yQmdFRUFaZFZBUVVCQVFkQTRlMGFUOVB5Z25ub2hJa0J6bDNndVlhMTMycW4KcXpPS0lnK0QvUG05dkJ3REFRb0pBQUQvYy9qVzJGdUg1cHNTcGZKVyttUlFxVGZla3BOcWR4V1VOSTNlTzN4Nwpnd2dSOGNKNEJCZ1dDQUFxQlFKakRoVjNDWkRVVXRrMEdOSTZ6eGFoQlA5clVjNG5yQXlIUVRQWkFOUlMyVFFZCjBqclBBaHNNQUFDcHRBRUFtL25KSWJ4UGtONFlIV1V0WWE0TUl0bHpqaER6VXNtV1E0LzhrYyt3cjBjQS8xNlAKN0NVMjlaUTB0UnB1cHdVL1daYXFualJKQStaaVRzWXkwRGgzQWNNQwo9RkFmSQotLS0tLUVORCBQR1AgUFJJVkFURSBLRVkgQkxPQ0stLS0tLQ==","generated":"2022-08-30T15:49:43.9620978+02:00"}}],"known_servers":{"Name":"","Servers":null},"message_servers":{"Name":"Message Servers","Servers":[{"server_data":{"Url":"http://127.0.0.1/meow/"},"last_check":"0001-01-01T00:00:00Z","me":{"generated":"0001-01-01T00:00:00Z"}},{"server_data":{"Url":"mqtt://127.0.0.1"},"last_check":"0001-01-01T00:00:00Z","me":{"generated":"0001-01-01T00:00:00Z"}},{"server_data":{"Url":"meow://127.0.0.1"},"last_check":"0001-01-01T00:00:00Z","me":{"generated":"0001-01-01T00:00:00Z"}}]}} \ No newline at end of file diff --git a/identity.go b/identity.go index 3a098b0..7341aa9 100644 --- a/identity.go +++ b/identity.go @@ -53,14 +53,6 @@ func (*Identity) FinalizeInvitation(peer *Peer, receivedContact *ContactCard) { } -func (*Identity) AddPeer(name string, peerPublicKey string) string { - var peer Peer - peer.Me = NewKeyPair() - peer.Contact.Name = name - peer.Contact.ContactPublicKey = peerPublicKey - return peer.Me.Public -} - func LoadIdentity(file string) (*Identity, error) { var id Identity indata, err := ioutil.ReadFile(file) @@ -68,10 +60,10 @@ func LoadIdentity(file string) (*Identity, error) { return nil, err } pass, err := helper.DecryptMessageWithPassword([]byte(key), string(indata)) - if err == nil { - err = json.Unmarshal([]byte(pass), &id) + if err != nil { return nil, err } + err = json.Unmarshal([]byte(pass), &id) return &id, err } diff --git a/identity_test.go b/identity_test.go index adcfb97..10768a8 100644 --- a/identity_test.go +++ b/identity_test.go @@ -3,6 +3,8 @@ package meowlib import ( "log" "testing" + + "github.com/stretchr/testify/assert" ) func TestCreate(t *testing.T) { @@ -10,21 +12,10 @@ func TestCreate(t *testing.T) { id.Save("test.id") } -func TestSave(t *testing.T) { - id := Identity{Nickname: "myname", - PublicKey: "pubk", - PrivateKey: "privk", - Status: "online", - } - id.Save("test.id") -} - func TestLoad(t *testing.T) { id, err := LoadIdentity("test.id") if err != nil { - log.Fatal((err.Error())) - } - if id.Nickname != "myname" { - log.Fatal("failed") + log.Println(err.Error()) } + assert.Equal(t, id.Nickname, "myname", "The two words should be the same.") } diff --git a/invitation.png b/invitation.png new file mode 100644 index 0000000000000000000000000000000000000000..d9bde5902d183e1206ab712636a8920b95d5ee09 GIT binary patch literal 530 zcmV+t0`2{YP)U8PPD4 zxfv0ujP}P^{|rmp&-tHf5)r{ zc{2EVTHQ@3_r;;R-QV-JthX^ND($nDnXoD}d{N(|uKXJY9GW<}*&7vKEA-j4;-=yE zi|V2Gb~Vb&2RsuU7$aRN^VE;p0(fvAcwF$f?|!T%onu4##B%A3#m0?@{U?-*{tKB& zs!Z5sEH@db1K|NQ$NoU8`>ffB3{7Jei-Wz6S`C`;z;{BMT^V`URh;xx$#5QZ6 zU#CwqvnqGl8FN2U0tnNXbRjTT$+EdjF2togX8qc^=v$1qyxS4VgU*<{?0l}6DR<|( zKrr!J&}tNEmdxrqK`j45fL2(n@?Ud;SWX@hOx!1!_)~(3rwAs#Aei`sVB!Lt7}=VE@b&08cu=lwa{=5daVW;ZbPe~q2U2EG#L#yL6cQ9d<(MLM#B$5 zZI{sSCA3RA8lHoauA$-YLDv*CoPwq_(Qp@(rizBwp{dr;a0b-c5gLB