Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions demos/passkeys-demo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
20 changes: 20 additions & 0 deletions demos/passkeys-demo/.prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"overrides": [
{
"files": [".prettierrc", ".babelrc", ".eslintrc", ".stylelintrc"],
"options": {
"parser": "json"
}
}
],
"printWidth": 90,
"proseWrap": "always",
"singleQuote": true,
"useTabs": false,
"semi": true,
"tabWidth": 2,
"trailingComma": "all",
"bracketSpacing": true,
"jsxBracketSameLine": false,
"arrowParens": "avoid"
}
149 changes: 149 additions & 0 deletions demos/passkeys-demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# LNC Demo - Basic Connect

This demo showcases the most basic flow to connect from a browser to a Lightning Terminal
(litd) node using the `lnc-web` NPM package.

## Running the demo

To run the demo, you'll need to have NodeJS installed and a Lightning Terminal node
accessible that you can obtain a pairing phrase from.

1. Clone this repo
```sh
$ git clone https://github.com/lightninglabs/lnc-web.git
$ cd lnc-web/demos/connect-demo
```
2. Install the dependencies
```sh
$ yarn install
```
3. Start the web app
```sh
$ yarn start
```
Your browser should open to http://localhost:3000 and you will see the home page.

## LNC Relevant Code

The `LNC` object in this app can be access from any component via the custom React hook
[useLNC](https://github.com/lightninglabs/lnc-web/blob/main/demos/connect-demo/src/hooks/useLNC.ts).
This hook returns three variables.

- `lnc` - the global `LNC` instance with full access to all of the `litd` RPC endpoints
```ts
const lnc = new LNC({});
```
- `connect` - a helper function that sets the `pairingPhrase` on the `lnc` object, then
attempts to connect to the node. If the connections is successful (`listChannels`
succeeds), then it will set the `password` on the `lnc` object which encrypts and stores
the keys in the browser's `localStorage`.
```ts
const connect = useCallback(async (pairingPhrase: string, password: string) => {
lnc.credentials.pairingPhrase = pairingPhrase;
await lnc.connect();
// verify we can fetch data
await lnc.lnd.lightning.listChannels();
// set the password after confirming the connection works
lnc.credentials.password = password;
}, []);
```
- `login` - a helper function that sets the `password` on the `lnc` object, which is used
to decrypt the data stored in `localStorage`. If the password is valid, the connection
is made.
```ts
const login = useCallback(async (password: string) => {
lnc.credentials.password = password;
await lnc.connect();
}, []);
```

On the [Home](./src/pages/Home.tsx) page, we can detect if the user has connected to the
node via the `isConnected` field.

```ts
const { lnc } = useLNC();

return (
<Page>
<h2 className="text-center">Welcome to lnc-web</h2>
<p className="text-center">
{lnc.isConnected
? 'You are now connected to your Lightning node.'
: 'Connect or Login to view your Lightning node info.'}
</p>
<GetInfo />
</Page>
);
```

In the [Page](./src/components/Page.tsx) component that displays the navbar, we can detect
whether to display a button to Connect, Login, or Logout based on the `lnc.isConnected`
and `lnc.credentials.isPaired` fields.

```ts
<Nav className="ml-auto">
{lnc.isConnected ? (
<>
<Navbar.Text>Connected</Navbar.Text>
<a href="/">
<Button variant="link">Logout</Button>
</a>
</>
) : lnc.credentials.isPaired ? (
<Link to="/login">
<Button>Login</Button>
</Link>
) : (
<Link to="/connect">
<Button>Connect</Button>
</Link>
)}
</Nav>
```

In the [GetInfo](./src/components/GetInfo.tsx) component, we call the
`lnc.lnd.lightning.GetInfo` RPC to fetch the node's information if the user has connected.
Once the info is set, it is rendered in the table.

```ts
const { lnc } = useLNC();
const [info, setInfo] = useState<any>();

useEffect(() => {
if (lnc.isConnected) {
const sendRequest = async () => {
const res = await lnc.lnd.lightning.getInfo();
setInfo(res);
};
sendRequest();
}
}, [lnc.isConnected, lnc.lnd.lightning]);
```

## Screenshots

### Welcome page with Connect button

![1_welcome](./public/img/1_welcome.png)

### Connect page

Enter your pairing phrase and a new password to use so you don't need to login again

![2_connect](./public/img/2_connect.png)

### Welcome page when connected

After connecting to your node, you'll be redirected back to the welcome page, but now it
will display some information obtained from calling `GetInfo` on `lnd`.

![3_connected](./public/img/3_connected.png)

### Login page

If you reload the page or click the Logout link, you will be taken back to the Welcome
page. It will detect that you have already connected from this browser in the past and
display a "Login" button instead of "Connect". When you click "Login", you'll be take to
the Login page where you only need to provide your password to reconnect to your node.

![4_login](./public/img/4_login.png)
50 changes: 50 additions & 0 deletions demos/passkeys-demo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"name": "connect-demo",
"version": "0.1.0",
"private": true,
"dependencies": {
"@lightninglabs/lnc-web": "0.2.1-alpha",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/node": "^16.11.39",
"@types/react": "^18.0.12",
"@types/react-dom": "^18.0.5",
"bootstrap": "^4.6.1",
"react": "^18.1.0",
"react-bootstrap": "^2.4.0",
"react-dom": "^18.1.0",
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"typescript": "^4.7.3",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"prettier": "2.6.2"
}
}
Binary file added demos/passkeys-demo/public/favicon.ico
Binary file not shown.
Binary file added demos/passkeys-demo/public/img/1_welcome.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demos/passkeys-demo/public/img/2_connect.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demos/passkeys-demo/public/img/3_connected.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demos/passkeys-demo/public/img/4_login.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 43 additions & 0 deletions demos/passkeys-demo/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
Binary file added demos/passkeys-demo/public/logo192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demos/passkeys-demo/public/logo512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions demos/passkeys-demo/public/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
3 changes: 3 additions & 0 deletions demos/passkeys-demo/public/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
9 changes: 9 additions & 0 deletions demos/passkeys-demo/src/App.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import App from './App';

test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});
21 changes: 21 additions & 0 deletions demos/passkeys-demo/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import Connect from './pages/Connect';
import Home from './pages/Home';
import Login from './pages/Login';

function App() {
return (
<>
<BrowserRouter>
<Routes>
<Route index element={<Home />} />
<Route path="connect" element={<Connect />} />
<Route path="login" element={<Login />} />
</Routes>
</BrowserRouter>
</>
);
}

export default App;
Loading