Add cwtchtools, add make payment tool

This commit is contained in:
Sarah Jamie Lewis 2022-10-03 11:00:36 -07:00
parent 0e10b47c42
commit 9c65ad4af3
5 changed files with 214 additions and 3 deletions

3
.gitignore vendored
View File

@ -29,3 +29,6 @@ arch/
testing/encryptedstorage/encrypted_storage_profiles
testing/encryptedstorage/tordir
*.tar.gz
data-dir-cwtchtool/
tokens
tordir/

View File

@ -696,7 +696,7 @@ func (e *engine) handlePeerMessage(hostname string, eventID string, context stri
e.eventManager.Publish(event.NewEvent(event.NewMessageFromPeerEngine, map[event.Field]string{event.TimestampReceived: time.Now().Format(time.RFC3339Nano), event.RemotePeer: hostname, event.Data: string(message)}))
// Send an explicit acknowledgement
// Every other protocol should have a explicit acknowledgement message e.g. value lookups have responses, and file handling has an explicit flow
// Every other protocol should have an explicit acknowledgement message e.g. value lookups have responses, and file handling has an explicit flow
if err := e.sendPeerMessage(hostname, pmodel.PeerMessage{ID: eventID, Context: event.ContextAck, Data: []byte{}}); err != nil {
e.eventManager.Publish(event.NewEvent(event.SendMessageToPeerError, map[event.Field]string{event.RemotePeer: hostname, event.EventID: eventID, event.Error: err.Error()}))
}

View File

@ -0,0 +1,59 @@
package connections
import (
"cwtch.im/cwtch/utils"
"git.openprivacy.ca/cwtch.im/tapir/applications"
"git.openprivacy.ca/cwtch.im/tapir/networks/tor"
"git.openprivacy.ca/cwtch.im/tapir/primitives"
"git.openprivacy.ca/cwtch.im/tapir/primitives/privacypass"
"git.openprivacy.ca/openprivacy/connectivity"
"git.openprivacy.ca/openprivacy/log"
"reflect"
"time"
)
// MakePayment uses the PoW based token protocol to obtain more tokens
func MakePayment(tokenServiceOnion string, tokenService *privacypass.TokenServer, acn connectivity.ACN, handler TokenBoardHandler) error {
log.Debugf("making a payment")
id, sk := primitives.InitializeEphemeralIdentity()
client := new(tor.BaseOnionService)
client.Init(acn, sk, &id)
defer client.Shutdown()
tokenApplication := new(applications.TokenApplication)
tokenApplication.TokenService = tokenService
powTokenApp := new(applications.ApplicationChain).
ChainApplication(new(applications.ProofOfWorkApplication), applications.SuccessfulProofOfWorkCapability).
ChainApplication(tokenApplication, applications.HasTokensCapability)
log.Debugf("waiting for successful PoW auth...")
tp := utils.TimeoutPolicy(time.Second * 30)
err := tp.ExecuteAction(func() error {
connected, err := client.Connect(tokenServiceOnion, powTokenApp)
if connected && err == nil {
log.Debugf("waiting for successful token acquisition...")
conn, err := client.WaitForCapabilityOrClose(tokenServiceOnion, applications.HasTokensCapability)
if err == nil {
powtapp, ok := conn.App().(*applications.TokenApplication)
if ok {
log.Debugf("updating tokens")
handler.NewTokenHandler(tokenServiceOnion, powtapp.Tokens)
log.Debugf("transcript: %v", powtapp.Transcript().OutputTranscriptToAudit())
conn.Close()
return nil
}
log.Errorf("invalid cast of powapp. this should never happen %v %v", powtapp, reflect.TypeOf(conn.App()))
return nil
}
return nil
}
return err
})
// we timed out
if err != nil {
log.Debugf("make payment timeout...")
return err
}
return err
}

150
tools/cwtch_tools.go Normal file
View File

@ -0,0 +1,150 @@
package main
import (
"crypto/rand"
"cwtch.im/cwtch/model"
"cwtch.im/cwtch/model/constants"
"cwtch.im/cwtch/protocol/connections"
"cwtch.im/cwtch/protocol/groups"
"encoding/base64"
"encoding/json"
"flag"
"fmt"
"git.openprivacy.ca/cwtch.im/tapir/primitives/privacypass"
"git.openprivacy.ca/openprivacy/connectivity/tor"
"git.openprivacy.ca/openprivacy/log"
"github.com/gtank/ristretto255"
mrand "math/rand"
"os"
path "path/filepath"
"strings"
"time"
)
var tool = flag.String("tool", "", "the tool to use")
var bundle = flag.String("bundle", "", "a server bundle to parse")
func main() {
flag.Parse()
if *tool == "" {
fmt.Fprintf(os.Stderr, "usage: cwtch_tools -tool <tool>\n")
flag.PrintDefaults()
}
switch *tool {
case "bundleparse":
bundle, err := bundleParse(*bundle)
if err == nil {
fmt.Printf("bundle: %s\n", bundle.Serialize())
} else {
fmt.Printf("error parsing bundle: %v", err)
}
case "gettokens":
getTokens(*bundle)
default:
fmt.Fprintf(os.Stderr, "unknown tool: %s \n", *tool)
}
}
func bundleParse(bundle string) (*model.KeyBundle, error) {
if strings.HasPrefix(bundle, constants.ServerPrefix) {
bundle, err := base64.StdEncoding.DecodeString(bundle[len(constants.ServerPrefix):])
if err != nil {
fmt.Printf("invalid server bundle: %v\n", err)
}
keyBundle, err := model.DeserializeAndVerify([]byte(bundle))
return keyBundle, err
} else {
return nil, fmt.Errorf("unknown bundle prefix")
}
}
func getTokens(bundle string) {
log.SetLevel(log.LevelDebug)
keyBundle, err := bundleParse(bundle)
if err != nil {
log.Errorf("error parsing keybundle: %v", err)
return
}
privacyPassKey, err := keyBundle.GetKey(model.KeyTypePrivacyPass)
if err != nil {
log.Errorf("error parsing keybundle: %v", err)
return
}
tokenServiceKey, err := keyBundle.GetKey(model.KeyTypeTokenOnion)
if err != nil {
log.Errorf("error parsing keybundle: %v", err)
return
}
os.Mkdir("tordir", 0700)
dataDir := path.Join("tordir", "tor")
os.MkdirAll(dataDir, 0700)
// we don't need real randomness for the port, just to avoid a possible conflict...
mrand.Seed(int64(time.Now().Nanosecond()))
socksPort := mrand.Intn(1000) + 9051
controlPort := mrand.Intn(1000) + 9052
// generate a random password
key := make([]byte, 64)
_, err = rand.Read(key)
if err != nil {
log.Errorf("insufficient randomness: %v", err)
return
}
torDataDir := "./data-dir-cwtchtool"
if err = os.MkdirAll(torDataDir, 0700); err != nil {
log.Errorf("could not create data dir")
return
}
tor.NewTorrc().WithSocksPort(socksPort).WithOnionTrafficOnly().WithHashedPassword(base64.StdEncoding.EncodeToString(key)).WithControlPort(controlPort).Build("tordir/tor/torrc")
acn, err := tor.NewTorACNWithAuth("./tordir", path.Join("..", "tor"), torDataDir, controlPort, tor.HashedPasswordAuthenticator{Password: base64.StdEncoding.EncodeToString(key)})
if err != nil {
log.Errorf("Could not start Tor: %v", err)
return
}
acn.WaitTillBootstrapped()
defer acn.Close()
Y := new(ristretto255.Element)
Y.UnmarshalText([]byte(privacyPassKey))
tokenServer := privacypass.NewTokenServer()
tokenServer.Y = Y
err = connections.MakePayment(string(tokenServiceKey), tokenServer, acn, Handler{})
if err != nil {
log.Errorf("timed out trying to get payments")
}
}
type Handler struct {
}
func (h Handler) GroupMessageHandler(server string, gm *groups.EncryptedGroupMessage) {
}
func (h Handler) ServerAuthedHandler(server string) {
}
func (h Handler) ServerSyncedHandler(server string) {
}
func (h Handler) ServerClosedHandler(server string) {
}
func (h Handler) NewTokenHandler(tokenService string, tokens []*privacypass.Token) {
data, _ := json.Marshal(tokens)
os.WriteFile("tokens", data, 0600)
}
func (h Handler) FetchToken(tokenService string) (*privacypass.Token, int, error) {
return nil, 0, nil
}

View File

@ -12,7 +12,6 @@ type TimeoutPolicy time.Duration
// ExecuteAction runs a function and returns an error if it hasn't returned
// by the time specified by TimeoutPolicy
func (tp *TimeoutPolicy) ExecuteAction(action func() error) error {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(*tp))
defer cancel()