This repository has been archived on 2020-04-20. You can view files and clone it, but cannot push or open issues or pull requests.
libricochet-go/connection/outboundconnectionhandler.go

86 lines
2.8 KiB
Go

package connection
import (
"git.openprivacy.ca/openprivacy/libricochet-go/channels/v3/outbound"
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
"git.openprivacy.ca/openprivacy/libricochet-go/policies"
"git.openprivacy.ca/openprivacy/libricochet-go/utils"
"sync"
)
// 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
}
// ProcessAuthAsV3Client blocks until authentication has succeeded or failed with the
// provided identity, or the connection is closed. A non-nil error is returned in all
// cases other than successful authentication.
//
// ProcessAuthAsV3Client cannot be called at the same time as any other call to a Process
// 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.
func (och *OutboundConnectionHandler) ProcessAuthAsV3Client(v3identity identity.Identity) (bool, error) {
ach := new(AutoConnectionHandler)
ach.Init()
// Make sure that calls to Break in this function cannot race
var breakOnce sync.Once
var accepted, isKnownContact bool
authCallback := func(accept, known bool) {
accepted = accept
isKnownContact = known
// 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() })
}
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)
})
processResult <- err
}()
err := och.connection.Do(func() error {
_, err := och.connection.RequestOpenChannel("im.ricochet.auth.3dh",
&outbound.Client3DHAuthChannel{
ClientIdentity: v3identity,
ServerHostname: och.connection.RemoteHostname,
ClientAuthResult: authCallback,
})
return err
})
if err != nil {
breakOnce.Do(func() { och.connection.Break() })
return false, err
}
if err = <-processResult; err != nil {
return false, err
}
if accepted == true {
return isKnownContact, nil
}
return false, utils.ServerRejectedClientConnectionError
}