balanceofsatoshis 25.4.0 → 25.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +1 -1
  3. package/bos +2 -0
  4. package/chain/fund_transaction.js +10 -9
  5. package/chain/get_block_transactions.js +6 -5
  6. package/chain/recover_p2pk.js +5 -4
  7. package/chain/split_utxos.js +5 -4
  8. package/commands/fetch_request.js +32 -24
  9. package/display/get_icons.js +33 -22
  10. package/encryption/cbor_item_head.js +45 -0
  11. package/encryption/decode_cbor.js +35 -0
  12. package/encryption/decode_cbor_item.js +169 -0
  13. package/encryption/decrypt_with_node.js +21 -18
  14. package/encryption/decrypt_with_secret.js +5 -4
  15. package/encryption/encode_as_cbor.js +5 -12
  16. package/encryption/encode_cbor_item.js +90 -0
  17. package/encryption/index.js +2 -0
  18. package/lnd/get_socket.js +11 -10
  19. package/lnurl/auth.js +6 -5
  20. package/network/get_peers.js +9 -4
  21. package/network/probe.js +2 -0
  22. package/network/probe_destination.js +97 -68
  23. package/network/push_payment.js +42 -17
  24. package/network/send_gift.js +10 -9
  25. package/network/transfer_funds.js +6 -6
  26. package/nodes/register_node.js +34 -30
  27. package/offchain/create_invoice.js +21 -16
  28. package/offchain/get_invoice_amount.js +5 -4
  29. package/offchain/sign_payment_request.js +10 -9
  30. package/package.json +3 -4
  31. package/peers/detect_open_rule_violation.js +6 -5
  32. package/routing/get_chain_fees_chart.js +3 -2
  33. package/routing/get_fees_paid.js +30 -12
  34. package/services/initiate_balanced_channel.js +13 -7
  35. package/swaps/append_failing_edge.js +6 -5
  36. package/swaps/decode_swap_api_key.js +29 -25
  37. package/swaps/get_paid_service.js +38 -17
  38. package/swaps/get_routes_for_funding.js +52 -11
  39. package/swaps/get_swap_service.js +5 -4
  40. package/swaps/rebalance.js +78 -63
  41. package/swaps/swap_in.js +36 -26
  42. package/tags/get_tags.js +26 -15
  43. package/telegram/connect_to_telegram.js +17 -12
  44. package/telegram/get_socks_proxy.js +12 -13
  45. package/telegram/get_telegram_bot.js +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Versions
2
2
 
3
+ ## 25.5.0
4
+
5
+ - `probe`: Add `--ignore-expiry` to probe expired payment requests
6
+
3
7
  ## 25.4.0
4
8
 
5
9
  - `accounting`: After 2021-10-19 derive USD prices from chain payments data
package/README.md CHANGED
@@ -12,7 +12,7 @@ Supported LND versions:
12
12
 
13
13
  ## Install
14
14
 
15
- - Requires an [installation of Node v20+][nodejs-install-guide]
15
+ - Requires an [installation of Node.js v22+][nodejs-install-guide]
16
16
 
17
17
  ```shell
18
18
  npm install -g balanceofsatoshis
package/bos CHANGED
@@ -1657,6 +1657,7 @@ prog
1657
1657
  .option('--avoid <avoid>', 'Avoid forwarding via node/chan/tag', REPEATABLE)
1658
1658
  .option('--avoid-high-fee-routes', 'Avoid evaluating too-high fee routes')
1659
1659
  .option('--find-max', 'Find the maximum routeable amount on success route')
1660
+ .option('--ignore-expiry', 'Probe even when the request has expired')
1660
1661
  .option('--in <public_key>', 'Route through specific peer of destination')
1661
1662
  .option('--max-fee <max_fee>', 'Max expected fee for route', INT, 1337)
1662
1663
  .option('--max-paths <max>', 'Maximum paths to use for find-max', INT, 1)
@@ -1679,6 +1680,7 @@ prog
1679
1680
  find_max: !!options.findMax ? 16777215 : undefined,
1680
1681
  fs: {getFile: readFile},
1681
1682
  in_through: inThrough.public_key,
1683
+ is_ignoring_expiry: !!options.ignoreExpiry,
1682
1684
  is_strict_max_fee: !!options.avoidHighFeeRoutes,
1683
1685
  max_fee: options.maxFee,
1684
1686
  max_paths: options.maxPaths,
@@ -1,5 +1,6 @@
1
1
  const asyncAuto = require('async/auto');
2
2
  const asyncEach = require('async/each');
3
+ const asyncify = require('async/asyncify');
3
4
  const {broadcastTransaction} = require('ln-sync');
4
5
  const {componentsOfTransaction} = require('@alexbosworth/blockchain');
5
6
  const {formatTokens} = require('ln-sync');
@@ -112,10 +113,10 @@ module.exports = (args, cbk) => {
112
113
  getNetwork: ['validate', ({}, cbk) => getNetwork({lnd: args.lnd}, cbk)],
113
114
 
114
115
  // Derive a list of outputs to guide input selection
115
- outputs: ['validate', ({}, cbk) => {
116
+ outputs: ['validate', asyncify(() => {
116
117
  // Exit early when the amount is open ended and thus depends on inputs
117
118
  if (hasMaxAmount(args.amounts)) {
118
- return cbk();
119
+ return;
119
120
  }
120
121
 
121
122
  try {
@@ -125,11 +126,11 @@ module.exports = (args, cbk) => {
125
126
  return {address, tokens};
126
127
  });
127
128
 
128
- return cbk(null, outputs);
129
+ return outputs;
129
130
  } catch (err) {
130
- return cbk([400, err.message]);
131
+ throw [400, err.message];
131
132
  }
132
- }],
133
+ })],
133
134
 
134
135
  // Get UTXOs to use for input selection and final fee rate calculation
135
136
  getUtxos: ['validate', ({}, cbk) => getUtxos({lnd: args.lnd}, cbk)],
@@ -238,7 +239,7 @@ module.exports = (args, cbk) => {
238
239
  }],
239
240
 
240
241
  // Parse amounts and put together the final set of outputs
241
- finalOutputs: ['getMax', ({getMax}, cbk) => {
242
+ finalOutputs: ['getMax', asyncify(({getMax}) => {
242
243
  try {
243
244
  const outputs = args.addresses.map((address, i) => {
244
245
  const amount = args.amounts[i];
@@ -252,11 +253,11 @@ module.exports = (args, cbk) => {
252
253
  return {address, tokens: parseAmount({amount, variables}).tokens};
253
254
  });
254
255
 
255
- return cbk(null, outputs);
256
+ return outputs;
256
257
  } catch (err) {
257
- return cbk([400, err.message]);
258
+ throw [400, err.message];
258
259
  }
259
- }],
260
+ })],
260
261
 
261
262
  // Create a funded PSBT
262
263
  fund: [
@@ -1,4 +1,5 @@
1
1
  const asyncAuto = require('async/auto');
2
+ const asyncify = require('async/asyncify');
2
3
  const {getBlock} = require('ln-service');
3
4
  const {queryTransactions} = require('@alexbosworth/blockchain');
4
5
  const {returnResult} = require('asyncjs-util');
@@ -77,10 +78,10 @@ module.exports = (args, cbk) => {
77
78
  }],
78
79
 
79
80
  // Find the transactions in the block
80
- transactions: ['getBlock', ({getBlock}, cbk) => {
81
+ transactions: ['getBlock', asyncify(({getBlock}) => {
81
82
  // Exit early when there is no block to look through
82
83
  if (!getBlock.block) {
83
- return cbk(null, {transactions: []});
84
+ return {transactions: []};
84
85
  }
85
86
 
86
87
  try {
@@ -89,11 +90,11 @@ module.exports = (args, cbk) => {
89
90
  ids: args.ids,
90
91
  });
91
92
 
92
- return cbk(null, {transactions});
93
+ return {transactions};
93
94
  } catch (err) {
94
- return cbk([503, 'UnexpectedErrorParsingBlockTransactions', {err}]);
95
+ throw [503, 'UnexpectedErrorParsingBlockTransactions', {err}];
95
96
  }
96
- }],
97
+ })],
97
98
  },
98
99
  returnResult({reject, resolve, of: 'transactions'}, cbk));
99
100
  });
@@ -1,6 +1,7 @@
1
1
  const {createHash} = require('crypto');
2
2
 
3
3
  const asyncAuto = require('async/auto');
4
+ const asyncify = require('async/asyncify');
4
5
  const {broadcastChainTransaction} = require('ln-service');
5
6
  const {componentsOfTransaction} = require('@alexbosworth/blockchain');
6
7
  const {createChainAddress} = require('ln-service');
@@ -135,7 +136,7 @@ module.exports = ({id, lnd, request, vout}, cbk) => {
135
136
  recoveryScript: [
136
137
  'createAddress',
137
138
  'getNetwork',
138
- ({createAddress, getNetwork}, cbk) =>
139
+ asyncify(({createAddress, getNetwork}) =>
139
140
  {
140
141
  try {
141
142
  const {script} = outputScriptForAddress({
@@ -143,11 +144,11 @@ module.exports = ({id, lnd, request, vout}, cbk) => {
143
144
  network: getNetwork.network,
144
145
  });
145
146
 
146
- return cbk(null, {script});
147
+ return {script};
147
148
  } catch (err) {
148
- return cbk([503, 'FailedToParseRecoveryAddress', {err}]);
149
+ throw [503, 'FailedToParseRecoveryAddress', {err}];
149
150
  }
150
- }],
151
+ })],
151
152
 
152
153
  // Derive the sweep output, less the amount needed to pay for chain fees
153
154
  sweep: [
@@ -1,5 +1,6 @@
1
1
  const asyncAuto = require('async/auto');
2
2
  const asyncEach = require('async/each');
3
+ const asyncify = require('async/asyncify');
3
4
  const asyncMapSeries = require('async/mapSeries');
4
5
  const asyncReflect = require('async/reflect');
5
6
  const {broadcastChainTransaction} = require('ln-service');
@@ -85,7 +86,7 @@ module.exports = (args, cbk) => {
85
86
  getUtxos: ['validate', ({}, cbk) => getUtxos({lnd: args.lnd}, cbk)],
86
87
 
87
88
  // Select the inputs and the count of outputs that reach the count
88
- plan: ['feeRate', 'getUtxos', ({feeRate, getUtxos}, cbk) => {
89
+ plan: ['feeRate', 'getUtxos', asyncify(({feeRate, getUtxos}) => {
89
90
  try {
90
91
  const plan = utxoSplitPlan({
91
92
  count: args.count,
@@ -95,11 +96,11 @@ module.exports = (args, cbk) => {
95
96
  utxos: getUtxos.utxos,
96
97
  });
97
98
 
98
- return cbk(null, plan);
99
+ return plan;
99
100
  } catch (err) {
100
- return cbk([400, err.message]);
101
+ throw [400, err.message];
101
102
  }
102
- }],
103
+ })],
103
104
 
104
105
  // Generate addresses
105
106
  getAddresses: ['plan', ({plan}, cbk) => {
@@ -10,14 +10,12 @@ const timeoutSignals = new WeakMap();
10
10
  }
11
11
 
12
12
  @returns
13
- {
14
- request: <Request Function>
15
- }
13
+ <Request Function> (args, cbk) => {}
16
14
  */
17
15
  module.exports = ({fetch}, cbk) => {
18
16
  return (options, cbk) => {
19
17
  (async () => {
20
- const controller = new AbortController();
18
+ const controller = new AbortController();
21
19
 
22
20
  // Setup the timeout controller
23
21
  if (!!options.timeout) {
@@ -28,30 +26,40 @@ module.exports = ({fetch}, cbk) => {
28
26
 
29
27
  const url = options.url + encodeQs(options.qs);
30
28
 
31
- try {
32
- // Make the request
33
- const response = await fetch(url, {
34
- body: options.body || undefined,
35
- method: options.method || undefined,
36
- signal: controller.signal,
37
- });
29
+ // Only the request is guarded, so the callback is called once
30
+ const fetched = await (async () => {
31
+ try {
32
+ // Make the request
33
+ const response = await fetch(url, {
34
+ body: options.body || undefined,
35
+ method: options.method || undefined,
36
+ signal: controller.signal,
37
+ });
38
38
 
39
- const res = {statusCode: response.status};
39
+ const res = {statusCode: response.status};
40
40
 
41
- if (!!options.json) {
42
- return cbk(null, res, await response.json());
43
- } else {
44
- return cbk(null, res, await response.text());
45
- }
46
- } catch (err) {
47
- // Return request errors back
48
- return cbk(err);
49
- } finally {
50
- // Reset the timeout since the request is over
51
- if (!!options.timeout) {
52
- clearTimeout(timeoutSignals.get(controller.signal));
41
+ // Exit early when the response is JSON
42
+ if (!!options.json) {
43
+ return {res, body: await response.json()};
44
+ }
45
+
46
+ return {res, body: await response.text()};
47
+ } catch (err) {
48
+ return {err};
49
+ } finally {
50
+ // Reset the timeout since the request is over
51
+ if (!!options.timeout) {
52
+ clearTimeout(timeoutSignals.get(controller.signal));
53
+ }
53
54
  }
55
+ })();
56
+
57
+ // Exit early when the request failed
58
+ if (!!fetched.err) {
59
+ return cbk(fetched.err);
54
60
  }
61
+
62
+ return cbk(null, fetched.res, fetched.body);
55
63
  })();
56
64
  };
57
65
  };
@@ -1,4 +1,5 @@
1
1
  const asyncAuto = require('async/auto');
2
+ const asyncify = require('async/asyncify');
2
3
  const {returnResult} = require('asyncjs-util');
3
4
 
4
5
  const {homePath} = require('../storage');
@@ -38,38 +39,48 @@ module.exports = ({fs}, cbk) => {
38
39
  return cbk();
39
40
  },
40
41
 
41
- // Get icons from the tags file
42
- getIcons: ['validate', ({}, cbk) => {
42
+ // Get the tags file
43
+ getFile: ['validate', ({}, cbk) => {
43
44
  return fs.getFile(tagFilePath(), (err, res) => {
44
45
  // Exit early when there is no tag file
45
46
  if (!!err || !res) {
46
- return cbk(null, {nodes: []});
47
+ return cbk();
47
48
  }
48
49
 
49
- try {
50
- const file = parse(res.toString());
50
+ return cbk(null, res.toString());
51
+ });
52
+ }],
53
+
54
+ // Get icons from the tags file
55
+ getIcons: ['getFile', asyncify(({getFile}) => {
56
+ // Exit early when there is no tag file
57
+ if (!getFile) {
58
+ return {nodes: []};
59
+ }
51
60
 
52
- const keys = uniq(flatten(file.tags.map(n => n.nodes)));
61
+ try {
62
+ const file = parse(getFile);
53
63
 
54
- const nodes = keys.map(key => {
55
- // Only tags this node is included in
56
- const meta = file.tags.filter(tag => {
57
- return isArray(tag.nodes) && tag.nodes.includes(key);
58
- });
64
+ const keys = uniq(flatten(file.tags.map(n => n.nodes)));
59
65
 
60
- return {
61
- aliases: uniq(meta.map(n => n.alias)),
62
- icons: uniq(meta.map(n => n.icon)),
63
- public_key: key,
64
- };
66
+ const nodes = keys.map(key => {
67
+ // Only tags this node is included in
68
+ const meta = file.tags.filter(tag => {
69
+ return isArray(tag.nodes) && tag.nodes.includes(key);
65
70
  });
66
71
 
67
- return cbk(null, {nodes});
68
- } catch (err) {
69
- return cbk(null, {nodes: []});
70
- }
71
- });
72
- }],
72
+ return {
73
+ aliases: uniq(meta.map(n => n.alias)),
74
+ icons: uniq(meta.map(n => n.icon)),
75
+ public_key: key,
76
+ };
77
+ });
78
+
79
+ return {nodes};
80
+ } catch (err) {
81
+ return {nodes: []};
82
+ }
83
+ })],
73
84
  },
74
85
  returnResult({reject, resolve, of: 'getIcons'}, cbk));
75
86
  });
@@ -0,0 +1,45 @@
1
+ const additionalInfo = {1: 24, 2: 25, 4: 26, 8: 27};
2
+ const bitsPerByte = 8;
3
+ const largestSize = 8;
4
+ const majorTypeMultiplier = 32;
5
+ const maxInitialNumber = 23;
6
+ const sizes = [1, 2, 4];
7
+
8
+ /** Encode the head of a CBOR data item, its major type and its number
9
+
10
+ {
11
+ major: <Major Type Number>
12
+ number: <Length or Value Number>
13
+ }
14
+
15
+ @returns
16
+ {
17
+ head: <Data Item Head Buffer Object>
18
+ }
19
+ */
20
+ module.exports = ({major, number}) => {
21
+ const initial = major * majorTypeMultiplier;
22
+
23
+ // Exit early when the number fits into the initial byte
24
+ if (number <= maxInitialNumber) {
25
+ return {head: Buffer.from([initial + number])};
26
+ }
27
+
28
+ // The number follows the initial byte, in as few bytes as it fits into
29
+ const size = sizes.find(n => number < 2 ** (n * bitsPerByte)) || largestSize;
30
+
31
+ const head = Buffer.alloc(1 + size);
32
+
33
+ head[0] = initial + additionalInfo[size];
34
+
35
+ // Exit early when the number needs all eight bytes
36
+ if (size === largestSize) {
37
+ head.writeBigUInt64BE(BigInt(number), 1);
38
+
39
+ return {head};
40
+ }
41
+
42
+ head.writeUIntBE(number, 1, size);
43
+
44
+ return {head};
45
+ };
@@ -0,0 +1,35 @@
1
+ const decodeCborItem = require('./decode_cbor_item');
2
+
3
+ const hexAsBuffer = hex => Buffer.from(hex, 'hex');
4
+ const isString = n => typeof n === 'string';
5
+
6
+ /** Decode CBOR encoded data
7
+
8
+ {
9
+ cbor: <CBOR Encoded Hex String>
10
+ }
11
+
12
+ @throws
13
+ <Error>
14
+
15
+ @returns
16
+ {
17
+ value: <Decoded Value Object>
18
+ }
19
+ */
20
+ module.exports = ({cbor}) => {
21
+ if (!isString(cbor)) {
22
+ throw new Error('ExpectedHexEncodedCborToDecode');
23
+ }
24
+
25
+ const data = hexAsBuffer(cbor);
26
+
27
+ const {end, value} = decodeCborItem({data, start: 0});
28
+
29
+ // The data has to be a single item, with nothing left over
30
+ if (end !== data.length) {
31
+ throw new Error('UnexpectedDataAfterCborItem');
32
+ }
33
+
34
+ return {value};
35
+ };
@@ -0,0 +1,169 @@
1
+ const additionalInfoMask = 31;
2
+ const argumentSizes = {24: 1, 25: 2, 26: 4, 27: 8};
3
+ const arrayOfLength = length => [...Array(length)];
4
+ const firstSimpleValue = 20;
5
+ const {fromEntries} = Object;
6
+ const {isSafeInteger} = Number;
7
+ const isString = n => typeof n === 'string';
8
+ const majorTypeArray = 4;
9
+ const majorTypeBytes = 2;
10
+ const majorTypeMap = 5;
11
+ const majorTypeNegative = 1;
12
+ const majorTypeShift = 5;
13
+ const majorTypeSimple = 7;
14
+ const majorTypeText = 3;
15
+ const majorTypeUnsigned = 0;
16
+ const maxAdditionalInfo = 27;
17
+ const maxInitialNumber = 23;
18
+ const maxSafe = BigInt(Number.MAX_SAFE_INTEGER);
19
+ const simpleValues = [false, true, null, undefined];
20
+ const sizeOfLargestNumber = 8;
21
+
22
+ /** Decode the CBOR data item that starts at an index
23
+
24
+ {
25
+ data: <CBOR Encoded Data Buffer Object>
26
+ start: <Start Index Number>
27
+ }
28
+
29
+ @throws
30
+ <Error>
31
+
32
+ @returns
33
+ {
34
+ end: <Index After the End of the Data Item Number>
35
+ value: <Decoded Value Object>
36
+ }
37
+ */
38
+ module.exports = ({data, start}) => {
39
+ if (start >= data.length) {
40
+ throw new Error('UnexpectedEndOfCborData');
41
+ }
42
+
43
+ const info = data[start] & additionalInfoMask;
44
+ const major = data[start] >> majorTypeShift;
45
+
46
+ // Exit early when the item is false, true, null or undefined
47
+ if (major === majorTypeSimple) {
48
+ const index = info - firstSimpleValue;
49
+
50
+ if (index < 0 || index >= simpleValues.length) {
51
+ throw new Error('UnsupportedCborSimpleValue');
52
+ }
53
+
54
+ return {end: start + 1, value: simpleValues[index]};
55
+ }
56
+
57
+ // Indefinite lengths are not supported
58
+ if (info > maxAdditionalInfo) {
59
+ throw new Error('UnsupportedCborAdditionalInfo');
60
+ }
61
+
62
+ // A number too large for the initial byte follows after the initial byte
63
+ const size = info > maxInitialNumber ? argumentSizes[info] : 0;
64
+
65
+ const next = start + 1 + size;
66
+
67
+ if (next > data.length) {
68
+ throw new Error('UnexpectedEndOfCborData');
69
+ }
70
+
71
+ const readNumber = () => {
72
+ // Exit early when the number is in the initial byte
73
+ if (!size) {
74
+ return info;
75
+ }
76
+
77
+ // Exit early when the number is in one, two or four bytes
78
+ if (size !== sizeOfLargestNumber) {
79
+ return data.readUIntBE(start + 1, size);
80
+ }
81
+
82
+ const number = data.readBigUInt64BE(start + 1);
83
+
84
+ if (number > maxSafe) {
85
+ throw new Error('UnsupportedLargeCborNumber');
86
+ }
87
+
88
+ return Number(number);
89
+ };
90
+
91
+ const number = readNumber();
92
+
93
+ // Exit early when the item is an integer at or above zero
94
+ if (major === majorTypeUnsigned) {
95
+ return {end: next, value: number};
96
+ }
97
+
98
+ // Exit early when the item is a negative integer
99
+ if (major === majorTypeNegative) {
100
+ if (!isSafeInteger(-1 - number)) {
101
+ throw new Error('UnsupportedLargeCborNumber');
102
+ }
103
+
104
+ return {end: next, value: -1 - number};
105
+ }
106
+
107
+ // Exit early when the item is bytes or text
108
+ if (major === majorTypeBytes || major === majorTypeText) {
109
+ const end = next + number;
110
+
111
+ if (end > data.length) {
112
+ throw new Error('UnexpectedEndOfCborData');
113
+ }
114
+
115
+ const bytes = Buffer.from(data.subarray(next, end));
116
+
117
+ return {end, value: major === majorTypeText ? bytes.toString() : bytes};
118
+ }
119
+
120
+ // Exit early when the item is an array, decoding each item in order
121
+ if (major === majorTypeArray) {
122
+ // Every item takes up at least one byte
123
+ if (number > data.length - next) {
124
+ throw new Error('UnexpectedEndOfCborData');
125
+ }
126
+
127
+ const items = [];
128
+
129
+ const end = arrayOfLength(number).reduce(at => {
130
+ const item = module.exports({data, start: at});
131
+
132
+ items.push(item.value);
133
+
134
+ return item.end;
135
+ },
136
+ next);
137
+
138
+ return {end, value: items};
139
+ }
140
+
141
+ if (major !== majorTypeMap) {
142
+ throw new Error('UnsupportedCborTag');
143
+ }
144
+
145
+ // Every map entry takes up at least two bytes, a key and its value
146
+ if (number * 2 > data.length - next) {
147
+ throw new Error('UnexpectedEndOfCborData');
148
+ }
149
+
150
+ const entries = [];
151
+
152
+ // Decode each key followed by its value
153
+ const end = arrayOfLength(number).reduce(at => {
154
+ const key = module.exports({data, start: at});
155
+
156
+ if (!isString(key.value)) {
157
+ throw new Error('ExpectedTextKeysInCborMap');
158
+ }
159
+
160
+ const item = module.exports({data, start: key.end});
161
+
162
+ entries.push([key.value, item.value]);
163
+
164
+ return item.end;
165
+ },
166
+ next);
167
+
168
+ return {end, value: fromEntries(entries)};
169
+ };
@@ -1,10 +1,11 @@
1
1
  const asyncAuto = require('async/auto');
2
- const {decodeFirst} = require('cbor');
2
+ const asyncify = require('async/asyncify');
3
3
  const {diffieHellmanComputeSecret} = require('ln-service');
4
4
  const {getIdentity} = require('ln-service');
5
5
  const {getNode} = require('ln-service');
6
6
  const {returnResult} = require('asyncjs-util');
7
7
 
8
+ const decodeCbor = require('./decode_cbor');
8
9
  const decryptWithSecret = require('./decrypt_with_secret');
9
10
 
10
11
  const hexAsBuf = hex => Buffer.from(hex, 'hex');
@@ -41,27 +42,29 @@ module.exports = ({encrypted, lnd}, cbk) => {
41
42
  },
42
43
 
43
44
  // Decode encrypted CBOR
44
- decode: ['validate', ({}, cbk) => {
45
- return decodeFirst(encrypted, (err, details) => {
46
- if (!!err) {
47
- return cbk([400, 'ExpectedCborEncodedEncryptedData', {err}]);
48
- }
45
+ decode: ['validate', asyncify(() => {
46
+ let details;
49
47
 
50
- if (!details) {
51
- return cbk([400, 'ExpectedDecodedDetailsToDecryptWithNode']);
52
- }
48
+ try {
49
+ details = decodeCbor({cbor: encrypted}).value;
50
+ } catch (err) {
51
+ throw [400, 'ExpectedCborEncodedEncryptedData', {err}];
52
+ }
53
53
 
54
- if (!details.settings) {
55
- return cbk([400, 'ExpectedEncryptionSettingsToDecryptWithNode']);
56
- }
54
+ if (!details) {
55
+ throw [400, 'ExpectedDecodedDetailsToDecryptWithNode'];
56
+ }
57
57
 
58
- if (!isArray(details.settings.with)) {
59
- return cbk([400, 'ExpectedWithNodesPublicKeyToDecrypt']);
60
- }
58
+ if (!details.settings) {
59
+ throw [400, 'ExpectedEncryptionSettingsToDecryptWithNode'];
60
+ }
61
61
 
62
- return cbk(null, details);
63
- });
64
- }],
62
+ if (!isArray(details.settings.with)) {
63
+ throw [400, 'ExpectedWithNodesPublicKeyToDecrypt'];
64
+ }
65
+
66
+ return details;
67
+ })],
65
68
 
66
69
  // Get node public key
67
70
  getPublicKey: ['decode', ({decode}, cbk) => getIdentity({lnd}, cbk)],