core: Add protocol from s-rah and accept inbound connections
Start using Sarah's protocol implementation (plus some patches to be merged there), publish the local onion service, and handle inbound connections.
This commit is contained in:
parent
65f36de79e
commit
cf903a3b7d
|
@ -4,16 +4,21 @@ import (
|
|||
"crypto/rsa"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"github.com/special/notricochet/core/utils"
|
||||
"github.com/yawning/bulb/utils/pkcs1"
|
||||
"log"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Identity represents the local user, including their contact address,
|
||||
// and contains the contacts list.
|
||||
type Identity struct {
|
||||
core *Ricochet
|
||||
|
||||
address string
|
||||
privateKey *rsa.PrivateKey
|
||||
mutex sync.Mutex
|
||||
|
||||
address string
|
||||
privateKey *rsa.PrivateKey
|
||||
contactList *ContactList
|
||||
}
|
||||
|
||||
|
@ -22,19 +27,19 @@ func CreateIdentity(core *Ricochet) (*Identity, error) {
|
|||
core: core,
|
||||
}
|
||||
|
||||
err := me.loadIdentity()
|
||||
if err != nil {
|
||||
log.Printf("Loading identity failed: %v", err)
|
||||
if err := me.loadIdentity(); err != nil {
|
||||
log.Printf("Failed loading identity: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
contactList, err := LoadContactList(core)
|
||||
if err != nil {
|
||||
log.Printf("Loading contact list failed: %v", err)
|
||||
log.Printf("Failed loading contact list: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
me.contactList = contactList
|
||||
|
||||
go me.publishService(me.privateKey)
|
||||
return me, nil
|
||||
}
|
||||
|
||||
|
@ -52,19 +57,69 @@ func (me *Identity) loadIdentity() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
me.address, err = pkcs1.OnionAddr(&me.privateKey.PublicKey)
|
||||
me.address, err = utils.RicochetAddressFromKey(&me.privateKey.PublicKey)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if me.address == "" {
|
||||
return errors.New("Invalid onion address")
|
||||
}
|
||||
me.address = "ricochet:" + me.address
|
||||
|
||||
log.Printf("Loaded identity %s", me.address)
|
||||
} else {
|
||||
log.Printf("Initializing new identity")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (me *Identity) setPrivateKey(key *rsa.PrivateKey) error {
|
||||
me.mutex.Lock()
|
||||
defer me.mutex.Unlock()
|
||||
|
||||
if me.privateKey != nil || me.address != "" {
|
||||
return errors.New("Cannot change private key on identity")
|
||||
}
|
||||
|
||||
// Save key to config
|
||||
keyData, err := pkcs1.EncodePrivateKeyDER(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config := me.core.Config.OpenWrite()
|
||||
config.Identity.ServiceKey = base64.StdEncoding.EncodeToString(keyData)
|
||||
config.Save()
|
||||
|
||||
// Update Identity
|
||||
me.address, err = utils.RicochetAddressFromKey(&key.PublicKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
me.privateKey = key
|
||||
|
||||
log.Printf("Created new identity %s", me.address)
|
||||
return nil
|
||||
}
|
||||
|
||||
// BUG(special): No error handling for failures under publishService
|
||||
func (me *Identity) publishService(key *rsa.PrivateKey) {
|
||||
service, listener, err := me.core.Network.NewOnionListener(9878, key)
|
||||
if err != nil {
|
||||
log.Printf("Identity listener failed: %v", err)
|
||||
// XXX handle
|
||||
return
|
||||
}
|
||||
|
||||
if key == nil {
|
||||
err := me.setPrivateKey(service.PrivateKey.(*rsa.PrivateKey))
|
||||
if err != nil {
|
||||
log.Printf("Setting private key failed: %v", err)
|
||||
// XXX handle
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("Identity service published, accepting connections")
|
||||
go me.core.Protocol.ServeListener(listener)
|
||||
}
|
||||
|
||||
func (me *Identity) Address() string {
|
||||
return me.address
|
||||
}
|
||||
|
@ -72,3 +127,7 @@ func (me *Identity) Address() string {
|
|||
func (me *Identity) ContactList() *ContactList {
|
||||
return me.contactList
|
||||
}
|
||||
|
||||
func (me *Identity) PrivateKey() rsa.PrivateKey {
|
||||
return *me.privateKey
|
||||
}
|
||||
|
|
|
@ -154,7 +154,7 @@ func (n *Network) getConnection() *bulb.Conn {
|
|||
// This function will block until a control connection is available and
|
||||
// the service is added or the command has failed. If the control connection
|
||||
// is lost and reconnected, the service will be re-added automatically.
|
||||
// BUG: Errors that occur after reconnecting cannot be detected.
|
||||
// BUG(special): Errors that occur after reconnecting cannot be detected.
|
||||
func (n *Network) AddOnionPorts(ports []bulb.OnionPortSpec, key crypto.PrivateKey) (*OnionService, error) {
|
||||
if key == nil {
|
||||
// Ask for a new key, force RSA1024
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"encoding/asn1"
|
||||
protocol "github.com/s-rah/go-ricochet"
|
||||
"log"
|
||||
"net"
|
||||
)
|
||||
|
||||
type Protocol struct {
|
||||
core *Ricochet
|
||||
|
||||
service *protocol.Ricochet
|
||||
handler *protocolHandler
|
||||
}
|
||||
|
||||
// Implements protocol.RicochetService
|
||||
type protocolHandler struct {
|
||||
p *Protocol
|
||||
}
|
||||
|
||||
func CreateProtocol(core *Ricochet) *Protocol {
|
||||
p := &Protocol{
|
||||
core: core,
|
||||
service: new(protocol.Ricochet),
|
||||
}
|
||||
p.handler = &protocolHandler{p: p}
|
||||
p.service.Init()
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *Protocol) ServeListener(listener net.Listener) {
|
||||
p.service.ServeListener(p.handler, listener)
|
||||
}
|
||||
|
||||
// Strangely, ServeListener starts a background routine that watches a channel
|
||||
// on p.service for new connections and dispatches their events to the handler
|
||||
// for the listener. API needs a little work here.
|
||||
func (p *Protocol) Connect(address string) (*protocol.OpenConnection, error) {
|
||||
oc, err := p.service.Connect(address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
oc.MyHostname = p.core.Identity.Address()[9:]
|
||||
return oc, nil
|
||||
}
|
||||
|
||||
func (handler *protocolHandler) OnReady() {
|
||||
log.Printf("protocol: OnReady")
|
||||
}
|
||||
|
||||
func (handler *protocolHandler) OnConnect(oc *protocol.OpenConnection) {
|
||||
log.Printf("protocol: OnConnect: %v", oc)
|
||||
if oc.Client {
|
||||
log.Printf("Connected to %s", oc.OtherHostname)
|
||||
oc.IsAuthed = true // Outbound connections are authenticated
|
||||
oc.Authenticate(1)
|
||||
} else {
|
||||
// Strip ricochet:
|
||||
oc.MyHostname = handler.p.core.Identity.Address()[9:]
|
||||
}
|
||||
}
|
||||
|
||||
// Authentication Management
|
||||
func (handler *protocolHandler) OnAuthenticationRequest(oc *protocol.OpenConnection, channelID int32, clientCookie [16]byte) {
|
||||
log.Printf("protocol: OnAuthenticationRequest")
|
||||
oc.ConfirmAuthChannel(channelID, clientCookie)
|
||||
}
|
||||
|
||||
func (handler *protocolHandler) OnAuthenticationChallenge(oc *protocol.OpenConnection, channelID int32, serverCookie [16]byte) {
|
||||
log.Printf("protocol: OnAuthenticationChallenge")
|
||||
privateKey := handler.p.core.Identity.PrivateKey()
|
||||
publicKeyBytes, _ := asn1.Marshal(privateKey.PublicKey)
|
||||
oc.SendProof(1, serverCookie, publicKeyBytes, &privateKey)
|
||||
}
|
||||
|
||||
func (handler *protocolHandler) OnAuthenticationProof(oc *protocol.OpenConnection, channelID int32, publicKey []byte, signature []byte, isKnownContact bool) {
|
||||
result := oc.ValidateProof(channelID, publicKey, signature)
|
||||
log.Printf("protocol: OnAuthenticationProof, result: %v", result)
|
||||
oc.SendAuthenticationResult(channelID, result, isKnownContact)
|
||||
oc.IsAuthed = result
|
||||
oc.CloseChannel(channelID)
|
||||
}
|
||||
|
||||
func (handler *protocolHandler) OnAuthenticationResult(oc *protocol.OpenConnection, channelID int32, result bool, isKnownContact bool) {
|
||||
log.Printf("protocol: OnAuthenticationResult, result: %v, known: %v", result, isKnownContact)
|
||||
oc.IsAuthed = result
|
||||
}
|
||||
|
||||
// Contact Management
|
||||
func (handler *protocolHandler) IsKnownContact(hostname string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (handler *protocolHandler) OnContactRequest(oc *protocol.OpenConnection, channelID int32, nick string, message string) {
|
||||
}
|
||||
|
||||
func (handler *protocolHandler) OnContactRequestAck(oc *protocol.OpenConnection, channelID int32, status string) {
|
||||
}
|
||||
|
||||
// Managing Channels
|
||||
func (handler *protocolHandler) OnOpenChannelRequest(oc *protocol.OpenConnection, channelID int32, channelType string) {
|
||||
oc.AckOpenChannel(channelID, channelType)
|
||||
}
|
||||
|
||||
func (handler *protocolHandler) OnOpenChannelRequestSuccess(oc *protocol.OpenConnection, channelID int32) {
|
||||
}
|
||||
func (handler *protocolHandler) OnChannelClosed(oc *protocol.OpenConnection, channelID int32) {
|
||||
}
|
||||
|
||||
// Chat Messages
|
||||
func (handler *protocolHandler) OnChatMessage(oc *protocol.OpenConnection, channelID int32, messageID int32, message string) {
|
||||
}
|
||||
func (handler *protocolHandler) OnChatMessageAck(oc *protocol.OpenConnection, channelID int32, messageID int32) {
|
||||
}
|
||||
|
||||
// Handle Errors
|
||||
func (handler *protocolHandler) OnFailedChannelOpen(oc *protocol.OpenConnection, channelID int32, errorType string) {
|
||||
oc.UnsetChannel(channelID)
|
||||
}
|
||||
func (handler *protocolHandler) OnGenericError(oc *protocol.OpenConnection, channelID int32) {
|
||||
oc.RejectOpenChannel(channelID, "GenericError")
|
||||
}
|
||||
func (handler *protocolHandler) OnUnknownTypeError(oc *protocol.OpenConnection, channelID int32) {
|
||||
oc.RejectOpenChannel(channelID, "UnknownTypeError")
|
||||
}
|
||||
func (handler *protocolHandler) OnUnauthorizedError(oc *protocol.OpenConnection, channelID int32) {
|
||||
oc.RejectOpenChannel(channelID, "UnauthorizedError")
|
||||
}
|
||||
func (handler *protocolHandler) OnBadUsageError(oc *protocol.OpenConnection, channelID int32) {
|
||||
oc.RejectOpenChannel(channelID, "BadUsageError")
|
||||
}
|
||||
func (handler *protocolHandler) OnFailedError(oc *protocol.OpenConnection, channelID int32) {
|
||||
oc.RejectOpenChannel(channelID, "FailedError")
|
||||
}
|
|
@ -3,6 +3,7 @@ package core
|
|||
type Ricochet struct {
|
||||
Config *Config
|
||||
Network *Network
|
||||
Protocol *Protocol
|
||||
Identity *Identity
|
||||
}
|
||||
|
||||
|
@ -10,6 +11,7 @@ func (core *Ricochet) Init(conf *Config) error {
|
|||
var err error
|
||||
core.Config = conf
|
||||
core.Network = CreateNetwork()
|
||||
core.Protocol = CreateProtocol(core)
|
||||
core.Identity, err = CreateIdentity(core)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
Loading…
Reference in New Issue