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