Skip to content

Commit cea1791

Browse files
committed
chore: init lightning addresses
1 parent ff73661 commit cea1791

File tree

7 files changed

+138
-33
lines changed

7 files changed

+138
-33
lines changed

src/app.js

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
APP_NAME,
2020
APP_GITHUB,
2121
APP_TAGLINE,
22+
APP_SUBTAGLINE,
2223
APP_INPUT_PLACEHOLDER,
2324
} from './constants/app';
2425
import {
@@ -70,7 +71,40 @@ export class App extends PureComponent {
7071
getInvoiceDetails = async (text) => {
7172
try {
7273
let response;
73-
const { isLNURL, data } = await parseInvoice(text);
74+
const parsedInvoiceResponse = await parseInvoice(text);
75+
76+
// If this returns null is because there is no invoice to parse
77+
if (!parsedInvoiceResponse) {
78+
return this.setState(() => ({
79+
hasError: true,
80+
decodedInvoice: {},
81+
isInvoiceLoaded: false,
82+
error: { message: 'Please enter a valid invoice and try again.'},
83+
}));
84+
}
85+
86+
const { isLNURL, data, error } = parsedInvoiceResponse;
87+
88+
// If an error comes back from a nested operation in parsing it must
89+
// propagate back to the end user
90+
if (error && error.length > 0) {
91+
return this.setState(() => ({
92+
hasError: true,
93+
decodedInvoice: {},
94+
isInvoiceLoaded: false,
95+
error: { message: error },
96+
}));
97+
}
98+
99+
// If data is null it means the parser could not understand the invoice
100+
if (!data) {
101+
return this.setState(() => ({
102+
hasError: true,
103+
decodedInvoice: {},
104+
isInvoiceLoaded: false,
105+
error: { message: 'Could not parse/understand this invoice or request. Please try again.'},
106+
}));
107+
}
74108

75109
if (isLNURL) {
76110
response = await data;
@@ -305,6 +339,7 @@ export class App extends PureComponent {
305339
</div>
306340
<div className='logo__subtitle'>
307341
{APP_TAGLINE}
342+
<span className="logo__subtitle-small">{APP_SUBTAGLINE}</span>
308343
</div>
309344
</div>
310345
);

src/assets/styles/modules/error.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
color: $text-primary;
1616
font-size: $font-extra-small-size;
1717
font-weight: $font-weight-bold;
18+
line-height: 1.6;
1819

1920
@include larger-than(mobile) {
2021
font-size: $font-small-size;
Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
// Logo
22
.logo {
3+
width: 100%;
34
display: flex;
45
flex-direction: column;
56
align-items: flex-start;
67
justify-content: flex-start;
7-
width: 100%;
88
margin-bottom: $base-spacing + 5;
99

1010
@include larger-than(mobile) {
@@ -15,23 +15,37 @@
1515
}
1616

1717
&__title {
18-
font-weight: $font-weight-bold;
1918
color: $text-primary;
20-
font-size: $font-small-size;
19+
font-size: 24px;
20+
font-weight: $font-weight-bold;
2121

2222
@include larger-than(mobile) {
23-
font-size: $font-large-size;
23+
font-size: 60px;
2424
}
2525
}
2626

2727
&__subtitle {
28-
padding-top: $base-spacing;
29-
font-weight: $font-weight-regular;
28+
text-align: left;
3029
color: $text-tertiary;
30+
padding-top: $base-spacing;
31+
font-weight: $font-weight-bold;
3132
font-size: $font-extra-small-size;
3233

3334
@include larger-than(mobile) {
34-
font-size: $font-small-size;
35+
text-align: center;
36+
font-size: $font-base-size;
37+
}
38+
}
39+
40+
&__subtitle-small {
41+
display: block;
42+
font-size: 12px;
43+
color: $text-primary;
44+
padding-top: 0.5 * $base-spacing;
45+
font-weight: $font-weight-bold;
46+
47+
@include larger-than(mobile) {
48+
font-size: 16px;
3549
}
3650
}
3751
}

src/constants/app.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// App-Wide Constants
22
export const APP_NAME = 'Lightning Decoder';
3-
export const APP_TAGLINE = 'Decode Lightning Network Invoices (BOLT11 & LNURL)';
3+
export const APP_TAGLINE = 'Decode Lightning Network Requests';
4+
export const APP_SUBTAGLINE = 'BOLT11, LNURL, and Lightning Address'
45
export const APP_INPUT_PLACEHOLDER = 'Enter Invoice';
56
export const APP_GITHUB = 'https://github.com/andrerfneves/lightning-decoder';

src/utils/internet-identifier.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export const validateInternetIdentifier = (internetIdentifier) => {
2+
var re = /\S+@\S+\.\S+/;
3+
return re.test(internetIdentifier);
4+
}

src/utils/invoices.js

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,36 @@
1-
import bech32 from 'bech32';
21
import axios from 'axios';
2+
import bech32 from 'bech32';
33
import { Buffer } from 'buffer';
4+
5+
import { validateInternetIdentifier } from './internet-identifier';
46
import LightningPayReq from '../lib/bolt11';
57

68
const LIGHTNING_SCHEME = 'lightning';
79
const BOLT11_SCHEME = 'lnbc';
810
const LNURL_SCHEME = 'lnurl';
911

10-
export const parseInvoice = (invoice: string) => {
12+
export const parseInvoice = async (invoice: string) => {
1113
if (!invoice || invoice === '') {
1214
return null;
1315
}
1416

1517
const lcInvoice = invoice.trim().toLowerCase();
1618
let requestCode = lcInvoice;
1719

20+
// Check if this is a Lightning Address
21+
if (validateInternetIdentifier(requestCode)) {
22+
const { success, data, message } = await handleLightningAddress(requestCode);
23+
console.log({ success, data, message });
24+
25+
if (!success) {
26+
return {
27+
data: null,
28+
error: message,
29+
isLNURL: false,
30+
};
31+
}
32+
}
33+
1834
// Check if Invoice has `lightning` or `lnurl` prefixes
1935
// (9 chars + the `:` or `=` chars) --> 10 characters total
2036
const hasLightningPrefix = lcInvoice.indexOf(`${LIGHTNING_SCHEME}:`) !== -1;
@@ -59,6 +75,58 @@ const handleLNURL = (invoice: string) => {
5975
})
6076
};
6177

78+
const handleLightningAddress = (internetIdentifier: string) => {
79+
const addressArr = internetIdentifier.split('@');
80+
81+
// Must only have 2 fields (username and domain name)
82+
if (addressArr.length !== 2) {
83+
return {
84+
success: false,
85+
message: 'Invalid internet identifier format.',
86+
};
87+
}
88+
89+
const [username, domain] = addressArr;
90+
91+
// Must only have 2 fields (username and domain name)
92+
if (addressArr[1].indexOf('.') === -1) {
93+
return {
94+
success: false,
95+
message: 'Invalid internet identifier format.',
96+
};
97+
}
98+
99+
const url = `https://${domain}/.well-known/lnurlp/${username}`;
100+
101+
return axios.get('https://satcors.fiatjaf.com/?url=' + encodeURIComponent(url), {
102+
headers: {
103+
'Access-Control-Allow-Origin': '*',
104+
}
105+
}).then(res => {
106+
console.log({ url, username, domain });
107+
const imageEntry = JSON.parse(res.data.metadata)
108+
.find(([k]) => k.startsWith('image/'));
109+
110+
res.data.decodedMetadata = JSON.parse(res.data.metadata);
111+
res.data.domain = domain;
112+
113+
return {
114+
success: true,
115+
data: {
116+
domain,
117+
username,
118+
lnurlParams: res.data,
119+
image: imageEntry && `data:${imageEntry.join(',')}`,
120+
},
121+
}
122+
}).catch(_ => {
123+
return {
124+
success: false,
125+
message: 'This identifier does not support Lightning Address yet.',
126+
};
127+
});
128+
};
129+
62130
const handleBOLT11 = (invoice: string) => {
63131
// Check if Invoice starts with `lnbc` prefix
64132
if (!invoice.includes(BOLT11_SCHEME)) {
@@ -70,3 +138,4 @@ const handleBOLT11 = (invoice: string) => {
70138

71139
return result;
72140
};
141+

yarn.lock

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -858,13 +858,6 @@
858858
dependencies:
859859
regenerator-runtime "^0.13.2"
860860

861-
"@babel/runtime@^7.7.6":
862-
version "7.14.8"
863-
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.8.tgz#7119a56f421018852694290b9f9148097391b446"
864-
integrity sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg==
865-
dependencies:
866-
regenerator-runtime "^0.13.4"
867-
868861
"@babel/template@^7.1.0", "@babel/template@^7.4.0", "@babel/template@^7.4.4", "@babel/template@^7.6.0":
869862
version "7.6.0"
870863
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.6.0.tgz#7f0159c7f5012230dad64cca42ec9bdb5c9536e6"
@@ -3372,9 +3365,9 @@ data-urls@^1.0.0, data-urls@^1.1.0:
33723365
whatwg-url "^7.0.0"
33733366

33743367
date-fns@^2.1.0:
3375-
version "2.22.1"
3376-
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.22.1.tgz#1e5af959831ebb1d82992bf67b765052d8f0efc4"
3377-
integrity sha512-yUFPQjrxEmIsMqlHhAhmxkuH769baF21Kk+nZwZGyrMoyLA+LugaQtC0+Tqf9CBUUULWwUJt6Q5ySI3LJDDCGg==
3368+
version "2.23.0"
3369+
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.23.0.tgz#4e886c941659af0cf7b30fafdd1eaa37e88788a9"
3370+
integrity sha512-5ycpauovVyAk0kXNZz6ZoB9AYMZB4DObse7P3BPWmyEjXNORTI8EJ6X0uaSAq4sCHzM1uajzrkr6HnsLQpxGXA==
33783371

33793372
date-now@^0.1.4:
33803373
version "0.1.4"
@@ -4940,13 +4933,6 @@ hex-color-regex@^1.1.0:
49404933
resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"
49414934
integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==
49424935

4943-
history@^5.0.0:
4944-
version "5.0.0"
4945-
resolved "https://registry.yarnpkg.com/history/-/history-5.0.0.tgz#0cabbb6c4bbf835addb874f8259f6d25101efd08"
4946-
integrity sha512-3NyRMKIiFSJmIPdq7FxkNMJkQ7ZEtVblOQ38VtKaA0zZMW1Eo6Q6W8oDKEflr1kNNTItSnk4JMCO1deeSgbLLg==
4947-
dependencies:
4948-
"@babel/runtime" "^7.7.6"
4949-
49504936
hmac-drbg@^1.0.0, hmac-drbg@^1.0.1:
49514937
version "1.0.1"
49524938
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
@@ -8929,11 +8915,6 @@ regenerator-runtime@^0.11.0:
89298915
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
89308916
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
89318917

8932-
regenerator-runtime@^0.13.4:
8933-
version "0.13.7"
8934-
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
8935-
integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
8936-
89378918
regenerator-transform@^0.14.0:
89388919
version "0.14.1"
89398920
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.1.tgz#3b2fce4e1ab7732c08f665dfdb314749c7ddd2fb"

0 commit comments

Comments
 (0)