diff --git a/go.mod b/go.mod index 6ec34941..1e87ba21 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,7 @@ module github.com/lightninglabs/lightning-terminal require ( + github.com/btcsuite/btcd v0.22.0-beta.0.20211005184431-e3449998be39 github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f github.com/btcsuite/btcutil v1.0.3-0.20210527170813-e2ba6805a890 github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect @@ -8,6 +9,7 @@ require ( github.com/improbable-eng/grpc-web v0.12.0 github.com/jessevdk/go-flags v1.4.0 github.com/lightninglabs/faraday v0.2.7-alpha + github.com/lightninglabs/lightning-node-connect v0.1.4-alpha github.com/lightninglabs/lndclient v0.14.0-5 github.com/lightninglabs/loop v0.15.1-beta github.com/lightninglabs/pool v0.5.2-alpha @@ -16,9 +18,11 @@ require ( github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76 github.com/rs/cors v1.7.0 // indirect + github.com/stretchr/testify v1.7.0 + go.etcd.io/bbolt v1.3.6 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 - google.golang.org/grpc v1.38.0 - google.golang.org/protobuf v1.26.0 + google.golang.org/grpc v1.39.0 + google.golang.org/protobuf v1.27.1 gopkg.in/macaroon-bakery.v2 v2.1.0 gopkg.in/macaroon.v2 v2.1.0 ) diff --git a/go.sum b/go.sum index 688be089..1f0afdf4 100644 --- a/go.sum +++ b/go.sum @@ -80,6 +80,8 @@ github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13P github.com/btcsuite/btcd v0.20.1-beta.0.20200513120220-b470eee47728/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.20.1-beta.0.20200730232343-1db1b6f8217f/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= github.com/btcsuite/btcd v0.21.0-beta.0.20201208033208-6bd4c64a54fa/go.mod h1:Sv4JPQ3/M+teHz9Bo5jBpkNcP0x6r7rdihlNL/7tTAs= +github.com/btcsuite/btcd v0.21.0-beta.0.20210426180113-7eba688b65e5/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA= +github.com/btcsuite/btcd v0.21.0-beta.0.20210513141527-ee5896bad5be/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA= github.com/btcsuite/btcd v0.22.0-beta.0.20210803133449-f5a1fb9965e4/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA= github.com/btcsuite/btcd v0.22.0-beta.0.20211005184431-e3449998be39 h1:o6qacOzpKubr16y0RrE2fBauRZN1rDZ1YsE26ixCgQ0= github.com/btcsuite/btcd v0.22.0-beta.0.20211005184431-e3449998be39/go.mod h1:3PH+KbvLFfzBTCevQenPiDedjGQGt6aa70dVjJDWGTA= @@ -97,15 +99,18 @@ github.com/btcsuite/btcutil/psbt v1.0.3-0.20210527170813-e2ba6805a890 h1:0xUNvvw github.com/btcsuite/btcutil/psbt v1.0.3-0.20210527170813-e2ba6805a890/go.mod h1:LVveMu4VaNSkIRTZu2+ut0HDBRuYjqGocxDMNS1KuGQ= github.com/btcsuite/btcwallet v0.11.1-0.20200814001439-1d31f4ea6fc5/go.mod h1:YkEbJaCyN6yncq5gEp2xG0OKDwus2QxGCEXTNF27w5I= github.com/btcsuite/btcwallet v0.11.1-0.20200904022754-2c5947a45222/go.mod h1:owv9oZqM0HnUW+ByF7VqOgfs2eb0ooiePW/+Tl/i/Nk= +github.com/btcsuite/btcwallet v0.12.1-0.20210519225359-6ab9b615576f/go.mod h1:f1HuBGov5+OTp40Gh1vA+tvF6d7bbuLFTceJMRB7fXw= github.com/btcsuite/btcwallet v0.13.0 h1:gtLWwueRm27KQiHJpycybv3uMdK1eo87JexfTfzvEhk= github.com/btcsuite/btcwallet v0.13.0/go.mod h1:iLN1lG1MW0eREm+SikmPO8AZPz5NglBTEK/ErqkjGpo= github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0/go.mod h1:VufDts7bd/zs3GV13f/lXc/0lXrPnvxD/NvmpG/FEKU= +github.com/btcsuite/btcwallet/wallet/txauthor v1.0.1-0.20210519225359-6ab9b615576f/go.mod h1:VufDts7bd/zs3GV13f/lXc/0lXrPnvxD/NvmpG/FEKU= github.com/btcsuite/btcwallet/wallet/txauthor v1.1.0 h1:8pO0pvPX1rFRfRiol4oV6kX7dY5y4chPwhfVwUfvwtk= github.com/btcsuite/btcwallet/wallet/txauthor v1.1.0/go.mod h1:ktYuJyumYtwG+QQ832Q+kqvxWJRAei3Nqs5qhSn4nww= github.com/btcsuite/btcwallet/wallet/txrules v1.0.0/go.mod h1:UwQE78yCerZ313EXZwEiu3jNAtfXj2n2+c8RWiE/WNA= github.com/btcsuite/btcwallet/wallet/txrules v1.1.0 h1:Vg8G8zhNVjaCdwJg2QOmLoWn4RTP7K0J9xlwY8CJnLY= github.com/btcsuite/btcwallet/wallet/txrules v1.1.0/go.mod h1:Zn9UTqpiTH+HOd5BLzSBzULzlOPmcoeyQIA0cp0WbQQ= github.com/btcsuite/btcwallet/wallet/txsizes v1.0.0/go.mod h1:pauEU8UuMFiThe5PB3EO+gO5kx87Me5NvdQDsTuq6cs= +github.com/btcsuite/btcwallet/wallet/txsizes v1.0.1-0.20210519225359-6ab9b615576f/go.mod h1:pauEU8UuMFiThe5PB3EO+gO5kx87Me5NvdQDsTuq6cs= github.com/btcsuite/btcwallet/wallet/txsizes v1.1.0 h1:wZnOolEAeNOHzHTnznw/wQv+j35ftCIokNrnOTOU5o8= github.com/btcsuite/btcwallet/wallet/txsizes v1.1.0/go.mod h1:pauEU8UuMFiThe5PB3EO+gO5kx87Me5NvdQDsTuq6cs= github.com/btcsuite/btcwallet/walletdb v1.0.0/go.mod h1:bZTy9RyYZh9fLnSua+/CD48TJtYJSHjjYcSaszuxCCk= @@ -119,6 +124,7 @@ github.com/btcsuite/btcwallet/walletdb v1.3.6-0.20210803004036-eebed51155ec/go.m github.com/btcsuite/btcwallet/wtxmgr v1.0.0/go.mod h1:vc4gBprll6BP0UJ+AIGDaySoc7MdAmZf8kelfNb8CFY= github.com/btcsuite/btcwallet/wtxmgr v1.2.0/go.mod h1:h8hkcKUE3X7lMPzTUoGnNiw5g7VhGrKEW3KpR2r0VnY= github.com/btcsuite/btcwallet/wtxmgr v1.3.0/go.mod h1:awQsh1n/0ZrEQ+JZgWvHeo153ubzEisf/FyNtwI0dDk= +github.com/btcsuite/btcwallet/wtxmgr v1.3.1-0.20210706234807-aaf03fee735a/go.mod h1:UM38ixX8VwJ9qey4umf//0H3ndn5kSImFZ46V54Nd5Q= github.com/btcsuite/btcwallet/wtxmgr v1.3.1-0.20210822222949-9b5a201c344c h1:owWPexGfK4eSK4/Zy+XK2lET5qsnW7FRAc8OCOdD0Fg= github.com/btcsuite/btcwallet/wtxmgr v1.3.1-0.20210822222949-9b5a201c344c/go.mod h1:UM38ixX8VwJ9qey4umf//0H3ndn5kSImFZ46V54Nd5Q= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= @@ -148,6 +154,7 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5 h1:xD/lrqdvwsc+O2bjSSi3YqY73Ke3LAiSCx49aCesA0E= @@ -200,6 +207,7 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fergusstrange/embedded-postgres v1.10.0 h1:YnwF6xAQYmKLAXXrrRx4rHDLih47YJwVPvg8jeKfdNg= @@ -216,6 +224,10 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= 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= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -231,8 +243,21 @@ github.com/go-openapi/errors v0.19.2 h1:a2kIyV3w+OS3S97zxUndRVD46+FhGOUBDFY7nmu4 github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= github.com/go-openapi/strfmt v0.19.5 h1:0utjKrw+BAh8s57XE9Xz8DUBsVvPmRUB6styvl9wWIM= github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -314,6 +339,7 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= @@ -449,6 +475,7 @@ github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec/go.mod h1:J+Gs4SYgM6 github.com/kkdai/bstream v1.0.0 h1:Se5gHwgp2VT2uHfDrkbbgbgEvV9cimLELwrPJctSjg8= github.com/kkdai/bstream v1.0.0/go.mod h1:FDnDOHt5Yx4p3FaHcioFT0QjDOtgUpvjeZqAs+NVZZA= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= @@ -467,6 +494,8 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -480,6 +509,10 @@ github.com/lightninglabs/faraday v0.2.7-alpha h1:lpSUk3RFfgr4/OCx1OdJ2AMHCAiTObK github.com/lightninglabs/faraday v0.2.7-alpha/go.mod h1:77P9EctYhneIXLvm9a6ylV9LCht/rj7j8mLwXpBgxB8= github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf h1:HZKvJUHlcXI/f/O0Avg7t8sqkPo78HFzjmeYFl6DPnc= github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk= +github.com/lightninglabs/lightning-node-connect v0.1.4-alpha h1:VliyPUSNjMvsoAbZB0GrYFdw+vgGoKOU2hX0sQmu+W4= +github.com/lightninglabs/lightning-node-connect v0.1.4-alpha/go.mod h1:LoKbA6vIrFi8hEBpK4czH66Lp+BK5A8e0wv7DSX64+o= +github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.1 h1:L4R+mg/9ExCuLxgZCpL+ZmdLOzDCvvgK7nmFqXA1FfY= +github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.1/go.mod h1:antQGRDRJiuyQF6l+k6NECCSImgCpwaZapATth2Chv4= github.com/lightninglabs/lndclient v0.11.0-4/go.mod h1:8/cTKNwgL87NX123gmlv3Xh6p1a7pvzu+40Un3PhHiI= github.com/lightninglabs/lndclient v0.14.0-5 h1:dI2/Y2fn9m5VuwMTd/DcF6y0DYdMy3pk0MPu4xNjj54= github.com/lightninglabs/lndclient v0.14.0-5/go.mod h1:2kH9vNoc29ghIkfMjxwSeK8yCxsYfR80XAJ9PU/QWWk= @@ -503,16 +536,19 @@ github.com/lightningnetwork/lightning-onion v1.0.2-0.20210520211913-522b799e65b1 github.com/lightningnetwork/lightning-onion v1.0.2-0.20210520211913-522b799e65b1/go.mod h1:rigfi6Af/KqsF7Za0hOgcyq2PNH4AN70AaMRxcJkff4= github.com/lightningnetwork/lnd v0.11.0-beta/go.mod h1:CzArvT7NFDLhVyW06+NJWSuWFmE6Ea+AjjA3txUBqTM= github.com/lightningnetwork/lnd v0.11.1-beta/go.mod h1:PGIgxy8aH70Li33YVYkHSaCM8m8LjEevk5h1Dpldrr4= +github.com/lightningnetwork/lnd v0.13.0-beta.rc5.0.20210728112744-ebabda671786/go.mod h1:3cmukt9wR4PX1va9Q78gmqSPYd6yhV1wcFemM5F+kT8= github.com/lightningnetwork/lnd v0.14.0-beta h1:q9ExaoRD7+Pv5UKbxBaszkAOX9pZrxre1YzEEq3pveY= github.com/lightningnetwork/lnd v0.14.0-beta/go.mod h1:qqOImM4QBKeIXsmUUsJznAbAaEF9iAPHAwfBZf9ld4Y= github.com/lightningnetwork/lnd/cert v1.0.2/go.mod h1:fmtemlSMf5t4hsQmcprSoOykypAPp+9c+0d0iqTScMo= github.com/lightningnetwork/lnd/cert v1.0.2/go.mod h1:fmtemlSMf5t4hsQmcprSoOykypAPp+9c+0d0iqTScMo= +github.com/lightningnetwork/lnd/cert v1.0.3/go.mod h1:3MWXVLLPI0Mg0XETm9fT4N9Vyy/8qQLmaM5589bEggM= github.com/lightningnetwork/lnd/cert v1.1.0 h1:Vgmse23SOB/ODIj+I5Utq1yuKLPbWQ34gUoNKfDs4pk= github.com/lightningnetwork/lnd/cert v1.1.0/go.mod h1:3MWXVLLPI0Mg0XETm9fT4N9Vyy/8qQLmaM5589bEggM= github.com/lightningnetwork/lnd/clock v1.0.1/go.mod h1:KnQudQ6w0IAMZi1SgvecLZQZ43ra2vpDNj7H/aasemg= github.com/lightningnetwork/lnd/clock v1.1.0 h1:/yfVAwtPmdx45aQBoXQImeY7sOIEr7IXlImRMBOZ7GQ= github.com/lightningnetwork/lnd/clock v1.1.0/go.mod h1:KnQudQ6w0IAMZi1SgvecLZQZ43ra2vpDNj7H/aasemg= github.com/lightningnetwork/lnd/healthcheck v1.0.0/go.mod h1:u92p1JGFJNMSkMvztKEwmt1P3TRnLeJBXZ3M85xkU1E= +github.com/lightningnetwork/lnd/healthcheck v1.0.2/go.mod h1:u92p1JGFJNMSkMvztKEwmt1P3TRnLeJBXZ3M85xkU1E= github.com/lightningnetwork/lnd/healthcheck v1.2.0 h1:00bkNn+hGJM9j3Ht+ulf8YNcSx1HEYSDv5pf4HB1/uQ= github.com/lightningnetwork/lnd/healthcheck v1.2.0/go.mod h1:WSz3lsUjErJQZ3gb+zW32nM3WIHNiZ3A40GVoaQY5wU= github.com/lightningnetwork/lnd/kvdb v1.2.1 h1:QevYLPh6bh1SLIvlUaPbrpX/YMKzSPBfmGVvn2i8IlU= @@ -534,6 +570,7 @@ github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= @@ -543,6 +580,7 @@ github.com/mholt/archiver/v3 v3.5.0 h1:nE8gZIrw66cu4osS/U7UW7YDuGMHssxKutU8IfWxw github.com/mholt/archiver/v3 v3.5.0/go.mod h1:qqTTPUK/HZPFgFQ/TJ3BzvTpF/dPtFVJXdQbCmeMxwc= github.com/miekg/dns v0.0.0-20171125082028-79bfde677fa8/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg= github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -669,6 +707,10 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4 github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/zbase32 v0.0.0-20160707012821-501572607d02 h1:tcJ6OjwOMvExLlzrAVZute09ocAGa7KqOON60++Gz4E= github.com/tv42/zbase32 v0.0.0-20160707012821-501572607d02/go.mod h1:tHlrkM198S068ZqfrO6S8HsoJq2bF3ETfTL+kt4tInY= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= @@ -770,6 +812,7 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -838,6 +881,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -901,6 +945,8 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/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-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -974,6 +1020,7 @@ golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1097,8 +1144,9 @@ google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0 h1:Klz8I9kdtkIN6EpHHUOMLCYhTn/2WAe5a0s1hcBkdTI= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1110,8 +1158,9 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1158,6 +1207,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= +nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/litrpc/lit-sessions.pb.go b/litrpc/lit-sessions.pb.go index 0e3a3e1a..fe2ed19e 100644 --- a/litrpc/lit-sessions.pb.go +++ b/litrpc/lit-sessions.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 +// protoc-gen-go v1.27.1 // protoc v3.6.1 // source: lit-sessions.proto diff --git a/session/db.go b/session/db.go new file mode 100644 index 00000000..52a14114 --- /dev/null +++ b/session/db.go @@ -0,0 +1,113 @@ +package session + +import ( + "encoding/binary" + "fmt" + "os" + "path/filepath" + "time" + + "go.etcd.io/bbolt" +) + +const ( + // DBFilename is the default filename of the session database. + DBFilename = "session.db" + + // dbFilePermission is the default permission the session database file + // is created with. + dbFilePermission = 0600 + + // DefaultSessionDBTimeout is the default maximum time we wait for the + // session bbolt database to be opened. If the database is already + // opened by another process, the unique lock cannot be obtained. With + // the timeout we error out after the given time instead of just + // blocking for forever. + DefaultSessionDBTimeout = 5 * time.Second +) + +var ( + // byteOrder is the default byte order we'll use for serialization + // within the database. + byteOrder = binary.BigEndian +) + +// DB is a bolt-backed persistent store. +type DB struct { + *bbolt.DB +} + +// NewDB creates a new bolt database that can be found at the given directory. +func NewDB(dir, fileName string) (*DB, error) { + firstInit := false + path := filepath.Join(dir, fileName) + + // If the database file does not exist yet, create its directory. + if !fileExists(path) { + if err := os.MkdirAll(dir, 0700); err != nil { + return nil, err + } + firstInit = true + } + + db, err := initDB(path, firstInit) + if err != nil { + return nil, err + } + + // Attempt to sync the database's current version with the latest known + // version available. + if err := syncVersions(db); err != nil { + return nil, err + } + + return &DB{DB: db}, nil +} + +// fileExists reports whether the named file or directory exists. +func fileExists(path string) bool { + if _, err := os.Stat(path); err != nil { + if os.IsNotExist(err) { + return false + } + } + return true +} + +// initDB initializes all the required top-level buckets for the database. +func initDB(filepath string, firstInit bool) (*bbolt.DB, error) { + db, err := bbolt.Open(filepath, dbFilePermission, &bbolt.Options{ + Timeout: DefaultSessionDBTimeout, + }) + if err == bbolt.ErrTimeout { + return nil, fmt.Errorf("error while trying to open %s: timed "+ + "out after %v when trying to obtain exclusive lock", + filepath, DefaultSessionDBTimeout) + } + if err != nil { + return nil, err + } + + err = db.Update(func(tx *bbolt.Tx) error { + if firstInit { + metadataBucket, err := tx.CreateBucketIfNotExists( + metadataBucketKey, + ) + if err != nil { + return err + } + err = setDBVersion(metadataBucket, latestDBVersion) + if err != nil { + return err + } + } + + _, err = tx.CreateBucketIfNotExists(sessionBucketKey) + return err + }) + if err != nil { + return nil, err + } + + return db, nil +} diff --git a/session/interface.go b/session/interface.go new file mode 100644 index 00000000..022ba6f5 --- /dev/null +++ b/session/interface.go @@ -0,0 +1,94 @@ +package session + +import ( + "encoding/binary" + "fmt" + "time" + + "github.com/btcsuite/btcd/btcec" + "github.com/lightninglabs/lightning-node-connect/mailbox" + "gopkg.in/macaroon.v2" +) + +// Type represents the type of session. +type Type uint8 + +const ( + TypeMacaroonReadonly Type = 0 + TypeMacaroonAdmin Type = 1 + TypeMacaroonCustom Type = 2 + TypeUIPassword Type = 3 +) + +// State represents the state of a session. +type State uint8 + +const ( + StateCreated State = 0 + StateInUse State = 1 + StateRevoked State = 2 + StateExpired State = 3 +) + +// Session is a struct representing a long-term Terminal Connect session. +type Session struct { + Label string + State State + Type Type + Expiry time.Time + ServerAddr string + DevServer bool + MacaroonRootKey uint64 + Macaroon *macaroon.Macaroon + PairingSecret [mailbox.NumPasswordBytes]byte + LocalPrivateKey *btcec.PrivateKey + LocalPublicKey *btcec.PublicKey + RemotePublicKey *btcec.PublicKey +} + +// NewSession creates a new session with the given user-defined parameters. +func NewSession(label string, typ Type, expiry time.Time, serverAddr string, + devServer bool) (*Session, error) { + + _, pairingSecret, err := mailbox.NewPassword() + if err != nil { + return nil, fmt.Errorf("error deriving pairing secret: %v", err) + } + + privateKey, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + return nil, fmt.Errorf("error deriving private key: %v", err) + } + pubKey := privateKey.PubKey() + macRootKey := binary.BigEndian.Uint64(pubKey.SerializeCompressed()[0:8]) + + return &Session{ + Label: label, + State: StateCreated, + Type: typ, + Expiry: expiry, + ServerAddr: serverAddr, + DevServer: devServer, + MacaroonRootKey: macRootKey, + PairingSecret: pairingSecret, + LocalPrivateKey: privateKey, + LocalPublicKey: pubKey, + RemotePublicKey: nil, + }, nil +} + +// Store is the interface a persistent storage must implement for storing and +// retrieving Terminal Connect sessions. +type Store interface { + // StoreSession stores a session in the store. If a session with the + // same local public key already exists, the existing record is updated/ + // overwritten instead. + StoreSession(*Session) error + + // ListSessions returns all sessions currently known to the store. + ListSessions() ([]*Session, error) + + // RevokeSession updates the state of the session with the given local + // public key to be revoked. + RevokeSession(*btcec.PublicKey) error +} diff --git a/session/log.go b/session/log.go new file mode 100644 index 00000000..1f0026f6 --- /dev/null +++ b/session/log.go @@ -0,0 +1,25 @@ +package session + +import ( + "github.com/btcsuite/btclog" + "github.com/lightningnetwork/lnd/build" +) + +const Subsystem = "SESS" + +// log is a logger that is initialized with no output filters. This +// means the package will not perform any logging by default until the caller +// requests it. +var log btclog.Logger + +// The default amount of logging is none. +func init() { + UseLogger(build.NewSubLogger(Subsystem, nil)) +} + +// UseLogger uses a specified Logger to output package logging info. +// This should be used in preference to SetLogWriter if the caller is also +// using btclog. +func UseLogger(logger btclog.Logger) { + log = logger +} diff --git a/session/metadata.go b/session/metadata.go new file mode 100644 index 00000000..1094eebb --- /dev/null +++ b/session/metadata.go @@ -0,0 +1,122 @@ +package session + +import ( + "errors" + "fmt" + + "go.etcd.io/bbolt" +) + +// migration is a function which takes a prior outdated version of the database +// instance and mutates the key/bucket structure to arrive at a more up-to-date +// version of the database. +type migration func(tx *bbolt.Tx) error + +var ( + // metadataBucketKey stores all the metadata concerning the state of the + // database. + metadataBucketKey = []byte("metadata") + + // dbVersionKey is the key used for storing/retrieving the current + // database version. + dbVersionKey = []byte("version") + + // ErrDBReversion is returned when detecting an attempt to revert to a + // prior database version. + ErrDBReversion = errors.New("cannot revert to prior version") + + // dbVersions is storing all versions of database. If the current + // version of the database doesn't match the latest version this list + // will be used for retrieving all migration function that are need to + // apply to the current db. + dbVersions []migration + + latestDBVersion = uint32(len(dbVersions)) +) + +// getDBVersion retrieves the current database version. +func getDBVersion(bucket *bbolt.Bucket) (uint32, error) { + versionBytes := bucket.Get(dbVersionKey) + if versionBytes == nil { + return 0, errors.New("database version not found") + } + return byteOrder.Uint32(versionBytes), nil +} + +// setDBVersion updates the current database version. +func setDBVersion(bucket *bbolt.Bucket, version uint32) error { + var b [4]byte + byteOrder.PutUint32(b[:], version) + return bucket.Put(dbVersionKey, b[:]) +} + +// getBucket retrieves the bucket with the given key. +func getBucket(tx *bbolt.Tx, key []byte) (*bbolt.Bucket, error) { + bucket := tx.Bucket(key) + if bucket == nil { + return nil, fmt.Errorf("bucket \"%v\" does not exist", + string(key)) + } + return bucket, nil +} + +// syncVersions function is used for safe db version synchronization. It +// applies migration functions to the current database and recovers the +// previous state of db if at least one error/panic appeared during migration. +func syncVersions(db *bbolt.DB) error { + var currentVersion uint32 + err := db.View(func(tx *bbolt.Tx) error { + metadata, err := getBucket(tx, metadataBucketKey) + if err != nil { + return err + } + currentVersion, err = getDBVersion(metadata) + return err + }) + if err != nil { + return err + } + + log.Infof("Checking for schema update: latest_version=%v, "+ + "db_version=%v", latestDBVersion, currentVersion) + + switch { + + // If the database reports a higher version that we are aware of, the + // user is probably trying to revert to a prior version of lnd. We fail + // here to prevent reversions and unintended corruption. + case currentVersion > latestDBVersion: + log.Errorf("Refusing to revert from db_version=%d to "+ + "lower version=%d", currentVersion, + latestDBVersion) + + return ErrDBReversion + + // If the current database version matches the latest version number, + // then we don't need to perform any migrations. + case currentVersion == latestDBVersion: + return nil + } + + log.Infof("Performing database schema migration") + + // Otherwise, we execute the migrations serially within a single + // database transaction to ensure the migration is atomic. + return db.Update(func(tx *bbolt.Tx) error { + for v := currentVersion; v < latestDBVersion; v++ { + log.Infof("Applying migration #%v", v+1) + + migration := dbVersions[v] + if err := migration(tx); err != nil { + log.Infof("Unable to apply migration #%v", v+1) + return err + } + } + + metadata, err := getBucket(tx, metadataBucketKey) + if err != nil { + return err + } + return setDBVersion(metadata, latestDBVersion) + }) +} diff --git a/session/server.go b/session/server.go new file mode 100644 index 00000000..da3dfb81 --- /dev/null +++ b/session/server.go @@ -0,0 +1,127 @@ +package session + +import ( + "crypto/tls" + "fmt" + "sync" + + "github.com/btcsuite/btcd/btcec" + "github.com/lightninglabs/lightning-node-connect/mailbox" + "github.com/lightningnetwork/lnd/keychain" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" +) + +type sessionID [33]byte + +type GRPCServerCreator func(opts ...grpc.ServerOption) *grpc.Server + +type mailboxSession struct { + server *grpc.Server + + wg sync.WaitGroup +} + +func (m *mailboxSession) start(session *Session, + serverCreator GRPCServerCreator, authData []byte) error { + + tlsConfig := &tls.Config{} + if session.DevServer { + tlsConfig = &tls.Config{InsecureSkipVerify: true} + } + + // Start the mailbox gRPC server. + mailboxServer, err := mailbox.NewServer( + session.ServerAddr, session.PairingSecret[:], + grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)), + ) + if err != nil { + return err + } + + ecdh := &keychain.PrivKeyECDH{PrivKey: session.LocalPrivateKey} + noiseConn := mailbox.NewNoiseGrpcConn( + ecdh, authData, session.PairingSecret[:], + ) + m.server = serverCreator(grpc.Creds(noiseConn)) + + m.wg.Add(1) + go m.run(mailboxServer) + + return nil +} + +func (m *mailboxSession) run(mailboxServer *mailbox.Server) { + defer m.wg.Done() + + log.Infof("Mailbox RPC server listening on %s", mailboxServer.Addr()) + if err := m.server.Serve(mailboxServer); err != nil { + log.Errorf("Unable to serve mailbox gRPC: %v", err) + } +} + +func (m *mailboxSession) stop() { + m.server.Stop() + m.wg.Wait() +} + +type Server struct { + serverCreator GRPCServerCreator + + activeSessions map[sessionID]*mailboxSession + activeSessionsMtx sync.Mutex + + quit chan struct{} +} + +func NewServer(serverCreator GRPCServerCreator) *Server { + return &Server{ + serverCreator: serverCreator, + activeSessions: make(map[sessionID]*mailboxSession), + quit: make(chan struct{}), + } +} + +func (s *Server) StartSession(session *Session, authData []byte) error { + s.activeSessionsMtx.Lock() + defer s.activeSessionsMtx.Unlock() + + var id sessionID + copy(id[:], session.LocalPublicKey.SerializeCompressed()) + + _, ok := s.activeSessions[id] + if ok { + return fmt.Errorf("session %x is already active", id[:]) + } + + s.activeSessions[id] = &mailboxSession{} + return s.activeSessions[id].start(session, s.serverCreator, authData) +} + +func (s *Server) StopSession(localPublicKey *btcec.PublicKey) error { + s.activeSessionsMtx.Lock() + defer s.activeSessionsMtx.Unlock() + + var id sessionID + copy(id[:], localPublicKey.SerializeCompressed()) + + _, ok := s.activeSessions[id] + if !ok { + return fmt.Errorf("session %x is not active", id[:]) + } + + s.activeSessions[id].stop() + delete(s.activeSessions, id) + + return nil +} + +func (s *Server) Stop() { + s.activeSessionsMtx.Lock() + defer s.activeSessionsMtx.Unlock() + + for id, session := range s.activeSessions { + session.stop() + delete(s.activeSessions, id) + } +} diff --git a/session/store.go b/session/store.go new file mode 100644 index 00000000..e4c8fa3d --- /dev/null +++ b/session/store.go @@ -0,0 +1,104 @@ +package session + +import ( + "bytes" + "errors" + + "github.com/btcsuite/btcd/btcec" + "go.etcd.io/bbolt" +) + +var ( + // sessionBucketKey is the top level bucket where we can find all + // information about sessions. These sessions are indexed by their + // public key. + sessionBucketKey = []byte("session") + + // ErrSessionNotFound is an error returned when we attempt to retrieve + // information about a session but it is not found. + ErrSessionNotFound = errors.New("session not found") +) + +// getSessionKey returns the key for a session. +func getSessionKey(session *Session) []byte { + return session.LocalPublicKey.SerializeCompressed() +} + +// StoreSession stores a session in the store. If a session with the +// same local public key already exists, the existing record is updated/ +// overwritten instead. +func (db *DB) StoreSession(session *Session) error { + var buf bytes.Buffer + if err := SerializeSession(&buf, session); err != nil { + return err + } + sessionKey := getSessionKey(session) + + return db.Update(func(tx *bbolt.Tx) error { + sessionBucket, err := getBucket(tx, sessionBucketKey) + if err != nil { + return err + } + + return sessionBucket.Put(sessionKey, buf.Bytes()) + }) +} + +// ListSessions returns all sessions currently known to the store. +func (db *DB) ListSessions() ([]*Session, error) { + var sessions []*Session + err := db.View(func(tx *bbolt.Tx) error { + sessionBucket, err := getBucket(tx, sessionBucketKey) + if err != nil { + return err + } + + return sessionBucket.ForEach(func(k, v []byte) error { + // We'll also get buckets here, skip those (identified + // by nil value). + if v == nil { + return nil + } + + session, err := DeserializeSession(bytes.NewReader(v)) + if err != nil { + return err + } + sessions = append(sessions, session) + + return nil + }) + }) + + if err != nil { + return nil, err + } + + return sessions, nil +} + +// RevokeSession updates the state of the session with the given local +// public key to be revoked. +func (db *DB) RevokeSession(key *btcec.PublicKey) error { + var session *Session + err := db.View(func(tx *bbolt.Tx) error { + sessionBucket, err := getBucket(tx, sessionBucketKey) + if err != nil { + return err + } + + sessionBytes := sessionBucket.Get(key.SerializeCompressed()) + if len(sessionBytes) == 0 { + return ErrSessionNotFound + } + + session, err = DeserializeSession(bytes.NewReader(sessionBytes)) + return err + }) + if err != nil { + return err + } + + session.State = StateRevoked + return db.StoreSession(session) +} diff --git a/session/tlv.go b/session/tlv.go new file mode 100644 index 00000000..de96506d --- /dev/null +++ b/session/tlv.go @@ -0,0 +1,154 @@ +package session + +import ( + "fmt" + "io" + "time" + + "github.com/btcsuite/btcd/btcec" + "github.com/lightningnetwork/lnd/tlv" + "gopkg.in/macaroon.v2" +) + +const ( + typeLabel tlv.Type = 1 + typeState tlv.Type = 2 + typeType tlv.Type = 3 + typeExpiry tlv.Type = 4 + typeServerAddr tlv.Type = 5 + typeDevServer tlv.Type = 6 + typeMacaroonRootKey tlv.Type = 7 + typeMacaroon tlv.Type = 8 + typePairingSecret tlv.Type = 9 + typeLocalPrivateKey tlv.Type = 10 + typeRemotePublicKey tlv.Type = 11 +) + +// SerializeSession binary serializes the given session to the writer using the +// tlv format. +func SerializeSession(w io.Writer, session *Session) error { + if session == nil { + return fmt.Errorf("session cannot be nil") + } + + var ( + label = []byte(session.Label) + state = uint8(session.State) + typ = uint8(session.Type) + expiry = uint64(session.Expiry.UnixNano()) + serverAddr = []byte(session.ServerAddr) + devServer = uint8(0) + pairingSecret = session.PairingSecret[:] + privateKey = session.LocalPrivateKey.Serialize() + ) + + if session.DevServer { + devServer = 1 + } + + tlvRecords := []tlv.Record{ + tlv.MakePrimitiveRecord(typeLabel, &label), + tlv.MakePrimitiveRecord(typeState, &state), + tlv.MakePrimitiveRecord(typeType, &typ), + tlv.MakePrimitiveRecord(typeExpiry, &expiry), + tlv.MakePrimitiveRecord(typeServerAddr, &serverAddr), + tlv.MakePrimitiveRecord(typeDevServer, &devServer), + tlv.MakePrimitiveRecord( + typeMacaroonRootKey, &session.MacaroonRootKey, + ), + } + + if session.Macaroon != nil { + macaroonBytes, err := session.Macaroon.MarshalBinary() + if err != nil { + return fmt.Errorf("error marshaling macaroon: %v", err) + } + + tlvRecords = append(tlvRecords, tlv.MakePrimitiveRecord( + typeMacaroon, &macaroonBytes), + ) + } + + tlvRecords = append( + tlvRecords, + tlv.MakePrimitiveRecord(typePairingSecret, &pairingSecret), + tlv.MakePrimitiveRecord(typeLocalPrivateKey, &privateKey), + ) + + if session.RemotePublicKey != nil { + tlvRecords = append(tlvRecords, tlv.MakePrimitiveRecord( + typeRemotePublicKey, &session.RemotePublicKey, + )) + } + + tlvStream, err := tlv.NewStream(tlvRecords...) + if err != nil { + return err + } + + return tlvStream.Encode(w) +} + +// DeserializeSession deserializes a session from the given reader, expecting +// the data to be encoded in the tlv format. +func DeserializeSession(r io.Reader) (*Session, error) { + var ( + session = &Session{} + label, serverAddr, macaroonBytes []byte + pairingSecret, privateKey []byte + state, typ, devServer uint8 + expiry uint64 + ) + tlvStream, err := tlv.NewStream( + tlv.MakePrimitiveRecord(typeLabel, &label), + tlv.MakePrimitiveRecord(typeState, &state), + tlv.MakePrimitiveRecord(typeType, &typ), + tlv.MakePrimitiveRecord(typeExpiry, &expiry), + tlv.MakePrimitiveRecord(typeServerAddr, &serverAddr), + tlv.MakePrimitiveRecord(typeDevServer, &devServer), + tlv.MakePrimitiveRecord( + typeMacaroonRootKey, &session.MacaroonRootKey, + ), + tlv.MakePrimitiveRecord(typeMacaroon, &macaroonBytes), + tlv.MakePrimitiveRecord(typePairingSecret, &pairingSecret), + tlv.MakePrimitiveRecord(typeLocalPrivateKey, &privateKey), + tlv.MakePrimitiveRecord( + typeRemotePublicKey, &session.RemotePublicKey, + ), + ) + if err != nil { + return nil, err + } + + parsedTypes, err := tlvStream.DecodeWithParsedTypes(r) + if err != nil { + return nil, err + } + + session.Label = string(label) + session.State = State(state) + session.Type = Type(typ) + session.Expiry = time.Unix(0, int64(expiry)) + session.ServerAddr = string(serverAddr) + session.DevServer = devServer == 1 + + if t, ok := parsedTypes[typeMacaroon]; ok && t == nil { + session.Macaroon = &macaroon.Macaroon{} + err := session.Macaroon.UnmarshalBinary(macaroonBytes) + if err != nil { + return nil, err + } + } + + if t, ok := parsedTypes[typePairingSecret]; ok && t == nil { + copy(session.PairingSecret[:], pairingSecret) + } + + if t, ok := parsedTypes[typeLocalPrivateKey]; ok && t == nil { + session.LocalPrivateKey, session.LocalPublicKey = btcec.PrivKeyFromBytes( + btcec.S256(), privateKey, + ) + } + + return session, nil +} diff --git a/session/tlv_test.go b/session/tlv_test.go new file mode 100644 index 00000000..57b2cbeb --- /dev/null +++ b/session/tlv_test.go @@ -0,0 +1,61 @@ +package session + +import ( + "bytes" + "github.com/btcsuite/btcd/btcec" + "testing" + "time" + + "github.com/stretchr/testify/require" + "gopkg.in/macaroon.v2" +) + +var ( + testRootKey = []byte("54321") + testID = []byte("dummyId") + testLocation = "lnd" + testVersion = macaroon.LatestVersion +) + +func createDummyMacaroon(t *testing.T) *macaroon.Macaroon { + dummyMacaroon, err := macaroon.New( + testRootKey, testID, testLocation, testVersion, + ) + if err != nil { + t.Fatalf("Error creating initial macaroon: %v", err) + } + return dummyMacaroon +} + +// TestSerializeDeserializeSession makes sure that a session can be serialized +// and deserialized from and to the tlv binary format successfully. +func TestSerializeDeserializeSession(t *testing.T) { + mac := createDummyMacaroon(t) + + session, err := NewSession( + "this is a session", TypeMacaroonCustom, time.Now(), + "foo.bar.baz:1234", true, + ) + require.NoError(t, err) + + _, remotePubKey := btcec.PrivKeyFromBytes(btcec.S256(), testRootKey) + session.RemotePublicKey = remotePubKey + session.Macaroon = mac + + var buf bytes.Buffer + require.NoError(t, SerializeSession(&buf, session)) + + deserializedSession, err := DeserializeSession(&buf) + require.NoError(t, err) + + // Apparently require.Equal doesn't work on time.Time when comparing as + // a struct. So we need to compare the timestamp itself and then make + // sure the rest of the session is equal separately. + require.Equal( + t, session.Expiry.UnixNano(), + deserializedSession.Expiry.UnixNano(), + ) + session.Expiry = time.Time{} + deserializedSession.Expiry = time.Time{} + require.Equal(t, session, deserializedSession) +}