Fixing up Server APIs
the build was successful Details

This commit is contained in:
Sarah Jamie Lewis 2020-11-02 15:53:13 -08:00
parent 499e4fad85
commit f6888b47f1
9 changed files with 106 additions and 46 deletions

View File

@ -297,6 +297,6 @@ const (
// Bool strings
const (
True = "true"
True = "true"
False = "false"
)
)

2
go.sum
View File

@ -1,5 +1,7 @@
cwtch.im/tapir v0.2.0 h1:7MkoR5+uEuPW34/O0GZRidnIjq/01Cfm8nl5IRuqpGc=
cwtch.im/tapir v0.2.0/go.mod h1:xzzZ28adyUXNkYL1YodcHsAiTt3IJ8Loc29YVn9mIEQ=
cwtch.im/tapir v0.2.1 h1:t1YJB9q5sV1A9xwiiwL6WVfw3dwQWLoecunuzT1PQtw=
cwtch.im/tapir v0.2.1/go.mod h1:xzzZ28adyUXNkYL1YodcHsAiTt3IJ8Loc29YVn9mIEQ=
git.openprivacy.ca/openprivacy/bine v0.0.3 h1:PSHUmNqaW7BZUX8n2eTDeNbjsuRe+t5Ae0Og+P+jDM0=
git.openprivacy.ca/openprivacy/bine v0.0.3/go.mod h1:13ZqhKyqakDsN/ZkQkIGNULsmLyqtXc46XBcnuXm/mU=
git.openprivacy.ca/openprivacy/connectivity v1.2.0 h1:dbZ5CRl11vg3BNHdzRKSlDP8OUtDB+mf6FkxMVf73qw=

View File

@ -262,9 +262,20 @@ func (e *engine) peerWithOnion(onion string) {
// peerWithTokenServer is the entry point for cwtchPeer - server relationships
// needs to be run in a goroutine as will block on Open.
func (e *engine) peerWithTokenServer(onion string, tokenServerOnion string, tokenServerY string) {
service, exists := e.ephemeralServices.Load(onion)
if exists {
connection := service.(*tor.BaseOnionService)
if conn, err := connection.GetConnection(onion); err == nil {
if conn.IsClosed() == false {
return
}
}
// Otherwise...let's reconnect
}
log.Debugf("Peering with Token Server %v %v", onion, tokenServerOnion)
e.ignoreOnShutdown(e.serverConnecting)(onion)
// Create a new ephemeral service for this connection
ephemeralService := new(tor.BaseOnionService)
eid, epk := primitives.InitializeEphemeralIdentity()

View File

@ -1,6 +1,7 @@
package main
import (
"crypto/rand"
"cwtch.im/cwtch/model"
cwtchserver "cwtch.im/cwtch/server"
"cwtch.im/tapir/primitives"
@ -9,7 +10,6 @@ import (
"git.openprivacy.ca/openprivacy/connectivity/tor"
"git.openprivacy.ca/openprivacy/log"
mrand "math/rand"
"crypto/rand"
"os"
"time"
)
@ -45,7 +45,7 @@ func main() {
// we don't need real randomness for the port, just to avoid a possible conflict...
mrand.Seed(int64(time.Now().Nanosecond()))
controlPort := mrand.Intn(1000)+9052
controlPort := mrand.Intn(1000) + 9052
// generate a random password
key := make([]byte, 64)
@ -54,7 +54,7 @@ func main() {
panic(err)
}
os.MkdirAll("tordir/tor",0700)
os.MkdirAll("tordir/tor", 0700)
tor.NewTorrc().WithHashedPassword(base64.StdEncoding.EncodeToString(key)).WithControlPort(controlPort).Build("./tordir/tor/torrc")
acn, err := tor.NewTorACNWithAuth("tordir", "", controlPort, tor.HashedPasswordAuthenticator{Password: base64.StdEncoding.EncodeToString(key)})

View File

@ -12,6 +12,7 @@ import (
type counter struct {
startTime time.Time
count uint64
total uint64
}
// Counter providers a threadsafe counter to use for storing long running counts
@ -25,7 +26,7 @@ type Counter interface {
// NewCounter initializes a counter starting at time.Now() and a count of 0 and returns it
func NewCounter() Counter {
c := &counter{startTime: time.Now(), count: 0}
c := &counter{startTime: time.Now(), count: 0, total: 0}
return c
}

View File

@ -19,6 +19,7 @@ const (
// Monitors is a package of metrics for a Cwtch Server including message count, CPU, Mem, and conns
type Monitors struct {
MessageCounter Counter
TotalMessageCounter Counter
Messages MonitorHistory
CPU MonitorHistory
Memory MonitorHistory
@ -36,7 +37,11 @@ func (mp *Monitors) Start(ts tapir.Service, configDir string, log bool) {
mp.starttime = time.Now()
mp.breakChannel = make(chan bool)
mp.MessageCounter = NewCounter()
mp.Messages = NewMonitorHistory(Count, Cumulative, func() (c float64) { c = float64(mp.MessageCounter.Count()); mp.MessageCounter.Reset(); return })
// Maintain a count of total messages
mp.TotalMessageCounter = NewCounter()
mp.Messages = NewMonitorHistory(Count, Cumulative, func() (c float64) { c = float64(mp.MessageCounter.Count()); mp.TotalMessageCounter.Add(int(c)); mp.MessageCounter.Reset(); return })
var pidUsageLock sync.Mutex
mp.CPU = NewMonitorHistory(Percent, Average, func() float64 {
pidUsageLock.Lock()

View File

@ -11,45 +11,46 @@ import (
"cwtch.im/tapir/persistence"
"cwtch.im/tapir/primitives"
"cwtch.im/tapir/primitives/privacypass"
"fmt"
"git.openprivacy.ca/openprivacy/connectivity"
"git.openprivacy.ca/openprivacy/connectivity/tor"
"git.openprivacy.ca/openprivacy/log"
"os"
"time"
"path"
)
// Server encapsulates a complete, compliant Cwtch server.
type Server struct {
service tapir.Service
config Config
metricsPack metrics.Monitors
closed bool
tokenTapirService tapir.Service
tokenServer *privacypass.TokenServer
tokenService primitives.Identity
tokenServicePrivKey ed25519.PrivateKey
service tapir.Service
config Config
metricsPack metrics.Monitors
tokenTapirService tapir.Service
tokenServer *privacypass.TokenServer
tokenService primitives.Identity
tokenServicePrivKey ed25519.PrivateKey
tokenServiceStopped bool
onionServiceStopped bool
running bool
existingMessageCount int
}
// Setup initialized a server from a given configuration
func (s *Server) Setup(serverConfig Config) {
s.config = serverConfig
bs := new(persistence.BoltPersistence)
bs.Open("./tokens.db")
bs.Open(path.Join(serverConfig.ConfigDir, "tokens.db"))
s.tokenServer = privacypass.NewTokenServerFromStore(bs)
s.tokenService = s.config.TokenServiceIdentity()
s.tokenServicePrivKey = s.config.TokenServerPrivateKey
}
// Identity returns the main onion identity of the server
func (s *Server) Identity() primitives.Identity {
return s.config.Identity()
}
// Run starts a server with the given privateKey
// TODO: surface errors
// TODO: handle HUP/KILL signals to exit and close Tor gracefully
// TODO: handle user input to exit
func (s *Server) Run(acn connectivity.ACN) {
s.closed = false
func (s *Server) Run(acn connectivity.ACN) error {
addressIdentity := tor.GetTorV3Hostname(s.config.PublicKey)
//tokenService := privacypass.NewTokenServer()
identity := primitives.InitializeIdentity("", &s.config.PrivateKey, &s.config.PublicKey)
var service tapir.Service
service = new(tor2.BaseOnionService)
@ -61,29 +62,30 @@ func (s *Server) Run(acn connectivity.ACN) {
ms := new(storage.MessageStore)
err := ms.Init(s.config.ConfigDir, s.config.MaxBufferLines, s.metricsPack.MessageCounter)
if err != nil {
log.Errorln(err)
acn.Close()
os.Exit(1)
return err
}
// Needed because we only collect metrics on a per-session basis
// TODO fix metrics so they persist across sessions?
s.existingMessageCount = len(ms.FetchMessages())
s.tokenTapirService = new(tor2.BaseOnionService)
s.tokenTapirService.Init(acn, s.tokenServicePrivKey, &s.tokenService)
tokenApplication := new(applications.TokenApplication)
tokenApplication.TokenService = s.tokenServer
powTokenApp := new(applications.ApplicationChain).
ChainApplication(new(applications.ProofOfWorkApplication), applications.SuccessfulProofOfWorkCapability).
ChainApplication(tokenApplication, applications.HasTokensCapability)
go func() {
s.tokenTapirService = new(tor2.BaseOnionService)
s.tokenTapirService.Init(acn, s.tokenServicePrivKey, &s.tokenService)
tokenApplication := new(applications.TokenApplication)
tokenApplication.TokenService = s.tokenServer
powTokenApp := new(applications.ApplicationChain).
ChainApplication(new(applications.ProofOfWorkApplication), applications.SuccessfulProofOfWorkCapability).
ChainApplication(tokenApplication, applications.HasTokensCapability)
s.tokenTapirService.Listen(powTokenApp)
s.tokenServiceStopped = true
}()
for true {
go func() {
s.service.Listen(NewTokenBoardServer(ms, s.tokenServer))
if s.closed {
return
}
time.Sleep(5 * time.Second)
}
s.onionServiceStopped = true
}()
s.running = true
return nil
}
// KeyBundle provides the signed keybundle of the server
@ -97,10 +99,44 @@ func (s *Server) KeyBundle() *model.KeyBundle {
return kb
}
// CheckStatus returns true if the server is running and/or an error if any part of the server needs to be restarted.
func (s *Server) CheckStatus() (bool, error) {
if s.onionServiceStopped == true || s.tokenServiceStopped == true {
return s.running, fmt.Errorf("one of more server components are down: onion:%v token service: %v", s.onionServiceStopped, s.tokenServiceStopped)
}
return s.running, nil
}
// Shutdown kills the app closing all connections and freeing all goroutines
func (s *Server) Shutdown() {
s.closed = true
s.service.Shutdown()
s.tokenTapirService.Shutdown()
s.metricsPack.Stop()
s.running = false
}
// Statistics is an encapsulation of information about the server that an operator might want to know at a glance.
type Statistics struct {
TotalMessages int
}
// GetStatistics is a stub method for providing some high level information about
// the server operation to bundling applications (e.g. the UI)
func (s *Server) GetStatistics() Statistics {
// TODO Statistics from Metrics is very awkward. Metrics needs an overhaul to make safe
total := s.existingMessageCount
if s.metricsPack.TotalMessageCounter != nil {
total += s.metricsPack.TotalMessageCounter.Count()
}
return Statistics{
TotalMessages: total,
}
}
// ConfigureAutostart sets whether this server should autostart (in the Cwtch UI/bundling application)
func (s *Server) ConfigureAutostart(autostart bool) {
s.config.AutoStart = autostart
s.config.Save(s.config.ConfigDir, s.config.FilePath)
}

View File

@ -19,12 +19,14 @@ type Reporting struct {
// Config is a struct for storing basic server configuration
type Config struct {
ConfigDir string `json:"-"`
FilePath string `json:"-"`
MaxBufferLines int `json:"maxBufferLines"`
PublicKey ed25519.PublicKey `json:"publicKey"`
PrivateKey ed25519.PrivateKey `json:"privateKey"`
TokenServerPublicKey ed25519.PublicKey `json:"tokenServerPublicKey"`
TokenServerPrivateKey ed25519.PrivateKey `json:"tokenServerPrivateKey"`
ServerReporting Reporting `json:"serverReporting"`
AutoStart bool `json:"autostart"`
}
// Identity returns an encapsulation of the servers keys
@ -61,6 +63,9 @@ func LoadConfig(configDir, filename string) Config {
ReportingGroupID: "",
ReportingServerAddr: "",
}
config.AutoStart = false
config.ConfigDir = configDir
config.FilePath = filename
raw, err := ioutil.ReadFile(path.Join(configDir, filename))
if err == nil {

View File

@ -139,7 +139,7 @@ func TestCwtchPeerIntegration(t *testing.T) {
if err != nil {
t.Fatalf("Could not start Tor: %v", err)
}
pid, err := acn.GetPID()
pid, _ := acn.GetPID()
t.Logf("Tor pid: %v", pid)
// ***** Cwtch Server management *****