diff --git a/model/group.go b/model/group.go index 25eee3b..6001f91 100644 --- a/model/group.go +++ b/model/group.go @@ -7,6 +7,9 @@ import ( "io" ) + +//Group defines and encapsulates Cwtch's conception of group chat. Which are sessions +// tied to a server under a given group key. Each group has a set of messages. type Group struct { GroupID string GroupKey [32]byte @@ -14,6 +17,7 @@ type Group struct { Timeline []Message } +// NewGroup initializes a new group associated with a given CwtchServer func NewGroup(server string) *Group { group := new(Group) group.GroupServer = server @@ -32,14 +36,17 @@ func NewGroup(server string) *Group { return group } +// AddMember ... func (g *Group) AddMember() { // TODO: Rotate Key } +// RemoveMember ... func (g *Group) RemoveMember() { // TODO: Rotate Key } +//EncryptMessage takes a message and encrypts the message under the group key. func (g *Group) EncryptMessage(message string) []byte { var nonce [24]byte if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil { @@ -49,6 +56,8 @@ func (g *Group) EncryptMessage(message string) []byte { return encrypted } +// DecryptMessage takes a ciphertext and returns true and the decrypted message if the +// cipher text can be successfully decrypted,else false. func (g *Group) DecryptMessage(ciphertext []byte) (bool, string) { var decryptNonce [24]byte copy(decryptNonce[:], ciphertext[:24]) diff --git a/model/message.go b/model/message.go index d5f86d0..d045ae2 100644 --- a/model/message.go +++ b/model/message.go @@ -4,6 +4,8 @@ import ( "time" ) + +// Message is a local representation of a given message sent over a group chat channel. type Message struct { Timestamp time.Time PeerID string diff --git a/model/profile.go b/model/profile.go index 2145e5f..13bcd99 100644 --- a/model/profile.go +++ b/model/profile.go @@ -11,11 +11,15 @@ import ( "io/ioutil" ) + +// PublicProfile is a local copy of a CwtchIdentity type PublicProfile struct { Name string Ed25519PublicKey ed25519.PublicKey } + +// Profile encapsulates all the attributes necessary to be a Cwtch Peer. type Profile struct { PublicProfile Contacts map[string]PublicProfile @@ -24,6 +28,7 @@ type Profile struct { Groups map[string]*Group } +// GenerateNewProfile creates a new profile, with new encryption and signing keys, and a profile name. func GenerateNewProfile(name string) *Profile { p := new(Profile) p.Name = name @@ -38,7 +43,7 @@ func GenerateNewProfile(name string) *Profile { return p } -// GetCwtchIdentity returns the wire message for conveying this profiles identity. +// GetCwtchIdentityPacket returns the wire message for conveying this profiles identity. func (p *Profile) GetCwtchIdentityPacket() (message []byte) { ci := &protocol.CwtchIdentity{ Name: p.Name, @@ -79,11 +84,14 @@ func (p *Profile) VerifyMessage(onion string, message string, signature []byte) return ed25519.Verify(p.Contacts[onion].Ed25519PublicKey, []byte(message), signature) } +// SignMessage takes a given message and returns an Ed21159 signature func (p *Profile) SignMessage(message string) []byte { sig := ed25519.Sign(p.Ed25519PrivateKey, []byte(message)) return sig } +//StartGroup when given a server, creates a new Group under this profile and returns the group id an a precomputed +// invite which can be sent on the wire. func (p *Profile) StartGroup(server string) (groupID string, invite []byte) { group := NewGroup(server) p.AddGroup(group) @@ -101,7 +109,7 @@ func (p *Profile) StartGroup(server string) (groupID string, invite []byte) { return } -// ProcessInvite +// ProcessInvite adds a new group invite to the profile. func (p *Profile) ProcessInvite(gci *protocol.GroupChatInvite) { group := new(Group) group.GroupID = gci.GetGroupName() @@ -110,13 +118,13 @@ func (p *Profile) ProcessInvite(gci *protocol.GroupChatInvite) { p.AddGroup(group) } -// AddGroup +// AddGroup is a conveniance method for adding a group to a profle. func (p *Profile) AddGroup(group *Group) { p.Groups[group.GroupID] = group } -// EncryptMessageToGroup -func (p *Profile) AttemptDecryption(ciphertext []byte, signature []byte) (success bool, groupId string, onion string, message string) { +// AttemptDecryption takes a ciphertext and signature and attempts to decrypt it under known groups. +func (p *Profile) AttemptDecryption(ciphertext []byte, signature []byte) (success bool, groupID string, onion string, message string) { for id, group := range p.Groups { success, message := group.DecryptMessage(ciphertext) if success { @@ -131,7 +139,8 @@ func (p *Profile) AttemptDecryption(ciphertext []byte, signature []byte) (succes return false, "", "", "" } -// EncryptMessageToGroup +// EncryptMessageToGroup when given a message and a group, encrypts and signs the message under the group and +// profile func (p *Profile) EncryptMessageToGroup(message string, groupid string) (ciphertext []byte, signature []byte) { group := p.Groups[groupid] ciphertext = group.EncryptMessage(message) @@ -139,11 +148,13 @@ func (p *Profile) EncryptMessageToGroup(message string, groupid string) (ciphert return } +// Save makes a opy of the profile in the given file func (p *Profile) Save(profilefile string) error { bytes, _ := json.Marshal(p) return ioutil.WriteFile(profilefile, bytes, 0600) } +// LoadProfile loads a saved profile from a file. func LoadProfile(profilefile string) (*Profile, error) { bytes, _ := ioutil.ReadFile(profilefile) profile := new(Profile) diff --git a/model/profile_test b/model/profile_test index b2cfc87..a5d6c85 100644 --- a/model/profile_test +++ b/model/profile_test @@ -1 +1 @@ -{"Name":"Sarah","Ed25519PublicKey":"/B8dEVHus01Da+YnNGXTkcO4kx0IOIiUXfUb8jCKtCA=","Contacts":{},"Ed25519PrivateKey":"4BKKduiLawCLymPakXQ8KR7rk3+mcKkXBjdvX6MUpiH8Hx0RUe6zTUNr5ic0ZdORw7iTHQg4iJRd9RvyMIq0IA==","OnionPrivateKey":{"N":122894509251387918537344449363582844899371582871503138947591748059687692350624757973436500610485234906492758491648918955960649482658707961407465134777548850040832459753903991632513446336436075872130848944818392546778020468818008658094247574580293640095581476556568537356529453655090205726813812773136632293627,"E":65537,"D":14834650086023617552663868332625904237284718435333648659755532277952749350531645640292600459733413084902638393997811890391758824134657349019553178833715134614120468834956286694945442257374600339998005616482726880381216386928218674308996477590581500573205360929206003857898285894073647530982811784307255428401,"Primes":[11399281077950092701265950373080119600146585644302247801593315654188006980066408020813759117244884225514463927040243360808856555139261087338484716581806083,10780899989307726072173333462686027108707159501939065538297724308089670254067834791777651673196745149447212427380713841130876160570417436683376001317203369],"Precomputed":{"Dp":6660379190943512057568637131482734023968339373050668672942173780157272430546147915421829868891482777109111687965958142302710456831905420699227257386674985,"Dq":717059722803795992318897120158817037198140108167178642315635141354698454880169856071513551786999894814233165554610855447907123974647139882857561221015449,"Qinv":3661289130630961871097580877408594138463407662738278774315778153391032147854364535225179585092033532454907736889755632942438448844816650105956852053425750,"CRTValues":[]}},"Groups":{}} \ No newline at end of file +{"Name":"Sarah","Ed25519PublicKey":"T7ug35aRhuImJfE90ymczSgAi90cHdbQMqEhBM/4+T0=","Contacts":{},"Ed25519PrivateKey":"TSquPGWkVc13XEbOkkFaSmQgArJ3vhUAnOHUpipXiZNPu6DflpGG4iYl8T3TKZzNKACL3Rwd1tAyoSEEz/j5PQ==","OnionPrivateKey":{"N":147543015664120090366421447952970860504590941099804565923233227773815393474636918222730428033531903648100909217280034128017566946683746667285202590815509702891937867545391137542704927905354957814668191780596816701004171603996891826892371194711906073796279656017597798465364500891427388525790476841047404602167,"E":65537,"D":5684515839173340680458583030673534381709448498970147076554677512380546386368894189730905149528786131673021282231900852545041069020194093945330676439403114856356392314290322709016451155034411809521466849420244883177134443565565861016638701771436637981361005194284315380514984476353929411384168768558877308473,"Primes":[12931099477754593259784498055463781428153030935578361605358730348734406074416483185277800291372847230179833495402846932178915478884892963290117615988576301,11409935861829750400775707403393062540845554732277302700883351106026835771931816136175131558089707680685127543513601477653608896039540199753620444032990067],"Precomputed":{"Dp":3748099023138475266839591758267695988665867764045448480330110345370687974573378619520836997954111509292401499590650782362187442771219719100036227372613873,"Dq":1182655512297015342058217196259350807024487744272086260388797230011143253410025283626618073364715874618827096191279656342233627276143195094776136782521347,"Qinv":12011761893821155933799466829578837010916497100434672750257270979155184673238141008807799214221585212198300042270714718819586501480079276451027729262322408,"CRTValues":[]}},"Groups":{}} \ No newline at end of file diff --git a/peer/connections/peerserverconnection_test.go b/peer/connections/peerserverconnection_test.go index 8ed2e3a..bfd6fe5 100644 --- a/peer/connections/peerserverconnection_test.go +++ b/peer/connections/peerserverconnection_test.go @@ -72,7 +72,7 @@ func TestPeerServerConnection(t *testing.T) { psc := NewPeerServerConnection("127.0.0.1:5451|kwke2hntvyfqm7dr") numcalls := 0 psc.GroupMessageHandler = func(s string, gm *protocol.GroupMessage) { - numcalls += 1 + numcalls++ } state := psc.GetState() if state != DISCONNECTED { diff --git a/peer/connections/state.go b/peer/connections/state.go index 42b5a20..5c1e2c0 100644 --- a/peer/connections/state.go +++ b/peer/connections/state.go @@ -1,7 +1,13 @@ package connections +// ConnectionState defines the various states a connection can be in from disconnected to authenticated type ConnectionState int +// Connection States +// DISCONNECTED - No existing connection has been made, or all attempts have failed +// CONNECTING - We are in the process of attempting to connect to a given endpoint +// CONNECTED - We have connected but not yet authenticated +// AUTHENTICATED - im.ricochet.auth-hidden-server has succeeded on thec onnection. const ( DISCONNECTED ConnectionState = iota CONNECTING diff --git a/peer/peer/peer_channel.go b/peer/peer/peer_channel.go index 271330d..da6ef63 100644 --- a/peer/peer/peer_channel.go +++ b/peer/peer/peer_channel.go @@ -27,7 +27,7 @@ type CwtchPeerChannelHandler interface { HandleGroupInvite(*protocol.GroupChatInvite) } -// Type returns the type string for this channel, e.g. "im.ricochet.Cwtch". +// SendMessage sends a raw message on this channel func (cpc *CwtchPeerChannel) SendMessage(data []byte) { cpc.channel.SendMessage(data) } diff --git a/protocol/spam/spamguard.go b/protocol/spam/spamguard.go index de99b66..d83dd3c 100644 --- a/protocol/spam/spamguard.go +++ b/protocol/spam/spamguard.go @@ -10,6 +10,7 @@ import ( "io" ) +// Guard implements a spam protection mechanism for Cwtch Servers. type Guard struct { Difficulty int nonce [24]byte