From f2207f797d0c682db38eb877736a43995d9c3d57 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Wed, 24 Aug 2022 20:38:41 +0200 Subject: [PATCH 1/6] amboss --- channelAcceptor.go | 13 +++++++++++-- go.mod | 4 ++++ go.sum | 16 +++++++++++++--- main_test.go | 30 +++++++++++++++++++++--------- rules/ChannelAccept.js | 14 ++++++++++++-- rules/HtlcForward.js | 4 +++- rules/rules.go | 4 ++-- 7 files changed, 66 insertions(+), 19 deletions(-) diff --git a/channelAcceptor.go b/channelAcceptor.go index ff07d2d..02ed9ed 100644 --- a/channelAcceptor.go +++ b/channelAcceptor.go @@ -6,6 +6,7 @@ import ( "fmt" "sync" + "github.com/callebtc/electronwall/api" "github.com/callebtc/electronwall/rules" "github.com/callebtc/electronwall/types" "github.com/lightningnetwork/lnd/lnrpc" @@ -23,11 +24,19 @@ func (app *App) getChannelAcceptEvent(ctx context.Context, req lnrpc.ChannelAcce if err != nil { log.Errorf(err.Error()) } + + noeInfo, err := api.GetApiNodeinfo(string(req.NodePubkey)) + if err != nil { + log.Errorf(err.Error()) + } + return types.ChannelAcceptEvent{ PubkeyFrom: hex.EncodeToString(req.NodePubkey), AliasFrom: alias, NodeInfo: info, Event: &req, + OneMl: noeInfo.OneMl, + Amboss: noeInfo.Amboss, }, nil } @@ -172,9 +181,9 @@ func (app *App) channelAcceptDecision(req lnrpc.ChannelAcceptRequest) (bool, err } // parse and make decision - log.Infof(hex.EncodeToString(req.NodePubkey)) + log.Infof("TRYING %s", string(req.NodePubkey)) for _, pubkey := range listToParse { - if hex.EncodeToString(req.NodePubkey) == pubkey || pubkey == "*" { + if string(req.NodePubkey) == pubkey || pubkey == "*" { accept = !accept break } diff --git a/go.mod b/go.mod index 86bdda1..c7852c4 100644 --- a/go.mod +++ b/go.mod @@ -6,8 +6,12 @@ require ( github.com/dop251/goja v0.0.0-20220815083517-0c74f9139fd6 github.com/jinzhu/configor v1.2.1 github.com/lightningnetwork/lnd v0.14.3-beta + github.com/machinebox/graphql v0.2.2 + github.com/matryer/is v1.4.0 // indirect github.com/sirupsen/logrus v1.8.1 github.com/stretchr/testify v1.7.0 + golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect + golang.org/x/tools v0.1.10 // indirect google.golang.org/grpc v1.46.2 gopkg.in/macaroon.v2 v2.1.0 ) diff --git a/go.sum b/go.sum index f656cf0..2ed80fc 100644 --- a/go.sum +++ b/go.sum @@ -527,9 +527,13 @@ github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQ github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 h1:sjOGyegMIhvgfq5oaue6Td+hxZuf3tDC8lAPrFldqFw= github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796/go.mod h1:3p7ZTf9V1sNPI5H8P3NkTFF4LuwMdPl2DodF60qAKqY= github.com/ltcsuite/ltcutil v0.0.0-20181217130922-17f3b04680b6/go.mod h1:8Vg/LTOO0KYa/vlHWJ6XZAevPQThGH5sufO0Hrou/lA= +github.com/machinebox/graphql v0.2.2 h1:dWKpJligYKhYKO5A2gvNhkJdQMNZeChZYyBbrZkBZfo= +github.com/machinebox/graphql v0.2.2/go.mod h1:F+kbVMHuwrQ5tYgU9JXlnskM8nOaFxCAEolaQybkjWA= github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= +github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -721,6 +725,7 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5-0.20200615073812-232d8fc87f50/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= @@ -842,6 +847,7 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20170915142106-8351a756f30f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -887,8 +893,9 @@ golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210913180222-943fd674d43e h1:+b/22bPvDYt4NPDcy4xAGCmON713ONAWFeY3Z7I3tR8= golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -968,8 +975,10 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210915083310-ed5796bab164 h1:7ZDGnxgHAMw7thfC5bEos0RDAccZKxioiWBhfIe+tvw= golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1052,8 +1061,9 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/main_test.go b/main_test.go index 8b380b5..10f8438 100644 --- a/main_test.go +++ b/main_test.go @@ -453,14 +453,14 @@ func TestChannelAllowlist_CorrectKey(t *testing.T) { app := NewApp(ctx, client) Configuration.ChannelMode = "allowlist" - Configuration.ChannelAllowlist = []string{"6d792d7075626b65792d69732d766572792d6c6f6e672d666f722d7472696d6d696e672d7075626b6579"} + Configuration.ChannelAllowlist = []string{"03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"} app.DispatchChannelAcceptor(ctx) // correct key: should be allowed client.channelAcceptorRequests <- &lnrpc.ChannelAcceptRequest{ - NodePubkey: []byte("my-pubkey-is-very-long-for-trimming-pubkey"), + NodePubkey: []byte("03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"), FundingAmt: 1337000, PendingChanId: []byte("759495353533530113"), } @@ -468,15 +468,27 @@ func TestChannelAllowlist_CorrectKey(t *testing.T) { resp := <-client.channelAcceptorResponses require.Equal(t, resp.Accept, true) +} +func TestChannelAllowlist_WrongKey(t *testing.T) { + client := newLndclientMock() + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + app := NewApp(ctx, client) + + Configuration.ChannelMode = "allowlist" + Configuration.ChannelAllowlist = []string{"03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"} + + app.DispatchChannelAcceptor(ctx) // wrong key: should be denied client.channelAcceptorRequests <- &lnrpc.ChannelAcceptRequest{ - NodePubkey: []byte("WRONG PUBKEY"), + NodePubkey: []byte("WRONG-KEY"), FundingAmt: 1337000, PendingChanId: []byte("759495353533530113"), } - resp = <-client.channelAcceptorResponses + resp := <-client.channelAcceptorResponses require.Equal(t, resp.Accept, false) } func TestChannelAllowlist_Wildcard(t *testing.T) { @@ -493,7 +505,7 @@ func TestChannelAllowlist_Wildcard(t *testing.T) { Configuration.ChannelAllowlist = []string{"*"} client.channelAcceptorRequests <- &lnrpc.ChannelAcceptRequest{ - NodePubkey: []byte("WRONG PUBKEY"), + NodePubkey: []byte("03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"), FundingAmt: 1337000, PendingChanId: []byte("759495353533530113"), } @@ -510,14 +522,14 @@ func TestChannelDenylist_Match(t *testing.T) { app := NewApp(ctx, client) Configuration.ChannelMode = "denylist" - Configuration.ChannelDenylist = []string{"6d792d7075626b65792d69732d766572792d6c6f6e672d666f722d7472696d6d696e672d7075626b6579"} + Configuration.ChannelDenylist = []string{"03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"} app.DispatchChannelAcceptor(ctx) // should be denied client.channelAcceptorRequests <- &lnrpc.ChannelAcceptRequest{ - NodePubkey: []byte("my-pubkey-is-very-long-for-trimming-pubkey"), + NodePubkey: []byte("03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"), FundingAmt: 1337000, PendingChanId: []byte("759495353533530113"), } @@ -534,13 +546,13 @@ func TestChannelAllowlist_Match(t *testing.T) { app := NewApp(ctx, client) Configuration.ChannelMode = "allowlist" - Configuration.ChannelAllowlist = []string{"6d792d7075626b65792d69732d766572792d6c6f6e672d666f722d7472696d6d696e672d7075626b6579"} + Configuration.ChannelAllowlist = []string{"03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"} app.DispatchChannelAcceptor(ctx) // should be allowed client.channelAcceptorRequests <- &lnrpc.ChannelAcceptRequest{ - NodePubkey: []byte("my-pubkey-is-very-long-for-trimming-pubkey"), + NodePubkey: []byte("03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"), FundingAmt: 1337000, PendingChanId: []byte("759495353533530113"), } diff --git a/rules/ChannelAccept.js b/rules/ChannelAccept.js index 3b5e594..023ce90 100644 --- a/rules/ChannelAccept.js +++ b/rules/ChannelAccept.js @@ -1,2 +1,12 @@ -ChannelAccept.Event.FundingAmt >= 750000; - +if ( + ChannelAccept.Event.FundingAmt >= 750000 && + ChannelAccept.OneMl.LastUpdate > 1661227900 && + ChannelAccept.OneMl.Noderank.Availability > 100 && + ChannelAccept.Amboss.Socials.Info.Email + // ( + // ChannelAccept.Amboss.Socials.Info.Email.length > 0 || + // ChannelAccept.Amboss.Socials.Info.Twitter.length >0 || + // ChannelAccept.Amboss.Socials.Info.Telegram.length >0 + // ) + // ChannelAccept.Amboss.Amboss.IsPrime == false +) { true } else { false } diff --git a/rules/HtlcForward.js b/rules/HtlcForward.js index efa69bd..40e9a6d 100644 --- a/rules/HtlcForward.js +++ b/rules/HtlcForward.js @@ -1,2 +1,4 @@ -HtlcForward.Event.OutgoingAmountMsat >= 100000 +if ( + HtlcForward.Event.OutgoingAmountMsat >= 100000 +) { true } else { false } diff --git a/rules/rules.go b/rules/rules.go index ba0f086..6480cc8 100644 --- a/rules/rules.go +++ b/rules/rules.go @@ -2,11 +2,11 @@ package rules import ( "fmt" - "log" "os" "github.com/callebtc/electronwall/types" "github.com/dop251/goja" + log "github.com/sirupsen/logrus" ) func Apply(s interface{}, decision_chan chan bool) (accept bool, err error) { @@ -41,7 +41,7 @@ func Apply(s interface{}, decision_chan chan bool) (accept bool, err error) { // execute script v, err := vm.RunString(string(js_script)) if err != nil { - fmt.Print(err.Error()) + log.Errorf("JS error: %v", err) return } From 4867d649c9e60a9e9ab5d0ef580d10fca69bdc93 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Wed, 24 Aug 2022 20:40:16 +0200 Subject: [PATCH 2/6] add --- api/1ml.go | 76 +++++++++++++++++ api/amboss.go | 224 ++++++++++++++++++++++++++++++++++++++++++++++++++ api/api.go | 34 ++++++++ 3 files changed, 334 insertions(+) create mode 100644 api/1ml.go create mode 100644 api/amboss.go create mode 100644 api/api.go diff --git a/api/1ml.go b/api/1ml.go new file mode 100644 index 0000000..895c64b --- /dev/null +++ b/api/1ml.go @@ -0,0 +1,76 @@ +package api + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "time" + + log "github.com/sirupsen/logrus" +) + +type OneML_NodeInfoResponse struct { + LastUpdate int `json:"last_update"` + PubKey string `json:"pub_key"` + Alias string `json:"alias"` + Addresses []struct { + Network string `json:"network"` + Addr string `json:"addr"` + } `json:"addresses"` + Color string `json:"color"` + Capacity int `json:"capacity"` + Channelcount int `json:"channelcount"` + Noderank struct { + Capacity int `json:"capacity"` + Channelcount int `json:"channelcount"` + Age int `json:"age"` + Growth int `json:"growth"` + Availability int `json:"availability"` + } `json:"noderank"` +} + +type OneMlClient struct { +} + +func GetOneMlClient() OneMlClient { + return OneMlClient{} +} + +func (c *OneMlClient) GetNodeInfo(pubkey string) (OneML_NodeInfoResponse, error) { + + url := fmt.Sprintf("https://1ml.com/node/%s/json", pubkey) + + log.Infof("Getting info from 1ml.com for %s", pubkey) + + client := http.Client{ + Timeout: time.Second * 2, // Timeout after 2 seconds + } + + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + log.Fatal(err) + } + + res, getErr := client.Do(req) + if getErr != nil { + log.Fatal(getErr) + } + + if res.Body != nil { + defer res.Body.Close() + } + + body, readErr := ioutil.ReadAll(res.Body) + if readErr != nil { + log.Fatal(readErr) + } + + r := OneML_NodeInfoResponse{} + jsonErr := json.Unmarshal(body, &r) + if jsonErr != nil { + log.Errorf("[1ml] api error: %v", jsonErr) + } + + return r, nil +} diff --git a/api/amboss.go b/api/amboss.go new file mode 100644 index 0000000..a914969 --- /dev/null +++ b/api/amboss.go @@ -0,0 +1,224 @@ +package api + +import ( + "context" + "time" + + "github.com/machinebox/graphql" + log "github.com/sirupsen/logrus" +) + +type AutoGenerated struct { + Data struct { + GetNode struct { + GraphInfo struct { + Node struct { + Alias string `json:"alias"` + } `json:"node"` + } `json:"graph_info"` + } `json:"getNode"` + } `json:"data"` +} + +var simple_query = `query Node($pubkey: String!) { + getNode(pubkey: $pubkey) { + graph_info { + node { + alias + } + } + } + }` + +type Amboss_NodeInfoResponse struct { + Socials struct { + Info struct { + Email string `json:"email"` + Telegram string `json:"telegram"` + Twitter string `json:"twitter"` + LightningAddress string `json:"lightning_address"` + Website string `json:"website"` + Pubkey string `json:"pubkey"` + MinChannelSize interface{} `json:"minChannelSize"` + Message string `json:"message"` + TwitterVerified bool `json:"twitter_verified"` + Updated time.Time `json:"updated"` + } `json:"info"` + } `json:"socials"` + GraphInfo struct { + LastUpdate time.Time `json:"last_update"` + Metrics struct { + Capacity string `json:"capacity"` + CapacityRank int `json:"capacity_rank"` + Channels int `json:"channels"` + ChannelsRank int `json:"channels_rank"` + } `json:"metrics"` + Node struct { + Addresses []struct { + Addr string `json:"addr"` + IPInfo struct { + City string `json:"city"` + Country string `json:"country"` + CountryCode string `json:"country_code"` + } `json:"ip_info"` + Network string `json:"network"` + } `json:"addresses"` + LastUpdate int `json:"last_update"` + Color string `json:"color"` + Features []struct { + FeatureID string `json:"feature_id"` + IsKnown bool `json:"is_known"` + IsRequired bool `json:"is_required"` + Name string `json:"name"` + } `json:"features"` + } `json:"node"` + } `json:"graph_info"` + Amboss struct { + IsFavorite bool `json:"is_favorite"` + IsPrime bool `json:"is_prime"` + NumberFavorites int `json:"number_favorites"` + NewChannelGossipDelta struct { + Mean string `json:"mean"` + Sd string `json:"sd"` + } `json:"new_channel_gossip_delta"` + Notifications struct { + NumberSubscribers int `json:"number_subscribers"` + } `json:"notifications"` + } `json:"amboss"` +} + +type Amboss_NodeInfoResponse_Nested struct { + Data struct { + GetNode struct { + Amboss_NodeInfoResponse + } `json:"getNode"` + } `json:"data"` +} + +var amboss_graphql_query = `query Info($pubkey: String!) { + getNode(pubkey: $pubkey) { + socials { + info { + email + telegram + twitter + lightning_address + website + pubkey + minChannelSize + message + twitter_verified + updated + } + } + graph_info { + last_update + metrics { + capacity + capacity_rank + channels + channels_rank + } + node { + addresses { + addr + ip_info { + city + country + country_code + } + network + } + last_update + color + features { + feature_id + is_known + is_required + name + } + } + } + amboss { + is_favorite + is_prime + number_favorites + new_channel_gossip_delta { + mean + sd + } + notifications { + number_subscribers + } + } + } + }` + +var amboss_graphql_variabnes = `{ + "pubkey": "%s" + } +` + +type AmbossClient struct { +} + +func GetAmbossClient() AmbossClient { + return AmbossClient{} +} + +func (c *AmbossClient) GetNodeInfo(pubkey string) (Amboss_NodeInfoResponse, error) { + + url := "https://api.amboss.space/graphql" + log.Infof("Getting info from amboss.space for %s", pubkey) + + graphqlClient := graphql.NewClient(url) + graphqlRequest := graphql.NewRequest(simple_query) + graphqlRequest.Var("pubkey", pubkey) + // set header fields + graphqlRequest.Header.Set("Cache-Control", "no-cache") + graphqlRequest.Header.Set("Content-Type", "application/json") + + var r_nested *AutoGenerated + if err := graphqlClient.Run(context.Background(), graphqlRequest, &r_nested); err != nil { + log.Errorf("[amboss] api error: %v", err) + } + + // r := r_nested.Data.GetNode.Amboss_NodeInfoResponse + + return Amboss_NodeInfoResponse{}, nil + // jsonData := map[string]string{ + // "query": query, + // "variables": variables, + // } + + // client := http.Client{ + // Timeout: time.Second * 2, // Timeout after 2 seconds + // } + + // req, err := http.NewRequest(http.MethodGet, url, nil) + // if err != nil { + // log.Fatal(err) + // } + + // res, getErr := client.Do(req) + // if getErr != nil { + // log.Fatal(getErr) + // } + + // if res.Body != nil { + // defer res.Body.Close() + // } + + // body, readErr := ioutil.ReadAll(res.Body) + // if readErr != nil { + // log.Fatal(readErr) + // } + + // r := Amboss_NodeInfoResponse{} + // jsonErr := json.Unmarshal(body, &r) + // if jsonErr != nil { + // log.Errorf("API error: %v", jsonErr) + // } + + // return r, nil +} diff --git a/api/api.go b/api/api.go new file mode 100644 index 0000000..caa6387 --- /dev/null +++ b/api/api.go @@ -0,0 +1,34 @@ +package api + +import log "github.com/sirupsen/logrus" + +type ApiClient interface { + GetNodeInfo(pubkey string) OneML_NodeInfoResponse +} + +type ApiNodeInfo struct { + OneMl OneML_NodeInfoResponse + Amboss Amboss_NodeInfoResponse +} + +func GetApiNodeinfo(pubkey string) (ApiNodeInfo, error) { + // get info from 1ml + OnemlClient := GetOneMlClient() + onemlNodeInfo, err := OnemlClient.GetNodeInfo(pubkey) + if err != nil { + log.Errorf(err.Error()) + onemlNodeInfo = OneML_NodeInfoResponse{} + } + + // get info from amboss + ambossClient := GetAmbossClient() + ambossNodeInfo, err := ambossClient.GetNodeInfo(pubkey) + if err != nil { + log.Errorf(err.Error()) + ambossNodeInfo = Amboss_NodeInfoResponse{} + } + return ApiNodeInfo{ + OneMl: onemlNodeInfo, + Amboss: ambossNodeInfo, + }, err +} From ef375c01bdfa5ac5aeb48d0732cac7b78b33932b Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Wed, 24 Aug 2022 22:20:14 +0200 Subject: [PATCH 3/6] api done --- api/amboss.go | 47 +++++--------------------------------- api/api.go | 4 ++-- api_test/main.go | 51 ++++++++++++++++++++++++++++++++++++++++++ channelAcceptor.go | 4 ++-- rules/ChannelAccept.js | 32 ++++++++++++++++---------- rules/rules.go | 6 ----- 6 files changed, 80 insertions(+), 64 deletions(-) create mode 100644 api_test/main.go diff --git a/api/amboss.go b/api/amboss.go index a914969..94e806d 100644 --- a/api/amboss.go +++ b/api/amboss.go @@ -167,58 +167,21 @@ func GetAmbossClient() AmbossClient { } func (c *AmbossClient) GetNodeInfo(pubkey string) (Amboss_NodeInfoResponse, error) { - url := "https://api.amboss.space/graphql" log.Infof("Getting info from amboss.space for %s", pubkey) graphqlClient := graphql.NewClient(url) - graphqlRequest := graphql.NewRequest(simple_query) + graphqlRequest := graphql.NewRequest(amboss_graphql_query) graphqlRequest.Var("pubkey", pubkey) // set header fields graphqlRequest.Header.Set("Cache-Control", "no-cache") graphqlRequest.Header.Set("Content-Type", "application/json") - var r_nested *AutoGenerated - if err := graphqlClient.Run(context.Background(), graphqlRequest, &r_nested); err != nil { + var r_nested Amboss_NodeInfoResponse_Nested + if err := graphqlClient.Run(context.Background(), graphqlRequest, &r_nested.Data); err != nil { log.Errorf("[amboss] api error: %v", err) } - // r := r_nested.Data.GetNode.Amboss_NodeInfoResponse - - return Amboss_NodeInfoResponse{}, nil - // jsonData := map[string]string{ - // "query": query, - // "variables": variables, - // } - - // client := http.Client{ - // Timeout: time.Second * 2, // Timeout after 2 seconds - // } - - // req, err := http.NewRequest(http.MethodGet, url, nil) - // if err != nil { - // log.Fatal(err) - // } - - // res, getErr := client.Do(req) - // if getErr != nil { - // log.Fatal(getErr) - // } - - // if res.Body != nil { - // defer res.Body.Close() - // } - - // body, readErr := ioutil.ReadAll(res.Body) - // if readErr != nil { - // log.Fatal(readErr) - // } - - // r := Amboss_NodeInfoResponse{} - // jsonErr := json.Unmarshal(body, &r) - // if jsonErr != nil { - // log.Errorf("API error: %v", jsonErr) - // } - - // return r, nil + r := r_nested.Data.GetNode.Amboss_NodeInfoResponse + return r, nil } diff --git a/api/api.go b/api/api.go index caa6387..007f5cd 100644 --- a/api/api.go +++ b/api/api.go @@ -7,8 +7,8 @@ type ApiClient interface { } type ApiNodeInfo struct { - OneMl OneML_NodeInfoResponse - Amboss Amboss_NodeInfoResponse + OneMl OneML_NodeInfoResponse `json:"1ml"` + Amboss Amboss_NodeInfoResponse `json:"amboss"` } func GetApiNodeinfo(pubkey string) (ApiNodeInfo, error) { diff --git a/api_test/main.go b/api_test/main.go new file mode 100644 index 0000000..4fb5ad4 --- /dev/null +++ b/api_test/main.go @@ -0,0 +1,51 @@ +package main + +import ( + "os" + + "github.com/callebtc/electronwall/api" + "github.com/callebtc/electronwall/rules" + "github.com/callebtc/electronwall/types" + "github.com/lightningnetwork/lnd/lnrpc" + log "github.com/sirupsen/logrus" +) + +func main() { + if len(os.Args) < 2 { + log.Errorf("Pass node ID as argument.") + return + } + pubkey := os.Args[1] + log.Infof("pubkey: %s", pubkey) + pk_byte := []byte(pubkey) + decision_chan := make(chan bool, 1) + event := types.ChannelAcceptEvent{} + + event.Event = &lnrpc.ChannelAcceptRequest{} + + event.Event.FundingAmt = 1_000_000 + log.Infof("Funding amount: %d sat", event.Event.FundingAmt) + event.Event.NodePubkey = pk_byte + + req := lnrpc.ChannelAcceptRequest{} + req.NodePubkey = pk_byte + + nodeInfo, err := api.GetApiNodeinfo(string(req.NodePubkey)) + if err != nil { + log.Errorf(err.Error()) + } + // log.Infoln("1ML") + // // log.Infoln("%+v", noeInfo.OneMl) + // log.Printf("%+v\n", nodeInfo.OneMl) + // log.Infoln("Amboss") + // log.Printf("%+v\n", nodeInfo.Amboss) + + event.OneMl = nodeInfo.OneMl + event.Amboss = nodeInfo.Amboss + + rules_decision, err := rules.Apply(event, decision_chan) + if err != nil { + panic(err) + } + log.Infof("Decision: %t", rules_decision) +} diff --git a/channelAcceptor.go b/channelAcceptor.go index 02ed9ed..6ac1755 100644 --- a/channelAcceptor.go +++ b/channelAcceptor.go @@ -13,7 +13,7 @@ import ( log "github.com/sirupsen/logrus" ) -func (app *App) getChannelAcceptEvent(ctx context.Context, req lnrpc.ChannelAcceptRequest) (types.ChannelAcceptEvent, error) { +func (app *App) GetChannelAcceptEvent(ctx context.Context, req lnrpc.ChannelAcceptRequest) (types.ChannelAcceptEvent, error) { // print the incoming channel request alias, err := app.lnd.getNodeAlias(ctx, hex.EncodeToString(req.NodePubkey)) if err != nil { @@ -77,7 +77,7 @@ func (app *App) interceptChannelEvents(ctx context.Context) error { return err } - channelAcceptEvent, err := app.getChannelAcceptEvent(ctx, req) + channelAcceptEvent, err := app.GetChannelAcceptEvent(ctx, req) if err != nil { return err } diff --git a/rules/ChannelAccept.js b/rules/ChannelAccept.js index 023ce90..5cd8d05 100644 --- a/rules/ChannelAccept.js +++ b/rules/ChannelAccept.js @@ -1,12 +1,20 @@ -if ( - ChannelAccept.Event.FundingAmt >= 750000 && - ChannelAccept.OneMl.LastUpdate > 1661227900 && - ChannelAccept.OneMl.Noderank.Availability > 100 && - ChannelAccept.Amboss.Socials.Info.Email - // ( - // ChannelAccept.Amboss.Socials.Info.Email.length > 0 || - // ChannelAccept.Amboss.Socials.Info.Twitter.length >0 || - // ChannelAccept.Amboss.Socials.Info.Telegram.length >0 - // ) - // ChannelAccept.Amboss.Amboss.IsPrime == false -) { true } else { false } +// only channels > 0.75 Msat +ChannelAccept.Event.FundingAmt >= 750000 && +// nodes with high 1ML availability score +ChannelAccept.OneMl.Noderank.Availability > 100 && +// nodes with a low enough 1ML age rank +ChannelAccept.OneMl.Noderank.Age < 10000 && +( + // only nodes with Amboss contact data + ChannelAccept.Amboss.Socials.Info.Email || + ChannelAccept.Amboss.Socials.Info.Twitter || + ChannelAccept.Amboss.Socials.Info.Telegram +) && +( + // elitist: either nodes with amboss prime + ChannelAccept.Amboss.Amboss.IsPrime || + // or nodes with high-ranking capacity + ChannelAccept.Amboss.GraphInfo.Metrics.CapacityRank < 1000 || + // or nodes with high-ranking channel count + ChannelAccept.Amboss.GraphInfo.Metrics.ChannelsRank < 1000 +) diff --git a/rules/rules.go b/rules/rules.go index 6480cc8..da4aaa9 100644 --- a/rules/rules.go +++ b/rules/rules.go @@ -28,12 +28,6 @@ func Apply(s interface{}, decision_chan chan bool) (accept bool, err error) { if err != nil { log.Fatal(err) } - // case *routerrpc.ForwardHtlcInterceptRequest: - // vm.Set("HtlcForwardEvent", s) - // js_script, err = os.ReadFile("rules/ForwardHtlcInterceptRequest.js") - // if err != nil { - // log.Fatal(err) - // } default: return false, fmt.Errorf("no rule found for event type") } From edc4152faf7a9f30df1730da913fd0ea11b8001b Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Wed, 31 Aug 2022 14:09:17 +0200 Subject: [PATCH 4/6] works --- README.md | 190 +++++++++++++++++++++++++++++++++- api/1ml.go | 3 +- api/amboss.go | 28 +---- api/api.go | 45 +++++--- channelAcceptor.go | 27 ++--- config.yaml.example | 10 ++ config.go => config/config.go | 15 ++- helpers.go | 8 +- htlcInterceptor.go | 22 ++-- main.go | 11 +- main_test.go | 92 ++++++++-------- rules/HtlcForward.js | 1 + rules/rules.go | 7 ++ 13 files changed, 335 insertions(+), 124 deletions(-) rename config.go => config/config.go (87%) diff --git a/README.md b/README.md index 0a82b38..e779715 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ # ⚡️🛡 electronwall -A tiny firewall for LND that can filter Lightning **channel opening requests** and **HTLC forwards** on your node based on set rules. +A tiny firewall for LND that can filter Lightning **channel opening requests** and **HTLC forwards** based on your custom rules. -Currently, electronwall uses filter lists that either allow (allowlist) or reject (denylist) events from a list of node public keys for channel openings, or channel IDs and channel pairs for payment routings. +electronwall uses filter lists that either allow (allowlist) or reject (denylist) events from a list of node public keys for channel openings, or channel IDs and channel pairs for payment routings. + +You can also write [custom rules](#programmable-rules) using a builtin Javascript engine. ![electronwall0 3 2](https://user-images.githubusercontent.com/93376500/178162791-e6ba90c1-2798-471d-b7aa-0b12eae8bf2e.png) @@ -21,10 +23,192 @@ go build . You can download a binary for your system [here](https://github.com/callebtc/electronwall/releases). You'll still need a [config file](https://github.com/callebtc/electronwall/blob/main/config.yaml.example). ## Config -Edit `config.yaml.example` and rename to `config.yaml`. +Edit `config.yaml.example` and rename to `config.yaml`. ## Run ```bash ./electronwall ``` + +--------------- +# Rules + +## Allowlist and denylist + +Allowlist and denylist rules are set in `config.yaml` under the appropriate keys. See the [example](config.yaml.example) config. + +## Programmable rules + +electronwall has a Javascript engine called [goja](https://github.com/dop251/goja) that allows you to set custom rules. Note that you can only use pure Javascript (ECMAScript), you can't import a ton of other dependcies like with web applications. + +Rules are saved in the `rules/` directory. There are two files, one for channel open requests `ChannelAccept.js` and one for HTLC forwards `HtlcForward.js`. + +electronwall passes [contextual information](#contextual-information) to the Javascript engine that you can use to create rich rules. See below for a list of objects that are currently supported. + + Here is one rather complex rule for channel accept decisions in `ChannelAccept.js` for demonstration purposes: + + ```javascript + // only channels > 0.75 Msat +ChannelAccept.Event.FundingAmt >= 750000 && +// nodes with high 1ML availability score +ChannelAccept.OneMl.Noderank.Availability > 100 && +// nodes with a low enough 1ML age rank +ChannelAccept.OneMl.Noderank.Age < 10000 && +( + // only nodes with Amboss contact data + ChannelAccept.Amboss.Socials.Info.Email || + ChannelAccept.Amboss.Socials.Info.Twitter || + ChannelAccept.Amboss.Socials.Info.Telegram +) && +( + // elitist: either nodes with amboss prime + ChannelAccept.Amboss.Amboss.IsPrime || + // or nodes with high-ranking capacity + ChannelAccept.Amboss.GraphInfo.Metrics.CapacityRank < 1000 || + // or nodes with high-ranking channel count + ChannelAccept.Amboss.GraphInfo.Metrics.ChannelsRank < 1000 +) + ``` + + Here is an example `HtlcForward.js` + ```javascript + if ( + // only forward amounts larger than 100 sat + HtlcForward.Event.OutgoingAmountMsat >= 100000 +) { true } else { false } + ``` + +### Contextual information +Here is a list of all objects that are passed to the Javascript engine. You need to look at the structure of these objects in order to use them in a custom rule like the example above. + +#### LND: ChannelAcceptRequest `*.Event` +```go +type ChannelAcceptRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The pubkey of the node that wishes to open an inbound channel. + NodePubkey []byte `protobuf:"bytes,1,opt,name=node_pubkey,json=nodePubkey,proto3" json:"node_pubkey,omitempty"` + // The hash of the genesis block that the proposed channel resides in. + ChainHash []byte `protobuf:"bytes,2,opt,name=chain_hash,json=chainHash,proto3" json:"chain_hash,omitempty"` + // The pending channel id. + PendingChanId []byte `protobuf:"bytes,3,opt,name=pending_chan_id,json=pendingChanId,proto3" json:"pending_chan_id,omitempty"` + // The funding amount in satoshis that initiator wishes to use in the + // channel. + FundingAmt uint64 `protobuf:"varint,4,opt,name=funding_amt,json=fundingAmt,proto3" json:"funding_amt,omitempty"` + // The push amount of the proposed channel in millisatoshis. + PushAmt uint64 `protobuf:"varint,5,opt,name=push_amt,json=pushAmt,proto3" json:"push_amt,omitempty"` + // The dust limit of the initiator's commitment tx. + DustLimit uint64 `protobuf:"varint,6,opt,name=dust_limit,json=dustLimit,proto3" json:"dust_limit,omitempty"` + // The maximum amount of coins in millisatoshis that can be pending in this + // channel. + MaxValueInFlight uint64 `protobuf:"varint,7,opt,name=max_value_in_flight,json=maxValueInFlight,proto3" json:"max_value_in_flight,omitempty"` + // The minimum amount of satoshis the initiator requires us to have at all + // times. + ChannelReserve uint64 `protobuf:"varint,8,opt,name=channel_reserve,json=channelReserve,proto3" json:"channel_reserve,omitempty"` + // The smallest HTLC in millisatoshis that the initiator will accept. + MinHtlc uint64 `protobuf:"varint,9,opt,name=min_htlc,json=minHtlc,proto3" json:"min_htlc,omitempty"` + // The initial fee rate that the initiator suggests for both commitment + // transactions. + FeePerKw uint64 `protobuf:"varint,10,opt,name=fee_per_kw,json=feePerKw,proto3" json:"fee_per_kw,omitempty"` + // + //The number of blocks to use for the relative time lock in the pay-to-self + //output of both commitment transactions. + CsvDelay uint32 `protobuf:"varint,11,opt,name=csv_delay,json=csvDelay,proto3" json:"csv_delay,omitempty"` + // The total number of incoming HTLC's that the initiator will accept. + MaxAcceptedHtlcs uint32 `protobuf:"varint,12,opt,name=max_accepted_htlcs,json=maxAcceptedHtlcs,proto3" json:"max_accepted_htlcs,omitempty"` + // A bit-field which the initiator uses to specify proposed channel + // behavior. + ChannelFlags uint32 `protobuf:"varint,13,opt,name=channel_flags,json=channelFlags,proto3" json:"channel_flags,omitempty"` + // The commitment type the initiator wishes to use for the proposed channel. + CommitmentType CommitmentType `protobuf:"varint,14,opt,name=commitment_type,json=commitmentType,proto3,enum=lnrpc.CommitmentType" json:"commitment_type,omitempty"` +} + +``` + +#### 1ML node information `*.OneMl` +```go +type OneML_NodeInfoResponse struct { + LastUpdate int `json:"last_update"` + PubKey string `json:"pub_key"` + Alias string `json:"alias"` + Addresses []struct { + Network string `json:"network"` + Addr string `json:"addr"` + } `json:"addresses"` + Color string `json:"color"` + Capacity int `json:"capacity"` + Channelcount int `json:"channelcount"` + Noderank struct { + Capacity int `json:"capacity"` + Channelcount int `json:"channelcount"` + Age int `json:"age"` + Growth int `json:"growth"` + Availability int `json:"availability"` + } `json:"noderank"` +} +``` +#### Amboss node information `*.Amboss` +```go +type Amboss_NodeInfoResponse struct { + Socials struct { + Info struct { + Email string `json:"email"` + Telegram string `json:"telegram"` + Twitter string `json:"twitter"` + LightningAddress string `json:"lightning_address"` + Website string `json:"website"` + Pubkey string `json:"pubkey"` + MinChannelSize interface{} `json:"minChannelSize"` + Message string `json:"message"` + TwitterVerified bool `json:"twitter_verified"` + Updated time.Time `json:"updated"` + } `json:"info"` + } `json:"socials"` + GraphInfo struct { + LastUpdate time.Time `json:"last_update"` + Metrics struct { + Capacity string `json:"capacity"` + CapacityRank int `json:"capacity_rank"` + Channels int `json:"channels"` + ChannelsRank int `json:"channels_rank"` + } `json:"metrics"` + Node struct { + Addresses []struct { + Addr string `json:"addr"` + IPInfo struct { + City string `json:"city"` + Country string `json:"country"` + CountryCode string `json:"country_code"` + } `json:"ip_info"` + Network string `json:"network"` + } `json:"addresses"` + LastUpdate int `json:"last_update"` + Color string `json:"color"` + Features []struct { + FeatureID string `json:"feature_id"` + IsKnown bool `json:"is_known"` + IsRequired bool `json:"is_required"` + Name string `json:"name"` + } `json:"features"` + } `json:"node"` + } `json:"graph_info"` + Amboss struct { + IsFavorite bool `json:"is_favorite"` + IsPrime bool `json:"is_prime"` + NumberFavorites int `json:"number_favorites"` + NewChannelGossipDelta struct { + Mean string `json:"mean"` + Sd string `json:"sd"` + } `json:"new_channel_gossip_delta"` + Notifications struct { + NumberSubscribers int `json:"number_subscribers"` + } `json:"notifications"` + } `json:"amboss"` +} +``` + +#### Network information `*.Network` +*TBD* \ No newline at end of file diff --git a/api/1ml.go b/api/1ml.go index 895c64b..91f619f 100644 --- a/api/1ml.go +++ b/api/1ml.go @@ -7,6 +7,7 @@ import ( "net/http" "time" + "github.com/callebtc/electronwall/config" log "github.com/sirupsen/logrus" ) @@ -44,7 +45,7 @@ func (c *OneMlClient) GetNodeInfo(pubkey string) (OneML_NodeInfoResponse, error) log.Infof("Getting info from 1ml.com for %s", pubkey) client := http.Client{ - Timeout: time.Second * 2, // Timeout after 2 seconds + Timeout: time.Second * time.Duration(config.Configuration.ApiRules.OneMl.Timeout), } req, err := http.NewRequest(http.MethodGet, url, nil) diff --git a/api/amboss.go b/api/amboss.go index 94e806d..2a900df 100644 --- a/api/amboss.go +++ b/api/amboss.go @@ -4,32 +4,11 @@ import ( "context" "time" + "github.com/callebtc/electronwall/config" "github.com/machinebox/graphql" log "github.com/sirupsen/logrus" ) -type AutoGenerated struct { - Data struct { - GetNode struct { - GraphInfo struct { - Node struct { - Alias string `json:"alias"` - } `json:"node"` - } `json:"graph_info"` - } `json:"getNode"` - } `json:"data"` -} - -var simple_query = `query Node($pubkey: String!) { - getNode(pubkey: $pubkey) { - graph_info { - node { - alias - } - } - } - }` - type Amboss_NodeInfoResponse struct { Socials struct { Info struct { @@ -178,7 +157,10 @@ func (c *AmbossClient) GetNodeInfo(pubkey string) (Amboss_NodeInfoResponse, erro graphqlRequest.Header.Set("Content-Type", "application/json") var r_nested Amboss_NodeInfoResponse_Nested - if err := graphqlClient.Run(context.Background(), graphqlRequest, &r_nested.Data); err != nil { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(config.Configuration.ApiRules.Amboss.Timeout)) + defer cancel() + + if err := graphqlClient.Run(ctx, graphqlRequest, &r_nested.Data); err != nil { log.Errorf("[amboss] api error: %v", err) } diff --git a/api/api.go b/api/api.go index 007f5cd..bb0a179 100644 --- a/api/api.go +++ b/api/api.go @@ -1,6 +1,9 @@ package api -import log "github.com/sirupsen/logrus" +import ( + "github.com/callebtc/electronwall/config" + log "github.com/sirupsen/logrus" +) type ApiClient interface { GetNodeInfo(pubkey string) OneML_NodeInfoResponse @@ -12,23 +15,31 @@ type ApiNodeInfo struct { } func GetApiNodeinfo(pubkey string) (ApiNodeInfo, error) { - // get info from 1ml - OnemlClient := GetOneMlClient() - onemlNodeInfo, err := OnemlClient.GetNodeInfo(pubkey) - if err != nil { - log.Errorf(err.Error()) - onemlNodeInfo = OneML_NodeInfoResponse{} + response := ApiNodeInfo{ + OneMl: OneML_NodeInfoResponse{}, + Amboss: Amboss_NodeInfoResponse{}, } - // get info from amboss - ambossClient := GetAmbossClient() - ambossNodeInfo, err := ambossClient.GetNodeInfo(pubkey) - if err != nil { - log.Errorf(err.Error()) - ambossNodeInfo = Amboss_NodeInfoResponse{} + if config.Configuration.ApiRules.OneMl.Active { + // get info from 1ml + OnemlClient := GetOneMlClient() + onemlNodeInfo, err := OnemlClient.GetNodeInfo(pubkey) + if err != nil { + log.Errorf(err.Error()) + onemlNodeInfo = OneML_NodeInfoResponse{} + } + response.OneMl = onemlNodeInfo } - return ApiNodeInfo{ - OneMl: onemlNodeInfo, - Amboss: ambossNodeInfo, - }, err + + if config.Configuration.ApiRules.Amboss.Active { + // get info from amboss + ambossClient := GetAmbossClient() + ambossNodeInfo, err := ambossClient.GetNodeInfo(pubkey) + if err != nil { + log.Errorf(err.Error()) + ambossNodeInfo = Amboss_NodeInfoResponse{} + } + response.Amboss = ambossNodeInfo + } + return response, nil } diff --git a/channelAcceptor.go b/channelAcceptor.go index 6ac1755..1365213 100644 --- a/channelAcceptor.go +++ b/channelAcceptor.go @@ -7,6 +7,7 @@ import ( "sync" "github.com/callebtc/electronwall/api" + "github.com/callebtc/electronwall/config" "github.com/callebtc/electronwall/rules" "github.com/callebtc/electronwall/types" "github.com/lightningnetwork/lnd/lnrpc" @@ -25,7 +26,7 @@ func (app *App) GetChannelAcceptEvent(ctx context.Context, req lnrpc.ChannelAcce log.Errorf(err.Error()) } - noeInfo, err := api.GetApiNodeinfo(string(req.NodePubkey)) + noeInfo, err := api.GetApiNodeinfo(hex.EncodeToString(req.NodePubkey)) if err != nil { log.Errorf(err.Error()) } @@ -125,7 +126,7 @@ func (app *App) interceptChannelEvents(ctx context.Context) error { return err } // parse list - list_decision, err := app.channelAcceptDecision(req) + list_decision, err := app.channelAcceptListDecision(req) if err != nil { return err } @@ -137,7 +138,7 @@ func (app *App) interceptChannelEvents(ctx context.Context) error { res := lnrpc.ChannelAcceptResponse{} if accept { - if Configuration.LogJson { + if config.Configuration.LogJson { contextLogger.Infof("allow") } else { log.Infof("[channel] ✅ Allow channel %s", channel_info_string) @@ -152,13 +153,13 @@ func (app *App) interceptChannelEvents(ctx context.Context) error { } } else { - if Configuration.LogJson { + if config.Configuration.LogJson { contextLogger.Infof("deny") } else { log.Infof("[channel] ❌ Deny channel %s", channel_info_string) } res = lnrpc.ChannelAcceptResponse{Accept: false, - Error: Configuration.ChannelRejectMessage} + Error: config.Configuration.ChannelRejectMessage} } err = acceptClient.Send(&res) if err != nil { @@ -168,26 +169,26 @@ func (app *App) interceptChannelEvents(ctx context.Context) error { } -func (app *App) channelAcceptDecision(req lnrpc.ChannelAcceptRequest) (bool, error) { +func (app *App) channelAcceptListDecision(req lnrpc.ChannelAcceptRequest) (bool, error) { // determine mode and list of channels to parse var accept bool var listToParse []string - if Configuration.ChannelMode == "allowlist" { + if config.Configuration.ChannelMode == "allowlist" { accept = false - listToParse = Configuration.ChannelAllowlist - } else if Configuration.ChannelMode == "denylist" { + listToParse = config.Configuration.ChannelAllowlist + } else if config.Configuration.ChannelMode == "denylist" { accept = true - listToParse = Configuration.ChannelDenylist + listToParse = config.Configuration.ChannelDenylist } // parse and make decision - log.Infof("TRYING %s", string(req.NodePubkey)) for _, pubkey := range listToParse { - if string(req.NodePubkey) == pubkey || pubkey == "*" { + if hex.EncodeToString(req.NodePubkey) == pubkey || pubkey == "*" { accept = !accept break } } + log.Infof("[list] decision: %t", accept) return accept, nil } @@ -214,7 +215,7 @@ func (app *App) logChannelEvents(ctx context.Context) error { alias, ) - if Configuration.LogJson { + if config.Configuration.LogJson { contextLogger := log.WithFields(log.Fields{ "event": "channel", "capacity": event.GetOpenChannel().Capacity, diff --git a/config.yaml.example b/config.yaml.example index fe6b9c9..cd6b196 100644 --- a/config.yaml.example +++ b/config.yaml.example @@ -41,3 +41,13 @@ forward-allowlist: - "*->25328x256x0" # all forwards to this channel forward-denylist: - "9961472x65537x1" + +# ---- Javascript rules ---- +rules: + apply: true # whether to respect the rule decision + oneml: # 1ML.com API + active: true + timeout: 5 # API timeout in seconds + amboss: # Amboss.space API + active: true + timeout: 5 # API timeout in seconds diff --git a/config.go b/config/config.go similarity index 87% rename from config.go rename to config/config.go index a76445f..e26c51c 100644 --- a/config.go +++ b/config/config.go @@ -1,4 +1,4 @@ -package main +package config import ( "fmt" @@ -20,6 +20,17 @@ var Configuration = struct { ForwardMode string `yaml:"forward-mode"` ForwardAllowlist []string `yaml:"forward-allowlist"` ForwardDenylist []string `yaml:"forward-denylist"` + ApiRules struct { + Apply bool `yaml:"apply"` + OneMl struct { + Active bool `yaml:"active"` + Timeout int `yaml:"timeout"` + } `yaml:"oneml"` + Amboss struct { + Active bool `yaml:"active"` + Timeout int `yaml:"timeout"` + } `yaml:"amboss"` + } `yaml:"rules"` }{} func init() { @@ -31,8 +42,6 @@ func init() { } func checkConfig() { - setLogger(Configuration.Debug, Configuration.LogJson) - welcome() if Configuration.Host == "" { panic(fmt.Errorf("no host specified in config.yaml")) diff --git a/helpers.go b/helpers.go index 3689375..f774239 100644 --- a/helpers.go +++ b/helpers.go @@ -20,12 +20,12 @@ func trimPubKey(pubkey []byte) string { } } -func welcome() { - log.Info("---- ⚡️ electronwall 0.3.3 ⚡️ ----") +func Welcome() { + log.Info("---- ⚡️ electronwall 0.4 ⚡️ ----") } -// setLogger will initialize the log format -func setLogger(debug bool, json bool) { +// SetLogger will initialize the log format +func SetLogger(debug bool, json bool) { if json { customFormatter := new(log.JSONFormatter) customFormatter.TimestampFormat = "2006-01-02 15:04:05" diff --git a/htlcInterceptor.go b/htlcInterceptor.go index 6f805f3..b9915aa 100644 --- a/htlcInterceptor.go +++ b/htlcInterceptor.go @@ -8,6 +8,7 @@ import ( "strings" "sync" + "github.com/callebtc/electronwall/config" "github.com/callebtc/electronwall/rules" "github.com/callebtc/electronwall/types" "github.com/lightningnetwork/lnd/lnrpc/routerrpc" @@ -144,14 +145,14 @@ func (app *App) interceptHtlcEvents(ctx context.Context) error { } switch accept { case true: - if Configuration.LogJson { + if config.Configuration.LogJson { contextLogger.Infof("allow") } else { log.Infof("[forward] ✅ Allow HTLC %s", forward_info_string) } response.Action = routerrpc.ResolveHoldForwardAction_RESUME case false: - if Configuration.LogJson { + if config.Configuration.LogJson { contextLogger.Infof("deny") } else { log.Infof("[forward] ❌ Deny HTLC %s", forward_info_string) @@ -181,15 +182,15 @@ func (app *App) htlcInterceptDecision(ctx context.Context, event *routerrpc.Forw // time.Sleep(60 * time.Second) // determine filtering mode and list to parse - switch Configuration.ForwardMode { + switch config.Configuration.ForwardMode { case "allowlist": accept = false - listToParse = Configuration.ForwardAllowlist + listToParse = config.Configuration.ForwardAllowlist case "denylist": accept = true - listToParse = Configuration.ForwardDenylist + listToParse = config.Configuration.ForwardDenylist default: - return false, fmt.Errorf("unknown forward mode: %s", Configuration.ForwardMode) + return false, fmt.Errorf("unknown forward mode: %s", config.Configuration.ForwardMode) } // parse list and decide @@ -217,6 +218,7 @@ func (app *App) htlcInterceptDecision(ctx context.Context, event *routerrpc.Forw } } // decision_chan <- accept + log.Infof("[list] decision: %t", accept) return accept, nil } @@ -251,7 +253,7 @@ func (app *App) logHtlcEvents(ctx context.Context) error { switch event.Event.(type) { case *routerrpc.HtlcEvent_SettleEvent: - if Configuration.LogJson { + if config.Configuration.LogJson { contextLogger(event).Infof("SettleEvent") // contextLogger.Debugf("[forward] Preimage: %s", hex.EncodeToString(event.GetSettleEvent().Preimage)) } else { @@ -262,7 +264,7 @@ func (app *App) logHtlcEvents(ctx context.Context) error { } case *routerrpc.HtlcEvent_ForwardFailEvent: - if Configuration.LogJson { + if config.Configuration.LogJson { contextLogger(event).Infof("ForwardFailEvent") // contextLogger.Debugf("[forward] Reason: %s", event.GetForwardFailEvent()) } else { @@ -271,7 +273,7 @@ func (app *App) logHtlcEvents(ctx context.Context) error { } case *routerrpc.HtlcEvent_ForwardEvent: - if Configuration.LogJson { + if config.Configuration.LogJson { contextLogger(event).Infof("ForwardEvent") } else { log.Infof("[forward] HTLC ForwardEvent (chan_id:%s, htlc_id:%d)", ParseChannelID(event.IncomingChannelId), event.IncomingHtlcId) @@ -280,7 +282,7 @@ func (app *App) logHtlcEvents(ctx context.Context) error { // log.Debugf("[forward] Details: %s", event.GetForwardEvent().String()) case *routerrpc.HtlcEvent_LinkFailEvent: - if Configuration.LogJson { + if config.Configuration.LogJson { contextLogger(event).Infof("LinkFailEvent") // contextLogger(event).Debugf("[forward] Reason: %s", event.GetLinkFailEvent().FailureString) } else { diff --git a/main.go b/main.go index 2c04bf8..c00f9eb 100644 --- a/main.go +++ b/main.go @@ -5,6 +5,7 @@ import ( "io/ioutil" "sync" + "github.com/callebtc/electronwall/config" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/macaroons" @@ -39,11 +40,11 @@ func NewApp(ctx context.Context, lnd lndclient) *App { // gets the lnd grpc connection func getClientConnection(ctx context.Context) (*grpc.ClientConn, error) { - creds, err := credentials.NewClientTLSFromFile(Configuration.TLSPath, "") + creds, err := credentials.NewClientTLSFromFile(config.Configuration.TLSPath, "") if err != nil { return nil, err } - macBytes, err := ioutil.ReadFile(Configuration.MacaroonPath) + macBytes, err := ioutil.ReadFile(config.Configuration.MacaroonPath) if err != nil { return nil, err } @@ -60,8 +61,8 @@ func getClientConnection(ctx context.Context) (*grpc.ClientConn, error) { grpc.WithBlock(), grpc.WithPerRPCCredentials(cred), } - log.Infof("Connecting to %s", Configuration.Host) - conn, err := grpc.DialContext(ctx, Configuration.Host, opts...) + log.Infof("Connecting to %s", config.Configuration.Host) + conn, err := grpc.DialContext(ctx, config.Configuration.Host, opts...) if err != nil { return nil, err } @@ -84,6 +85,8 @@ func newLndClient(ctx context.Context) (*LndClient, error) { } func main() { + SetLogger(config.Configuration.Debug, config.Configuration.LogJson) + Welcome() ctx := context.Background() for { lnd, err := newLndClient(ctx) diff --git a/main_test.go b/main_test.go index 10f8438..a635f50 100644 --- a/main_test.go +++ b/main_test.go @@ -2,12 +2,12 @@ package main import ( "context" - "testing" - + "github.com/callebtc/electronwall/config" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" + "testing" ) func TestApp(t *testing.T) { @@ -33,8 +33,8 @@ func TestHTLCDenylist_BothMatch(t *testing.T) { app := NewApp(ctx, client) - Configuration.ForwardMode = "denylist" - Configuration.ForwardDenylist = []string{"700762x1327x1->690757x1005x1"} + config.Configuration.ForwardMode = "denylist" + config.Configuration.ForwardDenylist = []string{"700762x1327x1->690757x1005x1"} app.DispatchHTLCAcceptor(ctx) @@ -67,8 +67,8 @@ func TestHTLCDenylist_BothNoMatch(t *testing.T) { app := NewApp(ctx, client) - Configuration.ForwardMode = "denylist" - Configuration.ForwardDenylist = []string{"700762x1327x1->690757x1005x1"} + config.Configuration.ForwardMode = "denylist" + config.Configuration.ForwardDenylist = []string{"700762x1327x1->690757x1005x1"} app.DispatchHTLCAcceptor(ctx) @@ -101,12 +101,12 @@ func TestHTLCDenylist_WildCardOutBothMatch(t *testing.T) { app := NewApp(ctx, client) - Configuration.ForwardMode = "denylist" - Configuration.ForwardDenylist = []string{"700762x1327x1->690757x1005x1"} + config.Configuration.ForwardMode = "denylist" + config.Configuration.ForwardDenylist = []string{"700762x1327x1->690757x1005x1"} app.DispatchHTLCAcceptor(ctx) - Configuration.ForwardDenylist = []string{"700762x1327x1->*"} + config.Configuration.ForwardDenylist = []string{"700762x1327x1->*"} key := &routerrpc.CircuitKey{ ChanId: 770495967390531585, @@ -137,14 +137,14 @@ func TestHTLCDenylist_WildCardOutNoMatch(t *testing.T) { app := NewApp(ctx, client) - Configuration.ForwardMode = "denylist" - Configuration.ForwardDenylist = []string{"700762x1327x1->690757x1005x1"} + config.Configuration.ForwardMode = "denylist" + config.Configuration.ForwardDenylist = []string{"700762x1327x1->690757x1005x1"} app.DispatchHTLCAcceptor(ctx) // wildcard out, first key doesn't match: should be allowed - Configuration.ForwardDenylist = []string{"700762x1327x1->*"} + config.Configuration.ForwardDenylist = []string{"700762x1327x1->*"} key := &routerrpc.CircuitKey{ ChanId: 759495353533530113, @@ -176,11 +176,11 @@ func TestHTLCAllowlist_BothMatch(t *testing.T) { app.DispatchHTLCAcceptor(ctx) - Configuration.ForwardMode = "allowlist" + config.Configuration.ForwardMode = "allowlist" // both keys correct: should be allowed - Configuration.ForwardAllowlist = []string{"700762x1327x1->690757x1005x1"} - log.Tracef("[test] Mode: %s, Rules: %v", Configuration.ForwardMode, Configuration.ForwardAllowlist) + config.Configuration.ForwardAllowlist = []string{"700762x1327x1->690757x1005x1"} + log.Tracef("[test] Mode: %s, Rules: %v", config.Configuration.ForwardMode, config.Configuration.ForwardAllowlist) key := &routerrpc.CircuitKey{ ChanId: 770495967390531585, @@ -212,10 +212,10 @@ func TestHTLCAllowlist_BothNonMatch(t *testing.T) { app.DispatchHTLCAcceptor(ctx) - Configuration.ForwardMode = "allowlist" + config.Configuration.ForwardMode = "allowlist" // both keys wrong: should be denied - Configuration.ForwardAllowlist = []string{"700762x1327x1->690757x1005x1"} - log.Tracef("[test] Mode: %s, Rules: %v", Configuration.ForwardMode, Configuration.ForwardAllowlist) + config.Configuration.ForwardAllowlist = []string{"700762x1327x1->690757x1005x1"} + log.Tracef("[test] Mode: %s, Rules: %v", config.Configuration.ForwardMode, config.Configuration.ForwardAllowlist) key := &routerrpc.CircuitKey{ ChanId: 123456789876543210, @@ -246,10 +246,10 @@ func TestHTLCAllowlist_Wildcard(t *testing.T) { app.DispatchHTLCAcceptor(ctx) - Configuration.ForwardMode = "allowlist" + config.Configuration.ForwardMode = "allowlist" // wildcard: should be allowed - Configuration.ForwardAllowlist = []string{"*"} - log.Tracef("[test] Mode: %s, Rules: %v", Configuration.ForwardMode, Configuration.ForwardAllowlist) + config.Configuration.ForwardAllowlist = []string{"*"} + log.Tracef("[test] Mode: %s, Rules: %v", config.Configuration.ForwardMode, config.Configuration.ForwardAllowlist) key := &routerrpc.CircuitKey{ ChanId: 123456789876543210, HtlcId: 1337000, @@ -279,11 +279,11 @@ func TestHTLCAllowlist_WildcardIn(t *testing.T) { app.DispatchHTLCAcceptor(ctx) - Configuration.ForwardMode = "allowlist" + config.Configuration.ForwardMode = "allowlist" // wildcard in: should be allowed - Configuration.ForwardAllowlist = []string{"*->690757x1005x1"} - log.Tracef("[test] Mode: %s, Rules: %v", Configuration.ForwardMode, Configuration.ForwardAllowlist) + config.Configuration.ForwardAllowlist = []string{"*->690757x1005x1"} + log.Tracef("[test] Mode: %s, Rules: %v", config.Configuration.ForwardMode, config.Configuration.ForwardAllowlist) key := &routerrpc.CircuitKey{ ChanId: 123456789876543210, @@ -314,10 +314,10 @@ func TestHTLCAllowlist_WildcardOut(t *testing.T) { app.DispatchHTLCAcceptor(ctx) - Configuration.ForwardMode = "allowlist" + config.Configuration.ForwardMode = "allowlist" // wildcard out: should be allowed - Configuration.ForwardAllowlist = []string{"700762x1327x1->*"} - log.Tracef("[test] Mode: %s, Rules: %v", Configuration.ForwardMode, Configuration.ForwardAllowlist) + config.Configuration.ForwardAllowlist = []string{"700762x1327x1->*"} + log.Tracef("[test] Mode: %s, Rules: %v", config.Configuration.ForwardMode, config.Configuration.ForwardAllowlist) key := &routerrpc.CircuitKey{ ChanId: 770495967390531585, @@ -348,10 +348,10 @@ func TestHTLCAllowlist_WildcardOutWrongKeyIn(t *testing.T) { app.DispatchHTLCAcceptor(ctx) - Configuration.ForwardMode = "allowlist" + config.Configuration.ForwardMode = "allowlist" // wildcard out but wrong in key: should be denied - Configuration.ForwardAllowlist = []string{"700762x1327x1->*"} - log.Tracef("[test] Mode: %s, Rules: %v", Configuration.ForwardMode, Configuration.ForwardAllowlist) + config.Configuration.ForwardAllowlist = []string{"700762x1327x1->*"} + log.Tracef("[test] Mode: %s, Rules: %v", config.Configuration.ForwardMode, config.Configuration.ForwardAllowlist) key := &routerrpc.CircuitKey{ ChanId: 123456789876543210, @@ -382,10 +382,10 @@ func TestHTLCAllowlist_WildcardIn_WrongKeyOut(t *testing.T) { app.DispatchHTLCAcceptor(ctx) - Configuration.ForwardMode = "allowlist" + config.Configuration.ForwardMode = "allowlist" // wildcard in but wrong out key: should be denied - Configuration.ForwardAllowlist = []string{"*->700762x1327x1"} - log.Tracef("[test] Mode: %s, Rules: %v", Configuration.ForwardMode, Configuration.ForwardAllowlist) + config.Configuration.ForwardAllowlist = []string{"*->700762x1327x1"} + log.Tracef("[test] Mode: %s, Rules: %v", config.Configuration.ForwardMode, config.Configuration.ForwardAllowlist) key := &routerrpc.CircuitKey{ ChanId: 123456789876543210, @@ -416,10 +416,10 @@ func TestHTLCAllowlist_WildcardBoth(t *testing.T) { app.DispatchHTLCAcceptor(ctx) - Configuration.ForwardMode = "allowlist" + config.Configuration.ForwardMode = "allowlist" // wildcard both: should be allowed - Configuration.ForwardAllowlist = []string{"*->*"} - log.Tracef("[test] Mode: %s, Rules: %v", Configuration.ForwardMode, Configuration.ForwardAllowlist) + config.Configuration.ForwardAllowlist = []string{"*->*"} + log.Tracef("[test] Mode: %s, Rules: %v", config.Configuration.ForwardMode, config.Configuration.ForwardAllowlist) key := &routerrpc.CircuitKey{ ChanId: 123456789876543210, @@ -452,8 +452,8 @@ func TestChannelAllowlist_CorrectKey(t *testing.T) { app := NewApp(ctx, client) - Configuration.ChannelMode = "allowlist" - Configuration.ChannelAllowlist = []string{"03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"} + config.Configuration.ChannelMode = "allowlist" + config.Configuration.ChannelAllowlist = []string{"03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"} app.DispatchChannelAcceptor(ctx) @@ -476,8 +476,8 @@ func TestChannelAllowlist_WrongKey(t *testing.T) { app := NewApp(ctx, client) - Configuration.ChannelMode = "allowlist" - Configuration.ChannelAllowlist = []string{"03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"} + config.Configuration.ChannelMode = "allowlist" + config.Configuration.ChannelAllowlist = []string{"03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"} app.DispatchChannelAcceptor(ctx) // wrong key: should be denied @@ -501,8 +501,8 @@ func TestChannelAllowlist_Wildcard(t *testing.T) { app.DispatchChannelAcceptor(ctx) // wildcard: should be allowed - Configuration.ChannelMode = "allowlist" - Configuration.ChannelAllowlist = []string{"*"} + config.Configuration.ChannelMode = "allowlist" + config.Configuration.ChannelAllowlist = []string{"*"} client.channelAcceptorRequests <- &lnrpc.ChannelAcceptRequest{ NodePubkey: []byte("03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"), @@ -521,8 +521,8 @@ func TestChannelDenylist_Match(t *testing.T) { app := NewApp(ctx, client) - Configuration.ChannelMode = "denylist" - Configuration.ChannelDenylist = []string{"03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"} + config.Configuration.ChannelMode = "denylist" + config.Configuration.ChannelDenylist = []string{"03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"} app.DispatchChannelAcceptor(ctx) @@ -545,8 +545,8 @@ func TestChannelAllowlist_Match(t *testing.T) { app := NewApp(ctx, client) - Configuration.ChannelMode = "allowlist" - Configuration.ChannelAllowlist = []string{"03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"} + config.Configuration.ChannelMode = "allowlist" + config.Configuration.ChannelAllowlist = []string{"03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"} app.DispatchChannelAcceptor(ctx) diff --git a/rules/HtlcForward.js b/rules/HtlcForward.js index 40e9a6d..fdc66bd 100644 --- a/rules/HtlcForward.js +++ b/rules/HtlcForward.js @@ -1,4 +1,5 @@ if ( + // only forward amounts larger than 100 sat HtlcForward.Event.OutgoingAmountMsat >= 100000 ) { true } else { false } diff --git a/rules/rules.go b/rules/rules.go index da4aaa9..d549f4c 100644 --- a/rules/rules.go +++ b/rules/rules.go @@ -4,12 +4,18 @@ import ( "fmt" "os" + "github.com/callebtc/electronwall/config" "github.com/callebtc/electronwall/types" "github.com/dop251/goja" log "github.com/sirupsen/logrus" ) func Apply(s interface{}, decision_chan chan bool) (accept bool, err error) { + + if !config.Configuration.ApiRules.Apply { + return true, nil + } + vm := goja.New() var js_script []byte @@ -41,5 +47,6 @@ func Apply(s interface{}, decision_chan chan bool) (accept bool, err error) { accept = v.Export().(bool) decision_chan <- accept + log.Infof("[rules] decision: %t", accept) return accept, nil } From 24edbfd31e11df6dbbc78420a4fcb49df53e0286 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Wed, 31 Aug 2022 14:14:46 +0200 Subject: [PATCH 5/6] forgot types --- types/types.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 types/types.go diff --git a/types/types.go b/types/types.go new file mode 100644 index 0000000..cb745ba --- /dev/null +++ b/types/types.go @@ -0,0 +1,24 @@ +package types + +import ( + "github.com/callebtc/electronwall/api" + "github.com/lightningnetwork/lnd/lnrpc" + "github.com/lightningnetwork/lnd/lnrpc/routerrpc" +) + +type HtlcForwardEvent struct { + PubkeyFrom string + AliasFrom string + PubkeyTo string + AliasTo string + Event *routerrpc.ForwardHtlcInterceptRequest +} + +type ChannelAcceptEvent struct { + PubkeyFrom string + AliasFrom string + Event *lnrpc.ChannelAcceptRequest + NodeInfo *lnrpc.NodeInfo + OneMl api.OneML_NodeInfoResponse + Amboss api.Amboss_NodeInfoResponse +} From 60eb2792d22e28f46c68b1fee2ac4b65b0dea4d5 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Wed, 31 Aug 2022 14:42:48 +0200 Subject: [PATCH 6/6] fix test --- main_test.go | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/main_test.go b/main_test.go index a635f50..64e1483 100644 --- a/main_test.go +++ b/main_test.go @@ -2,12 +2,14 @@ package main import ( "context" + "encoding/hex" + "testing" + "github.com/callebtc/electronwall/config" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" - "testing" ) func TestApp(t *testing.T) { @@ -451,16 +453,16 @@ func TestChannelAllowlist_CorrectKey(t *testing.T) { defer cancel() app := NewApp(ctx, client) - + pubkey_str := "03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6" config.Configuration.ChannelMode = "allowlist" - config.Configuration.ChannelAllowlist = []string{"03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"} + config.Configuration.ChannelAllowlist = []string{pubkey_str} app.DispatchChannelAcceptor(ctx) // correct key: should be allowed - + pubkey, _ := hex.DecodeString(pubkey_str) client.channelAcceptorRequests <- &lnrpc.ChannelAcceptRequest{ - NodePubkey: []byte("03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"), + NodePubkey: pubkey, FundingAmt: 1337000, PendingChanId: []byte("759495353533530113"), } @@ -476,8 +478,9 @@ func TestChannelAllowlist_WrongKey(t *testing.T) { app := NewApp(ctx, client) + pubkey_str := "03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6" config.Configuration.ChannelMode = "allowlist" - config.Configuration.ChannelAllowlist = []string{"03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"} + config.Configuration.ChannelAllowlist = []string{pubkey_str} app.DispatchChannelAcceptor(ctx) // wrong key: should be denied @@ -500,12 +503,14 @@ func TestChannelAllowlist_Wildcard(t *testing.T) { app.DispatchChannelAcceptor(ctx) + pubkey_str := "03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6" // wildcard: should be allowed config.Configuration.ChannelMode = "allowlist" config.Configuration.ChannelAllowlist = []string{"*"} + pubkey, _ := hex.DecodeString(pubkey_str) client.channelAcceptorRequests <- &lnrpc.ChannelAcceptRequest{ - NodePubkey: []byte("03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"), + NodePubkey: pubkey, FundingAmt: 1337000, PendingChanId: []byte("759495353533530113"), } @@ -520,16 +525,16 @@ func TestChannelDenylist_Match(t *testing.T) { defer cancel() app := NewApp(ctx, client) - + pubkey_str := "03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6" config.Configuration.ChannelMode = "denylist" - config.Configuration.ChannelDenylist = []string{"03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"} + config.Configuration.ChannelDenylist = []string{pubkey_str} app.DispatchChannelAcceptor(ctx) // should be denied - + pubkey, _ := hex.DecodeString(pubkey_str) client.channelAcceptorRequests <- &lnrpc.ChannelAcceptRequest{ - NodePubkey: []byte("03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"), + NodePubkey: []byte(pubkey), FundingAmt: 1337000, PendingChanId: []byte("759495353533530113"), } @@ -544,15 +549,16 @@ func TestChannelAllowlist_Match(t *testing.T) { defer cancel() app := NewApp(ctx, client) - + pubkey_str := "03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6" config.Configuration.ChannelMode = "allowlist" - config.Configuration.ChannelAllowlist = []string{"03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"} + config.Configuration.ChannelAllowlist = []string{pubkey_str} app.DispatchChannelAcceptor(ctx) // should be allowed + pubkey, _ := hex.DecodeString(pubkey_str) client.channelAcceptorRequests <- &lnrpc.ChannelAcceptRequest{ - NodePubkey: []byte("03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"), + NodePubkey: []byte(pubkey), FundingAmt: 1337000, PendingChanId: []byte("759495353533530113"), }