Skip to content

Commit

Permalink
Release 0.0.6 (#73)
Browse files Browse the repository at this point in the history
* Updating version number

* Display Invoice Rune (#56)

* Display Invoice Rune

* Cosmetic updates for Invoice Rune

* Update plus/add icon svg (#70)

* Resolve commando-rune deprecation and use createrune instead (#72)

* Change invoice and offer to lowercase (#68)

* Add tests for address casing fix (#69)

* Update jsx camelCase property name

* Adding mock use-http hook

* Add tests for invoice and offer capital casing

---------

Co-authored-by: Michael Evans <[email protected]>
Co-authored-by: afxsoftware <[email protected]>
  • Loading branch information
3 people authored Sep 7, 2024
1 parent 180e141 commit 4399d8c
Show file tree
Hide file tree
Showing 44 changed files with 627 additions and 120 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
- ### Commando Authentication
- This application utilizes [lnmessage](https://github.com/aaronbarnardsound/lnmessage) and [commando](https://docs.corelightning.org/reference/lightning-commando) for connecting with core lightning node. The connection is trustless and end-to-end encrypted. Commando manages authentication and authorization through runes, which can grant either full or fine-grained permissions.
- The backend server reads `LIGHTNING_PUBKEY` & `LIGHTNING_RUNE` from the `COMMANDO_CONFIG` file for this communication.
- Values can either be set manually or script `entrypoint.sh` can be used to call `getinfo` and `commando-rune` methods and save values in `COMMANDO_CONFIG`.
- Values can either be set manually or script `entrypoint.sh` can be used to call `getinfo` and `createrune` methods and save values in `COMMANDO_CONFIG`.
- `entrypoint.sh` can only run for the locally installed lightning. If `cln-application` is running remotely then pubkey and
rune can be set manually.
- Sample commando config should look like:
Expand Down
22 changes: 22 additions & 0 deletions apps/backend/dist/controllers/shared.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import handleError from '../shared/error-handler.js';
import { APIError } from '../models/errors.js';
import { setSharedApplicationConfig, overrideSettingsWithEnvVariables } from '../shared/utils.js';
import { sep } from 'path';
import { LNMessage } from '../service/lightning.service.js';
class SharedController {
getApplicationSettings(req, res, next) {
try {
Expand Down Expand Up @@ -72,6 +73,7 @@ class SharedController {
.replace('-----BEGIN CERTIFICATE-----', '')
.replace('-----END CERTIFICATE-----', '');
}
LNMessage.refreshEnvVariables();
const CONNECT_WALLET_SETTINGS = {
LOCAL_HOST: process.env.LOCAL_HOST || '',
DEVICE_DOMAIN_NAME: process.env.DEVICE_DOMAIN_NAME || '',
Expand All @@ -87,6 +89,7 @@ class SharedController {
NODE_PUBKEY: process.env.LIGHTNING_PUBKEY || '',
COMMANDO_RUNE: process.env.COMMANDO_RUNE,
APP_VERSION: JSON.parse(packageData).version || '',
INVOICE_RUNE: process.env.INVOICE_RUNE || '',
};
res.status(200).json(CONNECT_WALLET_SETTINGS);
}
Expand Down Expand Up @@ -119,5 +122,24 @@ class SharedController {
handleError(error, req, res, next);
}
}
async saveInvoiceRune(req, res, next) {
try {
logger.info('Saving Invoice Rune');
const showRunes = await LNMessage.call('showrunes', []);
const invoiceRune = showRunes.runes.find(rune => rune.restrictions.some(restriction => restriction.alternatives.some(alternative => alternative.value === 'invoice')) &&
rune.restrictions.some(restriction => restriction.alternatives.some(alternative => alternative.value === 'listinvoices')));
if (invoiceRune && fs.existsSync(APP_CONSTANTS.COMMANDO_ENV_LOCATION)) {
const invoiceRuneString = `INVOICE_RUNE="${invoiceRune.rune}"\n`;
fs.appendFileSync(APP_CONSTANTS.COMMANDO_ENV_LOCATION, invoiceRuneString, 'utf-8');
res.status(201).send();
}
else {
throw new Error('Invoice rune not found or .commando-env does not exist.');
}
}
catch (error) {
handleError(error, req, res, next);
}
}
}
export default new SharedController();
1 change: 1 addition & 0 deletions apps/backend/dist/models/showrunes.type.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {};
3 changes: 3 additions & 0 deletions apps/backend/dist/routes/v1/shared.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ export class SharedRoutes extends CommonRoutesConfig {
this.app
.route(API_VERSION + SHARED_ROUTE + '/rate/:fiatCurrency')
.get(SharedController.getFiatRate);
this.app
.route(API_VERSION + SHARED_ROUTE + '/saveinvoicerune/')
.post(AuthController.isUserAuthenticated, SharedController.saveInvoiceRune);
return this.app;
}
}
34 changes: 29 additions & 5 deletions apps/backend/dist/service/lightning.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,14 @@ import Lnmessage from 'lnmessage';
import { LightningError } from '../models/errors.js';
import { HttpStatusCode, APP_CONSTANTS, LN_MESSAGE_CONFIG } from '../shared/consts.js';
import { logger } from '../shared/logger.js';
import { readFileSync } from 'fs';
export class LightningService {
lnMessage = null;
constructor() {
try {
logger.info('Getting Commando Rune');
if (fs.existsSync(APP_CONSTANTS.COMMANDO_ENV_LOCATION)) {
const DATA_SPLIT = (Buffer.from(fs.readFileSync(APP_CONSTANTS.COMMANDO_ENV_LOCATION)).toString() || '\n').split('\n');
process.env.LIGHTNING_PUBKEY = DATA_SPLIT[0].substring(18, DATA_SPLIT[0].length - 1);
process.env.COMMANDO_RUNE = DATA_SPLIT[1].substring(16, DATA_SPLIT[1].length - 1);
LN_MESSAGE_CONFIG.remoteNodePublicKey = process.env.LIGHTNING_PUBKEY;
APP_CONSTANTS.COMMANDO_RUNE = process.env.COMMANDO_RUNE;
this.refreshEnvVariables();
logger.info('lnMessage connecting with config: ' + JSON.stringify(LN_MESSAGE_CONFIG));
this.lnMessage = new Lnmessage(LN_MESSAGE_CONFIG);
this.lnMessage.connect();
Expand Down Expand Up @@ -53,5 +50,32 @@ export class LightningService {
}
});
};
refreshEnvVariables() {
const envVars = this.parseEnvFile(APP_CONSTANTS.COMMANDO_ENV_LOCATION);
process.env.LIGHTNING_PUBKEY = envVars.LIGHTNING_PUBKEY;
process.env.COMMANDO_RUNE = envVars.LIGHTNING_RUNE;
process.env.INVOICE_RUNE = envVars.INVOICE_RUNE !== undefined ? envVars.INVOICE_RUNE : '';
LN_MESSAGE_CONFIG.remoteNodePublicKey = process.env.LIGHTNING_PUBKEY;
APP_CONSTANTS.COMMANDO_RUNE = process.env.COMMANDO_RUNE;
}
parseEnvFile(filePath) {
try {
const content = readFileSync(filePath, 'utf8');
const lines = content.split('\n');
const envVars = {};
for (let line of lines) {
line = line.trim();
if (line && line.indexOf('=') !== -1 && !line.startsWith('#')) {
const [key, ...value] = line.split('=');
envVars[key] = value.join('=').replace(/(^"|"$)/g, '');
}
}
return envVars;
}
catch (err) {
logger.error('Error reading .commando-env file:', err);
return {};
}
}
}
export const LNMessage = new LightningService();
2 changes: 1 addition & 1 deletion apps/backend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cln-application-backend",
"version": "0.0.5",
"version": "0.0.6",
"description": "Core lightning application backend",
"private": true,
"license": "MIT",
Expand Down
29 changes: 29 additions & 0 deletions apps/backend/source/controllers/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import handleError from '../shared/error-handler.js';
import { APIError } from '../models/errors.js';
import { setSharedApplicationConfig, overrideSettingsWithEnvVariables } from '../shared/utils.js';
import { sep } from 'path';
import { LNMessage } from '../service/lightning.service.js';
import { ShowRunes } from '../models/showrunes.type.js';

class SharedController {
getApplicationSettings(req: Request, res: Response, next: NextFunction) {
Expand Down Expand Up @@ -82,6 +84,7 @@ class SharedController {
.replace('-----BEGIN CERTIFICATE-----', '')
.replace('-----END CERTIFICATE-----', '');
}
LNMessage.refreshEnvVariables();
const CONNECT_WALLET_SETTINGS = {
LOCAL_HOST: process.env.LOCAL_HOST || '',
DEVICE_DOMAIN_NAME: process.env.DEVICE_DOMAIN_NAME || '',
Expand All @@ -97,6 +100,7 @@ class SharedController {
NODE_PUBKEY: process.env.LIGHTNING_PUBKEY || '',
COMMANDO_RUNE: process.env.COMMANDO_RUNE,
APP_VERSION: JSON.parse(packageData).version || '',
INVOICE_RUNE: process.env.INVOICE_RUNE || '',
};
res.status(200).json(CONNECT_WALLET_SETTINGS);
} catch (error: any) {
Expand Down Expand Up @@ -127,6 +131,31 @@ class SharedController {
handleError(error, req, res, next);
}
}

async saveInvoiceRune(req: Request, res: Response, next: NextFunction) {
try {
logger.info('Saving Invoice Rune');
const showRunes: ShowRunes = await LNMessage.call('showrunes', []);
const invoiceRune = showRunes.runes.find(
rune =>
rune.restrictions.some(restriction =>
restriction.alternatives.some(alternative => alternative.value === 'invoice'),
) &&
rune.restrictions.some(restriction =>
restriction.alternatives.some(alternative => alternative.value === 'listinvoices'),
),
);
if (invoiceRune && fs.existsSync(APP_CONSTANTS.COMMANDO_ENV_LOCATION)) {
const invoiceRuneString = `INVOICE_RUNE="${invoiceRune.rune}"\n`;
fs.appendFileSync(APP_CONSTANTS.COMMANDO_ENV_LOCATION, invoiceRuneString, 'utf-8');
res.status(201).send();
} else {
throw new Error('Invoice rune not found or .commando-env does not exist.');
}
} catch (error: any) {
handleError(error, req, res, next);
}
}
}

export default new SharedController();
28 changes: 28 additions & 0 deletions apps/backend/source/models/showrunes.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export type ShowRunes = {
runes: Rune[];
isLoading: boolean;
error?: any;
};

export type Rune = {
rune: string;
unique_id: string;
restrictions: Restriction[];
restrictions_as_english: string;
stored?: boolean;
blacklisted?: boolean;
last_used?: number;
our_rune?: boolean;
};

export type Restriction = {
alternatives: Alternative[];
english: string;
};

export type Alternative = {
fieldname: string;
value: string;
condition: string;
english: string;
};
3 changes: 3 additions & 0 deletions apps/backend/source/routes/v1/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ export class SharedRoutes extends CommonRoutesConfig {
this.app
.route(API_VERSION + SHARED_ROUTE + '/rate/:fiatCurrency')
.get(SharedController.getFiatRate);
this.app
.route(API_VERSION + SHARED_ROUTE + '/saveinvoicerune/')
.post(AuthController.isUserAuthenticated, SharedController.saveInvoiceRune);
return this.app;
}
}
40 changes: 33 additions & 7 deletions apps/backend/source/service/lightning.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Lnmessage from 'lnmessage';
import { LightningError } from '../models/errors.js';
import { HttpStatusCode, APP_CONSTANTS, LN_MESSAGE_CONFIG } from '../shared/consts.js';
import { logger } from '../shared/logger.js';
import { readFileSync } from 'fs';

export class LightningService {
private lnMessage: any = null;
Expand All @@ -12,13 +13,7 @@ export class LightningService {
try {
logger.info('Getting Commando Rune');
if (fs.existsSync(APP_CONSTANTS.COMMANDO_ENV_LOCATION)) {
const DATA_SPLIT = (
Buffer.from(fs.readFileSync(APP_CONSTANTS.COMMANDO_ENV_LOCATION)).toString() || '\n'
).split('\n');
process.env.LIGHTNING_PUBKEY = DATA_SPLIT[0].substring(18, DATA_SPLIT[0].length - 1);
process.env.COMMANDO_RUNE = DATA_SPLIT[1].substring(16, DATA_SPLIT[1].length - 1);
LN_MESSAGE_CONFIG.remoteNodePublicKey = process.env.LIGHTNING_PUBKEY;
APP_CONSTANTS.COMMANDO_RUNE = process.env.COMMANDO_RUNE;
this.refreshEnvVariables();
logger.info('lnMessage connecting with config: ' + JSON.stringify(LN_MESSAGE_CONFIG));
this.lnMessage = new Lnmessage(LN_MESSAGE_CONFIG);
this.lnMessage.connect();
Expand Down Expand Up @@ -67,6 +62,37 @@ export class LightningService {
}
});
};

refreshEnvVariables() {
const envVars = this.parseEnvFile(APP_CONSTANTS.COMMANDO_ENV_LOCATION);

process.env.LIGHTNING_PUBKEY = envVars.LIGHTNING_PUBKEY;
process.env.COMMANDO_RUNE = envVars.LIGHTNING_RUNE;
process.env.INVOICE_RUNE = envVars.INVOICE_RUNE !== undefined ? envVars.INVOICE_RUNE : '';
LN_MESSAGE_CONFIG.remoteNodePublicKey = process.env.LIGHTNING_PUBKEY;
APP_CONSTANTS.COMMANDO_RUNE = process.env.COMMANDO_RUNE;
}

private parseEnvFile(filePath: string): { [key: string]: string } {
try {
const content = readFileSync(filePath, 'utf8');
const lines = content.split('\n');
const envVars: { [key: string]: string } = {};

for (let line of lines) {
line = line.trim();
if (line && line.indexOf('=') !== -1 && !line.startsWith('#')) {
const [key, ...value] = line.split('=');
envVars[key] = value.join('=').replace(/(^"|"$)/g, '');
}
}

return envVars;
} catch (err) {
logger.error('Error reading .commando-env file:', err);
return {};
}
}
}

export const LNMessage = new LightningService();
12 changes: 6 additions & 6 deletions apps/frontend/build/asset-manifest.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
{
"files": {
"main.css": "/static/css/main.6598f92c.css",
"main.js": "/static/js/main.7b5c5d6e.js",
"main.css": "/static/css/main.1ce19166.css",
"main.js": "/static/js/main.2875dcdc.js",
"static/media/Inter-Bold.ttf": "/static/media/Inter-Bold.88fa7ae373b07b41ecce.ttf",
"static/media/Inter-SemiBold.ttf": "/static/media/Inter-SemiBold.4d56bb21f2399db8ad48.ttf",
"static/media/Inter-Medium.ttf": "/static/media/Inter-Medium.6dcbc9bed1ec438907ee.ttf",
"static/media/Inter-Thin.ttf": "/static/media/Inter-Thin.f341ca512063c66296d1.ttf",
"index.html": "/index.html",
"main.6598f92c.css.map": "/static/css/main.6598f92c.css.map",
"main.7b5c5d6e.js.map": "/static/js/main.7b5c5d6e.js.map"
"main.1ce19166.css.map": "/static/css/main.1ce19166.css.map",
"main.2875dcdc.js.map": "/static/js/main.2875dcdc.js.map"
},
"entrypoints": [
"static/css/main.6598f92c.css",
"static/js/main.7b5c5d6e.js"
"static/css/main.1ce19166.css",
"static/js/main.2875dcdc.js"
]
}
2 changes: 1 addition & 1 deletion apps/frontend/build/index.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./images/cln-favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="color-scheme" content="light dark"><meta name="description" content="Core lightning application"/><link rel="apple-touch-icon" href="./images/cln-logo-dark.png"/><title>Core Lightning</title><script defer="defer" src="/static/js/main.7b5c5d6e.js"></script><link href="/static/css/main.6598f92c.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./images/cln-favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="color-scheme" content="light dark"><meta name="description" content="Core lightning application"/><link rel="apple-touch-icon" href="./images/cln-logo-dark.png"/><title>Core Lightning</title><script defer="defer" src="/static/js/main.2875dcdc.js"></script><link href="/static/css/main.1ce19166.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions apps/frontend/build/static/css/main.1ce19166.css.map

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion apps/frontend/build/static/css/main.6598f92c.css.map

This file was deleted.

3 changes: 3 additions & 0 deletions apps/frontend/build/static/js/main.2875dcdc.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions apps/frontend/build/static/js/main.2875dcdc.js.map

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions apps/frontend/build/static/js/main.4501e70f.js

Large diffs are not rendered by default.

Loading

0 comments on commit 4399d8c

Please sign in to comment.