forked from cwtch.im/cwtch
CLI now supports cwtch peering and invites
This commit is contained in:
parent
c28af5f7ae
commit
8d8eb89507
|
@ -3,3 +3,5 @@
|
||||||
*private_key*
|
*private_key*
|
||||||
*.messages
|
*.messages
|
||||||
*.test
|
*.test
|
||||||
|
*test_*
|
||||||
|
*_test*
|
||||||
|
|
30
app/app.go
30
app/app.go
|
@ -3,24 +3,38 @@ package app
|
||||||
import (
|
import (
|
||||||
"git.mascherari.press/cwtch/model"
|
"git.mascherari.press/cwtch/model"
|
||||||
"git.mascherari.press/cwtch/peer"
|
"git.mascherari.press/cwtch/peer"
|
||||||
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Application struct {
|
type Application struct {
|
||||||
Peer *peer.CwtchPeer
|
Peer *peer.CwtchPeer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *Application) NewProfile(name string, filename string) error {
|
func (app *Application) NewProfile(name string, filename string) error {
|
||||||
profile := peer.NewCwtchPeer(name)
|
profile := peer.NewCwtchPeer(name)
|
||||||
app.Peer = profile
|
app.Peer = profile
|
||||||
return profile.Save(filename)
|
err := profile.Save(filename)
|
||||||
|
if err == nil {
|
||||||
|
go func() {
|
||||||
|
err := app.Peer.Listen()
|
||||||
|
if err != nil {
|
||||||
|
log.Panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (app *Application) SetProfile(filename string) error {
|
func (app *Application) SetProfile(filename string) error {
|
||||||
profile,err := peer.LoadCwtchPeer(filename)
|
profile, err := peer.LoadCwtchPeer(filename)
|
||||||
app.Peer = profile
|
app.Peer = profile
|
||||||
if err == nil {
|
if err == nil {
|
||||||
app.Peer.Listen()
|
go func() {
|
||||||
|
err := app.Peer.Listen()
|
||||||
|
if err != nil {
|
||||||
|
log.Panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -33,12 +47,6 @@ func (app *Application) SendMessageToPeer(onion string) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *Application) GetPeers() []model.PublicProfile {
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (app *Application) GetNewMessages() []model.Message {
|
func (app *Application) GetNewMessages() []model.Message {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
app2 "git.mascherari.press/cwtch/app"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
app2 "git.mascherari.press/cwtch/app"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
quit := false
|
quit := false
|
||||||
app := app2.Application{}
|
app := app2.Application{}
|
||||||
|
profilefile := ""
|
||||||
for !quit {
|
for !quit {
|
||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
|
||||||
|
@ -40,6 +41,7 @@ func main() {
|
||||||
case "loadprofile":
|
case "loadprofile":
|
||||||
if len(commands) == 2 {
|
if len(commands) == 2 {
|
||||||
err := app.SetProfile(commands[1])
|
err := app.SetProfile(commands[1])
|
||||||
|
profilefile = commands[1]
|
||||||
if err == nil {
|
if err == nil {
|
||||||
fmt.Printf("Loaded profile for %v\n", commands[1])
|
fmt.Printf("Loaded profile for %v\n", commands[1])
|
||||||
} else {
|
} else {
|
||||||
|
@ -55,7 +57,25 @@ func main() {
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("Profile needs to be set")
|
fmt.Printf("Profile needs to be set")
|
||||||
}
|
}
|
||||||
|
case "invite":
|
||||||
|
if len(commands) == 2 {
|
||||||
|
fmt.Printf("Inviting cwtch:%v\n", commands[1])
|
||||||
|
app.PeerRequest(commands[1])
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Error inviting peer, usage: invite [onion]\n")
|
||||||
|
}
|
||||||
|
case "peers":
|
||||||
|
peers := app.Peer.GetPeers()
|
||||||
|
for p, s := range peers {
|
||||||
|
fmt.Printf("Name: %v Status: %v\n", p, s)
|
||||||
|
}
|
||||||
|
case "contacts":
|
||||||
|
for _, c := range app.Peer.Profile.Contacts {
|
||||||
|
fmt.Printf("Name: %v, Onion: %v, Trusted: %v\n", c.Name, c.Onion, c.Trusted)
|
||||||
|
}
|
||||||
|
case "save":
|
||||||
|
app.Peer.Save(profilefile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ type PublicProfile struct {
|
||||||
Ed25519PublicKey ed25519.PublicKey
|
Ed25519PublicKey ed25519.PublicKey
|
||||||
Trusted bool
|
Trusted bool
|
||||||
Blocked bool
|
Blocked bool
|
||||||
|
Onion string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Profile encapsulates all the attributes necessary to be a Cwtch Peer.
|
// Profile encapsulates all the attributes necessary to be a Cwtch Peer.
|
||||||
|
@ -29,7 +30,6 @@ type Profile struct {
|
||||||
Contacts map[string]PublicProfile
|
Contacts map[string]PublicProfile
|
||||||
Ed25519PrivateKey ed25519.PrivateKey
|
Ed25519PrivateKey ed25519.PrivateKey
|
||||||
OnionPrivateKey *rsa.PrivateKey
|
OnionPrivateKey *rsa.PrivateKey
|
||||||
Onion string
|
|
||||||
Groups map[string]*Group
|
Groups map[string]*Group
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ func (p *Profile) GetCwtchIdentityPacket() (message []byte) {
|
||||||
// AddCwtchIdentity takes a wire message and if it is a CwtchIdentity message adds the identity as a contact
|
// AddCwtchIdentity takes a wire message and if it is a CwtchIdentity message adds the identity as a contact
|
||||||
// otherwise returns an error
|
// otherwise returns an error
|
||||||
func (p *Profile) AddCwtchIdentity(onion string, ci *protocol.CwtchIdentity) {
|
func (p *Profile) AddCwtchIdentity(onion string, ci *protocol.CwtchIdentity) {
|
||||||
p.AddContact(onion, PublicProfile{Name: ci.GetName(), Ed25519PublicKey: ci.GetEd25519PublicKey()})
|
p.AddContact(onion, PublicProfile{Name: ci.GetName(), Ed25519PublicKey: ci.GetEd25519PublicKey(), Onion: onion})
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddContact allows direct manipulation of cwtch contacts
|
// AddContact allows direct manipulation of cwtch contacts
|
||||||
|
|
|
@ -38,6 +38,16 @@ func (m *Manager) ManageServerConnection(host string, handler func(string, *prot
|
||||||
m.lock.Unlock()
|
m.lock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Manager) GetPeers() map[string]ConnectionState {
|
||||||
|
rm := make(map[string]ConnectionState)
|
||||||
|
m.lock.Lock()
|
||||||
|
for onion, ppc := range m.peerConnections {
|
||||||
|
rm[onion] = ppc.GetState()
|
||||||
|
}
|
||||||
|
m.lock.Unlock()
|
||||||
|
return rm
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Manager) GetPeerPeerConnectionForOnion(host string) (ppc *PeerPeerConnection) {
|
func (m *Manager) GetPeerPeerConnectionForOnion(host string) (ppc *PeerPeerConnection) {
|
||||||
m.lock.Lock()
|
m.lock.Lock()
|
||||||
ppc = m.peerConnections[host]
|
ppc = m.peerConnections[host]
|
||||||
|
|
|
@ -41,6 +41,10 @@ func (ppc *PeerPeerConnection) HandleGroupInvite(gci *protocol.GroupChatInvite)
|
||||||
ppc.profile.ProcessInvite(gci, ppc.PeerHostname)
|
ppc.profile.ProcessInvite(gci, ppc.PeerHostname)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ppc *PeerPeerConnection) GetClientIdentityPacket() []byte {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ppc *PeerPeerConnection) SendGroupInvite(invite []byte) {
|
func (ppc *PeerPeerConnection) SendGroupInvite(invite []byte) {
|
||||||
ppc.connection.Do(func() error {
|
ppc.connection.Do(func() error {
|
||||||
channel := ppc.connection.Channel("im.cwtch.peer", channels.Outbound)
|
channel := ppc.connection.Channel("im.cwtch.peer", channels.Outbound)
|
||||||
|
@ -56,9 +60,10 @@ func (ppc *PeerPeerConnection) SendGroupInvite(invite []byte) {
|
||||||
|
|
||||||
// Run manages the setup and teardown of a peer->peer connection
|
// Run manages the setup and teardown of a peer->peer connection
|
||||||
func (ppc *PeerPeerConnection) Run() error {
|
func (ppc *PeerPeerConnection) Run() error {
|
||||||
|
ppc.state = CONNECTING
|
||||||
rc, err := goricochet.Open(ppc.PeerHostname)
|
rc, err := goricochet.Open(ppc.PeerHostname)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
rc.TraceLog(true)
|
rc.TraceLog(false)
|
||||||
ppc.connection = *rc
|
ppc.connection = *rc
|
||||||
ppc.state = CONNECTED
|
ppc.state = CONNECTED
|
||||||
_, err := connection.HandleOutboundConnection(&ppc.connection).ProcessAuthAsClient(identity.Initialize(ppc.profile.Name, ppc.profile.OnionPrivateKey))
|
_, err := connection.HandleOutboundConnection(&ppc.connection).ProcessAuthAsClient(identity.Initialize(ppc.profile.Name, ppc.profile.OnionPrivateKey))
|
||||||
|
|
|
@ -74,6 +74,10 @@ func (tp *TestPeer) HandleGroupInvite(gci *protocol.GroupChatInvite) {
|
||||||
tp.ReceivedGroupInvite = true
|
tp.ReceivedGroupInvite = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tp *TestPeer) GetClientIdentityPacket() []byte {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func TestPeerPeerConnection(t *testing.T) {
|
func TestPeerPeerConnection(t *testing.T) {
|
||||||
profile := model.GenerateNewProfile("sarah")
|
profile := model.GenerateNewProfile("sarah")
|
||||||
ppc := NewPeerPeerConnection("127.0.0.1:5452|kwke2hntvyfqm7dr", profile)
|
ppc := NewPeerPeerConnection("127.0.0.1:5452|kwke2hntvyfqm7dr", profile)
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/s-rah/go-ricochet/channels"
|
"github.com/s-rah/go-ricochet/channels"
|
||||||
"github.com/s-rah/go-ricochet/connection"
|
"github.com/s-rah/go-ricochet/connection"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -30,14 +31,26 @@ type CwtchPeer struct {
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
Log chan string `json:"-"`
|
Log chan string `json:"-"`
|
||||||
connectionsManager *connections.Manager
|
connectionsManager *connections.Manager
|
||||||
|
profilefile string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cp *CwtchPeer) setup() {
|
||||||
|
cp.Log = make(chan string)
|
||||||
|
cp.connectionsManager = connections.NewConnectionsManager()
|
||||||
|
cp.Init()
|
||||||
|
|
||||||
|
go cp.connectionsManager.AttemptReconnections()
|
||||||
|
|
||||||
|
for onion := range cp.Profile.Contacts {
|
||||||
|
cp.PeerWithOnion(onion)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCwtchPeer(name string) *CwtchPeer {
|
func NewCwtchPeer(name string) *CwtchPeer {
|
||||||
cp := new(CwtchPeer)
|
cp := new(CwtchPeer)
|
||||||
cp.Profile = model.GenerateNewProfile(name)
|
cp.Profile = model.GenerateNewProfile(name)
|
||||||
cp.Log = make(chan string)
|
cp.setup()
|
||||||
cp.connectionsManager = connections.NewConnectionsManager()
|
|
||||||
cp.Init()
|
|
||||||
return cp
|
return cp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +58,7 @@ func (cp *CwtchPeer) Save(profilefile string) error {
|
||||||
cp.mutex.Lock()
|
cp.mutex.Lock()
|
||||||
bytes, _ := json.Marshal(cp)
|
bytes, _ := json.Marshal(cp)
|
||||||
err := ioutil.WriteFile(profilefile, bytes, 0600)
|
err := ioutil.WriteFile(profilefile, bytes, 0600)
|
||||||
|
cp.profilefile = profilefile
|
||||||
cp.mutex.Unlock()
|
cp.mutex.Unlock()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -53,6 +67,8 @@ func LoadCwtchPeer(profilefile string) (*CwtchPeer, error) {
|
||||||
bytes, _ := ioutil.ReadFile(profilefile)
|
bytes, _ := ioutil.ReadFile(profilefile)
|
||||||
cp := new(CwtchPeer)
|
cp := new(CwtchPeer)
|
||||||
err := json.Unmarshal(bytes, &cp)
|
err := json.Unmarshal(bytes, &cp)
|
||||||
|
cp.setup()
|
||||||
|
cp.profilefile = profilefile
|
||||||
return cp, err
|
return cp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,6 +106,10 @@ func (cp *CwtchPeer) SendMessageToGroup(groupid string, message string) {
|
||||||
psc.SendGroupMessage(gm)
|
psc.SendGroupMessage(gm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cp *CwtchPeer) GetPeers() map[string]connections.ConnectionState {
|
||||||
|
return cp.connectionsManager.GetPeers()
|
||||||
|
}
|
||||||
|
|
||||||
func (cp *CwtchPeer) Listen() error {
|
func (cp *CwtchPeer) Listen() error {
|
||||||
cwtchpeer := new(application.RicochetApplication)
|
cwtchpeer := new(application.RicochetApplication)
|
||||||
l, err := application.SetupOnion("127.0.0.1:9051", "tcp4", "", cp.Profile.OnionPrivateKey, 9878)
|
l, err := application.SetupOnion("127.0.0.1:9051", "tcp4", "", cp.Profile.OnionPrivateKey, 9878)
|
||||||
|
@ -111,7 +131,7 @@ func (cp *CwtchPeer) Listen() error {
|
||||||
})
|
})
|
||||||
|
|
||||||
cwtchpeer.Init(cp.Profile.OnionPrivateKey, af, new(application.AcceptAllContactManager))
|
cwtchpeer.Init(cp.Profile.OnionPrivateKey, af, new(application.AcceptAllContactManager))
|
||||||
cp.Log <- "Running cwtch peer on " + l.Addr().String()
|
log.Printf("Running cwtch peer on %v", l.Addr().String())
|
||||||
cwtchpeer.Run(l)
|
cwtchpeer.Run(l)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -132,8 +152,9 @@ type CwtchPeerHandler struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cph *CwtchPeerHandler) ClientIdentity(ci *protocol.CwtchIdentity) {
|
func (cph *CwtchPeerHandler) ClientIdentity(ci *protocol.CwtchIdentity) {
|
||||||
cph.Peer.Log <- "Received Client Identity from " + cph.Onion + " " + ci.String()
|
log.Printf("Received Client Identity from %v %v\n", cph.Onion, ci.String())
|
||||||
cph.Peer.Profile.AddCwtchIdentity(cph.Onion, ci)
|
cph.Peer.Profile.AddCwtchIdentity(cph.Onion, ci)
|
||||||
|
cph.Peer.Save(cph.Peer.profilefile)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cph *CwtchPeerHandler) HandleGroupInvite(gci *protocol.GroupChatInvite) {
|
func (cph *CwtchPeerHandler) HandleGroupInvite(gci *protocol.GroupChatInvite) {
|
||||||
|
@ -142,3 +163,7 @@ func (cph *CwtchPeerHandler) HandleGroupInvite(gci *protocol.GroupChatInvite) {
|
||||||
|
|
||||||
func (cph *CwtchPeerHandler) HandleGroupMessage(gm *protocol.GroupMessage) {
|
func (cph *CwtchPeerHandler) HandleGroupMessage(gm *protocol.GroupMessage) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cph *CwtchPeerHandler) GetClientIdentityPacket() []byte {
|
||||||
|
return cph.Peer.Profile.GetCwtchIdentityPacket()
|
||||||
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ type CwtchPeerChannel struct {
|
||||||
type CwtchPeerChannelHandler interface {
|
type CwtchPeerChannelHandler interface {
|
||||||
ClientIdentity(*protocol.CwtchIdentity)
|
ClientIdentity(*protocol.CwtchIdentity)
|
||||||
HandleGroupInvite(*protocol.GroupChatInvite)
|
HandleGroupInvite(*protocol.GroupChatInvite)
|
||||||
|
GetClientIdentityPacket() []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendMessage sends a raw message on this channel
|
// SendMessage sends a raw message on this channel
|
||||||
|
@ -99,6 +100,10 @@ func (cpc *CwtchPeerChannel) Packet(data []byte) {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if cpp.GetCwtchIdentify() != nil {
|
if cpp.GetCwtchIdentify() != nil {
|
||||||
cpc.Handler.ClientIdentity(cpp.GetCwtchIdentify())
|
cpc.Handler.ClientIdentity(cpp.GetCwtchIdentify())
|
||||||
|
pkt := cpc.Handler.GetClientIdentityPacket()
|
||||||
|
if pkt != nil {
|
||||||
|
cpc.SendMessage(pkt)
|
||||||
|
}
|
||||||
} else if cpp.GetGroupChatInvite() != nil {
|
} else if cpp.GetGroupChatInvite() != nil {
|
||||||
cpc.Handler.HandleGroupInvite(cpp.GetGroupChatInvite())
|
cpc.Handler.HandleGroupInvite(cpp.GetGroupChatInvite())
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,10 @@ func (th *TestHandler) HandleGroupInvite(ci *protocol.GroupChatInvite) {
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (th *TestHandler) GetClientIdentityPacket() []byte {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func TestPeerChannel(t *testing.T) {
|
func TestPeerChannel(t *testing.T) {
|
||||||
th := new(TestHandler)
|
th := new(TestHandler)
|
||||||
cpc := new(CwtchPeerChannel)
|
cpc := new(CwtchPeerChannel)
|
||||||
|
|
Loading…
Reference in New Issue