@morseai/sdk 0.1.0-beta.5 → 0.1.0-beta.7

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.
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 MORSE Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md CHANGED
@@ -1,8 +1,12 @@
1
1
  # MORSE SDK
2
2
 
3
+ [![npm version](https://badge.fury.io/js/%40morseai%2Fsdk.svg)](https://badge.fury.io/js/%40morseai%2Fsdk)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue.svg)](https://www.typescriptlang.org/)
6
+
3
7
  TypeScript SDK for creating and accessing encrypted signals in the MORSE platform.
4
8
 
5
- **Version:** 0.1.0-beta.5 (Beta Release)
9
+ **Version:** 0.1.0-beta.7 (Beta Release)
6
10
 
7
11
  > ⚠️ **Beta Notice**: This is a beta release. The API is stable but may have minor changes before the 1.0.0 release. Please report any issues you encounter.
8
12
 
package/dist/index.d.mts CHANGED
@@ -103,7 +103,7 @@ interface CreateSignalResponse {
103
103
  expiresAt: string;
104
104
  }
105
105
  interface CreateSignalResponseEncrypted extends CreateSignalResponse {
106
- keyBase64: string;
106
+ keyBase64?: string;
107
107
  shareableLink: string;
108
108
  }
109
109
  interface OpenSignalResponse {
@@ -378,7 +378,7 @@ declare function getSignalUrl(baseUrl: string, signalId: string, keyBase64?: str
378
378
  declare function extractSignalIdFromUrl(url: string): string | null;
379
379
 
380
380
  declare function getCipherVersion(): string;
381
- declare function generateShareableLink(baseUrl: string, signalId: string, keyBase64: string): string;
381
+ declare function generateShareableLink(baseUrl: string, signalId: string, keyBase64?: string): string;
382
382
 
383
383
  /**
384
384
  * MORSE SDK - X25519 + XChaCha20-Poly1305 Encryption
package/dist/index.d.ts CHANGED
@@ -103,7 +103,7 @@ interface CreateSignalResponse {
103
103
  expiresAt: string;
104
104
  }
105
105
  interface CreateSignalResponseEncrypted extends CreateSignalResponse {
106
- keyBase64: string;
106
+ keyBase64?: string;
107
107
  shareableLink: string;
108
108
  }
109
109
  interface OpenSignalResponse {
@@ -378,7 +378,7 @@ declare function getSignalUrl(baseUrl: string, signalId: string, keyBase64?: str
378
378
  declare function extractSignalIdFromUrl(url: string): string | null;
379
379
 
380
380
  declare function getCipherVersion(): string;
381
- declare function generateShareableLink(baseUrl: string, signalId: string, keyBase64: string): string;
381
+ declare function generateShareableLink(baseUrl: string, signalId: string, keyBase64?: string): string;
382
382
 
383
383
  /**
384
384
  * MORSE SDK - X25519 + XChaCha20-Poly1305 Encryption
package/dist/index.js CHANGED
@@ -32,6 +32,7 @@ __export(crypto_x25519_exports, {
32
32
  deriveKeyPairFromWalletSignature: () => deriveKeyPairFromWalletSignature,
33
33
  generateSignalId: () => generateSignalId,
34
34
  openSharedSignal: () => openSharedSignal,
35
+ sealDataKey: () => sealDataKey,
35
36
  verifyKeyCertificate: () => verifyKeyCertificate
36
37
  });
37
38
  async function getSodium() {
@@ -291,6 +292,54 @@ async function openSharedSignal(encryptedPayloadBase64, payloadNonceBase64, seal
291
292
  );
292
293
  return payload;
293
294
  }
295
+ async function sealDataKey(dataKeyBytes, walletTarget, walletCreator, expiresAt, signalId, domain, chainId, signMessage) {
296
+ await getSodium();
297
+ const senderKeypair = sodium.crypto_box_keypair();
298
+ const recipientKeypair = await deriveKeyPairFromWalletSignature(
299
+ walletTarget,
300
+ domain,
301
+ chainId,
302
+ signMessage
303
+ );
304
+ const recipientPubKey = recipientKeypair.publicKey;
305
+ const sharedSecret = sodium.crypto_scalarmult(
306
+ senderKeypair.privateKey,
307
+ recipientPubKey
308
+ );
309
+ const salt = `MORSE_SEAL_${signalId}_v1`;
310
+ const info = "wrap_datakey";
311
+ const wrappingKey = await hkdfSha256(sharedSecret, salt, info, 32);
312
+ const sealedNonce = sodium.randombytes_buf(sodium.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES);
313
+ const expiresAtInt = Math.floor(Number(expiresAt));
314
+ const abiCoder = ethers.ethers.AbiCoder.defaultAbiCoder();
315
+ const senderEphemeralPubKeyHex = ethers.ethers.zeroPadValue(ethers.ethers.hexlify(senderKeypair.publicKey), 32);
316
+ const aad = abiCoder.encode(
317
+ ["string", "address", "address", "uint64", "string", "bytes32"],
318
+ [
319
+ signalId,
320
+ walletTarget.toLowerCase(),
321
+ walletCreator.toLowerCase(),
322
+ expiresAtInt,
323
+ exports.X25519_CIPHER_VERSION,
324
+ senderEphemeralPubKeyHex
325
+ ]
326
+ );
327
+ const aadBytes = ethers.ethers.getBytes(aad);
328
+ const aadHash = ethers.ethers.keccak256(aad).slice(2);
329
+ const sealedDataKey = sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(
330
+ dataKeyBytes,
331
+ aadBytes,
332
+ null,
333
+ sealedNonce,
334
+ wrappingKey
335
+ );
336
+ return {
337
+ sealedDataKey: Buffer.from(sealedDataKey).toString("base64"),
338
+ sealedNonce: Buffer.from(sealedNonce).toString("base64"),
339
+ senderEphemeralPublicKey: Buffer.from(senderKeypair.publicKey).toString("base64"),
340
+ aadHash
341
+ };
342
+ }
294
343
  function generateSignalId() {
295
344
  const bytes = new Uint8Array(16);
296
345
  globalThis.crypto.getRandomValues(bytes);
@@ -628,7 +677,7 @@ async function decryptFile(encryptedData, ivBase64, key) {
628
677
  return decrypted;
629
678
  }
630
679
  function generateShareableLink(baseUrl, signalId, keyBase64) {
631
- return `${baseUrl}/view/${signalId}#k=${encodeURIComponent(keyBase64)}`;
680
+ return `${baseUrl}/view/${signalId}`;
632
681
  }
633
682
 
634
683
  // src/implementations/v1/MorseSDKV1.ts
@@ -1250,6 +1299,35 @@ var MorseSDKV1 = class {
1250
1299
  async createPrivateSignalEncrypted(wallet, options) {
1251
1300
  const key = await generateKey();
1252
1301
  const keyBase64 = await exportKey(key);
1302
+ const signalId = options.signalId || generateSignalId();
1303
+ let expiresAtMs;
1304
+ if (options.expiresAt) {
1305
+ expiresAtMs = new Date(options.expiresAt).getTime();
1306
+ } else if (options.expiresIn) {
1307
+ const match = options.expiresIn.match(/^(\d+)([smhd])$/);
1308
+ if (!match) throw new Error("Invalid expiresIn format");
1309
+ const value = parseInt(match[1], 10);
1310
+ const unit = match[2];
1311
+ const multipliers = { s: 1e3, m: 6e4, h: 36e5, d: 864e5 };
1312
+ expiresAtMs = Date.now() + value * multipliers[unit];
1313
+ } else {
1314
+ expiresAtMs = Date.now() + 24 * 60 * 60 * 1e3;
1315
+ }
1316
+ const walletTarget = wallet.address;
1317
+ const walletCreator = wallet.address;
1318
+ const domain = "morse.app";
1319
+ const chainId = 8453;
1320
+ const keyBytes = this.base64ToUint8Array(keyBase64);
1321
+ const sealedBox = await sealDataKey(
1322
+ keyBytes,
1323
+ walletTarget.toLowerCase(),
1324
+ walletCreator.toLowerCase(),
1325
+ expiresAtMs,
1326
+ signalId,
1327
+ domain,
1328
+ chainId,
1329
+ wallet.signMessage
1330
+ );
1253
1331
  let encryptedText;
1254
1332
  let payloadNonce;
1255
1333
  let fileOptions;
@@ -1276,6 +1354,7 @@ var MorseSDKV1 = class {
1276
1354
  };
1277
1355
  }
1278
1356
  const signalOptions = {
1357
+ signalId,
1279
1358
  walletTarget: options.walletTarget,
1280
1359
  shareWithRecipient: options.shareWithRecipient,
1281
1360
  mode: options.mode,
@@ -1284,16 +1363,18 @@ var MorseSDKV1 = class {
1284
1363
  cipherVersion: getCipherVersion(),
1285
1364
  encryptedText,
1286
1365
  payloadNonce,
1366
+ sealedDataKey: sealedBox.sealedDataKey,
1367
+ sealedNonce: sealedBox.sealedNonce,
1368
+ senderEphemeralPublicKey: sealedBox.senderEphemeralPublicKey,
1369
+ aadHash: sealedBox.aadHash,
1287
1370
  file: fileOptions,
1288
1371
  onChainNotification: options.onChainNotification,
1289
- expiresAt: options.expiresAt,
1290
- expiresIn: options.expiresIn
1372
+ expiresAt: new Date(expiresAtMs).toISOString()
1291
1373
  };
1292
1374
  const result = await this.createSignal(wallet, signalOptions);
1293
- const shareableLink = generateShareableLink(FRONTEND_BASE_URL, result.signalId, keyBase64);
1375
+ const shareableLink = generateShareableLink(FRONTEND_BASE_URL, result.signalId);
1294
1376
  return {
1295
1377
  ...result,
1296
- keyBase64,
1297
1378
  shareableLink
1298
1379
  };
1299
1380
  }
@@ -1391,8 +1472,6 @@ var MorseSDKV1 = class {
1391
1472
  const shareableLink = `${FRONTEND_BASE_URL}/view/${result.signalId}`;
1392
1473
  return {
1393
1474
  ...result,
1394
- keyBase64: "",
1395
- // No key needed for X25519 signals
1396
1475
  shareableLink
1397
1476
  };
1398
1477
  }