mirror of
https://github.com/arnaucube/tor-eth-online-shop.git
synced 2026-02-06 19:26:39 +01:00
first commit
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
data-dir*
|
||||
config.yaml
|
||||
11
README.md
Normal file
11
README.md
Normal file
@@ -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
config.go
Normal file
23
config.go
Normal file
@@ -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
config.yaml
Normal file
2
config.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
privK: "da7079f082a1ced80c5dee3bf00752fd67f75321a637e5d5073ce1489af062d8"
|
||||
gethurl: "https://ropsten.infura.io/TFnR8BWJlqZOKxHHZNcs"
|
||||
2
configEXAMPLE.yaml
Normal file
2
configEXAMPLE.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
privK: "here the private key"
|
||||
gethurl: "here the Geth URL"
|
||||
32
eth.go
Normal file
32
eth.go
Normal file
@@ -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
main.go
Normal file
51
main.go
Normal file
@@ -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
rest.go
Normal file
19
rest.go
Normal file
@@ -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
utils.go
Normal file
23
utils.go
Normal file
@@ -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
www/index.html
Normal file
71
www/index.html
Normal file
@@ -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
www/index.js
Normal file
77
www/index.js
Normal file
@@ -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);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user