Initial Commit

This commit is contained in:
Sarah Jamie Lewis 2019-08-23 13:51:21 -07:00
parent 8086f20729
commit 5cf3152dd6
8 changed files with 316 additions and 1 deletions

5
.gitignore vendored
View File

@ -1,3 +1,4 @@
# ---> Go
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
@ -24,3 +25,7 @@ _testmain.go
*.test
*.prof
config.json
.idea/
tor/
vendor/

View File

@ -1,5 +1,5 @@
MIT License
Copyright (c) <year> <copyright holders>
Copyright (c) Open Privacy Research Society 2019
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

51
client/client.go Normal file
View File

@ -0,0 +1,51 @@
package main
import (
"cwtch.im/tapir"
"cwtch.im/tapir/applications"
"cwtch.im/tapir/networks/tor"
"cwtch.im/tapir/primitives"
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
"git.openprivacy.ca/openprivacy/libricochet-go/log"
"strings"
"time"
)
type PublicMemoClient struct {
applications.AuthApp
}
func (ma PublicMemoClient) NewInstance() tapir.Application {
return new(PublicMemoClient)
}
// 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 (ma *PublicMemoClient) Init(connection tapir.Connection) {
ma.AuthApp.Init(connection)
if connection.HasCapability(applications.AuthCapability) {
memo := connection.Expect()
for string(memo) != "{}" {
log.Infof("Received Public Memo: %s", strings.ReplaceAll(string(memo), "\n", "\\n"))
memo = connection.Expect()
}
}
}
func main() {
log.SetLevel(log.LevelDebug)
var acn connectivity.ACN
acn, _ = connectivity.StartTor("./", "")
acn.WaitTillBootstrapped()
id, sk := primitives.InitializeEphemeralIdentity()
var client tapir.Service
client = new(tor.BaseOnionService)
client.Init(acn, sk, &id)
client.Connect("a6lh4dju3jqmh6tghnfjdqqohnp3lvww3wgbtvkez4weswartvv75qqd", &PublicMemoClient{})
// Once connected, it shouldn't take long to authenticate and run the application. So for the purposes of this demo
// we will wait a little while then exit.
time.Sleep(time.Second * 10)
}

118
cmd/main.go Normal file
View File

@ -0,0 +1,118 @@
package main
import (
"cwtch.im/tapir"
"cwtch.im/tapir/applications"
"cwtch.im/tapir/networks/tor"
"cwtch.im/tapir/primitives"
"cwtch.im/zcash2cwtch"
"encoding/base64"
"encoding/hex"
"encoding/json"
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
"git.openprivacy.ca/openprivacy/libricochet-go/log"
"golang.org/x/crypto/ed25519"
"io/ioutil"
"sync"
"time"
)
type ZcashConfig struct {
Username string `json: "username"`
Password string `json: "password"`
Onion string `json: "onion"`
ZAddress string `json: "zaddress"`
PublicKey string `json: "publickey"`
PrivateKey string `json: "privatekey"`
}
type TapirServer struct {
acn connectivity.ACN
seenMap sync.Map
transactions []zcash2cwtch.ZcashTransaction
service tapir.Service
}
type MemoApp struct {
applications.AuthApp
service *TapirServer
}
func (ma MemoApp) NewInstance() tapir.Application {
memoApp := new(MemoApp)
memoApp.service = ma.service
return memoApp
}
// 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 (ma MemoApp) Init(connection tapir.Connection) {
ma.AuthApp.Init(connection)
if connection.HasCapability(applications.AuthCapability) {
for _, transaction := range ma.service.transactions {
memo, _ := hex.DecodeString(transaction.Memo)
connection.Send([]byte("{\"public\": \"" + string(memo) + "\"}"))
}
connection.Send([]byte("{}"))
}
}
func StartTapirServer() *TapirServer {
ts := new(TapirServer)
acn, _ := connectivity.StartTor("", "")
acn.WaitTillBootstrapped()
ts.acn = acn
configFile, _ := ioutil.ReadFile("config.json")
config := ZcashConfig{}
_ = json.Unmarshal([]byte(configFile), &config)
var service tapir.Service
service = new(tor.BaseOnionService)
// Initialize an onion service with one identity, but the auth app with another, this should
// trigger a failure in authentication protocol
sk, _ := base64.StdEncoding.DecodeString(config.PrivateKey)
pk, _ := base64.StdEncoding.DecodeString(config.PublicKey)
publicKey := ed25519.PublicKey(pk)
privateKey := ed25519.PrivateKey(sk)
id := primitives.InitializeIdentity("", &privateKey, &publicKey)
service.Init(acn, ed25519.PrivateKey(sk), &id)
ts.service = service
return ts
}
func (ts *TapirServer) Listen() {
ts.service.Listen(MemoApp{service: ts})
}
func (ts *TapirServer) Refresh() {
for {
configFile, _ := ioutil.ReadFile("config.json")
config := ZcashConfig{}
_ = json.Unmarshal([]byte(configFile), &config)
zc := zcash2cwtch.NewClient(config.Onion, config.Username, config.Password, ts.acn)
transactions, err := zc.ListReceivedTransactionsByAddress(config.ZAddress)
if err != nil {
log.Errorf("Error fetching zcash transactions: %v", err)
}
for _, transaction := range transactions {
_, exists := ts.seenMap.Load(transaction.TransactionID)
if !exists {
log.Infof("Got a new transaction txid:%s, amount %f", transaction.TransactionID, transaction.Amount)
ts.transactions = append(ts.transactions, transaction)
ts.seenMap.Store(transaction.TransactionID, true)
}
}
time.Sleep(time.Minute)
}
}
func main() {
log.SetLevel(log.LevelDebug)
ts := StartTapirServer()
go ts.Refresh()
ts.Listen()
}

17
go.mod Normal file
View File

@ -0,0 +1,17 @@
module cwtch.im/zcash2cwtch
go 1.12
require (
cwtch.im/tapir v0.1.10
git.openprivacy.ca/openprivacy/libricochet-go v1.0.6
github.com/golang/protobuf v1.3.2 // indirect
github.com/stretchr/objx v0.2.0 // indirect
github.com/stretchr/testify v1.4.0 // indirect
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 // indirect
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a // indirect
golang.org/x/text v0.3.2 // indirect
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
)

49
go.sum Normal file
View File

@ -0,0 +1,49 @@
cwtch.im/tapir v0.1.10 h1:V+TkmwXNd6gySZqlVw468wMYEkmDwMSyvhkkpOfUw7w=
cwtch.im/tapir v0.1.10/go.mod h1:EuRYdVrwijeaGBQ4OijDDRHf7R2MDSypqHkSl5DxI34=
git.openprivacy.ca/openprivacy/libricochet-go v1.0.4/go.mod h1:yMSG1gBaP4f1U+RMZXN85d29D39OK5s8aTpyVRoH5FY=
git.openprivacy.ca/openprivacy/libricochet-go v1.0.6 h1:5o4K2qn3otEE1InC5v5CzU0yL7Wl7DhVp4s8H3K6mXY=
git.openprivacy.ca/openprivacy/libricochet-go v1.0.6/go.mod h1:yMSG1gBaP4f1U+RMZXN85d29D39OK5s8aTpyVRoH5FY=
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7ISrnJIXKzwaspym5BTKGx93EI=
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0=
github.com/cretz/bine v0.1.0 h1:1/fvhLE+fk0bPzjdO5Ci+0ComYxEMuB1JhM4X5skT3g=
github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
golang.org/x/crypto v0.0.0-20190128193316-c7b33c32a30b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 h1:7KByu05hhLed2MO29w7p1XfZvZ13m8mub3shuVftRs0=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

9
transaction.go Normal file
View File

@ -0,0 +1,9 @@
package zcash2cwtch
type ZcashTransaction struct {
TransactionID string `json:"txid"`
Amount float64 `json:"amount"`
Memo string `json:"memo"`
Change bool `json:"change"`
OutIndex int `json:"outindex"`
}

66
zcash_client.go Normal file
View File

@ -0,0 +1,66 @@
package zcash2cwtch
import (
"bytes"
"encoding/base64"
"encoding/json"
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
"git.openprivacy.ca/openprivacy/libricochet-go/log"
"io/ioutil"
"net"
"net/http"
)
type ZcashResult struct {
Result interface{} `json:"result"`
}
type ZcashClient interface {
ListReceivedTransactionsByAddress(string) ([]ZcashTransaction, error)
}
type zcashOnionClient struct {
client http.Client
onion string
auth string
}
// NewClient creates a new Zcash rpc client over an onion address
func NewClient(onion string, username, password string, acn connectivity.ACN) ZcashClient {
zc := new(zcashOnionClient)
zc.onion = onion
zc.client = http.Client{
Transport: &http.Transport{
Dial: func(network, addr string) (net.Conn, error) {
conn, _, err := acn.Open(onion)
return conn, err
},
},
}
zc.auth = base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
return zc
}
func (zc *zcashOnionClient) ListReceivedTransactionsByAddress(address string) ([]ZcashTransaction, error) {
var jsonStr = []byte(`{"jsonrpc": "1.0", "id":"zcash2cwtch", "method": "z_listreceivedbyaddress", "params": ["` + address + `"]}`)
req, err := http.NewRequest("POST", "http://"+zc.onion+".onion:9878", bytes.NewBuffer(jsonStr))
if err != nil {
return nil, err
}
req.Header.Add("Authorization", "Basic "+zc.auth)
log.Debugf("Sending request to zcash server %v", req)
resp, err := zc.client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
log.Debugf("Got response from zcash server %s", body)
transactions := []ZcashTransaction{}
result := &ZcashResult{Result: &transactions}
err = json.Unmarshal(body, &result)
return transactions, err
}