2017-05-02 23:33:51 +00:00
|
|
|
package connection
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/s-rah/go-ricochet/channels"
|
2017-12-05 19:00:04 +00:00
|
|
|
"github.com/s-rah/go-ricochet/identity"
|
2017-05-02 23:33:51 +00:00
|
|
|
"github.com/s-rah/go-ricochet/policies"
|
2017-07-04 18:29:11 +00:00
|
|
|
"github.com/s-rah/go-ricochet/utils"
|
2017-09-16 21:50:39 +00:00
|
|
|
"sync"
|
2017-05-02 23:33:51 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// OutboundConnectionHandler is a convieniance wrapper for handling outbound
|
|
|
|
// connections
|
|
|
|
type OutboundConnectionHandler struct {
|
|
|
|
connection *Connection
|
|
|
|
}
|
|
|
|
|
|
|
|
// HandleOutboundConnection returns an OutboundConnectionHandler given a connection
|
|
|
|
func HandleOutboundConnection(c *Connection) *OutboundConnectionHandler {
|
|
|
|
och := new(OutboundConnectionHandler)
|
|
|
|
och.connection = c
|
|
|
|
return och
|
|
|
|
}
|
|
|
|
|
|
|
|
// ProcessAuthAsClient blocks until authentication has succeeded or failed with the
|
2017-12-13 19:33:35 +00:00
|
|
|
// provided identity, or the connection is closed. A non-nil error is returned in all
|
2017-05-02 23:33:51 +00:00
|
|
|
// cases other than successful authentication.
|
|
|
|
//
|
|
|
|
// ProcessAuthAsClient cannot be called at the same time as any other call to a Porcess
|
|
|
|
// function. Another Process function must be called after this function successfully
|
|
|
|
// returns to continue handling connection events.
|
|
|
|
//
|
|
|
|
// For successful authentication, the `known` return value indicates whether the peer
|
|
|
|
// accepts us as a known contact. Unknown contacts will generally need to send a contact
|
|
|
|
// request before any other activity.
|
2017-12-13 19:33:35 +00:00
|
|
|
func (och *OutboundConnectionHandler) ProcessAuthAsClient(identity identity.Identity) (bool, error) {
|
2017-06-27 17:39:33 +00:00
|
|
|
|
2017-12-13 19:33:35 +00:00
|
|
|
if !identity.Initialized() {
|
2017-07-04 18:29:11 +00:00
|
|
|
return false, utils.PrivateKeyNotSetError
|
|
|
|
}
|
2017-06-27 17:39:33 +00:00
|
|
|
|
2017-05-02 23:33:51 +00:00
|
|
|
ach := new(AutoConnectionHandler)
|
2017-09-16 13:46:28 +00:00
|
|
|
ach.Init()
|
2017-05-02 23:33:51 +00:00
|
|
|
|
2017-09-16 21:50:39 +00:00
|
|
|
// Make sure that calls to Break in this function cannot race
|
|
|
|
var breakOnce sync.Once
|
|
|
|
|
2017-09-16 13:46:28 +00:00
|
|
|
var accepted, isKnownContact bool
|
|
|
|
authCallback := func(accept, known bool) {
|
|
|
|
accepted = accept
|
|
|
|
isKnownContact = known
|
2017-09-16 21:50:39 +00:00
|
|
|
// Cause the Process() call below to return.
|
|
|
|
// If Break() is called from here, it _must_ use go, because this will
|
|
|
|
// execute in the Process goroutine, and Break() will deadlock.
|
|
|
|
breakOnce.Do(func() { go och.connection.Break() })
|
2017-09-16 13:46:28 +00:00
|
|
|
}
|
|
|
|
|
2017-09-16 21:50:39 +00:00
|
|
|
processResult := make(chan error, 1)
|
|
|
|
go func() {
|
|
|
|
// Break Process() if timed out; no-op if Process returned a conn error
|
|
|
|
defer func() { breakOnce.Do(func() { och.connection.Break() }) }()
|
|
|
|
policy := policies.UnknownPurposeTimeout
|
|
|
|
err := policy.ExecuteAction(func() error {
|
|
|
|
return och.connection.Process(ach)
|
2017-09-16 13:46:28 +00:00
|
|
|
})
|
2017-09-16 21:50:39 +00:00
|
|
|
processResult <- err
|
|
|
|
}()
|
|
|
|
|
|
|
|
err := och.connection.Do(func() error {
|
|
|
|
_, err := och.connection.RequestOpenChannel("im.ricochet.auth.hidden-service",
|
|
|
|
&channels.HiddenServiceAuthChannel{
|
2017-12-13 19:33:35 +00:00
|
|
|
Identity: identity,
|
2017-09-16 21:50:39 +00:00
|
|
|
ServerHostname: och.connection.RemoteHostname,
|
|
|
|
ClientAuthResult: authCallback,
|
|
|
|
})
|
|
|
|
return err
|
|
|
|
})
|
2017-09-16 13:46:28 +00:00
|
|
|
if err != nil {
|
2017-09-16 21:50:39 +00:00
|
|
|
breakOnce.Do(func() { och.connection.Break() })
|
2017-09-16 13:46:28 +00:00
|
|
|
return false, err
|
|
|
|
}
|
2017-05-02 23:33:51 +00:00
|
|
|
|
2017-09-16 21:50:39 +00:00
|
|
|
if err = <-processResult; err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
2017-05-02 23:33:51 +00:00
|
|
|
|
2017-09-16 21:50:39 +00:00
|
|
|
if accepted == true {
|
|
|
|
return isKnownContact, nil
|
2017-05-02 23:33:51 +00:00
|
|
|
}
|
2017-07-04 18:29:11 +00:00
|
|
|
return false, utils.ServerRejectedClientConnectionError
|
2017-05-02 23:33:51 +00:00
|
|
|
}
|