166 lines
4.6 KiB
Go
166 lines
4.6 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/tls"
|
|
"encoding/base64"
|
|
"encoding/gob"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
|
|
"github.com/gobuffalo/packr"
|
|
"github.com/kelseyhightower/envconfig"
|
|
"github.com/muesli/cache2go"
|
|
"github.com/ybbus/jsonrpc"
|
|
"github.com/zcash-hackworks/eccfaucet/pkg/eccfaucet"
|
|
"github.com/zcash-hackworks/eccfaucet/pkg/rpc"
|
|
)
|
|
|
|
type ECCfaucetConfig struct {
|
|
ListenPort string
|
|
ListenAddress string
|
|
RPCUser string
|
|
RPCPassword string
|
|
RPCHost string
|
|
RPCPort string
|
|
FundingAddress string
|
|
TLSCertFile string
|
|
TLSKeyFile string
|
|
TapAmount float64
|
|
TapWaitMinutes float64
|
|
OpStatusWaitSeconds int
|
|
}
|
|
|
|
func (c *ECCfaucetConfig) checkConfig() error {
|
|
if c.ListenPort == "" {
|
|
c.ListenPort = "3000"
|
|
}
|
|
if c.ListenAddress == "" {
|
|
c.ListenPort = "127.0.0.1"
|
|
}
|
|
if c.RPCHost == "" {
|
|
c.ListenPort = "localhost"
|
|
}
|
|
if c.ListenPort == "" {
|
|
c.ListenPort = "3000"
|
|
}
|
|
if c.FundingAddress == "" {
|
|
return fmt.Errorf("ECCFAUCET_FUNDINGADDRESS is required")
|
|
}
|
|
if (c.TLSCertFile == "" && c.TLSKeyFile != "") ||
|
|
(c.TLSCertFile != "" && c.TLSKeyFile == "") {
|
|
return fmt.Errorf("ECCFAUCET_TLSCERTFILE and ECCFAUCET_TLSKEYFILE are both required")
|
|
}
|
|
c.TapAmount = 1.0
|
|
c.TapWaitMinutes = 2
|
|
c.OpStatusWaitSeconds = 120
|
|
return nil
|
|
}
|
|
|
|
func getBlockchainInfo(rpcClient jsonrpc.RPCClient) (blockChainInfo *rpc.GetBlockchainInfo, err error) {
|
|
if err := rpcClient.CallFor(&blockChainInfo, "getblockchaininfo"); err != nil {
|
|
return nil, err
|
|
}
|
|
return
|
|
}
|
|
|
|
func getInfo(rpcClient jsonrpc.RPCClient) (info *rpc.GetBlockInfo, err error) {
|
|
if err := rpcClient.CallFor(&info, "getinfo"); err != nil {
|
|
return nil, err
|
|
}
|
|
return info, nil
|
|
}
|
|
|
|
func main() {
|
|
versionFlag := flag.Bool("version", false, "print version information")
|
|
flag.Parse()
|
|
if *versionFlag {
|
|
fmt.Printf("(version=%s, branch=%s, gitcommit=%s)\n", Version, Branch, GitCommit)
|
|
fmt.Printf("(go=%s, user=%s, date=%s)\n", GoVersion, BuildUser, BuildDate)
|
|
os.Exit(0)
|
|
}
|
|
|
|
var zConfig ECCfaucetConfig
|
|
err := envconfig.Process("eccfaucet", &zConfig)
|
|
if err != nil {
|
|
log.Fatal(err.Error())
|
|
}
|
|
if err = zConfig.checkConfig(); err != nil {
|
|
log.Fatalf("Config error: %s", err)
|
|
}
|
|
fmt.Printf("zfaucet: %#v\n", zConfig)
|
|
|
|
basicAuth := base64.StdEncoding.EncodeToString([]byte(zConfig.RPCUser + ":" + zConfig.RPCPassword))
|
|
var z eccfaucet.ECCFaucet
|
|
z.TapCache = cache2go.Cache("tapRequests")
|
|
z.FundingAddress = zConfig.FundingAddress
|
|
z.TapAmount = zConfig.TapAmount
|
|
z.TapWaitMinutes = zConfig.TapWaitMinutes
|
|
z.OpStatusWaitSeconds = zConfig.OpStatusWaitSeconds
|
|
z.Operations = make(map[string]eccfaucet.OperationStatus)
|
|
z.RPCConnetion = jsonrpc.NewClientWithOpts("http://"+zConfig.RPCHost+":"+zConfig.RPCPort,
|
|
&jsonrpc.RPCClientOpts{
|
|
CustomHeaders: map[string]string{
|
|
"Authorization": "Basic " + basicAuth,
|
|
}})
|
|
|
|
go z.ClearCache()
|
|
go z.UpdateZcashInfo()
|
|
|
|
box := packr.NewBox("./templates")
|
|
z.HomeHTML, err = box.FindString("eccfaucet.html")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
homeHandler := http.HandlerFunc(z.Home)
|
|
balanceHandler := http.HandlerFunc(z.Balance)
|
|
opsStatusHandler := http.HandlerFunc(z.OpsStatus)
|
|
addressHandler := http.HandlerFunc(z.Addresses)
|
|
mux := http.NewServeMux()
|
|
mux.Handle("/", homeHandler)
|
|
mux.Handle("/balance", z.OKMiddleware(balanceHandler))
|
|
mux.Handle("/addresses", z.OKMiddleware(addressHandler))
|
|
mux.Handle("/ops/status", z.OKMiddleware(opsStatusHandler))
|
|
log.Printf("Listening on :%s...\n", zConfig.ListenPort)
|
|
if zConfig.TLSCertFile != "" && zConfig.TLSKeyFile != "" {
|
|
// https://gist.github.com/denji/12b3a568f092ab951456
|
|
cfg := &tls.Config{
|
|
MinVersion: tls.VersionTLS12,
|
|
CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
|
|
PreferServerCipherSuites: true,
|
|
CipherSuites: []uint16{
|
|
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
|
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
|
tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
|
|
tls.TLS_RSA_WITH_AES_256_CBC_SHA,
|
|
},
|
|
}
|
|
srv := &http.Server{
|
|
Addr: zConfig.ListenAddress + ":" + zConfig.ListenPort,
|
|
Handler: mux,
|
|
TLSConfig: cfg,
|
|
TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler), 0),
|
|
}
|
|
err = srv.ListenAndServeTLS(zConfig.TLSCertFile, zConfig.TLSKeyFile)
|
|
|
|
} else {
|
|
err = http.ListenAndServe(zConfig.ListenAddress+":"+zConfig.ListenPort, mux)
|
|
}
|
|
log.Fatal(err)
|
|
}
|
|
|
|
// GetBytes returns a byte slice from an interface
|
|
func GetBytes(key interface{}) ([]byte, error) {
|
|
var buf bytes.Buffer
|
|
enc := gob.NewEncoder(&buf)
|
|
err := enc.Encode(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return buf.Bytes(), nil
|
|
|
|
}
|