Skip to content

Commit 7c26d04

Browse files
authored
Merge pull request #289 from lightninglabs/stateless-init-fix
Fix error handling with stateless init
2 parents 9e7b01d + 2895ed3 commit 7c26d04

File tree

6 files changed

+107
-45
lines changed

6 files changed

+107
-45
lines changed

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ If you’d prefer to compile from source code please follow [these instructions]
6969
Lightning Terminal is backwards compatible with `lnd` back to version v0.13.3-beta.
7070

7171
| LiT | LND |
72-
| ---------------- | ------------ |
72+
|------------------| ------------ |
73+
| **v0.6.1-alpha** | v0.13.3-beta |
7374
| **v0.6.0-alpha** | v0.13.3-beta |
7475
| **v0.5.2-alpha** | v0.12.0-beta |
7576
| **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
8687
## Daemon Versions packaged with LiT
8788

8889
| LiT | LND | Loop | Faraday | Pool |
89-
| ---------------- | ------------ | ----------- | ------------ |---------------|
90-
| **v0.6.0-alpha** | v0.14.1-beta | v0.15.1-beta | v0.2.7-alpha | v0.5.2-alpha |
90+
|------------------| ------------ | ----------- | ------------ |---------------|
91+
| **v0.6.1-alpha** | v0.14.1-beta | v0.15.1-beta | v0.2.7-alpha | v0.5.2-alpha |
9192
| **v0.5.3-alpha** | v0.13.3-beta | v0.14.1-beta | v0.2.6-alpha | v0.5.0-alpha |
9293
| **v0.5.2-alpha** | v0.13.3-beta | v0.14.1-beta | v0.2.6-alpha | v0.5.0-alpha |
9394
| **v0.5.1-alpha** | v0.13.0-beta | v0.14.1-beta | v0.2.6-alpha | v0.5.0-alpha |

app/src/components/connect/ConnectPage.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import React from 'react';
2-
import { Redirect } from 'react-router';
32
import { observer } from 'mobx-react-lite';
43
import styled from '@emotion/styled';
54
import nodeConnectSvg from 'assets/images/lightning-node-connect.svg';
@@ -12,7 +11,7 @@ import SessionList from './SessionList';
1211

1312
const Styled = {
1413
Wrapper: styled.section`
15-
padding: 80px 0 0 80px;
14+
padding-top: 80px;
1615
`,
1716
DisplayLarge: styled.div`
1817
font-family: ${props => props.theme.fonts.open.semiBold};
@@ -33,11 +32,7 @@ const Styled = {
3332

3433
const ConnectPage: React.FC = () => {
3534
const { l } = usePrefixedTranslation('cmps.connect.ConnectPage');
36-
const { appView, sessionStore } = useStore();
37-
38-
if (!appView.showLightningConnect) {
39-
return <Redirect to="/loop" />;
40-
}
35+
const { sessionStore } = useStore();
4136

4237
const { Wrapper, DisplayLarge, Description, Divider } = Styled;
4338
return !sessionStore.hasMultiple ? (

app/src/components/layout/NavMenu.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,7 @@ const NavMenu: React.FC = () => {
8484
<NavItem page="history" onClick={appView.goToHistory} />
8585
<NavItem page="pool" badge={l('common.preview')} onClick={appView.goToPool} />
8686
<NavItem page="settings" onClick={appView.goToSettings} />
87-
{appView.showLightningConnect && (
88-
<NavItem
89-
page="connect"
90-
badge={l('common.beta')}
91-
onClick={appView.goToConnect}
92-
/>
93-
)}
87+
<NavItem page="connect" badge={l('common.beta')} onClick={appView.goToConnect} />
9488
</Nav>
9589
</>
9690
);

app/src/store/views/appView.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,6 @@ export default class AppView {
3939
}
4040
}
4141

42-
/** determines if the Lightning Node Connect UI should be visible */
43-
get showLightningConnect() {
44-
const devOverride = !!localStorage.getItem('i-want-lnc');
45-
/** the unix timestamp (ms) when Lightning Node Connect should become visible */
46-
return devOverride || Date.now() > 1638288000000; // Nov 30 2021 11:00am EST
47-
}
48-
4942
/** Change to the Auth page */
5043
gotoAuth() {
5144
this.goTo(`${PUBLIC_URL}/`);

rpc_proxy.go

Lines changed: 69 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,24 @@ const (
3333
HeaderMacaroon = "Macaroon"
3434
)
3535

36+
// proxyErr is an error type that adds more context to an error occurring in the
37+
// proxy.
38+
type proxyErr struct {
39+
wrapped error
40+
proxyContext string
41+
}
42+
43+
// Error returns the error message as a string, including the proxy's context.
44+
func (e *proxyErr) Error() string {
45+
return fmt.Sprintf("proxy error with context %s: %v", e.proxyContext,
46+
e.wrapped)
47+
}
48+
49+
// Unwrap returns the wrapped error.
50+
func (e *proxyErr) Unwrap() error {
51+
return e.wrapped
52+
}
53+
3654
// newRpcProxy creates a new RPC proxy that can take any native gRPC, grpc-web
3755
// or REST request and delegate (and convert if necessary) it to the correct
3856
// component.
@@ -282,7 +300,7 @@ func (p *rpcProxy) director(ctx context.Context,
282300
authHeaders := md.Get("authorization")
283301
if len(authHeaders) == 1 {
284302
macBytes, err := p.basicAuthToMacaroon(
285-
authHeaders[0], requestURI,
303+
authHeaders[0], requestURI, nil,
286304
)
287305
if err != nil {
288306
return outCtx, nil, err
@@ -332,10 +350,17 @@ func (p *rpcProxy) UnaryServerInterceptor(
332350
// have proper macaroon support implemented in the UI. We allow
333351
// gRPC web requests to have it and "convert" the auth into a
334352
// proper macaroon now.
335-
newCtx, err := p.convertBasicAuth(ctx, info.FullMethod)
353+
newCtx, err := p.convertBasicAuth(ctx, info.FullMethod, nil)
336354
if err != nil {
337-
return nil, fmt.Errorf("error upgrading basic auth: %v",
338-
err)
355+
// Make sure we handle the case where the super macaroon
356+
// is still empty on startup.
357+
if pErr, ok := err.(*proxyErr); ok &&
358+
pErr.proxyContext == "supermacaroon" {
359+
360+
return nil, fmt.Errorf("super macaroon error: "+
361+
"%v", pErr)
362+
}
363+
return nil, err
339364
}
340365

341366
// With the basic auth converted to a macaroon if necessary,
@@ -369,9 +394,19 @@ func (p *rpcProxy) StreamServerInterceptor(
369394
// have proper macaroon support implemented in the UI. We allow
370395
// gRPC web requests to have it and "convert" the auth into a
371396
// proper macaroon now.
372-
ctx, err := p.convertBasicAuth(ss.Context(), info.FullMethod)
397+
ctx, err := p.convertBasicAuth(
398+
ss.Context(), info.FullMethod, nil,
399+
)
373400
if err != nil {
374-
return fmt.Errorf("error upgrading basic auth: %v", err)
401+
// Make sure we handle the case where the super macaroon
402+
// is still empty on startup.
403+
if pErr, ok := err.(*proxyErr); ok &&
404+
pErr.proxyContext == "supermacaroon" {
405+
406+
return fmt.Errorf("super macaroon error: "+
407+
"%v", pErr)
408+
}
409+
return err
375410
}
376411

377412
// With the basic auth converted to a macaroon if necessary,
@@ -390,21 +425,23 @@ func (p *rpcProxy) StreamServerInterceptor(
390425
// convertBasicAuth tries to convert the HTTP authorization header into a
391426
// macaroon based authentication header.
392427
func (p *rpcProxy) convertBasicAuth(ctx context.Context,
393-
requestURI string) (context.Context, error) {
428+
requestURI string, ctxErr error) (context.Context, error) {
394429

395430
md, ok := metadata.FromIncomingContext(ctx)
396431
if !ok {
397-
return ctx, nil
432+
return ctx, ctxErr
398433
}
399434

400435
authHeaders := md.Get("authorization")
401436
if len(authHeaders) == 0 {
402437
// No basic auth provided, we don't add a macaroon and let the
403438
// gRPC security interceptor reject the request.
404-
return ctx, nil
439+
return ctx, ctxErr
405440
}
406441

407-
macBytes, err := p.basicAuthToMacaroon(authHeaders[0], requestURI)
442+
macBytes, err := p.basicAuthToMacaroon(
443+
authHeaders[0], requestURI, ctxErr,
444+
)
408445
if err != nil || len(macBytes) == 0 {
409446
return ctx, err
410447
}
@@ -416,8 +453,8 @@ func (p *rpcProxy) convertBasicAuth(ctx context.Context,
416453
// basicAuthToMacaroon checks that the incoming request context has the expected
417454
// and valid basic authentication header then attaches the correct macaroon to
418455
// the context so it can be forwarded to the actual gRPC server.
419-
func (p *rpcProxy) basicAuthToMacaroon(basicAuth, requestURI string) ([]byte,
420-
error) {
456+
func (p *rpcProxy) basicAuthToMacaroon(basicAuth, requestURI string,
457+
ctxErr error) ([]byte, error) {
421458

422459
// The user specified an authorization header so this is very likely a
423460
// 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,
426463
// from the lnd backend.
427464
authHeaderParts := strings.Split(basicAuth, " ")
428465
if len(authHeaderParts) != 2 {
429-
return nil, nil
466+
return nil, ctxErr
430467
}
431468
if authHeaderParts[1] != p.basicAuth {
432-
return nil, nil
469+
return nil, ctxErr
433470
}
434471

435472
var (
@@ -473,7 +510,20 @@ func (p *rpcProxy) basicAuthToMacaroon(basicAuth, requestURI string) ([]byte,
473510
// If we have a super macaroon, we can use that one directly since it
474511
// will contain all permissions we need.
475512
case len(p.superMacaroon) > 0:
476-
return hex.DecodeString(p.superMacaroon)
513+
superMacData, err := hex.DecodeString(p.superMacaroon)
514+
515+
// Make sure we can avoid running into an empty macaroon here if
516+
// something went wrong with the decoding process (if we're
517+
// still starting up).
518+
if err != nil {
519+
return nil, &proxyErr{
520+
proxyContext: "supermacaroon",
521+
wrapped: fmt.Errorf("couldn't decode "+
522+
"super macaroon: %v", err),
523+
}
524+
}
525+
526+
return superMacData, nil
477527

478528
// If we have macaroon data directly, just encode them. This could be
479529
// 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,
489539
return readMacaroon(lncfg.CleanAndExpandPath(macPath))
490540
}
491541

492-
return nil, fmt.Errorf("unknown macaroon to use")
542+
return nil, &proxyErr{
543+
proxyContext: "auth",
544+
wrapped: fmt.Errorf("unknown macaroon to use"),
545+
}
493546
}
494547

495548
// dialBufConnBackend dials an in-memory connection to an RPC listener and

terminal.go

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -706,9 +706,16 @@ func (g *LightningTerminal) ValidateMacaroon(ctx context.Context,
706706
"syncing")
707707
}
708708

709-
return g.faradayServer.ValidateMacaroon(
709+
err = g.faradayServer.ValidateMacaroon(
710710
ctx, requiredPermissions, fullMethod,
711711
)
712+
if err != nil {
713+
return &proxyErr{
714+
proxyContext: "faraday",
715+
wrapped: fmt.Errorf("invalid macaroon: %v",
716+
err),
717+
}
718+
}
712719

713720
case isLoopURI(fullMethod):
714721
// In remote mode we just pass through the request, the remote
@@ -723,9 +730,16 @@ func (g *LightningTerminal) ValidateMacaroon(ctx context.Context,
723730
"syncing")
724731
}
725732

726-
return g.loopServer.ValidateMacaroon(
733+
err = g.loopServer.ValidateMacaroon(
727734
ctx, requiredPermissions, fullMethod,
728735
)
736+
if err != nil {
737+
return &proxyErr{
738+
proxyContext: "loop",
739+
wrapped: fmt.Errorf("invalid macaroon: %v",
740+
err),
741+
}
742+
}
729743

730744
case isPoolURI(fullMethod):
731745
// In remote mode we just pass through the request, the remote
@@ -740,14 +754,26 @@ func (g *LightningTerminal) ValidateMacaroon(ctx context.Context,
740754
"syncing")
741755
}
742756

743-
return g.poolServer.ValidateMacaroon(
757+
err = g.poolServer.ValidateMacaroon(
744758
ctx, requiredPermissions, fullMethod,
745759
)
760+
if err != nil {
761+
return &proxyErr{
762+
proxyContext: "pool",
763+
wrapped: fmt.Errorf("invalid macaroon: %v",
764+
err),
765+
}
766+
}
746767

747768
case isLitURI(fullMethod):
748-
_, err := g.rpcProxy.convertBasicAuth(ctx, fullMethod)
769+
wrap := fmt.Errorf("invalid basic auth")
770+
_, err := g.rpcProxy.convertBasicAuth(ctx, fullMethod, wrap)
749771
if err != nil {
750-
return err
772+
return &proxyErr{
773+
proxyContext: "lit",
774+
wrapped: fmt.Errorf("invalid auth: %v",
775+
err),
776+
}
751777
}
752778
}
753779

0 commit comments

Comments
 (0)