@oxyhq/core 3.4.1 → 3.4.3

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.
Files changed (174) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/AuthManager.js +91 -319
  3. package/dist/cjs/CrossDomainAuth.js +19 -106
  4. package/dist/cjs/HttpService.js +49 -73
  5. package/dist/cjs/OxyServices.base.js +2 -2
  6. package/dist/cjs/i18n/index.js +7 -1
  7. package/dist/cjs/i18n/locales/ar-SA.json +18 -2
  8. package/dist/cjs/i18n/locales/ca-ES.json +18 -2
  9. package/dist/cjs/i18n/locales/de-DE.json +18 -2
  10. package/dist/cjs/i18n/locales/en-US.json +16 -2
  11. package/dist/cjs/i18n/locales/es-ES.json +16 -2
  12. package/dist/cjs/i18n/locales/fr-FR.json +18 -2
  13. package/dist/cjs/i18n/locales/it-IT.json +18 -2
  14. package/dist/cjs/i18n/locales/ja-JP.json +18 -2
  15. package/dist/cjs/i18n/locales/ko-KR.json +18 -2
  16. package/dist/cjs/i18n/locales/locales/ar-SA.json +18 -2
  17. package/dist/cjs/i18n/locales/locales/ca-ES.json +18 -2
  18. package/dist/cjs/i18n/locales/locales/de-DE.json +18 -2
  19. package/dist/cjs/i18n/locales/locales/en-US.json +17 -3
  20. package/dist/cjs/i18n/locales/locales/es-ES.json +16 -2
  21. package/dist/cjs/i18n/locales/locales/fr-FR.json +18 -2
  22. package/dist/cjs/i18n/locales/locales/it-IT.json +18 -2
  23. package/dist/cjs/i18n/locales/locales/ja-JP.json +18 -2
  24. package/dist/cjs/i18n/locales/locales/ko-KR.json +18 -2
  25. package/dist/cjs/i18n/locales/locales/pt-PT.json +18 -2
  26. package/dist/cjs/i18n/locales/locales/zh-CN.json +18 -2
  27. package/dist/cjs/i18n/locales/pt-PT.json +18 -2
  28. package/dist/cjs/i18n/locales/zh-CN.json +18 -2
  29. package/dist/cjs/mixins/OxyServices.auth.js +20 -63
  30. package/dist/cjs/mixins/OxyServices.fedcm.js +10 -12
  31. package/dist/cjs/mixins/OxyServices.popup.js +50 -299
  32. package/dist/cjs/mixins/OxyServices.redirect.js +84 -348
  33. package/dist/cjs/mixins/OxyServices.silent.js +204 -0
  34. package/dist/cjs/mixins/OxyServices.sso.js +4 -5
  35. package/dist/cjs/mixins/OxyServices.utility.js +6 -15
  36. package/dist/cjs/mixins/index.js +5 -6
  37. package/dist/cjs/server/index.js +21 -0
  38. package/dist/cjs/server/rateLimit.js +77 -0
  39. package/dist/cjs/shared/utils/debugUtils.js +1 -1
  40. package/dist/cjs/utils/accountUtils.js +4 -4
  41. package/dist/cjs/utils/authHelpers.js +21 -15
  42. package/dist/cjs/utils/coldBoot.js +3 -3
  43. package/dist/cjs/utils/fapiAutoDetect.js +1 -1
  44. package/dist/esm/.tsbuildinfo +1 -1
  45. package/dist/esm/AuthManager.js +91 -319
  46. package/dist/esm/CrossDomainAuth.js +19 -106
  47. package/dist/esm/HttpService.js +49 -73
  48. package/dist/esm/OxyServices.base.js +2 -2
  49. package/dist/esm/i18n/index.js +7 -1
  50. package/dist/esm/i18n/locales/ar-SA.json +18 -2
  51. package/dist/esm/i18n/locales/ca-ES.json +18 -2
  52. package/dist/esm/i18n/locales/de-DE.json +18 -2
  53. package/dist/esm/i18n/locales/en-US.json +16 -2
  54. package/dist/esm/i18n/locales/es-ES.json +16 -2
  55. package/dist/esm/i18n/locales/fr-FR.json +18 -2
  56. package/dist/esm/i18n/locales/it-IT.json +18 -2
  57. package/dist/esm/i18n/locales/ja-JP.json +18 -2
  58. package/dist/esm/i18n/locales/ko-KR.json +18 -2
  59. package/dist/esm/i18n/locales/locales/ar-SA.json +18 -2
  60. package/dist/esm/i18n/locales/locales/ca-ES.json +18 -2
  61. package/dist/esm/i18n/locales/locales/de-DE.json +18 -2
  62. package/dist/esm/i18n/locales/locales/en-US.json +17 -3
  63. package/dist/esm/i18n/locales/locales/es-ES.json +16 -2
  64. package/dist/esm/i18n/locales/locales/fr-FR.json +18 -2
  65. package/dist/esm/i18n/locales/locales/it-IT.json +18 -2
  66. package/dist/esm/i18n/locales/locales/ja-JP.json +18 -2
  67. package/dist/esm/i18n/locales/locales/ko-KR.json +18 -2
  68. package/dist/esm/i18n/locales/locales/pt-PT.json +18 -2
  69. package/dist/esm/i18n/locales/locales/zh-CN.json +18 -2
  70. package/dist/esm/i18n/locales/pt-PT.json +18 -2
  71. package/dist/esm/i18n/locales/zh-CN.json +18 -2
  72. package/dist/esm/mixins/OxyServices.auth.js +20 -63
  73. package/dist/esm/mixins/OxyServices.fedcm.js +10 -12
  74. package/dist/esm/mixins/OxyServices.popup.js +52 -301
  75. package/dist/esm/mixins/OxyServices.redirect.js +84 -349
  76. package/dist/esm/mixins/OxyServices.silent.js +202 -0
  77. package/dist/esm/mixins/OxyServices.sso.js +4 -5
  78. package/dist/esm/mixins/OxyServices.utility.js +6 -15
  79. package/dist/esm/mixins/index.js +5 -6
  80. package/dist/esm/server/index.js +17 -0
  81. package/dist/esm/server/rateLimit.js +71 -0
  82. package/dist/esm/shared/utils/debugUtils.js +1 -1
  83. package/dist/esm/utils/accountUtils.js +4 -4
  84. package/dist/esm/utils/authHelpers.js +21 -15
  85. package/dist/esm/utils/coldBoot.js +3 -3
  86. package/dist/esm/utils/fapiAutoDetect.js +1 -1
  87. package/dist/types/.tsbuildinfo +1 -1
  88. package/dist/types/AuthManager.d.ts +26 -53
  89. package/dist/types/AuthManagerTypes.d.ts +5 -9
  90. package/dist/types/CrossDomainAuth.d.ts +13 -52
  91. package/dist/types/HttpService.d.ts +9 -8
  92. package/dist/types/OxyServices.base.d.ts +1 -1
  93. package/dist/types/OxyServices.d.ts +4 -10
  94. package/dist/types/index.d.ts +1 -1
  95. package/dist/types/mixins/OxyServices.analytics.d.ts +1 -1
  96. package/dist/types/mixins/OxyServices.appData.d.ts +1 -1
  97. package/dist/types/mixins/OxyServices.applications.d.ts +1 -1
  98. package/dist/types/mixins/OxyServices.assets.d.ts +1 -1
  99. package/dist/types/mixins/OxyServices.auth.d.ts +10 -31
  100. package/dist/types/mixins/OxyServices.contacts.d.ts +1 -1
  101. package/dist/types/mixins/OxyServices.devices.d.ts +1 -1
  102. package/dist/types/mixins/OxyServices.features.d.ts +1 -1
  103. package/dist/types/mixins/OxyServices.fedcm.d.ts +5 -5
  104. package/dist/types/mixins/OxyServices.language.d.ts +1 -1
  105. package/dist/types/mixins/OxyServices.location.d.ts +1 -1
  106. package/dist/types/mixins/OxyServices.managedAccounts.d.ts +1 -1
  107. package/dist/types/mixins/OxyServices.payment.d.ts +1 -1
  108. package/dist/types/mixins/OxyServices.popup.d.ts +18 -120
  109. package/dist/types/mixins/OxyServices.privacy.d.ts +1 -1
  110. package/dist/types/mixins/OxyServices.redirect.d.ts +13 -174
  111. package/dist/types/mixins/OxyServices.reputation.d.ts +1 -1
  112. package/dist/types/mixins/OxyServices.security.d.ts +1 -1
  113. package/dist/types/mixins/OxyServices.silent.d.ts +131 -0
  114. package/dist/types/mixins/OxyServices.sso.d.ts +4 -5
  115. package/dist/types/mixins/OxyServices.topics.d.ts +1 -1
  116. package/dist/types/mixins/OxyServices.user.d.ts +1 -1
  117. package/dist/types/mixins/OxyServices.utility.d.ts +3 -8
  118. package/dist/types/mixins/OxyServices.workspaces.d.ts +1 -1
  119. package/dist/types/mixins/index.d.ts +3 -3
  120. package/dist/types/models/interfaces.d.ts +5 -16
  121. package/dist/types/models/session.d.ts +0 -2
  122. package/dist/types/server/index.d.ts +18 -0
  123. package/dist/types/server/rateLimit.d.ts +40 -0
  124. package/dist/types/shared/utils/debugUtils.d.ts +1 -1
  125. package/dist/types/utils/authHelpers.d.ts +4 -3
  126. package/dist/types/utils/coldBoot.d.ts +2 -2
  127. package/dist/types/utils/fapiAutoDetect.d.ts +1 -1
  128. package/package.json +24 -2
  129. package/src/AuthManager.ts +100 -370
  130. package/src/AuthManagerTypes.ts +5 -9
  131. package/src/CrossDomainAuth.ts +22 -129
  132. package/src/HttpService.ts +55 -73
  133. package/src/OxyServices.base.ts +2 -3
  134. package/src/OxyServices.ts +9 -11
  135. package/src/__tests__/authManager.cookiePath.test.ts +19 -17
  136. package/src/__tests__/authManager.security.test.ts +7 -3
  137. package/src/__tests__/crossDomainAuth.test.ts +26 -118
  138. package/src/i18n/index.ts +7 -1
  139. package/src/i18n/locales/ar-SA.json +18 -2
  140. package/src/i18n/locales/ca-ES.json +18 -2
  141. package/src/i18n/locales/de-DE.json +18 -2
  142. package/src/i18n/locales/en-US.json +17 -3
  143. package/src/i18n/locales/es-ES.json +16 -2
  144. package/src/i18n/locales/fr-FR.json +18 -2
  145. package/src/i18n/locales/it-IT.json +18 -2
  146. package/src/i18n/locales/ja-JP.json +18 -2
  147. package/src/i18n/locales/ko-KR.json +18 -2
  148. package/src/i18n/locales/pt-PT.json +18 -2
  149. package/src/i18n/locales/zh-CN.json +18 -2
  150. package/src/index.ts +1 -1
  151. package/src/mixins/OxyServices.auth.ts +23 -75
  152. package/src/mixins/OxyServices.fedcm.ts +10 -12
  153. package/src/mixins/OxyServices.redirect.ts +82 -371
  154. package/src/mixins/OxyServices.silent.ts +272 -0
  155. package/src/mixins/OxyServices.sso.ts +5 -6
  156. package/src/mixins/OxyServices.utility.ts +9 -22
  157. package/src/mixins/__tests__/appData.test.ts +1 -1
  158. package/src/mixins/__tests__/onTokensChanged.test.ts +1 -1
  159. package/src/mixins/__tests__/reputation.test.ts +1 -1
  160. package/src/mixins/__tests__/serviceAuth.test.ts +7 -5
  161. package/src/mixins/__tests__/silent.test.ts +102 -0
  162. package/src/mixins/__tests__/verifyChallenge.test.ts +9 -14
  163. package/src/mixins/index.ts +6 -8
  164. package/src/models/interfaces.ts +5 -16
  165. package/src/models/session.ts +1 -3
  166. package/src/server/index.ts +19 -0
  167. package/src/server/rateLimit.ts +170 -0
  168. package/src/shared/utils/debugUtils.ts +1 -1
  169. package/src/utils/accountUtils.ts +4 -4
  170. package/src/utils/authHelpers.ts +23 -15
  171. package/src/utils/coldBoot.ts +4 -4
  172. package/src/utils/fapiAutoDetect.ts +1 -1
  173. package/src/mixins/OxyServices.popup.ts +0 -631
  174. package/src/mixins/__tests__/popup.test.ts +0 -374
@@ -4,28 +4,13 @@ exports.OxyServicesPopupAuthMixin = OxyServicesPopupAuthMixin;
4
4
  exports.PopupAuthMixin = OxyServicesPopupAuthMixin;
5
5
  const OxyServices_errors_1 = require("../OxyServices.errors");
6
6
  const debugUtils_1 = require("../shared/utils/debugUtils");
7
- const debug = (0, debugUtils_1.createDebugLogger)('PopupAuth');
7
+ const debug = (0, debugUtils_1.createDebugLogger)("PopupAuth");
8
8
  /**
9
- * Popup-based Cross-Domain Authentication Mixin
9
+ * Cross-domain browser auth helpers.
10
10
  *
11
- * Implements OAuth2-style authentication using popup windows and postMessage.
12
- * This is the primary authentication method for modern browsers, providing a
13
- * Google-like experience without full page redirects.
14
- *
15
- * Flow:
16
- * 1. Opens small popup window to auth.oxy.so
17
- * 2. User signs in (auth.oxy.so sets its own first-party cookie)
18
- * 3. auth.oxy.so sends token back via postMessage
19
- * 4. Popup closes, parent app has the session
20
- *
21
- * Features:
22
- * - No full page redirect (preserves app state)
23
- * - Works across different domains (homiio.com, mention.earth, etc.)
24
- * - Silent refresh using hidden iframe for seamless SSO
25
- * - CSRF protection via state parameter
26
- * - XSS protection via origin validation
27
- *
28
- * Browser Support: All modern browsers (IE11+)
11
+ * Popup sign-in is intentionally fail-closed in the clean session model because
12
+ * the historical implementation required bearer-token callback URLs. FedCM,
13
+ * redirect SSO, and silent iframe SSO are the supported browser paths.
29
14
  */
30
15
  function OxyServicesPopupAuthMixin(Base) {
31
16
  var _a;
@@ -35,125 +20,25 @@ function OxyServicesPopupAuthMixin(Base) {
35
20
  }
36
21
  /** Resolve auth URL from config or static default (method, not getter — getters break in TS mixins) */
37
22
  resolveAuthUrl() {
38
- return this.config.authWebUrl || this.constructor.DEFAULT_AUTH_URL;
23
+ return (this.config.authWebUrl || this.constructor.DEFAULT_AUTH_URL);
39
24
  }
40
25
  /**
41
- * Sign in using popup window
42
- *
43
- * Opens a centered popup window to auth.oxy.so where the user can sign in.
44
- * The popup automatically closes after successful authentication and the
45
- * session is returned to the parent window.
46
- *
47
- * @param options - Popup configuration options
48
- * @returns Session with access token and user data
49
- * @throws {OxyAuthenticationError} If popup is blocked or auth fails
50
- *
51
- * @example
52
- * ```typescript
53
- * const handleSignIn = async () => {
54
- * try {
55
- * const session = await oxyServices.signInWithPopup();
56
- * console.log('Signed in:', session.user);
57
- * } catch (error) {
58
- * if (error.message.includes('blocked')) {
59
- * alert('Please allow popups for this site');
60
- * }
61
- * }
62
- * };
63
- * ```
26
+ * Removed popup sign-in. Closes a caller-supplied popup handle and throws.
64
27
  */
65
28
  async signInWithPopup(options = {}) {
66
- if (typeof window === 'undefined') {
67
- throw new OxyServices_errors_1.OxyAuthenticationError('Popup authentication requires browser environment');
68
- }
69
- const state = this.generateState();
70
- const nonce = this.generateNonce();
71
- // Store state for CSRF protection
72
- this.storeAuthState(state, nonce);
73
- const width = options.width || this.constructor.POPUP_WIDTH;
74
- const height = options.height || this.constructor.POPUP_HEIGHT;
75
- const timeout = options.timeout || this.constructor.POPUP_TIMEOUT;
76
- const mode = options.mode || 'login';
77
- const authUrl = this.buildAuthUrl({
78
- mode,
79
- state,
80
- nonce,
81
- clientId: window.location.origin,
82
- redirectUri: `${this.resolveAuthUrl()}/auth/callback`,
83
- });
84
- // If the caller pre-opened a popup on the raw user gesture (recommended
85
- // path — see `openBlankPopup` and `PopupAuthOptions.popup`), navigate it
86
- // to the auth URL instead of issuing a fresh `window.open` (which would
87
- // be blocked once any prior `await` has consumed the user activation).
88
- let popup;
89
- const preOpened = options.popup ?? null;
90
- if (preOpened) {
91
- if (preOpened.closed) {
92
- // The pre-opened popup is gone — distinguish a user cancel (they
93
- // closed the blank window before sign-in could navigate it) from a
94
- // blocker rejection. Lumping these together as "Popup blocked" is
95
- // misleading: the popup was NOT blocked, it was opened successfully
96
- // and then dismissed.
97
- throw new OxyServices_errors_1.OxyAuthenticationError('Sign-in window was closed before authentication could start.');
98
- }
99
- try {
100
- preOpened.location.replace(authUrl);
101
- }
102
- catch (replaceError) {
103
- // `location.replace` can throw in sandboxed / cross-origin-locked
104
- // environments. Fall back to `href` assignment, which is more
105
- // permissive. Logged at debug-level so consumers can correlate
106
- // unusual sign-in behaviour without producing noise in normal flows.
107
- debug.warn('location.replace failed, falling back to location.href', replaceError);
108
- preOpened.location.href = authUrl;
109
- }
110
- popup = preOpened;
111
- }
112
- else {
113
- popup = this.openCenteredPopup(authUrl, 'Oxy Sign In', width, height);
29
+ if (typeof window === "undefined") {
30
+ throw new OxyServices_errors_1.OxyAuthenticationError("Popup authentication requires browser environment");
114
31
  }
115
- if (!popup) {
116
- throw new OxyServices_errors_1.OxyAuthenticationError('Popup blocked. Please allow popups for this site and try again.');
117
- }
118
- try {
119
- const session = await this.waitForPopupAuth(popup, state, timeout);
120
- // Store access token if present
121
- if (session && session.accessToken) {
122
- this.httpService.setTokens(session.accessToken);
123
- }
124
- // Fetch user data using the session ID
125
- // The callback page only sends sessionId/accessToken, not user data
126
- if (session && session.sessionId && !session.user) {
127
- try {
128
- const userData = await this.makeRequest('GET', `/session/user/${session.sessionId}`, undefined, { cache: false });
129
- if (userData) {
130
- session.user = userData;
131
- }
132
- }
133
- catch (userError) {
134
- debug.warn('Failed to fetch user data:', userError);
135
- // Continue without user data - caller can fetch separately
136
- }
137
- }
138
- return session;
139
- }
140
- catch (error) {
141
- throw error;
142
- }
143
- finally {
144
- this.clearAuthState(state);
32
+ if (options.popup && !options.popup.closed) {
33
+ options.popup.close();
145
34
  }
35
+ throw new OxyServices_errors_1.OxyAuthenticationError("Popup authentication has been removed because it required access-token callback URLs. Use FedCM or redirect authentication.");
146
36
  }
147
37
  /**
148
- * Sign up using popup window
149
- *
150
- * Same as signInWithPopup but opens the signup page by default.
151
- *
152
- * @param options - Popup configuration options
153
- * @returns Session with access token and user data
38
+ * Removed popup signup. Closes a caller-supplied popup handle and throws.
154
39
  */
155
40
  async signUpWithPopup(options = {}) {
156
- return this.signInWithPopup({ ...options, mode: 'signup' });
41
+ return this.signInWithPopup({ ...options, mode: "signup" });
157
42
  }
158
43
  /**
159
44
  * Silent sign-in using hidden iframe
@@ -163,7 +48,7 @@ function OxyServicesPopupAuthMixin(Base) {
163
48
  *
164
49
  * How it works:
165
50
  * 1. Creates hidden iframe pointing to auth.oxy.so/silent-auth
166
- * 2. If user has valid session at auth.oxy.so, it sends token via postMessage
51
+ * 2. If user has valid session at auth.oxy.so, it exchanges an opaque SSO code
167
52
  * 3. If not, iframe responds with null (no error thrown)
168
53
  *
169
54
  * This should be called on app startup to check for existing sessions.
@@ -185,7 +70,7 @@ function OxyServicesPopupAuthMixin(Base) {
185
70
  * ```
186
71
  */
187
72
  async silentSignIn(options = {}) {
188
- if (typeof window === 'undefined') {
73
+ if (typeof window === "undefined") {
189
74
  return null;
190
75
  }
191
76
  const timeout = options.timeout || this.constructor.SILENT_TIMEOUT;
@@ -199,13 +84,15 @@ function OxyServicesPopupAuthMixin(Base) {
199
84
  const authOrigin = options.authWebUrlOverride && options.authWebUrlOverride.length > 0
200
85
  ? options.authWebUrlOverride
201
86
  : this.resolveAuthUrl();
202
- const iframe = document.createElement('iframe');
203
- iframe.style.display = 'none';
204
- iframe.style.position = 'absolute';
205
- iframe.style.width = '0';
206
- iframe.style.height = '0';
207
- iframe.style.border = 'none';
208
- const silentUrl = `${authOrigin}/auth/silent?` + `client_id=${encodeURIComponent(clientId)}&` + `nonce=${nonce}`;
87
+ const iframe = document.createElement("iframe");
88
+ iframe.style.display = "none";
89
+ iframe.style.position = "absolute";
90
+ iframe.style.width = "0";
91
+ iframe.style.height = "0";
92
+ iframe.style.border = "none";
93
+ const silentUrl = `${authOrigin}/auth/silent?` +
94
+ `client_id=${encodeURIComponent(clientId)}&` +
95
+ `nonce=${nonce}`;
209
96
  iframe.src = silentUrl;
210
97
  document.body.appendChild(iframe);
211
98
  try {
@@ -218,7 +105,9 @@ function OxyServicesPopupAuthMixin(Base) {
218
105
  // -> 401 -> token-clear loop in consumer apps because callers gated
219
106
  // on `session?.user` and never installed the user via
220
107
  // `handleAuthSuccess`, while HttpService quietly held the token.
221
- const accessToken = session ? session.accessToken : undefined;
108
+ const accessToken = session
109
+ ? session.accessToken
110
+ : undefined;
222
111
  if (!session || !accessToken || !session.sessionId) {
223
112
  return null;
224
113
  }
@@ -236,14 +125,14 @@ function OxyServicesPopupAuthMixin(Base) {
236
125
  // missing-session response.
237
126
  if (!session.user) {
238
127
  try {
239
- const userData = await this.makeRequest('GET', `/session/user/${session.sessionId}`, undefined, { cache: false, retry: false });
128
+ const userData = await this.makeRequest("GET", `/session/user/${session.sessionId}`, undefined, { cache: false, retry: false });
240
129
  if (!userData) {
241
- throw new Error('Empty user response');
130
+ throw new Error("Empty user response");
242
131
  }
243
132
  session.user = userData;
244
133
  }
245
134
  catch (userError) {
246
- debug.warn('silentSignIn: failed to fetch user data, rolling back token', userError);
135
+ debug.warn("silentSignIn: failed to fetch user data, rolling back token", userError);
247
136
  if (previousAccessToken) {
248
137
  this.httpService.setTokens(previousAccessToken);
249
138
  }
@@ -265,32 +154,17 @@ function OxyServicesPopupAuthMixin(Base) {
265
154
  /**
266
155
  * Open a blank, centered popup window SYNCHRONOUSLY.
267
156
  *
268
- * Use this in a click (or other user-gesture) handler BEFORE any `await`
269
- * to capture the transient user-activation. Pass the returned handle into
270
- * `signInWithPopup({ popup })` once the async portion of the flow runs.
271
- *
272
- * Returns `null` if the browser's popup blocker rejected the open.
273
- *
274
- * @example
275
- * ```typescript
276
- * const onSignInClick = () => {
277
- * const popup = oxyServices.openBlankPopup();
278
- * (async () => {
279
- * const silent = await oxyServices.silentSignInWithFedCM();
280
- * if (silent) { popup?.close(); return; }
281
- * await oxyServices.signInWithPopup({ popup });
282
- * })();
283
- * };
284
- * ```
157
+ * Kept only so legacy callers can pass a handle to the removed popup method,
158
+ * which closes it before throwing. New auth code should use FedCM or redirect.
285
159
  */
286
160
  openBlankPopup(width, height) {
287
- if (typeof window === 'undefined') {
161
+ if (typeof window === "undefined") {
288
162
  return null;
289
163
  }
290
164
  const ctor = this.constructor;
291
165
  const w = width ?? ctor.POPUP_WIDTH;
292
166
  const h = height ?? ctor.POPUP_HEIGHT;
293
- return this.openCenteredPopup('about:blank', 'Oxy Sign In', w, h);
167
+ return this.openCenteredPopup("about:blank", "Oxy Sign In", w, h);
294
168
  }
295
169
  /**
296
170
  * Open a centered popup window
@@ -305,86 +179,15 @@ function OxyServicesPopupAuthMixin(Base) {
305
179
  `height=${height}`,
306
180
  `left=${left}`,
307
181
  `top=${top}`,
308
- 'toolbar=no',
309
- 'menubar=no',
310
- 'scrollbars=yes',
311
- 'resizable=yes',
312
- 'status=no',
313
- 'location=no',
314
- ].join(',');
182
+ "toolbar=no",
183
+ "menubar=no",
184
+ "scrollbars=yes",
185
+ "resizable=yes",
186
+ "status=no",
187
+ "location=no",
188
+ ].join(",");
315
189
  return window.open(url, title, features);
316
190
  }
317
- /**
318
- * Wait for authentication response from popup
319
- *
320
- * @private
321
- */
322
- async waitForPopupAuth(popup, expectedState, timeout) {
323
- return new Promise((resolve, reject) => {
324
- const timeoutId = setTimeout(() => {
325
- cleanup();
326
- reject(new OxyServices_errors_1.OxyAuthenticationError('Authentication timeout'));
327
- }, timeout);
328
- const messageHandler = (event) => {
329
- const authUrl = this.resolveAuthUrl();
330
- // Log all messages for debugging
331
- if (event.data && typeof event.data === 'object' && event.data.type) {
332
- debug.log('Message received:', {
333
- origin: event.origin,
334
- expectedOrigin: authUrl,
335
- type: event.data.type,
336
- hasSession: !!event.data.session,
337
- hasError: !!event.data.error,
338
- });
339
- }
340
- // CRITICAL: Verify origin to prevent XSS attacks
341
- if (event.origin !== authUrl) {
342
- return;
343
- }
344
- const { type, state, session, error } = event.data;
345
- if (type !== 'oxy_auth_response') {
346
- return;
347
- }
348
- debug.log('Valid auth response:', { state, expectedState, hasSession: !!session, error });
349
- // Verify state parameter to prevent CSRF attacks
350
- if (state !== expectedState) {
351
- cleanup();
352
- debug.error('State mismatch');
353
- reject(new OxyServices_errors_1.OxyAuthenticationError('Invalid state parameter. Possible CSRF attack.'));
354
- return;
355
- }
356
- cleanup();
357
- if (error) {
358
- debug.error('Auth error:', error);
359
- reject(new OxyServices_errors_1.OxyAuthenticationError(error));
360
- }
361
- else if (session) {
362
- debug.log('Session received successfully');
363
- resolve(session);
364
- }
365
- else {
366
- debug.error('No session in response');
367
- reject(new OxyServices_errors_1.OxyAuthenticationError('No session received from authentication server'));
368
- }
369
- };
370
- // Poll to detect if user closed the popup
371
- const pollInterval = setInterval(() => {
372
- if (popup.closed) {
373
- cleanup();
374
- reject(new OxyServices_errors_1.OxyAuthenticationError('Authentication cancelled by user'));
375
- }
376
- }, 500);
377
- const cleanup = () => {
378
- clearTimeout(timeoutId);
379
- clearInterval(pollInterval);
380
- window.removeEventListener('message', messageHandler);
381
- if (!popup.closed) {
382
- popup.close();
383
- }
384
- };
385
- window.addEventListener('message', messageHandler);
386
- });
387
- }
388
191
  /**
389
192
  * Wait for authentication response from iframe
390
193
  *
@@ -405,7 +208,7 @@ function OxyServicesPopupAuthMixin(Base) {
405
208
  return;
406
209
  }
407
210
  const { type, session } = event.data;
408
- if (type !== 'oxy_silent_auth') {
211
+ if (type !== "oxy_silent_auth") {
409
212
  return;
410
213
  }
411
214
  cleanup();
@@ -429,83 +232,31 @@ function OxyServicesPopupAuthMixin(Base) {
429
232
  clearTimeout(timeoutId);
430
233
  iframe.onerror = null;
431
234
  iframe.onabort = null;
432
- window.removeEventListener('message', messageHandler);
235
+ window.removeEventListener("message", messageHandler);
433
236
  };
434
- window.addEventListener('message', messageHandler);
237
+ window.addEventListener("message", messageHandler);
435
238
  });
436
239
  }
437
- /**
438
- * Build authentication URL with query parameters
439
- *
440
- * @private
441
- */
442
- buildAuthUrl(params) {
443
- const url = new URL(`${this.resolveAuthUrl()}/${params.mode}`);
444
- url.searchParams.set('response_type', 'token');
445
- url.searchParams.set('client_id', params.clientId);
446
- url.searchParams.set('redirect_uri', params.redirectUri);
447
- url.searchParams.set('state', params.state);
448
- url.searchParams.set('nonce', params.nonce);
449
- return url.toString();
450
- }
451
- /**
452
- * Generate cryptographically secure state for CSRF protection
453
- *
454
- * @private
455
- */
456
- generateState() {
457
- if (typeof crypto !== 'undefined' && crypto.randomUUID) {
458
- return crypto.randomUUID();
459
- }
460
- if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
461
- const bytes = new Uint8Array(16);
462
- crypto.getRandomValues(bytes);
463
- return Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('');
464
- }
465
- throw new Error('No secure random source available for state generation');
466
- }
467
240
  /**
468
241
  * Generate nonce for replay attack prevention
469
242
  *
470
243
  * @private
471
244
  */
472
245
  generateNonce() {
473
- if (typeof crypto !== 'undefined' && crypto.randomUUID) {
246
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
474
247
  return crypto.randomUUID();
475
248
  }
476
- if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
249
+ if (typeof crypto !== "undefined" && crypto.getRandomValues) {
477
250
  const bytes = new Uint8Array(16);
478
251
  crypto.getRandomValues(bytes);
479
- return Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('');
480
- }
481
- throw new Error('No secure random source available for nonce generation');
482
- }
483
- /**
484
- * Store auth state in session storage
485
- *
486
- * @private
487
- */
488
- storeAuthState(state, nonce) {
489
- if (typeof window !== 'undefined' && window.sessionStorage) {
490
- sessionStorage.setItem(`oxy_auth_state_${state}`, JSON.stringify({ nonce, timestamp: Date.now() }));
491
- }
492
- }
493
- /**
494
- * Clear auth state from session storage
495
- *
496
- * @private
497
- */
498
- clearAuthState(state) {
499
- if (typeof window !== 'undefined' && window.sessionStorage) {
500
- sessionStorage.removeItem(`oxy_auth_state_${state}`);
252
+ return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
501
253
  }
254
+ throw new Error("No secure random source available for nonce generation");
502
255
  }
503
256
  },
504
- _a.DEFAULT_AUTH_URL = 'https://auth.oxy.so',
257
+ _a.DEFAULT_AUTH_URL = "https://auth.oxy.so",
505
258
  _a.POPUP_WIDTH = 500,
506
259
  _a.POPUP_HEIGHT = 700,
507
- _a.POPUP_TIMEOUT = 60000 // 1 minute
508
- ,
509
260
  _a.SILENT_TIMEOUT = 5000 // 5 seconds
510
261
  ,
511
262
  _a;