diff --git a/README.md b/README.md
index 6bd4650e3..89bd307a4 100644
--- a/README.md
+++ b/README.md
@@ -69,7 +69,8 @@ If you’d prefer to compile from source code please follow [these instructions]
Lightning Terminal is backwards compatible with `lnd` back to version v0.13.3-beta.
| LiT | LND |
-| ---------------- | ------------ |
+|------------------| ------------ |
+| **v0.6.1-alpha** | v0.13.3-beta |
| **v0.6.0-alpha** | v0.13.3-beta |
| **v0.5.2-alpha** | v0.12.0-beta |
| **v0.5.1-alpha** | v0.12.0-beta |
@@ -86,8 +87,8 @@ Lightning Terminal is backwards compatible with `lnd` back to version v0.13.3-be
## Daemon Versions packaged with LiT
| LiT | LND | Loop | Faraday | Pool |
-| ---------------- | ------------ | ----------- | ------------ |---------------|
-| **v0.6.0-alpha** | v0.14.1-beta | v0.15.1-beta | v0.2.7-alpha | v0.5.2-alpha |
+|------------------| ------------ | ----------- | ------------ |---------------|
+| **v0.6.1-alpha** | v0.14.1-beta | v0.15.1-beta | v0.2.7-alpha | v0.5.2-alpha |
| **v0.5.3-alpha** | v0.13.3-beta | v0.14.1-beta | v0.2.6-alpha | v0.5.0-alpha |
| **v0.5.2-alpha** | v0.13.3-beta | v0.14.1-beta | v0.2.6-alpha | v0.5.0-alpha |
| **v0.5.1-alpha** | v0.13.0-beta | v0.14.1-beta | v0.2.6-alpha | v0.5.0-alpha |
diff --git a/app/src/components/connect/ConnectPage.tsx b/app/src/components/connect/ConnectPage.tsx
index 9a5d46023..bcf05837e 100644
--- a/app/src/components/connect/ConnectPage.tsx
+++ b/app/src/components/connect/ConnectPage.tsx
@@ -1,5 +1,4 @@
import React from 'react';
-import { Redirect } from 'react-router';
import { observer } from 'mobx-react-lite';
import styled from '@emotion/styled';
import nodeConnectSvg from 'assets/images/lightning-node-connect.svg';
@@ -12,7 +11,7 @@ import SessionList from './SessionList';
const Styled = {
Wrapper: styled.section`
- padding: 80px 0 0 80px;
+ padding-top: 80px;
`,
DisplayLarge: styled.div`
font-family: ${props => props.theme.fonts.open.semiBold};
@@ -33,11 +32,7 @@ const Styled = {
const ConnectPage: React.FC = () => {
const { l } = usePrefixedTranslation('cmps.connect.ConnectPage');
- const { appView, sessionStore } = useStore();
-
- if (!appView.showLightningConnect) {
- return ;
- }
+ const { sessionStore } = useStore();
const { Wrapper, DisplayLarge, Description, Divider } = Styled;
return !sessionStore.hasMultiple ? (
diff --git a/app/src/components/layout/NavMenu.tsx b/app/src/components/layout/NavMenu.tsx
index 6c49f39a8..93bebdeb8 100644
--- a/app/src/components/layout/NavMenu.tsx
+++ b/app/src/components/layout/NavMenu.tsx
@@ -84,13 +84,7 @@ const NavMenu: React.FC = () => {
- {appView.showLightningConnect && (
-
- )}
+
>
);
diff --git a/app/src/store/views/appView.ts b/app/src/store/views/appView.ts
index 3fde494ee..c4aafe911 100644
--- a/app/src/store/views/appView.ts
+++ b/app/src/store/views/appView.ts
@@ -39,13 +39,6 @@ export default class AppView {
}
}
- /** determines if the Lightning Node Connect UI should be visible */
- get showLightningConnect() {
- const devOverride = !!localStorage.getItem('i-want-lnc');
- /** the unix timestamp (ms) when Lightning Node Connect should become visible */
- return devOverride || Date.now() > 1638288000000; // Nov 30 2021 11:00am EST
- }
-
/** Change to the Auth page */
gotoAuth() {
this.goTo(`${PUBLIC_URL}/`);
diff --git a/rpc_proxy.go b/rpc_proxy.go
index 9bdc51c1f..a51c88298 100644
--- a/rpc_proxy.go
+++ b/rpc_proxy.go
@@ -33,6 +33,24 @@ const (
HeaderMacaroon = "Macaroon"
)
+// proxyErr is an error type that adds more context to an error occurring in the
+// proxy.
+type proxyErr struct {
+ wrapped error
+ proxyContext string
+}
+
+// Error returns the error message as a string, including the proxy's context.
+func (e *proxyErr) Error() string {
+ return fmt.Sprintf("proxy error with context %s: %v", e.proxyContext,
+ e.wrapped)
+}
+
+// Unwrap returns the wrapped error.
+func (e *proxyErr) Unwrap() error {
+ return e.wrapped
+}
+
// newRpcProxy creates a new RPC proxy that can take any native gRPC, grpc-web
// or REST request and delegate (and convert if necessary) it to the correct
// component.
@@ -282,7 +300,7 @@ func (p *rpcProxy) director(ctx context.Context,
authHeaders := md.Get("authorization")
if len(authHeaders) == 1 {
macBytes, err := p.basicAuthToMacaroon(
- authHeaders[0], requestURI,
+ authHeaders[0], requestURI, nil,
)
if err != nil {
return outCtx, nil, err
@@ -332,10 +350,17 @@ func (p *rpcProxy) UnaryServerInterceptor(
// have proper macaroon support implemented in the UI. We allow
// gRPC web requests to have it and "convert" the auth into a
// proper macaroon now.
- newCtx, err := p.convertBasicAuth(ctx, info.FullMethod)
+ newCtx, err := p.convertBasicAuth(ctx, info.FullMethod, nil)
if err != nil {
- return nil, fmt.Errorf("error upgrading basic auth: %v",
- err)
+ // Make sure we handle the case where the super macaroon
+ // is still empty on startup.
+ if pErr, ok := err.(*proxyErr); ok &&
+ pErr.proxyContext == "supermacaroon" {
+
+ return nil, fmt.Errorf("super macaroon error: "+
+ "%v", pErr)
+ }
+ return nil, err
}
// With the basic auth converted to a macaroon if necessary,
@@ -369,9 +394,19 @@ func (p *rpcProxy) StreamServerInterceptor(
// have proper macaroon support implemented in the UI. We allow
// gRPC web requests to have it and "convert" the auth into a
// proper macaroon now.
- ctx, err := p.convertBasicAuth(ss.Context(), info.FullMethod)
+ ctx, err := p.convertBasicAuth(
+ ss.Context(), info.FullMethod, nil,
+ )
if err != nil {
- return fmt.Errorf("error upgrading basic auth: %v", err)
+ // Make sure we handle the case where the super macaroon
+ // is still empty on startup.
+ if pErr, ok := err.(*proxyErr); ok &&
+ pErr.proxyContext == "supermacaroon" {
+
+ return fmt.Errorf("super macaroon error: "+
+ "%v", pErr)
+ }
+ return err
}
// With the basic auth converted to a macaroon if necessary,
@@ -390,21 +425,23 @@ func (p *rpcProxy) StreamServerInterceptor(
// convertBasicAuth tries to convert the HTTP authorization header into a
// macaroon based authentication header.
func (p *rpcProxy) convertBasicAuth(ctx context.Context,
- requestURI string) (context.Context, error) {
+ requestURI string, ctxErr error) (context.Context, error) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
- return ctx, nil
+ return ctx, ctxErr
}
authHeaders := md.Get("authorization")
if len(authHeaders) == 0 {
// No basic auth provided, we don't add a macaroon and let the
// gRPC security interceptor reject the request.
- return ctx, nil
+ return ctx, ctxErr
}
- macBytes, err := p.basicAuthToMacaroon(authHeaders[0], requestURI)
+ macBytes, err := p.basicAuthToMacaroon(
+ authHeaders[0], requestURI, ctxErr,
+ )
if err != nil || len(macBytes) == 0 {
return ctx, err
}
@@ -416,8 +453,8 @@ func (p *rpcProxy) convertBasicAuth(ctx context.Context,
// basicAuthToMacaroon checks that the incoming request context has the expected
// and valid basic authentication header then attaches the correct macaroon to
// the context so it can be forwarded to the actual gRPC server.
-func (p *rpcProxy) basicAuthToMacaroon(basicAuth, requestURI string) ([]byte,
- error) {
+func (p *rpcProxy) basicAuthToMacaroon(basicAuth, requestURI string,
+ ctxErr error) ([]byte, error) {
// The user specified an authorization header so this is very likely a
// gRPC Web call from the UI. But we only attach the macaroon if the
@@ -426,10 +463,10 @@ func (p *rpcProxy) basicAuthToMacaroon(basicAuth, requestURI string) ([]byte,
// from the lnd backend.
authHeaderParts := strings.Split(basicAuth, " ")
if len(authHeaderParts) != 2 {
- return nil, nil
+ return nil, ctxErr
}
if authHeaderParts[1] != p.basicAuth {
- return nil, nil
+ return nil, ctxErr
}
var (
@@ -473,7 +510,20 @@ func (p *rpcProxy) basicAuthToMacaroon(basicAuth, requestURI string) ([]byte,
// If we have a super macaroon, we can use that one directly since it
// will contain all permissions we need.
case len(p.superMacaroon) > 0:
- return hex.DecodeString(p.superMacaroon)
+ superMacData, err := hex.DecodeString(p.superMacaroon)
+
+ // Make sure we can avoid running into an empty macaroon here if
+ // something went wrong with the decoding process (if we're
+ // still starting up).
+ if err != nil {
+ return nil, &proxyErr{
+ proxyContext: "supermacaroon",
+ wrapped: fmt.Errorf("couldn't decode "+
+ "super macaroon: %v", err),
+ }
+ }
+
+ return superMacData, nil
// If we have macaroon data directly, just encode them. This could be
// for initial requests to lnd while we don't have the super macaroon
@@ -489,7 +539,10 @@ func (p *rpcProxy) basicAuthToMacaroon(basicAuth, requestURI string) ([]byte,
return readMacaroon(lncfg.CleanAndExpandPath(macPath))
}
- return nil, fmt.Errorf("unknown macaroon to use")
+ return nil, &proxyErr{
+ proxyContext: "auth",
+ wrapped: fmt.Errorf("unknown macaroon to use"),
+ }
}
// dialBufConnBackend dials an in-memory connection to an RPC listener and
diff --git a/terminal.go b/terminal.go
index db87c0576..943696d28 100644
--- a/terminal.go
+++ b/terminal.go
@@ -706,9 +706,16 @@ func (g *LightningTerminal) ValidateMacaroon(ctx context.Context,
"syncing")
}
- return g.faradayServer.ValidateMacaroon(
+ err = g.faradayServer.ValidateMacaroon(
ctx, requiredPermissions, fullMethod,
)
+ if err != nil {
+ return &proxyErr{
+ proxyContext: "faraday",
+ wrapped: fmt.Errorf("invalid macaroon: %v",
+ err),
+ }
+ }
case isLoopURI(fullMethod):
// In remote mode we just pass through the request, the remote
@@ -723,9 +730,16 @@ func (g *LightningTerminal) ValidateMacaroon(ctx context.Context,
"syncing")
}
- return g.loopServer.ValidateMacaroon(
+ err = g.loopServer.ValidateMacaroon(
ctx, requiredPermissions, fullMethod,
)
+ if err != nil {
+ return &proxyErr{
+ proxyContext: "loop",
+ wrapped: fmt.Errorf("invalid macaroon: %v",
+ err),
+ }
+ }
case isPoolURI(fullMethod):
// In remote mode we just pass through the request, the remote
@@ -740,14 +754,26 @@ func (g *LightningTerminal) ValidateMacaroon(ctx context.Context,
"syncing")
}
- return g.poolServer.ValidateMacaroon(
+ err = g.poolServer.ValidateMacaroon(
ctx, requiredPermissions, fullMethod,
)
+ if err != nil {
+ return &proxyErr{
+ proxyContext: "pool",
+ wrapped: fmt.Errorf("invalid macaroon: %v",
+ err),
+ }
+ }
case isLitURI(fullMethod):
- _, err := g.rpcProxy.convertBasicAuth(ctx, fullMethod)
+ wrap := fmt.Errorf("invalid basic auth")
+ _, err := g.rpcProxy.convertBasicAuth(ctx, fullMethod, wrap)
if err != nil {
- return err
+ return &proxyErr{
+ proxyContext: "lit",
+ wrapped: fmt.Errorf("invalid auth: %v",
+ err),
+ }
}
}