evernode-js-client 0.5.13 → 0.5.14

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,276 +0,0 @@
1
- const { BaseEvernodeClient } = require('./base-evernode-client');
2
- const { EvernodeEvents, MemoFormats, MemoTypes, ErrorCodes, ErrorReasons, EvernodeConstants } = require('../evernode-common');
3
- const { EncryptionHelper } = require('../encryption-helper');
4
- const { XrplAccount } = require('../xrpl-account');
5
- const { UtilHelpers } = require('../util-helpers');
6
- const { Buffer } = require('buffer');
7
- const codec = require('ripple-address-codec');
8
- const { EvernodeHelpers } = require('../evernode-helpers');
9
- const { TransactionHelper } = require('../transaction-helper');
10
-
11
- const DEFAULT_WAIT_TIMEOUT = 60000;
12
-
13
- const TenantEvents = {
14
- AcquireSuccess: EvernodeEvents.AcquireSuccess,
15
- AcquireError: EvernodeEvents.AcquireError,
16
- ExtendSuccess: EvernodeEvents.ExtendSuccess,
17
- ExtendError: EvernodeEvents.ExtendError,
18
- }
19
-
20
- class TenantClient extends BaseEvernodeClient {
21
-
22
- /**
23
- * Constructs a tenant client instance.
24
- * @param {string} xrpAddress XRPL address of the tenant.
25
- * @param {string} XRPL secret of the tenant.
26
- * @param {object} options [Optional] An object with 'rippledServer' URL and 'registryAddress'.
27
- */
28
- constructor(xrpAddress, xrpSecret, options = {}) {
29
- super(xrpAddress, xrpSecret, Object.values(TenantEvents), false, options);
30
- }
31
-
32
- async prepareAccount() {
33
- try {
34
- if (!await this.xrplAcc.getMessageKey())
35
- await this.xrplAcc.setAccountFields({ MessageKey: this.accKeyPair.publicKey });
36
- }
37
- catch (err) {
38
- console.log("Error in preparing user xrpl account for Evernode.", err);
39
- }
40
- }
41
-
42
- async getLeaseHost(hostAddress) {
43
- const host = new XrplAccount(hostAddress, null, { xrplApi: this.xrplApi });
44
- // Find an owned NFT with matching Evernode host NFT prefix.
45
- const nft = (await host.getNfts()).find(n => n.URI.startsWith(EvernodeConstants.NFT_PREFIX_HEX));
46
- if (!nft)
47
- throw { reason: ErrorReasons.HOST_INVALID, error: "Host is not registered." };
48
-
49
- // Check whether the token was actually issued from Evernode registry contract.
50
- const issuerHex = nft.NFTokenID.substr(8, 40);
51
- const issuerAddr = codec.encodeAccountID(Buffer.from(issuerHex, 'hex'));
52
- if (issuerAddr != this.registryAddress)
53
- throw { reason: ErrorReasons.HOST_INVALID, error: "Host is not registered." };
54
-
55
- // Check whether active.
56
- const hostInfo = await this.getHostInfo(host.address);
57
- if (!hostInfo)
58
- throw { reason: ErrorReasons.HOST_INVALID, error: "Host is not registered." };
59
- else if (!hostInfo.active)
60
- throw { reason: ErrorReasons.HOST_INACTIVE, error: "Host is not active." };
61
-
62
- return host;
63
- }
64
-
65
- /**
66
- *
67
- * @param {string} hostAddress XRPL address of the host to acquire the lease.
68
- * @param {object} requirement The instance requirements and configuration.
69
- * @param {object} options [Optional] Options for the XRPL transaction.
70
- * @returns The transaction result.
71
- */
72
- async acquireLeaseSubmit(hostAddress, requirement, options = {}) {
73
-
74
- const hostAcc = await this.getLeaseHost(hostAddress);
75
- let selectedOfferIndex = options.leaseOfferIndex;
76
-
77
- // Attempt to get first available offer, if offer is not specified in options.
78
- if (!selectedOfferIndex) {
79
- const nftOffers = await EvernodeHelpers.getLeaseOffers(hostAcc);
80
- selectedOfferIndex = nftOffers && nftOffers[0] && nftOffers[0].index;
81
-
82
- if (!selectedOfferIndex)
83
- throw { reason: ErrorReasons.NO_OFFER, error: "No offers available." };
84
- }
85
-
86
- // Encrypt the requirements with the host's encryption key (Specified in MessageKey field of the host account).
87
- const encKey = await hostAcc.getMessageKey();
88
- if (!encKey)
89
- throw { reason: ErrorReasons.INTERNAL_ERR, error: "Host encryption key not set." };
90
-
91
- const ecrypted = await EncryptionHelper.encrypt(encKey, requirement, {
92
- iv: options.iv, // Must be null or 16 bytes.
93
- ephemPrivateKey: options.ephemPrivateKey // Must be null or 32 bytes.
94
- });
95
-
96
- return this.xrplAcc.buyNft(selectedOfferIndex, [{ type: MemoTypes.ACQUIRE_LEASE, format: MemoFormats.BASE64, data: ecrypted }], options.transactionOptions);
97
- }
98
-
99
- /**
100
- * Watch for the acquire-success response after the acquire request is made.
101
- * @param {object} tx The transaction returned by the acquireLeaseSubmit function.
102
- * @param {object} options [Optional] Options for the XRPL transaction.
103
- * @returns An object including transaction details,instance info, and acquireReference Id.
104
- */
105
- async watchAcquireResponse(tx, options = {}) {
106
- console.log(`Waiting for acquire response... (txHash: ${tx.id})`);
107
-
108
- return new Promise(async (resolve, reject) => {
109
- let rejected = false;
110
- const failTimeout = setTimeout(() => {
111
- rejected = true;
112
- reject({ error: ErrorCodes.ACQUIRE_ERR, reason: ErrorReasons.TIMEOUT });
113
- }, options.timeout || DEFAULT_WAIT_TIMEOUT);
114
-
115
- let relevantTx = null;
116
- while (!rejected && !relevantTx) {
117
- const txList = await this.xrplAcc.getAccountTrx(tx.details.ledger_index);
118
- for (let t of txList) {
119
- t.tx.Memos = TransactionHelper.deserializeMemos(t.tx?.Memos);
120
- const res = await this.extractEvernodeEvent(t.tx);
121
- if ((res?.name === EvernodeEvents.AcquireSuccess || res?.name === EvernodeEvents.AcquireError) && res?.data?.acquireRefId === tx.id) {
122
- clearTimeout(failTimeout);
123
- relevantTx = res;
124
- break;
125
- }
126
- }
127
- await new Promise(resolveSleep => setTimeout(resolveSleep, 2000));
128
- }
129
-
130
- if (!rejected) {
131
- if (relevantTx?.name === TenantEvents.AcquireSuccess) {
132
- resolve({
133
- transaction: relevantTx?.data.transaction,
134
- instance: relevantTx?.data.payload.content,
135
- acquireRefId: relevantTx?.data.acquireRefId
136
- });
137
- } else if (relevantTx?.name === TenantEvents.AcquireError) {
138
- reject({
139
- error: ErrorCodes.ACQUIRE_ERR,
140
- transaction: relevantTx?.data.transaction,
141
- reason: relevantTx?.data.reason,
142
- acquireRefId: relevantTx?.data.acquireRefId
143
- });
144
- }
145
- }
146
- });
147
- }
148
-
149
- /**
150
- * Acquire an instance from a host
151
- * @param {string} hostAddress XRPL address of the host to acquire the lease.
152
- * @param {object} requirement The instance requirements and configuration.
153
- * @param {object} options [Optional] Options for the XRPL transaction.
154
- * @returns An object including transaction details,instance info, and acquireReference Id.
155
- */
156
- acquireLease(hostAddress, requirement, options = {}) {
157
- return new Promise(async (resolve, reject) => {
158
- const tx = await this.acquireLeaseSubmit(hostAddress, requirement, options).catch(error => {
159
- reject({ error: ErrorCodes.ACQUIRE_ERR, reason: error.reason || ErrorReasons.TRANSACTION_FAILURE, content: error.error || error });
160
- });
161
- if (tx) {
162
- try {
163
- const response = await this.watchAcquireResponse(tx, options);
164
- resolve(response);
165
- } catch (error) {
166
- reject(error);
167
- }
168
- }
169
- });
170
- }
171
-
172
- /**
173
- * This function is called by a tenant client to submit the extend lease transaction in certain host. This function will be called inside extendLease function. This function can take four parameters as follows.
174
- * @param {string} hostAddress XRPL account address of the host.
175
- * @param {number} amount Cost for the extended moments , in EVRs.
176
- * @param {string} tokenID Tenant received instance name. this name can be retrieve by performing acquire Lease.
177
- * @param {object} options This is an optional field and contains necessary details for the transactions.
178
- * @returns The transaction result.
179
- */
180
- async extendLeaseSubmit(hostAddress, amount, tokenID, options = {}) {
181
- const host = await this.getLeaseHost(hostAddress);
182
- return this.xrplAcc.makePayment(host.address, amount.toString(), EvernodeConstants.EVR, this.config.evrIssuerAddress,
183
- [{ type: MemoTypes.EXTEND_LEASE, format: MemoFormats.HEX, data: tokenID }], options.transactionOptions);
184
- }
185
-
186
- /**
187
- * This function watches for an extendlease-success response(transaction) and returns the response or throws the error response on extendlease-error response from the host XRPL account. This function is called within the extendLease function.
188
- * @param {object} tx Response of extendLeaseSubmit.
189
- * @param {object} options This is an optional field and contains necessary details for the transactions.
190
- * @returns An object including transaction details.
191
- */
192
- async watchExtendResponse(tx, options = {}) {
193
- console.log(`Waiting for extend lease response... (txHash: ${tx.id})`);
194
-
195
- return new Promise(async (resolve, reject) => {
196
- let rejected = false;
197
- const failTimeout = setTimeout(() => {
198
- rejected = true;
199
- reject({ error: ErrorCodes.EXTEND_ERR, reason: ErrorReasons.TIMEOUT });
200
- }, options.timeout || DEFAULT_WAIT_TIMEOUT);
201
-
202
- let relevantTx = null;
203
- while (!rejected && !relevantTx) {
204
- const txList = await this.xrplAcc.getAccountTrx(tx.details.ledger_index);
205
- for (let t of txList) {
206
- t.tx.Memos = TransactionHelper.deserializeMemos(t.tx.Memos);
207
- const res = await this.extractEvernodeEvent(t.tx);
208
- if ((res?.name === TenantEvents.ExtendSuccess || res?.name === TenantEvents.ExtendError) && res?.data?.extendRefId === tx.id) {
209
- clearTimeout(failTimeout);
210
- relevantTx = res;
211
- break;
212
- }
213
- }
214
- await new Promise(resolveSleep => setTimeout(resolveSleep, 1000));
215
- }
216
-
217
- if (!rejected) {
218
- if (relevantTx?.name === TenantEvents.ExtendSuccess) {
219
- resolve({
220
- transaction: relevantTx?.data.transaction,
221
- expiryMoment: relevantTx?.data.expiryMoment,
222
- extendeRefId: relevantTx?.data.extendRefId
223
- });
224
- } else if (relevantTx?.name === TenantEvents.ExtendError) {
225
- reject({
226
- error: ErrorCodes.EXTEND_ERR,
227
- transaction: relevantTx?.data.transaction,
228
- reason: relevantTx?.data.reason
229
- });
230
- }
231
- }
232
- });
233
- }
234
-
235
- /**
236
- * This function is called by a tenant client to extend an available instance in certain host. This function can take four parameters as follows.
237
- * @param {string} hostAddress XRPL account address of the host.
238
- * @param {number} moments 1190 ledgers (est. 1 hour).
239
- * @param {string} instanceName Tenant received instance name. this name can be retrieve by performing acquire Lease.
240
- * @param {object} options This is an optional field and contains necessary details for the transactions.
241
- * @returns An object including transaction details.
242
- */
243
- extendLease(hostAddress, moments, instanceName, options = {}) {
244
- return new Promise(async (resolve, reject) => {
245
- const tokenID = instanceName;
246
- const nft = (await this.xrplAcc.getNfts())?.find(n => n.NFTokenID == tokenID);
247
-
248
- if (!nft) {
249
- reject({ error: ErrorCodes.EXTEND_ERR, reason: ErrorReasons.NO_NFT, content: 'Could not find the nft for lease extend request.' });
250
- return;
251
- }
252
-
253
- let minLedgerIndex = this.xrplApi.ledgerIndex;
254
-
255
- // Get the agreement lease amount from the nft and calculate EVR amount to be sent.
256
- const uriInfo = UtilHelpers.decodeLeaseNftUri(nft.URI);
257
- const tx = await this.extendLeaseSubmit(hostAddress, moments * uriInfo.leaseAmount, tokenID, options).catch(error => {
258
- reject({ error: ErrorCodes.EXTEND_ERR, reason: error.reason || ErrorReasons.TRANSACTION_FAILURE, content: error.error || error });
259
- });
260
-
261
- if (tx) {
262
- try {
263
- const response = await this.watchExtendResponse(tx, minLedgerIndex, options)
264
- resolve(response);
265
- } catch (error) {
266
- reject(error);
267
- }
268
- }
269
- });
270
- }
271
- }
272
-
273
- module.exports = {
274
- TenantEvents,
275
- TenantClient
276
- }
package/src/defaults.js DELETED
@@ -1,21 +0,0 @@
1
- const DefaultValues = {
2
- registryAddress: 'raaFre81618XegCrzTzVotAmarBcqNSAvK',
3
- rippledServer: 'wss://hooks-testnet-v2.xrpl-labs.com',
4
- xrplApi: null,
5
- stateIndexId: 'evernodeindex'
6
- }
7
-
8
- class Defaults {
9
- static set(newDefaults) {
10
- Object.assign(DefaultValues, newDefaults)
11
- }
12
-
13
- static get() {
14
- return { ...DefaultValues };
15
- }
16
- }
17
-
18
- module.exports = {
19
- DefaultValues,
20
- Defaults
21
- }
package/src/eccrypto.js DELETED
@@ -1,258 +0,0 @@
1
- // Code taken from https://github.com/bitchan/eccrypto/blob/master/browser.js
2
- // We are using this code file directly because the full eccrypto library causes a conflict with
3
- // tiny-secp256k1 used by xrpl libs during ncc/webpack build.
4
-
5
- var EC = require("elliptic").ec;
6
- var ec = new EC("secp256k1");
7
- var browserCrypto = global.crypto || global.msCrypto || {};
8
- var subtle = browserCrypto.subtle || browserCrypto.webkitSubtle;
9
-
10
- var nodeCrypto = require('crypto');
11
-
12
- const EC_GROUP_ORDER = Buffer.from('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141', 'hex');
13
- const ZERO32 = Buffer.alloc(32, 0);
14
-
15
- function assert(condition, message) {
16
- if (!condition) {
17
- throw new Error(message || "Assertion failed");
18
- }
19
- }
20
-
21
- function isScalar(x) {
22
- return Buffer.isBuffer(x) && x.length === 32;
23
- }
24
-
25
- function isValidPrivateKey(privateKey) {
26
- if (!isScalar(privateKey)) {
27
- return false;
28
- }
29
- return privateKey.compare(ZERO32) > 0 && // > 0
30
- privateKey.compare(EC_GROUP_ORDER) < 0; // < G
31
- }
32
-
33
- // Compare two buffers in constant time to prevent timing attacks.
34
- function equalConstTime(b1, b2) {
35
- if (b1.length !== b2.length) {
36
- return false;
37
- }
38
- var res = 0;
39
- for (var i = 0; i < b1.length; i++) {
40
- res |= b1[i] ^ b2[i]; // jshint ignore:line
41
- }
42
- return res === 0;
43
- }
44
-
45
- /* This must check if we're in the browser or
46
- not, since the functions are different and does
47
- not convert using browserify */
48
- function randomBytes(size) {
49
- var arr = new Uint8Array(size);
50
- if (typeof browserCrypto.getRandomValues === 'undefined') {
51
- return Buffer.from(nodeCrypto.randomBytes(size));
52
- } else {
53
- browserCrypto.getRandomValues(arr);
54
- }
55
- return Buffer.from(arr);
56
- }
57
-
58
- function sha512(msg) {
59
- return new Promise(function (resolve) {
60
- var hash = nodeCrypto.createHash('sha512');
61
- var result = hash.update(msg).digest();
62
- resolve(new Uint8Array(result));
63
- });
64
- }
65
-
66
- function getAes(op) {
67
- return function (iv, key, data) {
68
- return new Promise(function (resolve) {
69
- if (subtle) {
70
- var importAlgorithm = { name: "AES-CBC" };
71
- var keyp = subtle.importKey("raw", key, importAlgorithm, false, [op]);
72
- return keyp.then(function (cryptoKey) {
73
- var encAlgorithm = { name: "AES-CBC", iv: iv };
74
- return subtle[op](encAlgorithm, cryptoKey, data);
75
- }).then(function (result) {
76
- resolve(Buffer.from(new Uint8Array(result)));
77
- });
78
- } else {
79
- if (op === 'encrypt') {
80
- var cipher = nodeCrypto.createCipheriv('aes-256-cbc', key, iv);
81
- let firstChunk = cipher.update(data);
82
- let secondChunk = cipher.final();
83
- resolve(Buffer.concat([firstChunk, secondChunk]));
84
- }
85
- else if (op === 'decrypt') {
86
- var decipher = nodeCrypto.createDecipheriv('aes-256-cbc', key, iv);
87
- let firstChunk = decipher.update(data);
88
- let secondChunk = decipher.final();
89
- resolve(Buffer.concat([firstChunk, secondChunk]));
90
- }
91
- }
92
- });
93
- };
94
- }
95
-
96
- var aesCbcEncrypt = getAes("encrypt");
97
- var aesCbcDecrypt = getAes("decrypt");
98
-
99
- function hmacSha256Sign(key, msg) {
100
- return new Promise(function (resolve) {
101
- var hmac = nodeCrypto.createHmac('sha256', Buffer.from(key));
102
- hmac.update(msg);
103
- var result = hmac.digest();
104
- resolve(result);
105
- });
106
- }
107
-
108
- function hmacSha256Verify(key, msg, sig) {
109
- return new Promise(function (resolve) {
110
- var hmac = nodeCrypto.createHmac('sha256', Buffer.from(key));
111
- hmac.update(msg);
112
- var expectedSig = hmac.digest();
113
- resolve(equalConstTime(expectedSig, sig));
114
- });
115
- }
116
-
117
- /**
118
- * Generate a new valid private key. Will use the window.crypto or window.msCrypto as source
119
- * depending on your browser.
120
- * @return {Buffer} A 32-byte private key.
121
- * @function
122
- */
123
- exports.generatePrivate = function () {
124
- var privateKey = randomBytes(32);
125
- while (!isValidPrivateKey(privateKey)) {
126
- privateKey = randomBytes(32);
127
- }
128
- return privateKey;
129
- };
130
-
131
- var getPublic = exports.getPublic = function (privateKey) {
132
- // This function has sync API so we throw an error immediately.
133
- assert(privateKey.length === 32, "Bad private key");
134
- assert(isValidPrivateKey(privateKey), "Bad private key");
135
- // XXX(Kagami): `elliptic.utils.encode` returns array for every
136
- // encoding except `hex`.
137
- return Buffer.from(ec.keyFromPrivate(privateKey).getPublic("arr"));
138
- };
139
-
140
- /**
141
- * Get compressed version of public key.
142
- */
143
- var getPublicCompressed = exports.getPublicCompressed = function (privateKey) { // jshint ignore:line
144
- assert(privateKey.length === 32, "Bad private key");
145
- assert(isValidPrivateKey(privateKey), "Bad private key");
146
- // See https://github.com/wanderer/secp256k1-node/issues/46
147
- let compressed = true;
148
- return Buffer.from(ec.keyFromPrivate(privateKey).getPublic(compressed, "arr"));
149
- };
150
-
151
- // NOTE(Kagami): We don't use promise shim in Browser implementation
152
- // because it's supported natively in new browsers (see
153
- // <http://caniuse.com/#feat=promises>) and we can use only new browsers
154
- // because of the WebCryptoAPI (see
155
- // <http://caniuse.com/#feat=cryptography>).
156
- exports.sign = function (privateKey, msg) {
157
- return new Promise(function (resolve) {
158
- assert(privateKey.length === 32, "Bad private key");
159
- assert(isValidPrivateKey(privateKey), "Bad private key");
160
- assert(msg.length > 0, "Message should not be empty");
161
- assert(msg.length <= 32, "Message is too long");
162
- resolve(Buffer.from(ec.sign(msg, privateKey, { canonical: true }).toDER()));
163
- });
164
- };
165
-
166
- exports.verify = function (publicKey, msg, sig) {
167
- return new Promise(function (resolve, reject) {
168
- assert(publicKey.length === 65 || publicKey.length === 33, "Bad public key");
169
- if (publicKey.length === 65) {
170
- assert(publicKey[0] === 4, "Bad public key");
171
- }
172
- if (publicKey.length === 33) {
173
- assert(publicKey[0] === 2 || publicKey[0] === 3, "Bad public key");
174
- }
175
- assert(msg.length > 0, "Message should not be empty");
176
- assert(msg.length <= 32, "Message is too long");
177
- if (ec.verify(msg, sig, publicKey)) {
178
- resolve(null);
179
- } else {
180
- reject(new Error("Bad signature"));
181
- }
182
- });
183
- };
184
-
185
- var derive = exports.derive = function (privateKeyA, publicKeyB) {
186
- return new Promise(function (resolve) {
187
- assert(Buffer.isBuffer(privateKeyA), "Bad private key");
188
- assert(Buffer.isBuffer(publicKeyB), "Bad public key");
189
- assert(privateKeyA.length === 32, "Bad private key");
190
- assert(isValidPrivateKey(privateKeyA), "Bad private key");
191
- assert(publicKeyB.length === 65 || publicKeyB.length === 33, "Bad public key");
192
- if (publicKeyB.length === 65) {
193
- assert(publicKeyB[0] === 4, "Bad public key");
194
- }
195
- if (publicKeyB.length === 33) {
196
- assert(publicKeyB[0] === 2 || publicKeyB[0] === 3, "Bad public key");
197
- }
198
- var keyA = ec.keyFromPrivate(privateKeyA);
199
- var keyB = ec.keyFromPublic(publicKeyB);
200
- var Px = keyA.derive(keyB.getPublic()); // BN instance
201
- resolve(Buffer.from(Px.toArray()));
202
- });
203
- };
204
-
205
- exports.encrypt = function (publicKeyTo, msg, opts) {
206
- opts = opts || {};
207
- // Tmp variables to save context from flat promises;
208
- var iv, ephemPublicKey, ciphertext, macKey;
209
- return new Promise(function (resolve) {
210
- var ephemPrivateKey = opts.ephemPrivateKey || randomBytes(32);
211
- // There is a very unlikely possibility that it is not a valid key
212
- while (!isValidPrivateKey(ephemPrivateKey)) {
213
- ephemPrivateKey = opts.ephemPrivateKey || randomBytes(32);
214
- }
215
- ephemPublicKey = getPublic(ephemPrivateKey);
216
- resolve(derive(ephemPrivateKey, publicKeyTo));
217
- }).then(function (Px) {
218
- return sha512(Px);
219
- }).then(function (hash) {
220
- iv = opts.iv || randomBytes(16);
221
- var encryptionKey = hash.slice(0, 32);
222
- macKey = hash.slice(32);
223
- return aesCbcEncrypt(iv, encryptionKey, msg);
224
- }).then(function (data) {
225
- ciphertext = data;
226
- var dataToMac = Buffer.concat([iv, ephemPublicKey, ciphertext]);
227
- return hmacSha256Sign(macKey, dataToMac);
228
- }).then(function (mac) {
229
- return {
230
- iv: iv,
231
- ephemPublicKey: ephemPublicKey,
232
- ciphertext: ciphertext,
233
- mac: mac,
234
- };
235
- });
236
- };
237
-
238
- exports.decrypt = function (privateKey, opts) {
239
- // Tmp variable to save context from flat promises;
240
- var encryptionKey;
241
- return derive(privateKey, opts.ephemPublicKey).then(function (Px) {
242
- return sha512(Px);
243
- }).then(function (hash) {
244
- encryptionKey = hash.slice(0, 32);
245
- var macKey = hash.slice(32);
246
- var dataToMac = Buffer.concat([
247
- opts.iv,
248
- opts.ephemPublicKey,
249
- opts.ciphertext
250
- ]);
251
- return hmacSha256Verify(macKey, dataToMac, opts.mac);
252
- }).then(function (macGood) {
253
- assert(macGood, "Bad MAC");
254
- return aesCbcDecrypt(opts.iv, encryptionKey, opts.ciphertext);
255
- }).then(function (msg) {
256
- return Buffer.from(new Uint8Array(msg));
257
- });
258
- };
@@ -1,96 +0,0 @@
1
- class ed25519 {
2
- static async #getLibrary() {
3
- const _sodium = require('libsodium-wrappers');
4
- await _sodium.ready;
5
- return _sodium;
6
- }
7
-
8
- static async encrypt(publicKeyBuf, messageBuf) {
9
- const sodium = await this.#getLibrary();
10
- const curve25519PublicKey = sodium.crypto_sign_ed25519_pk_to_curve25519(publicKeyBuf.slice(1));
11
- return Buffer.from(sodium.crypto_box_seal(messageBuf, curve25519PublicKey));
12
- }
13
-
14
- static async decrypt(privateKeyBuf, encryptedBuf) {
15
- const sodium = await this.#getLibrary();
16
- const keyPair = sodium.crypto_sign_seed_keypair(privateKeyBuf.slice(1));
17
- const curve25519PublicKey_ = sodium.crypto_sign_ed25519_pk_to_curve25519(keyPair.publicKey);
18
- const curve25519PrivateKey = sodium.crypto_sign_ed25519_sk_to_curve25519(keyPair.privateKey);
19
- return Buffer.from(sodium.crypto_box_seal_open(encryptedBuf, curve25519PublicKey_, curve25519PrivateKey));
20
- }
21
- }
22
-
23
- class secp256k1 {
24
- // Offsets of the properties in the encrypted buffer.
25
- static ivOffset = 65;
26
- static macOffset = this.ivOffset + 16;
27
- static ciphertextOffset = this.macOffset + 32;
28
-
29
- static #getLibrary() {
30
- const eccrypto = require('./eccrypto') // Using local copy of the eccrypto code file.
31
- return eccrypto;
32
- }
33
-
34
- static async encrypt(publicKeyBuf, messageBuf, options = {}) {
35
- const eccrypto = this.#getLibrary();
36
- // For the encryption library, both keys and data should be buffers.
37
- const encrypted = await eccrypto.encrypt(publicKeyBuf, messageBuf, options);
38
- // Concat all the properties of the encrypted object to a single buffer.
39
- return Buffer.concat([encrypted.ephemPublicKey, encrypted.iv, encrypted.mac, encrypted.ciphertext]);
40
- }
41
-
42
- static async decrypt(privateKeyBuf, encryptedBuf) {
43
- const eccrypto = this.#getLibrary();
44
- // Extract the buffer from the string and prepare encrypt object from buffer offsets for decryption.
45
- const encryptedObj = {
46
- ephemPublicKey: encryptedBuf.slice(0, this.ivOffset),
47
- iv: encryptedBuf.slice(this.ivOffset, this.macOffset),
48
- mac: encryptedBuf.slice(this.macOffset, this.ciphertextOffset),
49
- ciphertext: encryptedBuf.slice(this.ciphertextOffset)
50
- }
51
-
52
- const decrypted = await eccrypto.decrypt(privateKeyBuf.slice(1), encryptedObj)
53
- .catch(err => console.log(err));
54
-
55
- return decrypted;
56
- }
57
- }
58
-
59
- class EncryptionHelper {
60
- static contentFormat = 'base64';
61
- static keyFormat = 'hex';
62
- static ed25519KeyType = 'ed25519';
63
- static secp256k1KeyType = 'ecdsa-secp256k1';
64
-
65
- static #getAlgorithmFromKey(key) {
66
- const bytes = Buffer.from(key, this.keyFormat);
67
- return bytes.length === 33 && bytes.at(0) === 0xed
68
- ? this.ed25519KeyType
69
- : this.secp256k1KeyType;
70
- }
71
-
72
- static #getEncryptor(key) {
73
- const format = this.#getAlgorithmFromKey(key);
74
- return format === this.secp256k1KeyType ? secp256k1 : ed25519;
75
- }
76
-
77
- static async encrypt(publicKey, message, options = {}) {
78
- const publicKeyBuf = Buffer.from(publicKey, this.keyFormat);
79
- const messageBuf = Buffer.from(JSON.stringify(message));
80
- const encryptor = this.#getEncryptor(publicKey);
81
- const result = await encryptor.encrypt(publicKeyBuf, messageBuf, options);
82
- return result ? result.toString(this.contentFormat) : null;
83
- }
84
-
85
- static async decrypt(privateKey, encrypted) {
86
- const privateKeyBuf = Buffer.from(privateKey, this.keyFormat);
87
- const encryptedBuf = Buffer.from(encrypted, this.contentFormat);
88
- const encryptor = this.#getEncryptor(privateKey);
89
- const decrypted = await encryptor.decrypt(privateKeyBuf, encryptedBuf);
90
- return decrypted ? JSON.parse(decrypted.toString()) : null;
91
- }
92
- }
93
-
94
- module.exports = {
95
- EncryptionHelper
96
- }