Browse Source

first commit

master
arnaucode 5 years ago
parent
commit
7c773b4c3e
11 changed files with 313 additions and 0 deletions
  1. +2
    -0
      .gitignore
  2. +11
    -0
      README.md
  3. +23
    -0
      config.go
  4. +2
    -0
      config.yaml
  5. +2
    -0
      configEXAMPLE.yaml
  6. +32
    -0
      eth.go
  7. +51
    -0
      main.go
  8. +19
    -0
      rest.go
  9. +23
    -0
      utils.go
  10. +71
    -0
      www/index.html
  11. +77
    -0
      www/index.js

+ 2
- 0
.gitignore

@ -0,0 +1,2 @@
data-dir*
config.yaml

+ 11
- 0
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
```

+ 23
- 0
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)
}
}

+ 2
- 0
config.yaml

@ -0,0 +1,2 @@
privK: "da7079f082a1ced80c5dee3bf00752fd67f75321a637e5d5073ce1489af062d8"
gethurl: "https://ropsten.infura.io/TFnR8BWJlqZOKxHHZNcs"

+ 2
- 0
configEXAMPLE.yaml

@ -0,0 +1,2 @@
privK: "here the private key"
gethurl: "here the Geth URL"

+ 32
- 0
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
}

+ 51
- 0
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)
}

+ 19
- 0
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")
}

+ 23
- 0
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)
}
}
}

+ 71
- 0
www/index.html

@ -0,0 +1,71 @@
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<title>tor-eth-online-shop</title>
</head>
<body>
<div class="container">
<h1>tor-eth-online-shop</h1>
<div class="row" id="mainView">
<div class="col-md-9">
<div class="row">
<div class="col-md-4">
<div class="card">
<img class="card-img-top" src="https://vignette.wikia.nocookie.net/joke-battles/images/f/f7/711MkPTJ4OL._SL1500_.jpg" alt="Card image cap">
<div class="card-body">
<h5 class="card-title">Product 1</h5>
<p class="card-text">Description.</p>
<a onclick="addProduct('id1')" href="#" class="btn btn-outline-success float-right">Add to card</a>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<img class="card-img-top" src="https://5.imimg.com/data5/YX/SD/MY-2492706/slotted-carton-box-500x500.jpg" alt="Card image cap">
<div class="card-body">
<h5 class="card-title">Product 2</h5>
<p class="card-text">Description.</p>
<a onclick="addProduct('id2')" href="#" class="btn btn-outline-success float-right">Add to card</a>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<img class="card-img-top" src="https://image.shutterstock.com/image-photo/closed-cardboard-box-taped-isolated-260nw-168691364.jpg" alt="Card image cap">
<div class="card-body">
<h5 class="card-title">Product 3</h5>
<p class="card-text">Description.</p>
<a onclick="addProduct('id3')" href="#" class="btn btn-outline-success float-right">Add to card</a>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card">
<div class="card-body">
<h3>Selected products</h3>
<p id="list" class="card-text"></p>
<a onclick="purchase()" href="#" class="btn btn-outline-success float-right">Purchase</a>
</div>
</div>
</div>
</div>
</div>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="index.js"></script>
</body>
</html>

+ 77
- 0
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<products.length; i++) {
if(products[i].id == id) {
return(products[i]);
}
}
return("not found");
}
function addProduct(id) {
if (!list[id]) {
list[id] = 1;
} else {
list[id]++;
}
// update html
var total = 0;
var html = "";
html += "<ul class='list-group'>";
for (var property in list) {
if (list.hasOwnProperty(property)) {
html += "<li class='list-group-item'>";
html += property + " x" + list[property];
html += "<div class='float-right'>";
html += (getProduct(property).price * list[property]).toFixed(4) + " eth";
html += "</div>";
html += "</li>";
total = (+(total) + +(getProduct(property).price * list[property])).toFixed(4);
}
}
html += "</ul>";
html += "<br>";
html += "<div class='float-right'>";
html += "<b>Total: " + total + "</b>";
html += "</div>";
html += "<br>";
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);
});
}

Loading…
Cancel
Save