@txnlab/use-wallet 4.5.0 → 4.6.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.
package/dist/index.cjs CHANGED
@@ -5981,6 +5981,11 @@ var BaseWallet = class {
5981
5981
  this.logger.error("Method not supported: signData");
5982
5982
  throw new Error("Method not supported: signData");
5983
5983
  };
5984
+ canUsePrivateKey = false;
5985
+ withPrivateKey = async (_callback) => {
5986
+ this.logger.error("Method not supported: withPrivateKey");
5987
+ throw new Error("Method not supported: withPrivateKey");
5988
+ };
5984
5989
  // ---------- Derived Properties ------------------------------------ //
5985
5990
  get name() {
5986
5991
  return this.id.toUpperCase();
@@ -8234,6 +8239,116 @@ var MagicAuth = class extends BaseWallet {
8234
8239
 
8235
8240
  // src/wallets/mnemonic.ts
8236
8241
  var import_algosdk9 = __toESM(require("algosdk"), 1);
8242
+
8243
+ // src/secure-key.ts
8244
+ var secureLogger = logger.createScopedLogger("SecureKey");
8245
+ function zeroMemory(buffer) {
8246
+ if (!buffer || buffer.length === 0) return;
8247
+ try {
8248
+ if (typeof crypto !== "undefined" && crypto.getRandomValues) {
8249
+ crypto.getRandomValues(buffer);
8250
+ }
8251
+ buffer.fill(0);
8252
+ } catch {
8253
+ for (let i = 0; i < buffer.length; i++) {
8254
+ buffer[i] = 0;
8255
+ }
8256
+ }
8257
+ }
8258
+ function zeroString(str) {
8259
+ if (!str) return "";
8260
+ const arr = new Uint8Array(str.length);
8261
+ for (let i = 0; i < str.length; i++) {
8262
+ arr[i] = str.charCodeAt(i);
8263
+ }
8264
+ zeroMemory(arr);
8265
+ return "";
8266
+ }
8267
+ var SecureKeyContainer = class {
8268
+ _secretKey = null;
8269
+ _isCleared = false;
8270
+ constructor(secretKey) {
8271
+ this._secretKey = new Uint8Array(secretKey);
8272
+ }
8273
+ /**
8274
+ * Check if the key has been cleared
8275
+ */
8276
+ get isCleared() {
8277
+ return this._isCleared;
8278
+ }
8279
+ /**
8280
+ * Execute a callback with access to the secret key.
8281
+ * The key is automatically cleared if an error occurs.
8282
+ */
8283
+ async useKey(callback) {
8284
+ if (this._isCleared || !this._secretKey) {
8285
+ throw new Error("SecureKeyContainer: Key has been cleared");
8286
+ }
8287
+ try {
8288
+ return await callback(this._secretKey);
8289
+ } catch (error) {
8290
+ this.clear();
8291
+ throw error;
8292
+ }
8293
+ }
8294
+ /**
8295
+ * Execute a synchronous callback with access to the secret key.
8296
+ */
8297
+ useKeySync(callback) {
8298
+ if (this._isCleared || !this._secretKey) {
8299
+ throw new Error("SecureKeyContainer: Key has been cleared");
8300
+ }
8301
+ try {
8302
+ return callback(this._secretKey);
8303
+ } catch (error) {
8304
+ this.clear();
8305
+ throw error;
8306
+ }
8307
+ }
8308
+ /**
8309
+ * Securely clear the key from memory.
8310
+ * This should be called when the key is no longer needed.
8311
+ */
8312
+ clear() {
8313
+ if (this._secretKey && !this._isCleared) {
8314
+ zeroMemory(this._secretKey);
8315
+ this._secretKey = null;
8316
+ this._isCleared = true;
8317
+ secureLogger.debug("Key material cleared from memory");
8318
+ }
8319
+ }
8320
+ };
8321
+ async function withSecureKey(secretKey, callback) {
8322
+ const container = new SecureKeyContainer(secretKey);
8323
+ try {
8324
+ return await callback(container);
8325
+ } finally {
8326
+ container.clear();
8327
+ }
8328
+ }
8329
+ function withSecureKeySync(secretKey, callback) {
8330
+ const container = new SecureKeyContainer(secretKey);
8331
+ try {
8332
+ return callback(container);
8333
+ } finally {
8334
+ container.clear();
8335
+ }
8336
+ }
8337
+ async function deriveAlgorandAccountFromEd25519(ed25519Seed) {
8338
+ if (ed25519Seed.length !== 32) {
8339
+ throw new Error(`Invalid ed25519 seed length: expected 32 bytes, got ${ed25519Seed.length}`);
8340
+ }
8341
+ const nacl = await Promise.resolve().then(() => __toESM(require_nacl_fast(), 1));
8342
+ const algosdk15 = await import("algosdk");
8343
+ const keyPair = nacl.sign.keyPair.fromSeed(ed25519Seed);
8344
+ const address = algosdk15.encodeAddress(keyPair.publicKey);
8345
+ return {
8346
+ addr: address,
8347
+ sk: keyPair.secretKey
8348
+ };
8349
+ }
8350
+
8351
+ // src/wallets/mnemonic.ts
8237
8352
  var LOCAL_STORAGE_MNEMONIC_KEY = `${LOCAL_STORAGE_KEY}_mnemonic`;
8238
8353
  var ICON11 = `data:image/svg+xml;base64,${btoa(`
8239
8354
  <svg viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg">
@@ -8387,6 +8502,41 @@ var MnemonicWallet = class extends BaseWallet {
8387
8502
  });
8388
8503
  return txnsToSign;
8389
8504
  }
8505
+ canUsePrivateKey = true;
8506
+ /**
8507
+ * Provide scoped access to the private key via a callback.
8508
+ *
8509
+ * The callback receives a copy of the 64-byte Algorand secret key.
8510
+ * The copy is guaranteed to be zeroed from memory when the callback
8511
+ * completes, whether it succeeds or throws.
8512
+ *
8513
+ * **Note:** This method is blocked on MainNet. The Mnemonic wallet is intended
8514
+ * for development and testing only. For production use, see Web3Auth which
8515
+ * supports `withPrivateKey` on all networks.
8516
+ *
8517
+ * @example
8518
+ * ```typescript
8519
+ * const result = await wallet.withPrivateKey(async (secretKey) => {
8520
+ * // secretKey is a 64-byte Uint8Array
8521
+ * return doSomethingWith(secretKey)
8522
+ * })
8523
+ * // secretKey is zeroed at this point
8524
+ * ```
8525
+ */
8526
+ withPrivateKey = async (callback) => {
8527
+ this.checkMainnet();
8528
+ if (!this.account) {
8529
+ this.logger.error("Mnemonic wallet not connected");
8530
+ throw new Error("Mnemonic wallet not connected");
8531
+ }
8532
+ this.logger.debug("withPrivateKey: Providing private key access...");
8533
+ const skCopy = new Uint8Array(this.account.sk);
8534
+ try {
8535
+ return await callback(skCopy);
8536
+ } finally {
8537
+ zeroMemory(skCopy);
8538
+ }
8539
+ };
8390
8540
  signTransactions = async (txnGroup, indexesToSign) => {
8391
8541
  this.checkMainnet();
8392
8542
  try {
@@ -8626,116 +8776,6 @@ var PeraWallet = class extends BaseWallet {
8626
8776
 
8627
8777
  // src/wallets/web3auth.ts
8628
8778
  var import_algosdk11 = __toESM(require("algosdk"), 1);
8629
-
8630
- // src/secure-key.ts
8631
- var secureLogger = logger.createScopedLogger("SecureKey");
8632
- function zeroMemory(buffer) {
8633
- if (!buffer || buffer.length === 0) return;
8634
- try {
8635
- if (typeof crypto !== "undefined" && crypto.getRandomValues) {
8636
- crypto.getRandomValues(buffer);
8637
- }
8638
- buffer.fill(0);
8639
- } catch {
8640
- for (let i = 0; i < buffer.length; i++) {
8641
- buffer[i] = 0;
8642
- }
8643
- }
8644
- }
8645
- function zeroString(str) {
8646
- if (!str) return "";
8647
- const arr = new Uint8Array(str.length);
8648
- for (let i = 0; i < str.length; i++) {
8649
- arr[i] = str.charCodeAt(i);
8650
- }
8651
- zeroMemory(arr);
8652
- return "";
8653
- }
8654
- var SecureKeyContainer = class {
8655
- _secretKey = null;
8656
- _isCleared = false;
8657
- constructor(secretKey) {
8658
- this._secretKey = new Uint8Array(secretKey);
8659
- }
8660
- /**
8661
- * Check if the key has been cleared
8662
- */
8663
- get isCleared() {
8664
- return this._isCleared;
8665
- }
8666
- /**
8667
- * Execute a callback with access to the secret key.
8668
- * The key is automatically cleared if an error occurs.
8669
- */
8670
- async useKey(callback) {
8671
- if (this._isCleared || !this._secretKey) {
8672
- throw new Error("SecureKeyContainer: Key has been cleared");
8673
- }
8674
- try {
8675
- return await callback(this._secretKey);
8676
- } catch (error) {
8677
- this.clear();
8678
- throw error;
8679
- }
8680
- }
8681
- /**
8682
- * Execute a synchronous callback with access to the secret key.
8683
- */
8684
- useKeySync(callback) {
8685
- if (this._isCleared || !this._secretKey) {
8686
- throw new Error("SecureKeyContainer: Key has been cleared");
8687
- }
8688
- try {
8689
- return callback(this._secretKey);
8690
- } catch (error) {
8691
- this.clear();
8692
- throw error;
8693
- }
8694
- }
8695
- /**
8696
- * Securely clear the key from memory.
8697
- * This should be called when the key is no longer needed.
8698
- */
8699
- clear() {
8700
- if (this._secretKey && !this._isCleared) {
8701
- zeroMemory(this._secretKey);
8702
- this._secretKey = null;
8703
- this._isCleared = true;
8704
- secureLogger.debug("Key material cleared from memory");
8705
- }
8706
- }
8707
- };
8708
- async function withSecureKey(secretKey, callback) {
8709
- const container = new SecureKeyContainer(secretKey);
8710
- try {
8711
- return await callback(container);
8712
- } finally {
8713
- container.clear();
8714
- }
8715
- }
8716
- function withSecureKeySync(secretKey, callback) {
8717
- const container = new SecureKeyContainer(secretKey);
8718
- try {
8719
- return callback(container);
8720
- } finally {
8721
- container.clear();
8722
- }
8723
- }
8724
- async function deriveAlgorandAccountFromEd25519(ed25519Seed) {
8725
- if (ed25519Seed.length !== 32) {
8726
- throw new Error(`Invalid ed25519 seed length: expected 32 bytes, got ${ed25519Seed.length}`);
8727
- }
8728
- const nacl = await Promise.resolve().then(() => __toESM(require_nacl_fast(), 1));
8729
- const algosdk15 = await import("algosdk");
8730
- const keyPair = nacl.sign.keyPair.fromSeed(ed25519Seed);
8731
- const address = algosdk15.encodeAddress(keyPair.publicKey);
8732
- return {
8733
- addr: address,
8734
- sk: keyPair.secretKey
8735
- };
8736
- }
8737
-
8738
- // src/wallets/web3auth.ts
8739
8779
  var LOCAL_STORAGE_WEB3AUTH_KEY = `${LOCAL_STORAGE_KEY}:web3auth`;
8740
8780
  var ICON13 = `data:image/svg+xml;base64,${btoa(`
8741
8781
  <svg viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
@@ -9251,6 +9291,45 @@ var Web3AuthWallet = class extends BaseWallet {
9251
9291
  });
9252
9292
  return txnsToSign;
9253
9293
  }
9294
+ canUsePrivateKey = true;
9295
+ /**
9296
+ * Provide scoped access to the private key via a callback.
9297
+ *
9298
+ * The callback receives a 64-byte Algorand secret key (ed25519 seed + public key).
9299
+ * The key is a fresh copy that is guaranteed to be zeroed from memory when the
9300
+ * callback completes, whether it succeeds or throws.
9301
+ *
9302
+ * SECURITY: The key is fetched fresh from Web3Auth for each call and never cached.
9303
+ *
9304
+ * @example
9305
+ * ```typescript
9306
+ * const result = await wallet.withPrivateKey(async (secretKey) => {
9307
+ * // secretKey is a 64-byte Uint8Array
9308
+ * // Use for custom signing, authentication, etc.
9309
+ * return doSomethingWith(secretKey)
9310
+ * })
9311
+ * // secretKey is zeroed at this point
9312
+ * ```
9313
+ */
9314
+ withPrivateKey = async (callback) => {
9315
+ this.logger.debug("withPrivateKey: Providing private key access...");
9316
+ await this.ensureConnected();
9317
+ const keyContainer = await this.getSecureKey();
9318
+ try {
9319
+ return await keyContainer.useKey(async (secretKey) => {
9320
+ const account = await deriveAlgorandAccountFromEd25519(secretKey);
9321
+ const skCopy = new Uint8Array(account.sk);
9322
+ zeroMemory(account.sk);
9323
+ try {
9324
+ return await callback(skCopy);
9325
+ } finally {
9326
+ zeroMemory(skCopy);
9327
+ }
9328
+ });
9329
+ } finally {
9330
+ keyContainer.clear();
9331
+ }
9332
+ };
9254
9333
  /**
9255
9334
  * Sign transactions
9256
9335
  *