2017-05-02 23:33:51 +00:00
|
|
|
package application
|
|
|
|
|
|
|
|
import (
|
2017-07-04 18:29:11 +00:00
|
|
|
"crypto/rsa"
|
2018-06-08 21:54:31 +00:00
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go"
|
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
2017-07-04 18:29:11 +00:00
|
|
|
"log"
|
|
|
|
"net"
|
2018-01-01 18:06:58 +00:00
|
|
|
"sync"
|
2017-05-02 23:33:51 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// RicochetApplication bundles many useful constructs that are
|
|
|
|
// likely standard in a ricochet application
|
|
|
|
type RicochetApplication struct {
|
2018-01-08 00:51:46 +00:00
|
|
|
contactManager ContactManagerInterface
|
|
|
|
privateKey *rsa.PrivateKey
|
2018-05-30 17:51:40 +00:00
|
|
|
name string
|
2018-01-08 00:51:46 +00:00
|
|
|
l net.Listener
|
|
|
|
instances []*ApplicationInstance
|
|
|
|
lock sync.Mutex
|
|
|
|
aif ApplicationInstanceFactory
|
2017-05-02 23:33:51 +00:00
|
|
|
}
|
|
|
|
|
2018-05-30 17:51:40 +00:00
|
|
|
func (ra *RicochetApplication) Init(name string, pk *rsa.PrivateKey, af ApplicationInstanceFactory, cm ContactManagerInterface) {
|
|
|
|
ra.name = name
|
2017-07-04 18:29:11 +00:00
|
|
|
ra.privateKey = pk
|
2018-01-08 00:51:46 +00:00
|
|
|
ra.aif = af
|
2017-07-04 18:29:11 +00:00
|
|
|
ra.contactManager = cm
|
2018-01-01 18:06:58 +00:00
|
|
|
}
|
|
|
|
|
2018-01-10 01:31:54 +00:00
|
|
|
// TODO: Reimplement OnJoin, OnLeave Events.
|
2017-07-04 18:29:11 +00:00
|
|
|
func (ra *RicochetApplication) handleConnection(conn net.Conn) {
|
|
|
|
rc, err := goricochet.NegotiateVersionInbound(conn)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("There was an error")
|
|
|
|
conn.Close()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ich := connection.HandleInboundConnection(rc)
|
|
|
|
|
2018-05-30 17:51:40 +00:00
|
|
|
err = ich.ProcessAuthAsServer(identity.Initialize(ra.name, ra.privateKey), ra.contactManager.LookupContact)
|
2017-07-04 18:29:11 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Printf("There was an error")
|
|
|
|
conn.Close()
|
|
|
|
return
|
|
|
|
}
|
2018-01-02 17:23:20 +00:00
|
|
|
rc.TraceLog(true)
|
2018-01-08 00:51:46 +00:00
|
|
|
rai := ra.aif.GetApplicationInstance(rc)
|
2018-01-01 18:06:58 +00:00
|
|
|
ra.lock.Lock()
|
|
|
|
ra.instances = append(ra.instances, rai)
|
|
|
|
ra.lock.Unlock()
|
2017-07-04 18:29:11 +00:00
|
|
|
rc.Process(rai)
|
|
|
|
}
|
|
|
|
|
2018-05-09 19:02:25 +00:00
|
|
|
func (ra *RicochetApplication) HandleApplicationInstance(rai *ApplicationInstance) {
|
|
|
|
ra.lock.Lock()
|
|
|
|
ra.instances = append(ra.instances, rai)
|
|
|
|
ra.lock.Unlock()
|
|
|
|
}
|
|
|
|
|
2018-05-30 17:51:40 +00:00
|
|
|
// Open a connection to another Ricochet peer at onionAddress. If they are unknown to use, use requestMessage (otherwise can be blank)
|
|
|
|
func (ra *RicochetApplication) Open(onionAddress string, requestMessage string) (*ApplicationInstance, error) {
|
|
|
|
rc, err := goricochet.Open(onionAddress)
|
|
|
|
rc.TraceLog(true)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("Error in application.Open(): %v\n", err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
known, err := connection.HandleOutboundConnection(rc).ProcessAuthAsClient(identity.Initialize(ra.name, ra.privateKey))
|
|
|
|
rai := ra.aif.GetApplicationInstance(rc)
|
|
|
|
go rc.Process(rai)
|
|
|
|
|
|
|
|
if !known {
|
|
|
|
err := rc.Do(func() error {
|
|
|
|
_, err := rc.RequestOpenChannel("im.ricochet.contact.request",
|
|
|
|
&channels.ContactRequestChannel{
|
|
|
|
Handler: new(AcceptAllContactHandler),
|
|
|
|
Name: ra.name,
|
|
|
|
Message: requestMessage,
|
|
|
|
})
|
|
|
|
return err
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("could not contact %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ra.HandleApplicationInstance(rai)
|
|
|
|
return rai, nil
|
|
|
|
}
|
|
|
|
|
2018-01-08 00:51:46 +00:00
|
|
|
func (ra *RicochetApplication) Broadcast(do func(rai *ApplicationInstance)) {
|
2018-01-02 17:23:20 +00:00
|
|
|
ra.lock.Lock()
|
|
|
|
for _, rai := range ra.instances {
|
2018-01-08 00:51:46 +00:00
|
|
|
do(rai)
|
2018-01-02 17:23:20 +00:00
|
|
|
}
|
|
|
|
ra.lock.Unlock()
|
2018-01-01 18:06:58 +00:00
|
|
|
}
|
|
|
|
|
2017-11-02 23:43:11 +00:00
|
|
|
func (ra *RicochetApplication) Shutdown() {
|
|
|
|
ra.l.Close()
|
2018-05-30 17:51:40 +00:00
|
|
|
for _, instance := range ra.instances {
|
|
|
|
instance.Connection.Conn.Close()
|
|
|
|
}
|
2017-07-04 18:39:19 +00:00
|
|
|
}
|
|
|
|
|
2017-07-04 18:29:11 +00:00
|
|
|
func (ra *RicochetApplication) Run(l net.Listener) {
|
|
|
|
if ra.privateKey == nil || ra.contactManager == nil {
|
|
|
|
return
|
|
|
|
}
|
2017-07-04 18:39:19 +00:00
|
|
|
ra.l = l
|
2017-11-02 23:43:11 +00:00
|
|
|
var err error
|
2017-07-04 18:39:19 +00:00
|
|
|
for err == nil {
|
|
|
|
conn, err := ra.l.Accept()
|
2017-07-04 18:29:11 +00:00
|
|
|
if err == nil {
|
|
|
|
go ra.handleConnection(conn)
|
2017-07-04 18:39:19 +00:00
|
|
|
} else {
|
2017-11-02 23:43:11 +00:00
|
|
|
return
|
2017-07-04 18:29:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|