@ozura/elements 1.2.4-next.55 → 1.2.4-next.57

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.
@@ -430,17 +430,26 @@ class OzElement {
430
430
  accountNumber: 'account number',
431
431
  routingNumber: 'routing number',
432
432
  }[this.elementType]) !== null && _a !== void 0 ? _a : this.elementType} input`;
433
- // sandbox="allow-scripts" gives correct iframe isolation:
434
- // - Scripts run (allow-scripts), so the field JS executes normally.
435
- // - NO allow-same-origin: the frame cannot access window.parent's DOM,
436
- // localStorage, or cookies — prevents sandbox escape even if served
437
- // from the same origin.
438
- // - NO allow-top-navigation: a rogue/compromised element frame cannot
439
- // navigate window.top (clickjacking prevention).
440
- // - NO allow-forms / allow-popups: reduces attack surface.
441
- // Field values are delivered via postMessage, so no parent access is
442
- // needed allow-scripts alone is sufficient.
443
- iframe.setAttribute('sandbox', 'allow-scripts');
433
+ // sandbox="allow-scripts allow-same-origin" gives correct iframe isolation:
434
+ // - allow-scripts: JS runs, so the field JS executes normally.
435
+ // - allow-same-origin: the frame keeps its actual origin (elements.ozura.com
436
+ // in production) so that:
437
+ // (a) window.parent.postMessage() carries a real origin that OzVault can
438
+ // validate (without this the frame gets a null/opaque origin and every
439
+ // OZ_FRAME_READY message is silently dropped by the origin check), and
440
+ // (b) OzVault can deliver OZ_INIT back to the frame (postMessage to a
441
+ // null-origin target is never delivered).
442
+ // - In PRODUCTION the frames are served from elements.ozura.com and embedded
443
+ // on a different merchant domain — Same-Origin Policy already prevents the
444
+ // frame from accessing window.parent.document or merchant cookies, making
445
+ // allow-same-origin a no-op from a security perspective.
446
+ // - In LOCAL DEV (localhost) both parent and frames share the same origin;
447
+ // allow-same-origin alongside allow-scripts does technically weaken sandbox
448
+ // isolation, but this is a local dev server only — not a production risk.
449
+ // NOT included: allow-top-navigation, allow-popups, allow-forms — prevents
450
+ // a compromised element frame from navigating the merchant page or opening
451
+ // popups even if the CDN bundle were somehow replaced.
452
+ iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');
444
453
  // Use hash instead of query string — survives clean-URL redirects from static servers.
445
454
  // parentOrigin lets the frame target postMessage to the merchant origin instead of '*'.
446
455
  const parentOrigin = typeof window !== 'undefined' ? window.location.origin : '';
@@ -1026,7 +1035,7 @@ const DEFAULT_FRAME_BASE_URL = "https://lively-hill-097170c0f.4.azurestaticapps.
1026
1035
  * @example
1027
1036
  * // Recommended — pass sessionUrl and let the SDK call your backend automatically
1028
1037
  * const vault = await OzVault.create({
1029
- * pubKey: 'pk_prod_...', // or 'pk_test_...' for test mode
1038
+ * pubKey: 'pk_prod_...', // omit for test vault keys; required for production
1030
1039
  * sessionUrl: '/api/oz-session', // backend endpoint that calls ozura.createSession()
1031
1040
  * });
1032
1041
  * const cardNum = vault.createElement('cardNumber');
@@ -1134,8 +1143,15 @@ class OzVault {
1134
1143
  * @throws {OzError} if the session fetch fails, times out, or returns an empty string.
1135
1144
  */
1136
1145
  static async create(options, signal) {
1137
- if (!options.pubKey || !options.pubKey.trim()) {
1138
- throw new OzError('pubKey is required in options. Obtain your public key from the Ozura admin.');
1146
+ // pubKey is optional — test vault keys (from a Test project on the vault)
1147
+ // do not require a pub key. Production keys do. If provided, it must be
1148
+ // non-empty after trimming; if omitted entirely, warn but continue.
1149
+ if (options.pubKey !== undefined && !options.pubKey.trim()) {
1150
+ throw new OzError('pubKey must be a non-empty string. Omit the option entirely to use a test vault key.');
1151
+ }
1152
+ if (options.pubKey === undefined) {
1153
+ console.warn('[OzVault] pubKey not provided — this only works with a test vault key from a Test project on the vault. ' +
1154
+ 'For production, set pubKey to your pk_live_... or pk_prod_... value.');
1139
1155
  }
1140
1156
  // Normalize the session callback. Priority: sessionUrl > getSessionKey > fetchWaxKey (deprecated).
1141
1157
  // This allows merchants to use the clean new API without touching legacy code.
@@ -1344,6 +1360,7 @@ class OzVault {
1344
1360
  const requestId = `req-${uuid()}`;
1345
1361
  this.log('createBankToken() called');
1346
1362
  return new Promise((resolve, reject) => {
1363
+ var _a;
1347
1364
  const resetCountAtStart = this._resetCount;
1348
1365
  const cleanup = () => {
1349
1366
  if (this._resetCount === resetCountAtStart)
@@ -1364,7 +1381,7 @@ class OzVault {
1364
1381
  type: 'OZ_BANK_TOKENIZE',
1365
1382
  requestId,
1366
1383
  tokenizationSessionId: this.tokenizationSessionId,
1367
- pubKey: this.pubKey,
1384
+ pubKey: (_a = this.pubKey) !== null && _a !== void 0 ? _a : '',
1368
1385
  firstName: options.firstName.trim(),
1369
1386
  lastName: options.lastName.trim(),
1370
1387
  fieldCount: readyBankElements.length,
@@ -1463,6 +1480,7 @@ class OzVault {
1463
1480
  billingPresent: Boolean(options.billing),
1464
1481
  });
1465
1482
  return new Promise((resolve, reject) => {
1483
+ var _a;
1466
1484
  // Capture the reset generation so cleanup() only zeros _tokenizing when it
1467
1485
  // still belongs to this invocation — not a newer one that started after a reset.
1468
1486
  const resetCountAtStart = this._resetCount;
@@ -1487,7 +1505,7 @@ class OzVault {
1487
1505
  type: 'OZ_TOKENIZE',
1488
1506
  requestId,
1489
1507
  tokenizationSessionId: this.tokenizationSessionId,
1490
- pubKey: this.pubKey,
1508
+ pubKey: (_a = this.pubKey) !== null && _a !== void 0 ? _a : '',
1491
1509
  firstName,
1492
1510
  lastName,
1493
1511
  fieldCount: readyElements.length,
@@ -1935,6 +1953,7 @@ class OzVault {
1935
1953
  if (willRefresh) {
1936
1954
  const resetCountAtRetry = this._resetCount;
1937
1955
  this.refreshWaxKey().then(() => {
1956
+ var _a;
1938
1957
  if (this._destroyed) {
1939
1958
  pending.reject(new OzError('Vault destroyed during wax key refresh.'));
1940
1959
  return;
@@ -1967,7 +1986,7 @@ class OzVault {
1967
1986
  type: 'OZ_TOKENIZE',
1968
1987
  requestId: newRequestId,
1969
1988
  tokenizationSessionId: this.tokenizationSessionId,
1970
- pubKey: this.pubKey,
1989
+ pubKey: (_a = this.pubKey) !== null && _a !== void 0 ? _a : '',
1971
1990
  firstName: pending.firstName,
1972
1991
  lastName: pending.lastName,
1973
1992
  fieldCount: pending.fieldCount,
@@ -2011,6 +2030,7 @@ class OzVault {
2011
2030
  if (this.isRefreshableAuthError(errorCode, raw) && !bankPending.retried && this._storedFetchWaxKey) {
2012
2031
  const resetCountAtRetry = this._resetCount;
2013
2032
  this.refreshWaxKey().then(() => {
2033
+ var _a;
2014
2034
  if (this._destroyed) {
2015
2035
  bankPending.reject(new OzError('Vault destroyed during wax key refresh.'));
2016
2036
  return;
@@ -2033,7 +2053,7 @@ class OzVault {
2033
2053
  type: 'OZ_BANK_TOKENIZE',
2034
2054
  requestId: newRequestId,
2035
2055
  tokenizationSessionId: this.tokenizationSessionId,
2036
- pubKey: this.pubKey,
2056
+ pubKey: (_a = this.pubKey) !== null && _a !== void 0 ? _a : '',
2037
2057
  firstName: bankPending.firstName,
2038
2058
  lastName: bankPending.lastName,
2039
2059
  fieldCount: bankPending.fieldCount,