Refactor to better define boundaries, formatting and linting
This commit is contained in:
parent
3cada87147
commit
6cf2862681
|
@ -1,8 +1,9 @@
|
|||
package tapir
|
||||
package applications
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/subtle"
|
||||
"cwtch.im/tapir"
|
||||
"encoding/json"
|
||||
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
||||
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
||||
|
@ -26,13 +27,13 @@ type AuthApp struct {
|
|||
}
|
||||
|
||||
// NewInstance creates a new instance of the AuthApp
|
||||
func (ea AuthApp) NewInstance() Application {
|
||||
func (ea AuthApp) NewInstance() tapir.Application {
|
||||
return new(AuthApp)
|
||||
}
|
||||
|
||||
// Init runs the entire AuthApp protocol, at the end of the protocol either the connection is granted AUTH capability
|
||||
// or the connection is closed.
|
||||
func (ea AuthApp) Init(connection *Connection) {
|
||||
func (ea AuthApp) Init(connection *tapir.Connection) {
|
||||
longTermPubKey := ed25519.PublicKey(connection.ID.PublicKeyBytes())
|
||||
epk, esk, _ := ed25519.GenerateKey(rand.Reader)
|
||||
ephemeralPublicKey := ed25519.PublicKey(epk)
|
||||
|
@ -46,7 +47,7 @@ func (ea AuthApp) Init(connection *Connection) {
|
|||
var remoteAuthMessage AuthMessage
|
||||
err := json.Unmarshal(message, &remoteAuthMessage)
|
||||
if err != nil {
|
||||
connection.conn.Close()
|
||||
connection.Close()
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -96,6 +97,6 @@ func (ea AuthApp) Init(connection *Connection) {
|
|||
connection.SetCapability(AuthCapability)
|
||||
} else {
|
||||
log.Errorf("Failed Decrypt Challenge: [%x] [%x]\n", remoteChallenge, challengeBytes)
|
||||
connection.conn.Close()
|
||||
connection.Close()
|
||||
}
|
||||
}
|
|
@ -4,6 +4,8 @@ import (
|
|||
"crypto/rand"
|
||||
"crypto/sha512"
|
||||
"cwtch.im/tapir"
|
||||
"cwtch.im/tapir/applications"
|
||||
"cwtch.im/tapir/networks/tor"
|
||||
"cwtch.im/tapir/primitives"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
|
@ -25,8 +27,9 @@ type Notification struct {
|
|||
Message string
|
||||
}
|
||||
|
||||
// NotificationClient allows publishing and reading from the notifications server
|
||||
type NotificationClient struct {
|
||||
tapir.AuthApp
|
||||
applications.AuthApp
|
||||
connection *tapir.Connection
|
||||
}
|
||||
|
||||
|
@ -40,7 +43,7 @@ func (nc NotificationClient) NewInstance() tapir.Application {
|
|||
func (nc *NotificationClient) Init(connection *tapir.Connection) {
|
||||
// First run the Authentication App
|
||||
nc.AuthApp.Init(connection)
|
||||
if connection.HasCapability(tapir.AuthCapability) {
|
||||
if connection.HasCapability(applications.AuthCapability) {
|
||||
nc.connection = connection
|
||||
}
|
||||
}
|
||||
|
@ -70,15 +73,14 @@ func (nc NotificationClient) Check(topic string) bool {
|
|||
return bf.Check(hashedTopic[:])
|
||||
}
|
||||
|
||||
|
||||
type NotificationRequest struct {
|
||||
type notificationRequest struct {
|
||||
RequestType string
|
||||
RequestData map[string]string
|
||||
}
|
||||
|
||||
// PIRApp is a trivial implementation of a basic p2p application
|
||||
// NotificationsServer implements the metadata resistant notifications server
|
||||
type NotificationsServer struct {
|
||||
tapir.AuthApp
|
||||
applications.AuthApp
|
||||
Filter *primitives.BloomFilter
|
||||
}
|
||||
|
||||
|
@ -89,13 +91,14 @@ func (ns NotificationsServer) NewInstance() tapir.Application {
|
|||
return app
|
||||
}
|
||||
|
||||
// Init initializes the application.
|
||||
func (ns NotificationsServer) Init(connection *tapir.Connection) {
|
||||
// First run the Authentication App
|
||||
ns.AuthApp.Init(connection)
|
||||
if connection.HasCapability(tapir.AuthCapability) {
|
||||
if connection.HasCapability(applications.AuthCapability) {
|
||||
for {
|
||||
request := connection.Expect()
|
||||
var nr NotificationRequest
|
||||
var nr notificationRequest
|
||||
json.Unmarshal(request, &nr)
|
||||
log.Debugf("Received Request %v", nr)
|
||||
switch nr.RequestType {
|
||||
|
@ -140,7 +143,7 @@ func main() {
|
|||
|
||||
// Init the Server running the Simple App.
|
||||
var service tapir.Service
|
||||
service = new(tapir.BaseOnionService)
|
||||
service = new(tor.BaseOnionService)
|
||||
service.Init(acn, sk, id)
|
||||
bf := new(primitives.BloomFilter)
|
||||
bf.Init(1024)
|
||||
|
@ -154,25 +157,21 @@ func client(acn connectivity.ACN, key ed25519.PublicKey) {
|
|||
pk := ed25519.PublicKey(pubkey)
|
||||
id := identity.InitializeV3("client", &sk, &pk)
|
||||
var client tapir.Service
|
||||
client = new(tapir.BaseOnionService)
|
||||
client = new(tor.BaseOnionService)
|
||||
client.Init(acn, sk, id)
|
||||
|
||||
cid, _ := client.Connect(utils.GetTorV3Hostname(key), new(NotificationClient))
|
||||
|
||||
|
||||
conn, err := client.WaitForCapabilityOrClose(cid, tapir.AuthCapability)
|
||||
conn, err := client.WaitForCapabilityOrClose(cid, applications.AuthCapability)
|
||||
if err == nil {
|
||||
log.Debugf("Client has Auth: %v", conn.HasCapability(tapir.AuthCapability))
|
||||
log.Debugf("Client has Auth: %v", conn.HasCapability(applications.AuthCapability))
|
||||
nc := conn.App.(*NotificationClient)
|
||||
|
||||
// Basic Demonstration of Notification
|
||||
log.Infof("Checking #astronomy: %v", nc.Check("#astronomy"))
|
||||
log.Infof("Publishing to #astronomy: %v", nc.Check("#astronomy"))
|
||||
nc.Publish("#astronomy", "New #Astronomy Post!")
|
||||
log.Infof("Checking #astronomy: %v", nc.Check("#astronomy"))
|
||||
}
|
||||
|
||||
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ type BloomFilter struct {
|
|||
B []bool
|
||||
}
|
||||
|
||||
|
||||
// Init constructs a bloom filter of size m
|
||||
func (bf *BloomFilter) Init(m int) {
|
||||
bf.B = make([]bool, m)
|
||||
|
@ -57,4 +56,3 @@ func (bf BloomFilter) Check(msg []byte) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
118
service.go
118
service.go
|
@ -2,9 +2,7 @@ package tapir
|
|||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
||||
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
||||
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
||||
|
@ -13,7 +11,6 @@ import (
|
|||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Service defines the interface for a Tapir Service
|
||||
|
@ -25,7 +22,7 @@ type Service interface {
|
|||
WaitForCapabilityOrClose(connectionID string, capability string) (*Connection, error)
|
||||
}
|
||||
|
||||
// This is a fairly arbitrary number that very much depends on the application and the available bandwidth/server
|
||||
// MaxLength is a fairly arbitrary number that very much depends on the application and the available bandwidth/server
|
||||
// storage.
|
||||
const MaxLength = 8192
|
||||
|
||||
|
@ -39,7 +36,7 @@ type Connection struct {
|
|||
App Application
|
||||
ID identity.Identity
|
||||
Outbound bool
|
||||
closed bool
|
||||
Closed bool
|
||||
}
|
||||
|
||||
// NewConnection creates a new Connection
|
||||
|
@ -72,6 +69,10 @@ func (c *Connection) HasCapability(name string) bool {
|
|||
return ok
|
||||
}
|
||||
|
||||
// Close forcibly closes the connection
|
||||
func (c *Connection) Close() {
|
||||
c.conn.Close()
|
||||
}
|
||||
|
||||
// Expect blocks and reads a single Tapir packet (1024 bytes), from the connection.
|
||||
func (c *Connection) Expect() []byte {
|
||||
|
@ -81,7 +82,7 @@ func (c *Connection) Expect() []byte {
|
|||
if n != MaxLength || err != nil {
|
||||
log.Errorf("[%v -> %v] Wire Error Reading, Read %d bytes, Error: %v", c.hostname, c.ID.Hostname(), n, err)
|
||||
c.conn.Close()
|
||||
c.closed = true
|
||||
c.Closed = true
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
|
@ -94,7 +95,7 @@ func (c *Connection) Expect() []byte {
|
|||
} else {
|
||||
log.Errorf("[%v -> %v] Error Decrypting Message On Wire", c.hostname, c.ID.Hostname())
|
||||
c.conn.Close()
|
||||
c.closed = true
|
||||
c.Closed = true
|
||||
return []byte{}
|
||||
}
|
||||
}
|
||||
|
@ -119,9 +120,9 @@ func (c *Connection) Send(message []byte) {
|
|||
if c.encrypted {
|
||||
var nonce [24]byte
|
||||
if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {
|
||||
// TODO: Surface is Erro
|
||||
// TODO: Surface is Error
|
||||
c.conn.Close()
|
||||
c.closed = true
|
||||
c.Closed = true
|
||||
}
|
||||
// MaxLength - 40 = MaxLength - 24 nonce bytes and 16 auth tag.
|
||||
encrypted := secretbox.Seal(nonce[:], buffer[0:MaxLength-40], &nonce, &c.key)
|
||||
|
@ -131,103 +132,6 @@ func (c *Connection) Send(message []byte) {
|
|||
_, err := c.conn.Write(buffer)
|
||||
if err != nil {
|
||||
c.conn.Close()
|
||||
c.closed = true
|
||||
c.Closed = true
|
||||
}
|
||||
}
|
||||
|
||||
// BaseOnionService is a concrete implementation of the service interface over Tor onion services.
|
||||
type BaseOnionService struct {
|
||||
connections sync.Map
|
||||
acn connectivity.ACN
|
||||
id identity.Identity
|
||||
privateKey ed25519.PrivateKey
|
||||
}
|
||||
|
||||
// Init initializes a BaseOnionService with a given private key and identity
|
||||
// The private key is needed to initialize the Onion listen socket, ideally we could just pass an Identity in here.
|
||||
func (s *BaseOnionService) Init(acn connectivity.ACN, sk ed25519.PrivateKey, id identity.Identity) {
|
||||
// run add onion
|
||||
// get listen context
|
||||
s.acn = acn
|
||||
s.id = id
|
||||
s.privateKey = sk
|
||||
}
|
||||
|
||||
|
||||
|
||||
// WaitForCapabilityOrClose blocks until the connection has the given capability or the underlying connection is closed
|
||||
// (through error or user action)
|
||||
func (s * BaseOnionService) WaitForCapabilityOrClose(cid string, name string) (*Connection, error) {
|
||||
conn, err := s.GetConnection(cid)
|
||||
if err == nil {
|
||||
for {
|
||||
if conn.HasCapability(name) {
|
||||
return conn, nil
|
||||
}
|
||||
if conn.closed {
|
||||
return nil, errors.New("connection is closed")
|
||||
}
|
||||
time.Sleep(time.Millisecond * 200)
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
// GetConnection returns a connection for a given hostname.
|
||||
func (s *BaseOnionService) GetConnection(connectionID string) (*Connection, error) {
|
||||
conn, ok := s.connections.Load(connectionID)
|
||||
if !ok {
|
||||
return nil, errors.New("no connection found")
|
||||
}
|
||||
connection := conn.(*Connection)
|
||||
return connection, nil
|
||||
}
|
||||
|
||||
// Connect initializes a new outbound connection to the given peer, using the defined Application
|
||||
func (s *BaseOnionService) Connect(hostname string, app Application) (string, error) {
|
||||
// connects to a remote server
|
||||
// spins off to a connection struct
|
||||
log.Debugf("Connecting to %v", hostname)
|
||||
conn, _, err := s.acn.Open(hostname)
|
||||
if err == nil {
|
||||
connectionID := s.getNewConnectionID()
|
||||
log.Debugf("Connected to %v [%v]", hostname, connectionID)
|
||||
s.connections.Store(connectionID, NewConnection(s.id, hostname, true, conn, app.NewInstance()))
|
||||
return connectionID, nil
|
||||
}
|
||||
log.Debugf("Error connecting to %v %v", hostname, err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
func (s *BaseOnionService) getNewConnectionID() string {
|
||||
id := make([]byte, 10)
|
||||
rand.Read(id)
|
||||
connectionID := "connection-" + base64.StdEncoding.EncodeToString(id)
|
||||
return connectionID
|
||||
}
|
||||
|
||||
// Listen starts a blocking routine that waits for incoming connections and initializes connections with them based
|
||||
// on the given Application.
|
||||
func (s *BaseOnionService) Listen(app Application) error {
|
||||
// accepts a new connection
|
||||
// spins off to a connection struct
|
||||
ls, err := s.acn.Listen(s.privateKey, 9878)
|
||||
log.Debugf("Starting a service on %v ", ls.AddressFull())
|
||||
if err == nil {
|
||||
for {
|
||||
conn, err := ls.Accept()
|
||||
if err == nil {
|
||||
tempHostname := s.getNewConnectionID()
|
||||
log.Debugf("Accepted connection from %v", tempHostname)
|
||||
s.connections.Store(tempHostname, NewConnection(s.id, tempHostname, false, conn, app.NewInstance()))
|
||||
} else {
|
||||
ls.Close()
|
||||
log.Debugf("Error accepting connection %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Debugf("Error listening to connection %v", err)
|
||||
return err
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue