diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f00cf94 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +data-dir* +config.yaml diff --git a/README.md b/README.md new file mode 100644 index 0000000..17ff3f7 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# tor-eth-online-shop + +Online shop through Tor hidden service, that allows payments in Ethereum. + + +## Run +First edit configEXAMPLE.yaml to config.yaml, and edit the content. +Then, run: +``` +go run *.go +``` diff --git a/config.go b/config.go new file mode 100644 index 0000000..078fdbb --- /dev/null +++ b/config.go @@ -0,0 +1,23 @@ +package main + +import "github.com/spf13/viper" + +type Config struct { + GethURL string + PrivK string +} + +var config Config + +func ReadConfig(path, filename string) { + viper.SetConfigName(filename) + viper.AddConfigPath(path) + viper.SetConfigType("yaml") + if err := viper.ReadInConfig(); err != nil { + panic(err) + } + err := viper.Unmarshal(&config) + if err != nil { + panic(err) + } +} diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..8cb49b4 --- /dev/null +++ b/config.yaml @@ -0,0 +1,2 @@ +privK: "da7079f082a1ced80c5dee3bf00752fd67f75321a637e5d5073ce1489af062d8" +gethurl: "https://ropsten.infura.io/TFnR8BWJlqZOKxHHZNcs" diff --git a/configEXAMPLE.yaml b/configEXAMPLE.yaml new file mode 100644 index 0000000..528206d --- /dev/null +++ b/configEXAMPLE.yaml @@ -0,0 +1,2 @@ +privK: "here the private key" +gethurl: "here the Geth URL" diff --git a/eth.go b/eth.go new file mode 100644 index 0000000..e89ad20 --- /dev/null +++ b/eth.go @@ -0,0 +1,32 @@ +package main + +import ( + "crypto/ecdsa" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" +) + +var ( + client *ethclient.Client + key *ecdsa.PrivateKey + address common.Address +) + +func Web3Open() error { + // geth set up + var err error + + client, err = ethclient.Dial(config.GethURL) + if err != nil { + return err + } + key, err = crypto.HexToECDSA(config.PrivK) + if err != nil { + return err + } + address = crypto.PubkeyToAddress(key.PublicKey) + + return nil +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..744fba7 --- /dev/null +++ b/main.go @@ -0,0 +1,51 @@ +package main + +import ( + "context" + "fmt" + "log" + "net/http" + "os" + "time" + + "github.com/cretz/bine/tor" + "github.com/ipsn/go-libtor" +) + +func main() { + ReadConfig(".", "config") + + // Start tor with some defaults + elevated verbosity + fmt.Println("Starting and registering onion service, please wait a bit...") + t, err := tor.Start(nil, &tor.StartConf{ProcessCreator: libtor.Creator, DebugWriter: os.Stderr}) + if err != nil { + log.Panicf("Failed to start tor: %v", err) + } + defer t.Close() + + // Wait at most a few minutes to publish the service + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) + defer cancel() + + // Create an onion service to listen on any port but show as 80 + onion, err := t.Listen(ctx, &tor.ListenConf{RemotePorts: []int{80}}) + if err != nil { + log.Panicf("Failed to create onion service: %v", err) + } + defer onion.Close() + + fmt.Printf("Please open a Tor capable browser and navigate to http://%v.onion\n", onion.ID) + + // connect to eth + // Ethereum + err = Web3Open() + if err != nil { + log.Fatal(err) + } + + // Run a Hello-World HTTP service until terminated + http.Handle("/", http.FileServer(http.Dir("./www"))) + http.HandleFunc("/api/purchase", handlePurchase) + http.HandleFunc("/api/txid", handleTxId) + http.Serve(onion, nil) +} diff --git a/rest.go b/rest.go new file mode 100644 index 0000000..a2eb9df --- /dev/null +++ b/rest.go @@ -0,0 +1,19 @@ +package main + +import ( + "fmt" + "net/http" +) + +func handlePurchase(w http.ResponseWriter, r *http.Request) { + challenge, err := generateChallenge(20) + if err != nil { + panic(err) + return + } + fmt.Fprintf(w, challenge) +} +func handleTxId(w http.ResponseWriter, r *http.Request) { + + fmt.Fprintf(w, "ack") +} diff --git a/utils.go b/utils.go new file mode 100644 index 0000000..afa2914 --- /dev/null +++ b/utils.go @@ -0,0 +1,23 @@ +package main + +import ( + "crypto/rand" + "math/big" +) + +func generateChallenge(length int) (string, error) { + result := "" + for { + if len(result) >= length { + return result, nil + } + num, err := rand.Int(rand.Reader, big.NewInt(int64(127))) + if err != nil { + return "", err + } + n := num.Int64() + if n > 32 && n < 127 { + result += string(n) + } + } +} diff --git a/www/index.html b/www/index.html new file mode 100644 index 0000000..dff3812 --- /dev/null +++ b/www/index.html @@ -0,0 +1,71 @@ + + + + + + + + + tor-eth-online-shop + + +
+

tor-eth-online-shop

+
+
+
+
+
+ Card image cap +
+
Product 1
+

Description.

+ Add to card +
+
+
+
+
+ Card image cap +
+
Product 2
+

Description.

+ Add to card +
+
+
+
+
+ Card image cap +
+
Product 3
+

Description.

+ Add to card +
+
+
+
+
+
+
+
+

Selected products

+

+ Purchase +
+
+
+
+
+ + + + + + + + + + + + diff --git a/www/index.js b/www/index.js new file mode 100644 index 0000000..aa9700e --- /dev/null +++ b/www/index.js @@ -0,0 +1,77 @@ +var products = [ + { + id: 'id1', + title: 'beer1', + price: '0.1' + }, + { + id: 'id2', + title: 'beer2', + price: '0.1' + }, + { + id: 'id3', + title: 'beer3', + price: '0.1' + } +]; +var list = {}; +function getProduct(id) { + for(var i=0; i"; + html += ""; + html += "
"; + document.getElementById("list").innerHTML = html; +} + +function purchase() { + var total = 0; + for (var property in list) { + if (list.hasOwnProperty(property)) { + total = (+(total) + +(getProduct(property).price * list[property])).toFixed(4); + } + } + var answ = confirm("total to pay: " + total + " eth"); + if (!answ) { + return; + } + axios.post('/api/purchase', { + list: list + }) + .then(function (response) { + console.log(response); + }) + .catch(function (error) { + console.log(error); + }); +}