112 lines
2.7 KiB
Go
112 lines
2.7 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"fmt"
|
|
mrand "math/rand"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"cwtch.im/cwtch/app"
|
|
"cwtch.im/cwtch/protocol/connections"
|
|
"cwtch.im/cwtch/settings"
|
|
"git.openprivacy.ca/openprivacy/connectivity/tor"
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
)
|
|
|
|
const (
|
|
offline = iota
|
|
connecting
|
|
connected
|
|
)
|
|
|
|
func isConnected(m model) (bool, tea.Msg) {
|
|
switch m.acnState {
|
|
case offline:
|
|
return false, acnOfflineMsg{}
|
|
case connecting:
|
|
return false, acnConnectingMsg{}
|
|
default:
|
|
return true, acnAlreadyOnlineMsg{}
|
|
}
|
|
}
|
|
|
|
func turnAcnOn(m *model) tea.Msg {
|
|
mrand.New(mrand.NewSource(int64(time.Now().Nanosecond())))
|
|
port := mrand.Intn(1000) + 9600
|
|
controlPort := port + 1
|
|
|
|
key := make([]byte, 64)
|
|
_, err := rand.Read(key)
|
|
if err != nil {
|
|
return acnErrMsg{err: fmt.Errorf("unable to generate control port password: %s", err)}
|
|
}
|
|
|
|
if err := os.MkdirAll(path.Join(m.userDir, "/.tor", "tor"), 0700); err != nil {
|
|
return acnErrMsg{err: fmt.Errorf("unable to create tor directory: %s", err)}
|
|
}
|
|
|
|
if err := os.MkdirAll(path.Join(m.userDir, "profiles"), 0700); err != nil {
|
|
return acnErrMsg{err: fmt.Errorf("unable to create profiles directory: %s", err)}
|
|
}
|
|
|
|
if err := tor.NewTorrc().
|
|
WithSocksPort(port).
|
|
WithOnionTrafficOnly().
|
|
WithControlPort(controlPort).
|
|
WithHashedPassword(base64.StdEncoding.EncodeToString(key)).
|
|
Build(filepath.Join(m.userDir, ".tor", "tor", "torrc")); err != nil {
|
|
return acnErrMsg{err: fmt.Errorf("unable to initialise torrc builder: %s", err)}
|
|
}
|
|
|
|
m.sendStatus("Initialising Tor ACN...")
|
|
|
|
acn, err := tor.NewTorACNWithAuth(
|
|
path.Join(m.userDir, "/.tor"),
|
|
"",
|
|
path.Join(m.userDir, "/.tor", "data"),
|
|
controlPort,
|
|
tor.HashedPasswordAuthenticator{
|
|
Password: base64.StdEncoding.EncodeToString(key),
|
|
},
|
|
)
|
|
if err != nil {
|
|
return acnErrMsg{err: fmt.Errorf("unable to bootstrap tor: %s", err)}
|
|
}
|
|
|
|
m.sendStatus("Waiting for ACN to bootstrap...")
|
|
|
|
if err := acn.WaitTillBootstrapped(); err != nil {
|
|
return acnErrMsg{err: fmt.Errorf("unable to initialise tor: %s", err)}
|
|
}
|
|
|
|
settingsFile, err := settings.InitGlobalSettingsFile(m.userDir, "")
|
|
if err != nil {
|
|
return acnErrMsg{err: fmt.Errorf("unable to initialise settings: %s", err)}
|
|
}
|
|
gSettings := settingsFile.ReadGlobalSettings()
|
|
gSettings.ExperimentsEnabled = false
|
|
gSettings.DownloadPath = "./"
|
|
settingsFile.WriteGlobalSettings(gSettings)
|
|
|
|
app := app.NewApp(acn, m.userDir, settingsFile)
|
|
app.InstallEngineHooks(connections.DefaultEngineHooks{})
|
|
|
|
return acnOnMsg{
|
|
app: app,
|
|
acn: acn,
|
|
}
|
|
}
|
|
|
|
func turnAcnOff(m *model, quitProgram bool) tea.Msg {
|
|
if m.acnState != offline {
|
|
logToFile(*m, "Shutting down application and ACN now")
|
|
m.app.Shutdown()
|
|
m.acn.Close()
|
|
}
|
|
return acnOffMsg{quitProgram: quitProgram}
|
|
}
|