@medialane/sdk 0.195.0 → 0.198.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/{chunk-7G7YIGXJ.cjs → chunk-2R7XBA34.cjs} +81 -49
- package/dist/chunk-2R7XBA34.cjs.map +1 -0
- package/dist/{chunk-ZCHP5D7S.js → chunk-6WVUUBFI.js} +80 -50
- package/dist/chunk-6WVUUBFI.js.map +1 -0
- package/dist/{errors-C39AqEX6.d.cts → errors-CZm-NZK0.d.cts} +12 -6
- package/dist/{errors-Cc9W7FFi.d.ts → errors-h6H6cj3Q.d.ts} +12 -6
- package/dist/index.cjs +79 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/starknet/index.cjs +75 -67
- package/dist/starknet/index.d.cts +2 -2
- package/dist/starknet/index.d.ts +2 -2
- package/dist/starknet/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-7G7YIGXJ.cjs.map +0 -1
- package/dist/chunk-ZCHP5D7S.js.map +0 -1
|
@@ -1090,6 +1090,9 @@ async function deriveAesKey(prfSecret, hkdfInfo) {
|
|
|
1090
1090
|
["encrypt", "decrypt"]
|
|
1091
1091
|
);
|
|
1092
1092
|
}
|
|
1093
|
+
function generateDeviceKey() {
|
|
1094
|
+
return crypto.subtle.generateKey({ name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"]);
|
|
1095
|
+
}
|
|
1093
1096
|
function generateStarkKeyPair() {
|
|
1094
1097
|
const privateKeyHex = "0x" + Array.from(ec.starkCurve.utils.randomPrivateKey()).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1095
1098
|
return { privateKeyHex, publicKeyHex: ec.starkCurve.getStarkKey(privateKeyHex) };
|
|
@@ -1212,6 +1215,38 @@ function computeAccountAddress(ownerPubkey, salt = 0) {
|
|
|
1212
1215
|
);
|
|
1213
1216
|
}
|
|
1214
1217
|
|
|
1218
|
+
// src/wallet/device-keys.ts
|
|
1219
|
+
var DATABASE = "medialane-wallet";
|
|
1220
|
+
var STORE = "device-keys";
|
|
1221
|
+
function open() {
|
|
1222
|
+
return new Promise((resolve, reject) => {
|
|
1223
|
+
const request = indexedDB.open(DATABASE, 1);
|
|
1224
|
+
request.onupgradeneeded = () => request.result.createObjectStore(STORE);
|
|
1225
|
+
request.onsuccess = () => resolve(request.result);
|
|
1226
|
+
request.onerror = () => reject(request.error);
|
|
1227
|
+
});
|
|
1228
|
+
}
|
|
1229
|
+
async function run(mode, act) {
|
|
1230
|
+
const db = await open();
|
|
1231
|
+
try {
|
|
1232
|
+
return await new Promise((resolve, reject) => {
|
|
1233
|
+
const request = act(db.transaction(STORE, mode).objectStore(STORE));
|
|
1234
|
+
request.onsuccess = () => resolve(request.result);
|
|
1235
|
+
request.onerror = () => reject(request.error);
|
|
1236
|
+
});
|
|
1237
|
+
} finally {
|
|
1238
|
+
db.close();
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
var indexedDbDeviceKeys = {
|
|
1242
|
+
async save(credentialId, key) {
|
|
1243
|
+
await run("readwrite", (store) => store.put(key, credentialId));
|
|
1244
|
+
},
|
|
1245
|
+
async load(credentialId) {
|
|
1246
|
+
return await run("readonly", (store) => store.get(credentialId)) ?? null;
|
|
1247
|
+
}
|
|
1248
|
+
};
|
|
1249
|
+
|
|
1215
1250
|
// src/wallet/passkey.ts
|
|
1216
1251
|
var PasskeyCancelledError = class extends Error {
|
|
1217
1252
|
constructor(message = "Passkey prompt was cancelled.") {
|
|
@@ -1219,6 +1254,12 @@ var PasskeyCancelledError = class extends Error {
|
|
|
1219
1254
|
this.name = "PasskeyCancelledError";
|
|
1220
1255
|
}
|
|
1221
1256
|
};
|
|
1257
|
+
var DeviceKeyMissingError = class extends Error {
|
|
1258
|
+
constructor() {
|
|
1259
|
+
super("This browser no longer holds the wallet key. Recover the wallet with its recovery key.");
|
|
1260
|
+
this.name = "DeviceKeyMissingError";
|
|
1261
|
+
}
|
|
1262
|
+
};
|
|
1222
1263
|
var PasskeyUnsupportedError = class extends Error {
|
|
1223
1264
|
constructor(reason) {
|
|
1224
1265
|
super(
|
|
@@ -1251,21 +1292,7 @@ function createPasskeyOwner(config) {
|
|
|
1251
1292
|
if (!api) throw new PasskeyUnsupportedError("no-webauthn");
|
|
1252
1293
|
return api;
|
|
1253
1294
|
};
|
|
1254
|
-
const browserRefusesPrf = async () => {
|
|
1255
|
-
const read = config.clientCapabilities ?? (typeof PublicKeyCredential !== "undefined" && typeof PublicKeyCredential.getClientCapabilities === "function" ? () => PublicKeyCredential.getClientCapabilities() : void 0);
|
|
1256
|
-
if (!read) return false;
|
|
1257
|
-
try {
|
|
1258
|
-
return (await read())["extension:prf"] === false;
|
|
1259
|
-
} catch {
|
|
1260
|
-
return false;
|
|
1261
|
-
}
|
|
1262
|
-
};
|
|
1263
|
-
const ensurePrfPossible = async () => {
|
|
1264
|
-
credentialsApi();
|
|
1265
|
-
if (await browserRefusesPrf()) throw new PasskeyUnsupportedError("no-prf");
|
|
1266
|
-
};
|
|
1267
1295
|
async function registerPasskey() {
|
|
1268
|
-
await ensurePrfPossible();
|
|
1269
1296
|
let credential;
|
|
1270
1297
|
try {
|
|
1271
1298
|
credential = await credentialsApi().create({
|
|
@@ -1293,53 +1320,55 @@ function createPasskeyOwner(config) {
|
|
|
1293
1320
|
const prf = credential.getClientExtensionResults().prf;
|
|
1294
1321
|
return {
|
|
1295
1322
|
credentialId: encodeBase64(credential.rawId),
|
|
1296
|
-
prfFirst: prf?.results?.first ?? null
|
|
1297
|
-
prfEnabled: prf?.enabled
|
|
1323
|
+
prfFirst: prf?.results?.first ?? null
|
|
1298
1324
|
};
|
|
1299
1325
|
}
|
|
1300
|
-
async function
|
|
1301
|
-
await ensurePrfPossible();
|
|
1302
|
-
let assertion;
|
|
1326
|
+
async function assertPasskey(credentialId, extensions) {
|
|
1303
1327
|
try {
|
|
1304
|
-
|
|
1328
|
+
return await credentialsApi().get({
|
|
1305
1329
|
publicKey: {
|
|
1306
1330
|
challenge: randomBytes(32),
|
|
1307
1331
|
rpId: config.relyingPartyId(),
|
|
1308
1332
|
allowCredentials: [{ type: "public-key", id: decodeBase64(credentialId) }],
|
|
1309
1333
|
userVerification: "required",
|
|
1310
|
-
extensions
|
|
1334
|
+
...extensions ? { extensions } : {}
|
|
1311
1335
|
}
|
|
1312
1336
|
});
|
|
1313
1337
|
} catch (err) {
|
|
1314
1338
|
if (isPasskeyCancellation(err)) throw new PasskeyCancelledError();
|
|
1315
1339
|
throw err;
|
|
1316
1340
|
}
|
|
1341
|
+
}
|
|
1342
|
+
async function prfSecret(credentialId) {
|
|
1343
|
+
const assertion = await assertPasskey(credentialId, {
|
|
1344
|
+
prf: { eval: { first: config.prfSalt } }
|
|
1345
|
+
});
|
|
1317
1346
|
const result = assertion.getClientExtensionResults().prf?.results?.first;
|
|
1318
1347
|
if (!result) throw new PasskeyUnsupportedError("no-prf");
|
|
1319
1348
|
return new Uint8Array(result);
|
|
1320
1349
|
}
|
|
1321
|
-
const
|
|
1322
|
-
|
|
1323
|
-
if (
|
|
1324
|
-
|
|
1325
|
-
try {
|
|
1326
|
-
await signal({ rpId: config.relyingPartyId(), credentialId: base64url });
|
|
1327
|
-
} catch {
|
|
1328
|
-
return;
|
|
1350
|
+
const deviceKeys = config.deviceKeys ?? indexedDbDeviceKeys;
|
|
1351
|
+
async function lockFor(registration) {
|
|
1352
|
+
if (registration.prfFirst) {
|
|
1353
|
+
return { aes: await deriveAesKey(new Uint8Array(registration.prfFirst), config.hkdfInfo) };
|
|
1329
1354
|
}
|
|
1330
|
-
};
|
|
1331
|
-
async function secretFromRegistration(registration) {
|
|
1332
|
-
if (registration.prfFirst) return new Uint8Array(registration.prfFirst);
|
|
1333
1355
|
try {
|
|
1334
|
-
|
|
1335
|
-
return await prfSecret(registration.credentialId);
|
|
1356
|
+
return { aes: await deriveAesKey(await prfSecret(registration.credentialId), config.hkdfInfo) };
|
|
1336
1357
|
} catch (err) {
|
|
1337
|
-
if (err instanceof PasskeyUnsupportedError)
|
|
1338
|
-
throw err;
|
|
1358
|
+
if (!(err instanceof PasskeyUnsupportedError) || err.reason !== "no-prf") throw err;
|
|
1339
1359
|
}
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1360
|
+
const aes = await generateDeviceKey();
|
|
1361
|
+
await deviceKeys.save(registration.credentialId, aes);
|
|
1362
|
+
return { aes, lock: "device" };
|
|
1363
|
+
}
|
|
1364
|
+
async function unlockFor(sealed) {
|
|
1365
|
+
if (sealed.lock !== "device") return deriveAesKey(await prfSecret(sealed.credentialId), config.hkdfInfo);
|
|
1366
|
+
await assertPasskey(sealed.credentialId);
|
|
1367
|
+
const aes = await deviceKeys.load(sealed.credentialId);
|
|
1368
|
+
if (!aes) throw new DeviceKeyMissingError();
|
|
1369
|
+
return aes;
|
|
1370
|
+
}
|
|
1371
|
+
async function seal(aes, privateKeyHex) {
|
|
1343
1372
|
const iv = randomBytes(12);
|
|
1344
1373
|
const ciphertext = await sealPrivateKey(aes, iv, privateKeyHex);
|
|
1345
1374
|
return { iv: encodeBase64(iv), ciphertext: encodeBase64(ciphertext) };
|
|
@@ -1347,36 +1376,37 @@ function createPasskeyOwner(config) {
|
|
|
1347
1376
|
return {
|
|
1348
1377
|
async createOwnerKey() {
|
|
1349
1378
|
const registration = await registerPasskey();
|
|
1350
|
-
const
|
|
1379
|
+
const { aes, lock } = await lockFor(registration);
|
|
1351
1380
|
const { privateKeyHex, publicKeyHex } = generateStarkKeyPair();
|
|
1352
|
-
const { iv, ciphertext } = await seal(
|
|
1381
|
+
const { iv, ciphertext } = await seal(aes, privateKeyHex);
|
|
1353
1382
|
return {
|
|
1354
1383
|
sealed: {
|
|
1355
1384
|
credentialId: registration.credentialId,
|
|
1356
1385
|
ownerPubKey: publicKeyHex,
|
|
1357
1386
|
address: computeAccountAddress(publicKeyHex, 0),
|
|
1358
1387
|
iv,
|
|
1359
|
-
ciphertext
|
|
1388
|
+
ciphertext,
|
|
1389
|
+
...lock ? { lock } : {}
|
|
1360
1390
|
},
|
|
1361
1391
|
privateKeyHex
|
|
1362
1392
|
};
|
|
1363
1393
|
},
|
|
1364
1394
|
async unlockOwnerKey(sealed) {
|
|
1365
|
-
const
|
|
1366
|
-
const aes = await deriveAesKey(secret, config.hkdfInfo);
|
|
1395
|
+
const aes = await unlockFor(sealed);
|
|
1367
1396
|
return unsealPrivateKey(aes, decodeBase64(sealed.iv), decodeBase64(sealed.ciphertext));
|
|
1368
1397
|
},
|
|
1369
1398
|
async sealImportedOwnerKey(recovery) {
|
|
1370
1399
|
const { privateKeyHex, publicKeyHex } = starkKeyPairFromPrivateKey(recovery.privateKey);
|
|
1371
1400
|
const registration = await registerPasskey();
|
|
1372
|
-
const
|
|
1373
|
-
const { iv, ciphertext } = await seal(
|
|
1401
|
+
const { aes, lock } = await lockFor(registration);
|
|
1402
|
+
const { iv, ciphertext } = await seal(aes, privateKeyHex);
|
|
1374
1403
|
return {
|
|
1375
1404
|
credentialId: registration.credentialId,
|
|
1376
1405
|
ownerPubKey: publicKeyHex,
|
|
1377
1406
|
address: recovery.walletAddress,
|
|
1378
1407
|
iv,
|
|
1379
|
-
ciphertext
|
|
1408
|
+
ciphertext,
|
|
1409
|
+
...lock ? { lock } : {}
|
|
1380
1410
|
};
|
|
1381
1411
|
}
|
|
1382
1412
|
};
|
|
@@ -1818,6 +1848,6 @@ var UserFacingError = class extends Error {
|
|
|
1818
1848
|
}
|
|
1819
1849
|
};
|
|
1820
1850
|
|
|
1821
|
-
export { ApiClient, DEFAULT_CURRENCY, FeeConfigSchema, InvalidStarkPrivateKeyError, MedialaneApiError, PasskeyCancelledError, PasskeyUnsupportedError, STARKNET_COLLECTION_1155_CLASS_HASH, STARKNET_COLLECTION_1155_CONTRACT, STARKNET_COLLECTION_1155_FACTORY_CLASS_HASH, STARKNET_COLLECTION_1155_START_BLOCK, STARKNET_COLLECTION_721_CONTRACT, STARKNET_COLLECTION_721_START_BLOCK, STARKNET_CREATOR_COIN_CLASS_HASH, STARKNET_CREATOR_COIN_EKUBO_LAUNCHER, STARKNET_CREATOR_COIN_FACTORY_CLASS_HASH, STARKNET_CREATOR_COIN_FACTORY_CONTRACT, STARKNET_CREATOR_COIN_START_BLOCK, STARKNET_DATA_TOKENIZATION_721_CONTRACT, STARKNET_DROP_COLLECTION_CLASS_HASH, STARKNET_DROP_FACTORY_CONTRACT, STARKNET_DROP_FACTORY_START_BLOCK, STARKNET_EKUBO_CORE, STARKNET_GENESIS_MINT_CONTRACT, STARKNET_GENESIS_NFT_URI, STARKNET_IPCOLLECTION_CLASS_HASH, STARKNET_IPNFT_CLASS_HASH, STARKNET_IP_CLUB_COLLECTION_CLASS_HASH, STARKNET_IP_CLUB_FACTORY_CONTRACT, STARKNET_IP_SPONSORSHIP_CLASS_HASH, STARKNET_IP_SPONSORSHIP_CONTRACT, STARKNET_IP_TICKETS_FACTORY_CONTRACT, STARKNET_IP_TICKET_COLLECTION_CLASS_HASH, STARKNET_MARKETPLACE_1155_CLASS_HASH, STARKNET_MARKETPLACE_1155_CONTRACT, STARKNET_MARKETPLACE_1155_START_BLOCK, STARKNET_MARKETPLACE_721_CLASS_HASH, STARKNET_MARKETPLACE_721_CONTRACT, STARKNET_MARKETPLACE_721_START_BLOCK, STARKNET_MEDIAWALLET_CLASS_HASH, STARKNET_NFTCOMMENTS_CONTRACT, STARKNET_POP_COLLECTION_CLASS_HASH, STARKNET_POP_FACTORY_CONTRACT, STARKNET_POP_FACTORY_START_BLOCK, SUPPORTED_TOKENS, SUPPORTED_URL_CHAINS, UserFacingError, assetHref, chainFromSlug, chainSlug, coinHref, collectionHref, computeAccountAddress, createPasskeyOwner, deriveAesKey, dropHref, encodeU256, formatAmount, generateStarkKeyPair, getListableTokens, getService, getServicesByCapability, getTokenByAddress, getTokenBySymbol, hasCapability, isServiceId, listServices, normalizeAddress, normalizeHash, ownerConstructorCalldata, parseAmount, profileHref, resolveAppFeeConfig, resolveConfig, resolveFeeConfig, sealPrivateKey, shortenAddress, signWithPrivateKey, starkKeyPairFromPrivateKey, stringifyBigInts, u256ToBigInt, unsealPrivateKey };
|
|
1822
|
-
//# sourceMappingURL=chunk-
|
|
1823
|
-
//# sourceMappingURL=chunk-
|
|
1851
|
+
export { ApiClient, DEFAULT_CURRENCY, DeviceKeyMissingError, FeeConfigSchema, InvalidStarkPrivateKeyError, MedialaneApiError, PasskeyCancelledError, PasskeyUnsupportedError, STARKNET_COLLECTION_1155_CLASS_HASH, STARKNET_COLLECTION_1155_CONTRACT, STARKNET_COLLECTION_1155_FACTORY_CLASS_HASH, STARKNET_COLLECTION_1155_START_BLOCK, STARKNET_COLLECTION_721_CONTRACT, STARKNET_COLLECTION_721_START_BLOCK, STARKNET_CREATOR_COIN_CLASS_HASH, STARKNET_CREATOR_COIN_EKUBO_LAUNCHER, STARKNET_CREATOR_COIN_FACTORY_CLASS_HASH, STARKNET_CREATOR_COIN_FACTORY_CONTRACT, STARKNET_CREATOR_COIN_START_BLOCK, STARKNET_DATA_TOKENIZATION_721_CONTRACT, STARKNET_DROP_COLLECTION_CLASS_HASH, STARKNET_DROP_FACTORY_CONTRACT, STARKNET_DROP_FACTORY_START_BLOCK, STARKNET_EKUBO_CORE, STARKNET_GENESIS_MINT_CONTRACT, STARKNET_GENESIS_NFT_URI, STARKNET_IPCOLLECTION_CLASS_HASH, STARKNET_IPNFT_CLASS_HASH, STARKNET_IP_CLUB_COLLECTION_CLASS_HASH, STARKNET_IP_CLUB_FACTORY_CONTRACT, STARKNET_IP_SPONSORSHIP_CLASS_HASH, STARKNET_IP_SPONSORSHIP_CONTRACT, STARKNET_IP_TICKETS_FACTORY_CONTRACT, STARKNET_IP_TICKET_COLLECTION_CLASS_HASH, STARKNET_MARKETPLACE_1155_CLASS_HASH, STARKNET_MARKETPLACE_1155_CONTRACT, STARKNET_MARKETPLACE_1155_START_BLOCK, STARKNET_MARKETPLACE_721_CLASS_HASH, STARKNET_MARKETPLACE_721_CONTRACT, STARKNET_MARKETPLACE_721_START_BLOCK, STARKNET_MEDIAWALLET_CLASS_HASH, STARKNET_NFTCOMMENTS_CONTRACT, STARKNET_POP_COLLECTION_CLASS_HASH, STARKNET_POP_FACTORY_CONTRACT, STARKNET_POP_FACTORY_START_BLOCK, SUPPORTED_TOKENS, SUPPORTED_URL_CHAINS, UserFacingError, assetHref, chainFromSlug, chainSlug, coinHref, collectionHref, computeAccountAddress, createPasskeyOwner, deriveAesKey, dropHref, encodeU256, formatAmount, generateStarkKeyPair, getListableTokens, getService, getServicesByCapability, getTokenByAddress, getTokenBySymbol, hasCapability, indexedDbDeviceKeys, isServiceId, listServices, normalizeAddress, normalizeHash, ownerConstructorCalldata, parseAmount, profileHref, resolveAppFeeConfig, resolveConfig, resolveFeeConfig, sealPrivateKey, shortenAddress, signWithPrivateKey, starkKeyPairFromPrivateKey, stringifyBigInts, u256ToBigInt, unsealPrivateKey };
|
|
1852
|
+
//# sourceMappingURL=chunk-6WVUUBFI.js.map
|
|
1853
|
+
//# sourceMappingURL=chunk-6WVUUBFI.js.map
|