Compare commits

...

5 Commits

Author SHA1 Message Date
bumi 1e40a617f9 Simplify configuration and remove nesting
We do not have that many config options. Nesting is not needed right now
and makes it only more complicated
2020-10-25 22:48:00 +01:00
bumi 77a96bdd83 Sorry go fmt 2020-10-25 22:16:05 +01:00
bumi f81937a7dd Add config.toml to gitignore 2020-10-25 22:16:05 +01:00
bumi 38b60b8383 Add example config file 2020-10-25 22:16:05 +01:00
bumi dcaa4f6cc4 Add Support for macaroon and cert as HEX strings
This also changes the configuration options.
Now multiple config sources are supported:

1. cli flags
2. environment variables
3. config toml file
2020-10-25 22:16:05 +01:00
7 changed files with 165 additions and 39 deletions

3
.gitignore vendored
View File

@ -1 +1,2 @@
vendor
vendor
config.toml

View File

@ -39,24 +39,49 @@ LnMe can easily run next to LND on the same system.
To connect to the lnd node the cert, macaroon and address of the lnd node has to be configured. LnMe uses the LND defaults.
* `address`: Host and port of the lnd gRPC service. default: localhost:10009
* `cert`: Path to the lnd cert file. default: ~/.lnd/tls.cert
* `macaroon`: Path to the macaroon file. default: ~/.lnd/data/chain/bitcoin/mainnet/invoice.macaroon
* `lnd-address`: Host and port of the LND gRPC service. default: localhost:10009
* `lnd-cert-path`: Path to the LND TLS cert file. default: ~/.lnd/tls.cert
* `lnd-macaroon-path`: Path to the LND macaroon file. default: ~/.lnd/data/chain/bitcoin/mainnet/invoice.macaroon (invoice.macaroon is recommended)
Instead of the path to the macaroon and cert files you can also provide the hex strings:
* `lnd-cert`: LND TLS cert as HEX string.
* `lnd-macaroon`: LND macaroon file. (invoice.macaroon is recommended)
#### Other configuration
* `static-path`: Path to a folder that you want to serve with LnMe (e.g. /home/bitcoin/lnme/website). Use this if you want to customize your ⚡website. default: disabled
* `disable-website`: Disable the default LnMe website. Disable the website if you only want to embed the LnMe widget on your existing website.
* `disable-cors`: Disable CORS headers. (default: false)
* `bind`: Host and port to listen on. (default: :1323)
* `port`: Port to listen on. (default: 1323)
* `request-limit`: Limit the allowed requests per second. (default: 5)
Depending on your deployment needs LnMe can be configured using the following options:
1. Command line flags
2. Environment variables
3. Config TOML file
#### Examples:
##### Command line flags:
$ lnme --help
$ lnme --address=lndhost.com:10009 --bind=localhost:4711
$ lnme --lnd-address=lndhost.com:10009 --port=4711
$ lnme --disable-website
##### TOML config file
See [config.toml.example](./toml.config.example) for an example file.
$ lnme --config=/path/to/config.toml
##### Environment variables
All environment variables must be prefixed by `LNME_` use `_` instead of `-`
$ LNME_LND_ADDRESS=127.0.0.1:10005 lnme
### Deployment

11
config.toml.example Normal file
View File

@ -0,0 +1,11 @@
disable-website = false
disable-cors = false
request-limit = 5
port = "1323"
static-path = "" # Blank means disabled
lnd-address = "127.0.0.1:10009"
lnd-cert = "TLS cert as hex"
lnd-cert-path = "Alternative to cert. Path to TLS cert file"
lnd-macaroon = "Macaroon as hex"
lnd-macaroon-path = "Alternative to macaroon. Path to macaroon file"

2
go.mod
View File

@ -5,8 +5,10 @@ go 1.15
require (
github.com/GeertJohan/go.rice v1.0.0
github.com/didip/tollbooth/v6 v6.0.2
github.com/knadh/koanf v0.14.0
github.com/labstack/echo/v4 v4.1.17
github.com/lightningnetwork/lnd v0.11.1-beta
github.com/paked/configure v0.0.0-20190218140148-28f9c3f21a44
google.golang.org/grpc v1.33.0
gopkg.in/macaroon.v2 v2.1.0
)

17
go.sum
View File

@ -84,9 +84,12 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/frankban/quicktest v1.0.0/go.mod h1:R98jIehRai+d1/3Hv2//jOVCTJhW1VBavT6B6CuGq2k=
github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
@ -123,12 +126,14 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmg
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.14.3 h1:OCJlWkOUoTnl0neNGlf4fUm3TmbEtguw7vR+nGtnDjY=
github.com/grpc-ecosystem/grpc-gateway v1.14.3/go.mod h1:6CwZWGDSPRJidgKAtJVvND6soZe6fT7iteq8wDPdhb0=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
github.com/jackpal/go-nat-pmp v0.0.0-20170405195558-28a68d0c24ad/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
@ -146,6 +151,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec h1:n1NeQ3SgUHyISrjFFoO5dR748Is8dBL9qpaTNfphQrs=
github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
github.com/knadh/koanf v0.14.0 h1:h9XeG4wEiEuxdxqv/SbY7TEK+7vzrg/dOaGB+S6+mPo=
github.com/knadh/koanf v0.14.0/go.mod h1:H5mEFsTeWizwFXHKtsITL5ipsLTuAMQoGuQpp+1JL9U=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@ -188,6 +195,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
github.com/miekg/dns v0.0.0-20171125082028-79bfde677fa8 h1:PRMAcldsl4mXKJeRNB/KVNz6TlbS6hk2Rs42PqgU3Ws=
github.com/miekg/dns v0.0.0-20171125082028-79bfde677fa8/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4=
github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
@ -198,6 +207,9 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/paked/configure v0.0.0-20190218140148-28f9c3f21a44/go.mod h1:y9MA8YrqgIDBMhU+Dgzu5okImVGccMdjHnWv6md5rfs=
github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI=
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@ -213,12 +225,14 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rhnvrm/simples3 v0.5.0/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA=
github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
@ -294,10 +308,12 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h
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/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6 h1:DvY3Zkh7KabQE/kfzMvYvKirSiguP9Q/veMtkYyf0o8=
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -350,6 +366,7 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -1,11 +1,13 @@
package ln
import (
"fmt"
"context"
"encoding/hex"
"io/ioutil"
"log"
"os"
"crypto/x509"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/macaroons"
@ -29,7 +31,9 @@ type Invoice struct {
type LNDoptions struct {
Address string
CertFile string
CertHex string
MacaroonFile string
MacaroonHex string
}
type LNDclient struct {
@ -103,23 +107,52 @@ func (c LNDclient) GetInvoice(paymentHashStr string) (Invoice, error) {
func NewLNDclient(lndOptions LNDoptions) (LNDclient, error) {
result := LNDclient{}
creds, err := credentials.NewClientTLSFromFile(lndOptions.CertFile, "")
if err != nil {
return result, err
}
// Get credentials either from a hex string or a file
var creds credentials.TransportCredentials
// if a hex string is provided
if lndOptions.CertHex != "" {
cp := x509.NewCertPool()
cert, err := hex.DecodeString(lndOptions.CertHex)
if err != nil {
return result, err
}
cp.AppendCertsFromPEM(cert)
creds = credentials.NewClientTLSFromCert(cp, "")
// if a path to a cert file is provided
} else if lndOptions.CertFile != "" {
credsFromFile, err := credentials.NewClientTLSFromFile(lndOptions.CertFile, "")
if err != nil {
return result, err
}
creds = credsFromFile // make it available outside of the else if block
} else {
return result, fmt.Errorf("LND credential is missing")
}
opts := []grpc.DialOption{
grpc.WithTransportCredentials(creds),
}
macaroonData, err := ioutil.ReadFile(lndOptions.MacaroonFile)
if err != nil {
return result, err
}
mac := &macaroon.Macaroon{}
if err = mac.UnmarshalBinary(macaroonData); err != nil {
return result, err
}
var macaroonData []byte
if lndOptions.MacaroonHex != "" {
macBytes, err := hex.DecodeString(lndOptions.MacaroonHex)
if err != nil {
return result, err
}
macaroonData = macBytes
} else if lndOptions.MacaroonFile != "" {
macBytes, err := ioutil.ReadFile(lndOptions.MacaroonFile)
if err != nil {
return result, err
}
macaroonData = macBytes // make it available outside of the else if block
} else {
return result, fmt.Errorf("LND macaroon is missing")
}
mac := &macaroon.Macaroon{}
if err := mac.UnmarshalBinary(macaroonData); err != nil {
return result, err
}
macCred := macaroons.NewMacaroonCredential(mac)
opts = append(opts, grpc.WithPerRPCCredentials(macCred))

79
lnme.go
View File

@ -6,11 +6,17 @@ import (
"github.com/bumi/lnme/ln"
"github.com/didip/tollbooth/v6"
"github.com/didip/tollbooth/v6/limiter"
"github.com/knadh/koanf"
"github.com/knadh/koanf/parsers/toml"
"github.com/knadh/koanf/providers/basicflag"
"github.com/knadh/koanf/providers/env"
"github.com/knadh/koanf/providers/file"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"log"
"net/http"
"os"
"strings"
)
// Middleware for request limited to prevent too many requests
@ -35,24 +41,15 @@ type Invoice struct {
}
func main() {
address := flag.String("address", "localhost:10009", "The host and port of the lnd gRPC server.")
certFile := flag.String("cert", "~/.lnd/tls.cert", "Path to the lnd tls.cert file.")
macaroonFile := flag.String("macaroon", "~/.lnd/data/chain/bitcoin/mainnet/invoice.macaroon", "Path to the lnd macaroon file.")
bind := flag.String("bind", ":1323", "Host and port to bind on.")
staticPath := flag.String("static-path", "", "Path to a static assets directory. Leave blank to not serve any static files.")
disableWebsite := flag.Bool("disable-website", false, "Disable default embedded website.")
disableCors := flag.Bool("disable-cors", false, "Disable CORS headers.")
requestLimit := flag.Float64("request-limit", 5, "Request limit per second.")
flag.Parse()
cfg := LoadConfig()
e := echo.New()
// Serve static files if configured
if *staticPath != "" {
e.Static("/", *staticPath)
if cfg.String("static-path") != "" {
e.Static("/", cfg.String("static-path"))
// Serve default page
} else if !*disableWebsite {
} else if !cfg.Bool("disable-website") {
rootBox := rice.MustFindBox("files/root")
indexPage, err := rootBox.String("index.html")
if err == nil {
@ -69,7 +66,7 @@ func main() {
e.GET("/lnme/*", echo.WrapHandler(http.StripPrefix("/lnme/", assetHandler)))
// CORS settings
if !*disableCors {
if !cfg.Bool("disable-cors") {
e.Use(middleware.CORS())
}
@ -77,17 +74,19 @@ func main() {
e.Use(middleware.Recover())
// Request limit per second. DoS protection
if *requestLimit > 0 {
limiter := tollbooth.NewLimiter(*requestLimit, nil)
if cfg.Int("request-limit") > 0 {
limiter := tollbooth.NewLimiter(cfg.Float64("request-limit"), nil)
e.Use(LimitMiddleware(limiter))
}
// Setup lightning client
stdOutLogger.Printf("Connection to %s using macaroon %s and cert %s", *address, *macaroonFile, *certFile)
stdOutLogger.Printf("Connecting to %s", cfg.String("lnd-address"))
lndOptions := ln.LNDoptions{
Address: *address,
CertFile: *certFile,
MacaroonFile: *macaroonFile,
Address: cfg.String("lnd-address"),
CertFile: cfg.String("lnd-cert-path"),
CertHex: cfg.String("lnd-cert"),
MacaroonFile: cfg.String("lnd-macaroon-path"),
MacaroonHex: cfg.String("lnd-macaroon"),
}
lnClient, err := ln.NewLNDclient(lndOptions)
if err != nil {
@ -142,5 +141,43 @@ func main() {
return c.JSON(http.StatusOK, "pong")
})
e.Logger.Fatal(e.Start(*bind))
e.Logger.Fatal(e.Start(":" + cfg.String("port")))
}
func LoadConfig() *koanf.Koanf {
k := koanf.New(".")
f := flag.NewFlagSet("LnMe", flag.ExitOnError)
f.String("lnd-address", "localhost:10009", "The host and port of the LND gRPC server.")
f.String("lnd-macaroon-path", "~/.lnd/data/chain/bitcoin/mainnet/invoice.macaroon", "Path to the LND macaroon file.")
f.String("lnd-cert-path", "~/.lnd/tls.cert", "Path to the LND tls.cert file.")
f.Bool("disable-website", false, "Disable default embedded website.")
f.Bool("disable-cors", false, "Disable CORS headers.")
f.Float64("request-limit", 5, "Request limit per second.")
f.String("static-path", "", "Path to a static assets directory.")
f.String("port", "1323", "Port to bind on.")
var configPath string
f.StringVar(&configPath, "config", "config.toml", "Path to a .toml config file.")
f.Parse(os.Args[1:])
// Load config from flags, including defaults
if err := k.Load(basicflag.Provider(f, "."), nil); err != nil {
log.Fatalf("Error loading config: %v", err)
}
// Load config from environment variables
k.Load(env.Provider("LNME_", ".", func(s string) string {
return strings.Replace(strings.ToLower(strings.TrimPrefix(s, "LNME_")), "_", "-", -1)
}), nil)
// Load config from file if available
if configPath != "" {
if _, err := os.Stat(configPath); err == nil {
if err := k.Load(file.Provider(configPath), toml.Parser()); err != nil {
log.Fatalf("Error loading config file: %v", err)
}
}
}
return k
}