Fixing some race conditions, adding more error checking

This commit is contained in:
Sarah Jamie Lewis 2018-05-09 12:09:00 -07:00
parent b4eb27ae1d
commit ec0c341bb1
17 changed files with 162 additions and 117 deletions

View File

@ -6,6 +6,7 @@ import (
"github.com/c-bata/go-prompt"
"strings"
"time"
)
var app app2.Application
@ -38,7 +39,7 @@ var usages = map[string]string{
"peers": "",
"contacts": "",
"groups": "",
"info": "",
"info": "",
"send": "send [groupid] [message]",
"timeline": "timeline [groupid]",
"accept-invite": "accept-invite [groupid]",
@ -46,8 +47,8 @@ var usages = map[string]string{
"invite-to-group": "invite-to-group [peerid] [groupid]",
"new-group": "new-group [server]",
"help": "",
"trust": "trust [peerid]",
"block": "block [peerid]",
"trust": "trust [peerid]",
"block": "block [peerid]",
}
func completer(d prompt.Document) []prompt.Suggest {
@ -326,6 +327,36 @@ func main() {
for _, command := range suggestions {
fmt.Printf("%-18s%-56s%s\n", command.Text, command.Description, usages[command.Text])
}
case "sendlots":
if len(commands) == 2 {
group := app.Peer.Profile.GetGroupByGroupId(commands[1])
if group == nil {
fmt.Printf("Error: group does not exist\n")
} else {
for i := 0; i < 100; i++ {
fmt.Printf("Sending message: %v\n", i)
err := app.Peer.SendMessageToGroup(commands[1], fmt.Sprintf("this is message %v", i))
if err != nil {
fmt.Printf("could not send message %v because %v", i, err)
}
}
fmt.Printf("Waiting 5 seconds for message to process...\n")
time.Sleep(time.Second * 5)
timeline := group.GetTimeline()
for i := 0; i < 100; i++ {
found := false
for _, m := range timeline.Messages {
if m.Message == fmt.Sprintf("this is message %v", i) {
found = true
}
}
if !found {
fmt.Printf("message %v was never received\n", i)
}
}
}
}
}
}
app.Peer.Save(profilefile)

View File

@ -8,8 +8,8 @@ import (
"github.com/s-rah/go-ricochet/utils"
"golang.org/x/crypto/nacl/secretbox"
"io"
"time"
"sync"
"time"
)
//Group defines and encapsulates Cwtch's conception of group chat. Which are sessions
@ -22,7 +22,7 @@ type Group struct {
Timeline Timeline
Accepted bool
Owner string
lock sync.Mutex
lock sync.Mutex
}
// NewGroup initializes a new group associated with a given CwtchServer
@ -70,7 +70,7 @@ func (g *Group) AddMessage(message *protocol.DecryptedGroupMessage, verified boo
timelineMessage := &Message{
Message: message.GetText(),
Timestamp: time.Unix(int64(message.GetTimestamp()), 0),
Received: time.Now(),
Received: time.Now(),
Signature: message.GetSignature(),
Verified: verified,
PeerID: message.GetOnion(),

View File

@ -14,7 +14,7 @@ type Timeline struct {
// Message is a local representation of a given message sent over a group chat channel.
type Message struct {
Timestamp time.Time
Received time.Time
Received time.Time
PeerID string
Message string
Signature []byte

View File

@ -13,8 +13,8 @@ func TestTranscriptConsistency(t *testing.T) {
// Setup the Group
sarah := GenerateNewProfile("Sarah")
alice := GenerateNewProfile("Alice")
sarah.AddContact(alice.Onion, alice.PublicProfile)
alice.AddContact(sarah.Onion, sarah.PublicProfile)
sarah.AddContact(alice.Onion, &alice.PublicProfile)
alice.AddContact(sarah.Onion, &sarah.PublicProfile)
gid, invite := alice.StartGroup("aaa.onion")
gci := &protocol.CwtchPeerPacket{}
@ -23,21 +23,23 @@ func TestTranscriptConsistency(t *testing.T) {
group := alice.GetGroupByGroupId(gid)
c1 := sarah.EncryptMessageToGroup("Hello World 1", group.GroupID)
t.Logf("group: %v, sarah %v", group, sarah)
c1, _ := sarah.EncryptMessageToGroup("Hello World 1", group.GroupID)
alice.AttemptDecryption(c1)
c2 := alice.EncryptMessageToGroup("Hello World 2", group.GroupID)
c2, _ := alice.EncryptMessageToGroup("Hello World 2", group.GroupID)
alice.AttemptDecryption(c2)
c3 := alice.EncryptMessageToGroup("Hello World 3", group.GroupID)
c3, _ := alice.EncryptMessageToGroup("Hello World 3", group.GroupID)
alice.AttemptDecryption(c3)
time.Sleep(time.Second * 1)
c4 := alice.EncryptMessageToGroup("Hello World 4", group.GroupID)
c4, _ := alice.EncryptMessageToGroup("Hello World 4", group.GroupID)
alice.AttemptDecryption(c4)
c5 := alice.EncryptMessageToGroup("Hello World 5", group.GroupID)
c5, _ := alice.EncryptMessageToGroup("Hello World 5", group.GroupID)
_, m1 := sarah.AttemptDecryption(c1)
_, m2 := sarah.AttemptDecryption(c2)

View File

@ -5,12 +5,12 @@ import (
"crypto/rsa"
"encoding/asn1"
"encoding/json"
"errors"
"git.mascherari.press/cwtch/protocol"
"github.com/golang/protobuf/proto"
"github.com/s-rah/go-ricochet/utils"
"golang.org/x/crypto/ed25519"
"io/ioutil"
// "log"
"strconv"
"time"
)
@ -50,6 +50,7 @@ func GenerateNewProfile(name string) *Profile {
p.Onion = utils.GetTorHostname(publicKeyBytes)
p.Contacts = make(map[string]*PublicProfile)
p.Contacts[p.Onion] = &p.PublicProfile
p.Groups = make(map[string]*Group)
return p
}
@ -106,10 +107,10 @@ func (p *Profile) SignMessage(message string) []byte {
func (p *Profile) StartGroup(server string) (groupID string, invite []byte) {
group := NewGroup(server)
groupID = group.GroupID
signedGroupId := p.SignMessage(groupID)
signedGroupId := p.SignMessage(groupID + server)
group.SignGroup(signedGroupId)
invite = group.Invite()
p.AddGroup(group)
p.Groups[group.GroupID] = group
return
}
@ -133,8 +134,13 @@ func (p *Profile) ProcessInvite(gci *protocol.GroupChatInvite, peerHostname stri
func (p *Profile) AddGroup(group *Group) {
existingGroup, exists := p.Groups[group.GroupID]
if !exists {
// owned := ed25519.Verify(p.Contacts[group.Owner].Ed25519PublicKey,[]byte(group.GroupID),group.SignedGroupID)
p.Groups[group.GroupID] = group
owner, ok := p.Contacts[group.Owner]
if ok {
valid := ed25519.Verify(owner.Ed25519PublicKey, []byte(group.GroupID+group.GroupServer), group.SignedGroupID)
if valid {
p.Groups[group.GroupID] = group
}
}
} else if exists && existingGroup.Owner == group.Owner {
p.Groups[group.GroupID] = group
}
@ -161,26 +167,29 @@ func (p *Profile) AttemptDecryption(ciphertext []byte) (bool, *Message) {
// 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) {
func (p *Profile) EncryptMessageToGroup(message string, groupID string) ([]byte, error) {
group := p.Groups[groupID]
timestamp := time.Now().Unix()
signature := p.SignMessage(message + groupID + strconv.Itoa(int(timestamp)))
var prevSig []byte
if len(group.Timeline.Messages) > 0 {
prevSig = group.Timeline.Messages[len(group.Timeline.Messages)-1].Signature
} else {
prevSig = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
if group != nil {
timestamp := time.Now().Unix()
signature := p.SignMessage(message + groupID + strconv.Itoa(int(timestamp)))
var prevSig []byte
if len(group.Timeline.Messages) > 0 {
prevSig = group.Timeline.Messages[len(group.Timeline.Messages)-1].Signature
} else {
prevSig = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
}
dm := &protocol.DecryptedGroupMessage{
Onion: proto.String(p.Onion),
Text: proto.String(message),
SignedGroupId: group.SignedGroupID[:],
Timestamp: proto.Int32(int32(timestamp)),
Signature: signature,
PreviousMessageSig: prevSig,
}
ciphertext := group.EncryptMessage(dm)
return ciphertext, nil
}
dm := &protocol.DecryptedGroupMessage{
Onion: proto.String(p.Onion),
Text: proto.String(message),
SignedGroupId: group.SignedGroupID[:],
Timestamp: proto.Int32(int32(timestamp)),
Signature: signature,
PreviousMessageSig: prevSig,
}
ciphertext = group.EncryptMessage(dm)
return
return nil, errors.New("group does not exist")
}
// Save makes a opy of the profile in the given file

View File

@ -1 +1 @@
{"Name":"Sarah","Ed25519PublicKey":"Q6dF7nCKD6BfqgGLBk0FCCYBdWBLv7Ts8uqw2zOf02A=","Trusted":false,"Blocked":false,"Onion":"lrkqzljkc5cgzmpz","Contacts":{},"Ed25519PrivateKey":"Fy9HObWaw9EH8N3jXNQtD9UgL0Yd7feY5L+oR7uNnXdDp0XucIoPoF+qAYsGTQUIJgF1YEu/tOzy6rDbM5/TYA==","OnionPrivateKey":{"N":107498703462635665473764971520727195625141645315352207633904323688914544197828221612438071393137838030896432787991102883141045406182879952109587171872209559960156106354960716467157362368090179490551994133414470776568822115434428749245942446198318143880845039325380939873177604289430737365718905329111360343777,"E":65537,"D":66650934838346851867814606295271813891877956204037743640936696656474260172643727314338596411016111670467760958042487061561457482564584036102063950773690623873787097606677998053221231028080886156972583586531026258726212233434099244761970868656273357504083063877021130260355845678915219099393211715317011636225,"Primes":[10332071347522235902804485468145791866057055098286157383486988408098332066944447770996594012391982280205811088346484428102348931474084528799982497053772929,10404370996568393072795074320321443437318186756296376448713064693902356814671757730321014302625680493962881120033122151552975123796575551159729969846473313],"Precomputed":{"Dp":1495964493593519637482822872686198926057271401309753992582938386017746814520589360193275258000633533070981909720002300048265697403872439900865677625513089,"Dq":9954139888243813632868821504775543966969614535400447071284280168032892482669848809815187112454533967864971071413045943887011813741384006488948667765441249,"Qinv":9010750810541828585160172405562139672487565596169846634421581721158830598191896975588357263133581085970784950793654150830626201363086339113136601110542205,"CRTValues":[]}},"Groups":{}}
{"Name":"Sarah","Ed25519PublicKey":"FH0bgqmhOuDPu/uXhm5ZT2BuA323JzPBd0Kf3B1YxZA=","Trusted":false,"Blocked":false,"Onion":"y6rv5psc5wruugyx","Contacts":{"y6rv5psc5wruugyx":{"Name":"Sarah","Ed25519PublicKey":"FH0bgqmhOuDPu/uXhm5ZT2BuA323JzPBd0Kf3B1YxZA=","Trusted":false,"Blocked":false,"Onion":"y6rv5psc5wruugyx"}},"Ed25519PrivateKey":"JMnZpsSi1hY6ziZqEaO2kk0ID9+XKm3nOiVoMJazbNIUfRuCqaE64M+7+5eGbllPYG4DfbcnM8F3Qp/cHVjFkA==","OnionPrivateKey":{"N":134057991576218556828017459230656270170181976065106440664426101908559409913157558701412664226096530310039819285641603796528668425856812146294423697678905284504161436672881228795123245277153307076066056625279711139065658846052615035565877781519956303024388960852968254724005382280308994893755778995867984769237,"E":65537,"D":119111293612512116271655044493966989822690945058076323906946181761988105028352909702660473288151745730711181119106925691927679973719306212959462470296819405321699089033715265196316348982251250275981258387949939751153694376595038421083397851309304042337114325061140172676796510776973712466297887452957497017473,"Primes":[11012092321802935235393019477644583097314933484252577291348472528127020714587871982369210353940819563472891086714033880185118457292396210254630513786328037,12173707562439882498035952564416877264727009547626505009495704590991075365448508893781170020376584913732483057163277808299913173595097515219539586115287601],"Precomputed":{"Dp":1484196888452100751243214383417529067528004142185376431854998822664235072889431515331297359603876576653738300028152971049562099779723449733420073062157797,"Dq":716821604337328632069224116851316498536422629114708986246607626480225824118677934923806935145539789463870059929400019259797746874337874959674737366966673,"Qinv":7022175560771039220943597791205895336996303269499099474897105311693825279448116080639519964317539885032301904250731793359527590562893328519648160444244943,"CRTValues":[]}},"Groups":{}}

View File

@ -40,8 +40,8 @@ func TestProfileIdentity(t *testing.T) {
func TestProfileGroup(t *testing.T) {
sarah := GenerateNewProfile("Sarah")
alice := GenerateNewProfile("Alice")
sarah.AddContact(alice.Onion, alice.PublicProfile)
alice.AddContact(sarah.Onion, sarah.PublicProfile)
sarah.AddContact(alice.Onion, &alice.PublicProfile)
alice.AddContact(sarah.Onion, &sarah.PublicProfile)
gid, invite := alice.StartGroup("aaa.onion")
gci := &protocol.CwtchPeerPacket{}
@ -49,7 +49,7 @@ func TestProfileGroup(t *testing.T) {
sarah.ProcessInvite(gci.GetGroupChatInvite(), alice.Onion)
group := alice.GetGroupByGroupId(gid)
c := sarah.EncryptMessageToGroup("Hello World", group.GroupID)
c, _ := sarah.EncryptMessageToGroup("Hello World", group.GroupID)
alice.AttemptDecryption(c)
gid2, invite2 := alice.StartGroup("bbb.onion")
@ -57,20 +57,25 @@ func TestProfileGroup(t *testing.T) {
proto.Unmarshal(invite2, gci2)
sarah.ProcessInvite(gci2.GetGroupChatInvite(), alice.Onion)
group2 := alice.GetGroupByGroupId(gid2)
c2 := sarah.EncryptMessageToGroup("Hello World", group2.GroupID)
c2, _ := sarah.EncryptMessageToGroup("Hello World", group2.GroupID)
alice.AttemptDecryption(c2)
bob := GenerateNewProfile("bob")
bob.AddContact(alice.Onion, &alice.PublicProfile)
bob.ProcessInvite(gci2.GetGroupChatInvite(), alice.Onion)
c3 := bob.EncryptMessageToGroup("Bobs Message", group2.GroupID)
ok, message := alice.AttemptDecryption(c3)
if ok != true || message.Verified == true {
t.Errorf("Bobs message to the group should be decrypted but not verified by alice instead %v %v", message, ok)
}
c3, err := bob.EncryptMessageToGroup("Bobs Message", group2.GroupID)
if err == nil {
ok, message := alice.AttemptDecryption(c3)
if ok != true || message.Verified == true {
t.Errorf("Bobs message to the group should be decrypted but not verified by alice instead %v %v", message, ok)
}
eve := GenerateNewProfile("eve")
ok, _ = eve.AttemptDecryption(c3)
if ok {
t.Errorf("Eves hould not be able to decrypt messages!")
eve := GenerateNewProfile("eve")
ok, _ = eve.AttemptDecryption(c3)
if ok {
t.Errorf("Eves hould not be able to decrypt messages!")
}
} else {
t.Errorf("Bob failed to encrypt a message to the group")
}
}

View File

@ -1,18 +0,0 @@
package model
import (
"testing"
)
// Nothing in this file constitutes a cryptographic proof, but acts to prevent regressions in expected protocol
// behaviour.
// When a new member joins the group, they should be unable to decrypt any past messages
func TestGroupForwardSecrecy(t *testing.T) {
t.Fatalf("Failed")
}
// When a member leaves the group, they should be unable to decrypt any future messages.
func TestGroupBackwardSecrecy(t *testing.T) {
t.Fatalf("Failed")
}

View File

@ -74,40 +74,39 @@ func (psc *PeerServerConnection) Break() error {
return psc.connection.Break()
}
func (psc *PeerServerConnection) SendGroupMessage(gm *protocol.GroupMessage) {
for psc.state != AUTHENTICATED {
time.Sleep(time.Second * 2)
func (psc *PeerServerConnection) SendGroupMessage(gm *protocol.GroupMessage) error {
if psc.state != AUTHENTICATED {
return errors.New("peer is not yet connected & authenticated to server cannot send message")
}
log.Printf("Opening a Channel to Send")
psc.connection.Do(func() error {
err := psc.connection.Do(func() error {
psc.connection.RequestOpenChannel("im.cwtch.server.send", &send.CwtchPeerSendChannel{})
return nil
})
log.Printf("Waiting...")
// TODO We have to wait to receive the channel result before we can continue
// We should have a better mechanism for this kindof interaction
log.Printf("CWTCH PEER Sending...")
send:
time.Sleep(time.Second * 2)
err := psc.connection.Do(func() error {
channel := psc.connection.Channel("im.cwtch.server.send", channels.Outbound)
if channel == nil {
return errors.New("No Channel")
}
sendchannel, ok := channel.Handler.(*send.CwtchPeerSendChannel)
if ok {
sendchannel.SendGroupMessage(gm)
errCount := 0
for errCount < 5 {
time.Sleep(time.Second * 1)
err = psc.connection.Do(func() error {
channel := psc.connection.Channel("im.cwtch.server.send", channels.Outbound)
if channel == nil {
return errors.New("no channel found")
}
sendchannel, ok := channel.Handler.(*send.CwtchPeerSendChannel)
if ok {
return sendchannel.SendGroupMessage(gm)
}
return errors.New("channel is not a peer send channel (this should definitely not happen)")
})
if err != nil {
errCount++
} else {
return errors.New("Failed")
return nil
}
return nil
})
for err != nil {
log.Printf("CHANNEL ERROR %v", err)
goto send
}
log.Printf("Done")
return err
}
func (psc *PeerServerConnection) HandleGroupMessage(gm *protocol.GroupMessage) {

View File

@ -71,7 +71,6 @@ func (cp *CwtchPeer) Save(profilefile string) error {
return err
}
func LoadCwtchPeer(profilefile string) (*CwtchPeer, error) {
bytes, _ := ioutil.ReadFile(profilefile)
cp := new(CwtchPeer)
@ -123,14 +122,17 @@ func (cp *CwtchPeer) SendMessageToGroup(groupid string, message string) error {
}
psc := cp.connectionsManager.GetPeerServerConnectionForOnion(group.GroupServer)
if psc == nil {
return errors.New("could not find server to send message to")
return errors.New("could not find server connection to send message to")
}
ct, err := cp.Profile.EncryptMessageToGroup(message, groupid)
if err != nil {
return err
}
ct := cp.Profile.EncryptMessageToGroup(message, groupid)
gm := &protocol.GroupMessage{
Ciphertext: ct,
}
psc.SendGroupMessage(gm)
return nil
err = psc.SendGroupMessage(gm)
return err
}
func (cp *CwtchPeer) GetPeers() map[string]connections.ConnectionState {
@ -142,7 +144,7 @@ func (cp *CwtchPeer) GetServers() map[string]connections.ConnectionState {
}
func (cp *CwtchPeer) TrustPeer(peer string) error {
_,ok := cp.Profile.Contacts[peer]
_, ok := cp.Profile.Contacts[peer]
if !ok {
return errors.New("peer does not exist")
}
@ -152,7 +154,7 @@ func (cp *CwtchPeer) TrustPeer(peer string) error {
}
func (cp *CwtchPeer) BlockPeer(peer string) error {
_,ok := cp.Profile.Contacts[peer]
_, ok := cp.Profile.Contacts[peer]
if !ok {
return errors.New("peer does not exist")
}

View File

@ -73,15 +73,20 @@ func (cplc *CwtchPeerSendChannel) OpenOutboundResult(err error, crm *Protocol_Da
}
// SendGroupMessage performs the spamguard proof of work and sends a message.
func (cplc *CwtchPeerSendChannel) SendGroupMessage(gm *protocol.GroupMessage) {
sgsolve := cplc.spamGuard.SolveChallenge(cplc.challenge, gm.GetCiphertext())
gm.Spamguard = sgsolve[:]
csp := &protocol.CwtchServerPacket{
GroupMessage: gm,
func (cplc *CwtchPeerSendChannel) SendGroupMessage(gm *protocol.GroupMessage) error {
if cplc.channel.Pending == false {
sgsolve := cplc.spamGuard.SolveChallenge(cplc.challenge, gm.GetCiphertext())
gm.Spamguard = sgsolve[:]
csp := &protocol.CwtchServerPacket{
GroupMessage: gm,
}
packet, _ := proto.Marshal(csp)
cplc.channel.SendMessage(packet)
cplc.channel.CloseChannel()
} else {
return errors.New("channel isn't set up yet")
}
packet, _ := proto.Marshal(csp)
cplc.channel.SendMessage(packet)
cplc.channel.CloseChannel()
return nil
}
// Packet should never be

View File

@ -1 +1 @@
{"Profile":{"Name":"alice","Ed25519PublicKey":"zjwuZF+0Op1KvzzOhqeHSbvXu0U5djPgTwKpAXU//7I=","Trusted":false,"Blocked":false,"Onion":"cgb6lexebisn6vpt","Contacts":{},"Ed25519PrivateKey":"2lHp48zadAzBVtVEjviPijgcVx4Djle0DJ4A5thMgSnOPC5kX7Q6nUq/PM6Gp4dJu9e7RTl2M+BPAqkBdT//sg==","OnionPrivateKey":{"N":147157004733998659199661812977704646877524902240221974034556056889821412558230773103992139173929507205012402066934484772524414251527816699766158278653365683529647303492589077999418406692030398982986134250109986822607454250083546220790801592188854654036322143842183727153411958706262869490046244589596814484207,"E":65537,"D":69165161921072992345197107361524577532819621949517943546186584988284007065187336984028409340899806375574057721100797022263294508290146601200802195055611675878933653952917037806259598451163914910457010547243954518097830998995842836616848924363378592869926704087730180750445525914371624821666069356678694847337,"Primes":[11763039476614882926577453250579526149631348162928663166529586678426982975960723170685888779927126269335313361708713193749880911707050422735813878237869163,12510117391559317555937472239718194296052069062441314136877360692383786524485845690577241127778855759836876789006855569037256017877501872991377132347214989],"Precomputed":{"Dp":1278485896393301662969180760545614916212583623976392995333784669887779418309782735627135599423545789652798222003618781437667298382430080124924886013829471,"Dq":8164208322581015485411991511554498528192425558091078408139596209976876415647033281749066985597474111543452099818777372899635929087702444540354302920340953,"Qinv":2274603529611181793096917499650639342446510507100204826932356686902897257746923946968375987728128727917910029163224849482139316568187669695882958003364055,"CRTValues":[]}},"Groups":{}}}
{"Profile":{"Name":"alice","Ed25519PublicKey":"W6naGYWbCXL80XXDgpKE7V+siJo6o9bbGyTvUnUKILE=","Trusted":false,"Blocked":false,"Onion":"ycnqegkvvkz5gsvs","Contacts":{"ycnqegkvvkz5gsvs":{"Name":"alice","Ed25519PublicKey":"W6naGYWbCXL80XXDgpKE7V+siJo6o9bbGyTvUnUKILE=","Trusted":false,"Blocked":false,"Onion":"ycnqegkvvkz5gsvs"}},"Ed25519PrivateKey":"KvmZ7aWoB5RVmkloWri+316/wfA/CyGn0pcYS34WN7xbqdoZhZsJcvzRdcOCkoTtX6yImjqj1tsbJO9SdQogsQ==","OnionPrivateKey":{"N":138578445730948217399235853380745007937830927545752074120752000142489179414948896312808960302192046016583916437398543221534462954288785032720766262144773721364963084161409242148120269561063898622509706451288561156808651123385134272354840396173775759747294322189173896763873375202344132814058552323894612271379,"E":65537,"D":66260191577658320344575654997009713119915009011301814160670837488213389782059578785391177198063535925899470611750930777881256864604625902701343234975183920374575910046121511808611558969522048550963186520107773724296757371157728176877458332331908465537431591104876047516596838295433500859876997952335609406401,"Primes":[13275044288223673053268894137348396823019805659935753695111177485542609507887379320301691989583038422110723796993226398199751492392227091252491529012654327,10439019465560768307866940717986678867283694780656194070584524560148251882718648675994212565947390303977286149767780033032504469772695284927646948863796677],"Precomputed":{"Dp":5339834254331941789069908406682918611600288643166857483719438803635721376427469881773550883155897567537160699091130724771378745478796566513544740952921149,"Dq":6887615251084321564924765912178799470531367716104711656104878564862147484026383377308478349087250013492864037140982596218296928108413824489317205789392741,"Qinv":2094027238282876917718460475743388991144681081516298156361631729627217848136364125434066438976020876853031955793909233935538173930073006469995174800032241,"CRTValues":[]}},"Groups":{}}}

View File

@ -8,6 +8,7 @@ import (
"github.com/s-rah/go-ricochet/utils"
"github.com/s-rah/go-ricochet/wire/control"
"io"
//"fmt"
)
// Guard implements a spam protection mechanism for Cwtch Servers.
@ -69,6 +70,7 @@ func (sg *Guard) SolveChallenge(challenge []byte, message []byte) []byte {
}
}
}
//fmt.Printf("[SOLVED] %x\n",sha256.Sum256(solve))
return spamguard[:]
}

View File

@ -2,20 +2,20 @@ package main
import (
cwtchserver "git.mascherari.press/cwtch/server"
"log"
"os"
"github.com/s-rah/go-ricochet/utils"
"io/ioutil"
"log"
"os"
)
const privateKeyFile = "./private_key"
func checkAndGenPrivateKey(privateKeyFile string) {
if _, err := os.Stat(privateKeyFile); os.IsNotExist(err) {
if _, err := os.Stat(privateKeyFile); os.IsNotExist(err) {
log.Printf("no private key found!")
log.Printf("generating new private key...")
pk, pk_err := utils.GeneratePrivateKey()
if pk_err != nil {
if pk_err != nil {
log.Fatalf("error generating new private key: %v\n", err)
}
err := ioutil.WriteFile(privateKeyFile, []byte(utils.PrivateKeyToString(pk)), 0400)

View File

@ -7,6 +7,7 @@ import (
"github.com/golang/protobuf/proto"
"github.com/s-rah/go-ricochet/channels"
"github.com/s-rah/go-ricochet/wire/control"
"log"
)
// CwtchChannel implements the ChannelHandler interface for a channel of
@ -92,8 +93,12 @@ func (cc *CwtchServerSendChannel) Packet(data []byte) {
ok := cc.spamguard.ValidateChallenge(gm.GetCiphertext(), gm.GetSpamguard())
if ok {
cc.Handler.HandleGroupMessage(gm)
} else {
log.Printf("[ERROR] Failed to validate spamguard %v\n", gm)
}
}
} else {
log.Printf("[ERROR] Failed to decode packet on SEND channel %v\n", err)
}
cc.channel.CloseChannel()
}

View File

@ -9,7 +9,6 @@ import (
"github.com/s-rah/go-ricochet/channels"
"github.com/s-rah/go-ricochet/utils"
"log"
)
type Server struct {

View File

@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"git.mascherari.press/cwtch/protocol"
"log"
"os"
"sync"
)
@ -61,7 +62,10 @@ func (ms *MessageStore) FetchMessages() (messages []*protocol.GroupMessage) {
func (ms *MessageStore) AddMessage(gm protocol.GroupMessage) {
ms.lock.Lock()
ms.messages = append(ms.messages, &gm)
s, _ := json.Marshal(gm)
s, err := json.Marshal(gm)
if err != nil {
log.Printf("[ERROR] Failed to unmarshal group message %v\n", err)
}
fmt.Fprintf(ms.file, "%s\n", s)
ms.lock.Unlock()
}