mailsentry-auth 0.1.4 → 0.1.6
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.d.mts +36 -40
- package/dist/index.d.ts +36 -40
- package/dist/index.js +86 -108
- package/dist/index.mjs +86 -108
- package/dist/middleware.mjs +114 -72
- package/dist/utils/cookie-utils.d.mts +86 -0
- package/dist/utils/cookie-utils.d.ts +86 -0
- package/dist/utils/cookie-utils.js +97 -22
- package/dist/utils/cookie-utils.mjs +97 -22
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -83,34 +83,33 @@ var AuthEventType = /* @__PURE__ */ ((AuthEventType3) => {
|
|
|
83
83
|
return AuthEventType3;
|
|
84
84
|
})(AuthEventType || {});
|
|
85
85
|
var PageType = /* @__PURE__ */ ((PageType3) => {
|
|
86
|
-
PageType3["LOGIN"] = "login";
|
|
86
|
+
PageType3["LOGIN"] = "/login";
|
|
87
87
|
PageType3["DASHBOARD"] = "dashboard";
|
|
88
88
|
PageType3["HOME"] = "/";
|
|
89
89
|
return PageType3;
|
|
90
90
|
})(PageType || {});
|
|
91
91
|
var NavigationAction = /* @__PURE__ */ ((NavigationAction2) => {
|
|
92
92
|
NavigationAction2["NONE"] = "none";
|
|
93
|
-
NavigationAction2["
|
|
94
|
-
NavigationAction2["MODAL"] = "modal";
|
|
95
|
-
NavigationAction2["CURRENT"] = "current";
|
|
93
|
+
NavigationAction2["RELOAD"] = "reload";
|
|
96
94
|
return NavigationAction2;
|
|
97
95
|
})(NavigationAction || {});
|
|
98
96
|
var PageTypePatterns = {
|
|
99
|
-
["login" /* LOGIN */]: "login" /* LOGIN */,
|
|
100
|
-
["dashboard" /* DASHBOARD */]: "dashboard" /* DASHBOARD
|
|
97
|
+
["/login" /* LOGIN */]: "/login" /* LOGIN */,
|
|
98
|
+
["dashboard" /* DASHBOARD */]: "dashboard" /* DASHBOARD */,
|
|
99
|
+
["/" /* HOME */]: "/" /* HOME */
|
|
101
100
|
};
|
|
102
101
|
var CrossTabBehaviorConfig = {
|
|
103
|
-
["login" /* LOGIN */]: {
|
|
104
|
-
["auth.logged_in" /* LoggedIn */]: { action: "
|
|
105
|
-
["auth.logged_out" /* LoggedOut */]: { action: "
|
|
102
|
+
["/login" /* LOGIN */]: {
|
|
103
|
+
["auth.logged_in" /* LoggedIn */]: { action: "reload" /* RELOAD */ },
|
|
104
|
+
["auth.logged_out" /* LoggedOut */]: { action: "reload" /* RELOAD */ },
|
|
106
105
|
["auth.email_verified" /* EmailVerified */]: { action: "none" /* NONE */ },
|
|
107
106
|
["auth.signin_required_modal" /* SignInRequiredModal */]: { action: "none" /* NONE */ }
|
|
108
107
|
},
|
|
109
108
|
["dashboard" /* DASHBOARD */]: {
|
|
110
|
-
["auth.logged_in" /* LoggedIn */]: { action: "
|
|
111
|
-
["auth.logged_out" /* LoggedOut */]: { action: "
|
|
112
|
-
["auth.email_verified" /* EmailVerified */]: { action: "
|
|
113
|
-
["auth.signin_required_modal" /* SignInRequiredModal */]: { action: "
|
|
109
|
+
["auth.logged_in" /* LoggedIn */]: { action: "reload" /* RELOAD */ },
|
|
110
|
+
["auth.logged_out" /* LoggedOut */]: { action: "reload" /* RELOAD */ },
|
|
111
|
+
["auth.email_verified" /* EmailVerified */]: { action: "reload" /* RELOAD */ },
|
|
112
|
+
["auth.signin_required_modal" /* SignInRequiredModal */]: { action: "none" /* NONE */ }
|
|
114
113
|
},
|
|
115
114
|
["/" /* HOME */]: {
|
|
116
115
|
["auth.logged_in" /* LoggedIn */]: { action: "none" /* NONE */ },
|
|
@@ -253,12 +252,12 @@ var getVerificationField = (codeLength = 5, options = {}) => ({
|
|
|
253
252
|
});
|
|
254
253
|
|
|
255
254
|
// src/config/middleware.ts
|
|
256
|
-
var
|
|
255
|
+
var _MiddlewareConfig = class _MiddlewareConfig {
|
|
257
256
|
/**
|
|
258
257
|
* Get the base domain from environment or use default
|
|
259
258
|
*/
|
|
260
259
|
static getBaseDomain() {
|
|
261
|
-
return process.env.NEXT_PUBLIC_BASE_DOMAIN
|
|
260
|
+
return process.env.NEXT_PUBLIC_BASE_DOMAIN;
|
|
262
261
|
}
|
|
263
262
|
/**
|
|
264
263
|
* Get the protocol based on environment
|
|
@@ -266,35 +265,44 @@ var MiddlewareConfig = class {
|
|
|
266
265
|
static getProtocol() {
|
|
267
266
|
return process.env.NODE_ENV === "production" ? "https" : "http";
|
|
268
267
|
}
|
|
269
|
-
/**
|
|
270
|
-
* Get the dashboard subdomain URL
|
|
271
|
-
*/
|
|
272
|
-
static getDashboardUrl(path = "") {
|
|
273
|
-
return `${this.getProtocol()}://${this.SUBDOMAINS.DASHBOARD}.${this.getBaseDomain()}${path}`;
|
|
274
|
-
}
|
|
275
268
|
};
|
|
276
|
-
//
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
269
|
+
// Common constants
|
|
270
|
+
_MiddlewareConfig.CONSTANTS = {
|
|
271
|
+
LOGIN_PATH: "/login",
|
|
272
|
+
DASHBOARD_SUBDOMAIN: "dashboard",
|
|
273
|
+
PUBLIC_PATH: "/public",
|
|
274
|
+
PUBLIC_API_PATH: "/api/public"
|
|
275
|
+
};
|
|
276
|
+
// Route Protection Configuration
|
|
277
|
+
// PATTERNS_TO_PROTECT: Routes that require authentication (whitelist approach recommended for security)
|
|
278
|
+
// PATTERNS_TO_EXCLUDE: Routes to explicitly exclude from protection (e.g., login page, public assets)
|
|
279
|
+
_MiddlewareConfig.PROTECTED_ROUTES = {
|
|
280
|
+
// Routes that MUST be protected
|
|
281
|
+
INCLUDE: [
|
|
282
|
+
"/"
|
|
283
|
+
// Protect everything by default (since dashboard.cutly.io/ is the root)
|
|
284
|
+
],
|
|
285
|
+
// Routes that should NEVER be protected (public)
|
|
286
|
+
EXCLUDE: [
|
|
287
|
+
_MiddlewareConfig.CONSTANTS.LOGIN_PATH,
|
|
288
|
+
_MiddlewareConfig.CONSTANTS.PUBLIC_PATH,
|
|
289
|
+
_MiddlewareConfig.CONSTANTS.PUBLIC_API_PATH
|
|
290
|
+
]
|
|
284
291
|
};
|
|
285
292
|
// HTTP methods to process
|
|
286
|
-
|
|
293
|
+
_MiddlewareConfig.ALLOWED_METHODS = ["GET", "HEAD"];
|
|
287
294
|
// Query parameters
|
|
288
|
-
|
|
295
|
+
_MiddlewareConfig.QUERY_PARAMS = {
|
|
289
296
|
LOGIN_REQUIRED: "sign_in_required",
|
|
290
297
|
AUTH_CHECKED: "auth_checked",
|
|
291
298
|
REDIRECT_URL: "redirect_url"
|
|
292
299
|
};
|
|
293
300
|
// Query parameter values
|
|
294
|
-
|
|
301
|
+
_MiddlewareConfig.QUERY_VALUES = {
|
|
295
302
|
LOGIN_REQUIRED: "true",
|
|
296
303
|
AUTH_CHECKED: "1"
|
|
297
304
|
};
|
|
305
|
+
var MiddlewareConfig = _MiddlewareConfig;
|
|
298
306
|
var middlewareMatcher = [
|
|
299
307
|
"/((?!api|_next/static|_next/image|_next/webpack-hmr|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico|css|js)$).*)"
|
|
300
308
|
];
|
|
@@ -406,19 +414,55 @@ function init(converter, defaultAttributes) {
|
|
|
406
414
|
}
|
|
407
415
|
var api = init(defaultConverter, { path: "/" });
|
|
408
416
|
|
|
417
|
+
// src/services/utils/url-utils.ts
|
|
418
|
+
var UrlUtils = class {
|
|
419
|
+
/**
|
|
420
|
+
* Extract subdomain from hostname
|
|
421
|
+
* Example: "dashboard.cutly.io" -> "dashboard"
|
|
422
|
+
*/
|
|
423
|
+
static getSubdomain(hostname) {
|
|
424
|
+
if (!hostname || /^\d{1,3}(\.\d{1,3}){3}/.test(hostname) || hostname.startsWith(MiddlewareConfig.getBaseDomain())) {
|
|
425
|
+
return null;
|
|
426
|
+
}
|
|
427
|
+
const parts = hostname.split(".");
|
|
428
|
+
return parts.length >= 2 ? parts[0] : null;
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Get root domain for cookie scope
|
|
432
|
+
* Example: "dashboard.cutly.io" -> ".cutly.io"
|
|
433
|
+
* Example: "cutly.io" -> ".cutly.io"
|
|
434
|
+
*/
|
|
435
|
+
static getRootDomain(hostname) {
|
|
436
|
+
if (!hostname || /^\d+\.\d+\.\d+\.\d+$/.test(hostname)) {
|
|
437
|
+
return null;
|
|
438
|
+
}
|
|
439
|
+
const parts = hostname.split(".");
|
|
440
|
+
if (parts.length >= 2) {
|
|
441
|
+
return `.${parts.slice(-2).join(".")}`;
|
|
442
|
+
}
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Check if URL has auth-related query parameters
|
|
447
|
+
*/
|
|
448
|
+
static hasAuthParams(url) {
|
|
449
|
+
return url.includes(MiddlewareConfig.QUERY_PARAMS.AUTH_CHECKED);
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
|
|
409
453
|
// src/services/utils/cookie-utils.ts
|
|
410
454
|
var _CookieUtils = class _CookieUtils {
|
|
411
455
|
/**
|
|
412
|
-
* Get the access token cookie key
|
|
456
|
+
* Get the access token cookie key
|
|
413
457
|
*/
|
|
414
458
|
static getAccessTokenKey() {
|
|
415
|
-
return
|
|
459
|
+
return "auth_access_token";
|
|
416
460
|
}
|
|
417
461
|
/**
|
|
418
|
-
* Get the refresh token cookie key
|
|
462
|
+
* Get the refresh token cookie key
|
|
419
463
|
*/
|
|
420
464
|
static getRefreshTokenKey() {
|
|
421
|
-
return
|
|
465
|
+
return "auth_refresh_token";
|
|
422
466
|
}
|
|
423
467
|
/**
|
|
424
468
|
* Get root domain for subdomain support
|
|
@@ -426,26 +470,10 @@ var _CookieUtils = class _CookieUtils {
|
|
|
426
470
|
*/
|
|
427
471
|
static getRootDomain() {
|
|
428
472
|
if (typeof window === "undefined") {
|
|
429
|
-
const baseDomain = process.env.NEXT_PUBLIC_BASE_DOMAIN;
|
|
430
|
-
if (baseDomain && process.env.NODE_ENV === "production") {
|
|
431
|
-
return `.${baseDomain}`;
|
|
432
|
-
}
|
|
433
|
-
return void 0;
|
|
434
|
-
}
|
|
435
|
-
const hostname = window.location.hostname;
|
|
436
|
-
if (hostname === "localhost" || hostname === "127.0.0.1") {
|
|
437
|
-
return void 0;
|
|
438
|
-
}
|
|
439
|
-
if (/^\d+\.\d+\.\d+\.\d+$/.test(hostname)) {
|
|
440
473
|
return void 0;
|
|
441
474
|
}
|
|
442
|
-
|
|
443
|
-
if (parts.length >= 2) {
|
|
444
|
-
return `.${parts.slice(-2).join(".")}`;
|
|
445
|
-
}
|
|
446
|
-
return void 0;
|
|
475
|
+
return UrlUtils.getRootDomain(window.location.hostname) || void 0;
|
|
447
476
|
}
|
|
448
|
-
// Use current domain in development
|
|
449
477
|
/**
|
|
450
478
|
* Get common cookie options
|
|
451
479
|
*/
|
|
@@ -644,7 +672,7 @@ var _CookieUtils = class _CookieUtils {
|
|
|
644
672
|
}
|
|
645
673
|
};
|
|
646
674
|
// Domain configuration - computed once
|
|
647
|
-
_CookieUtils.COOKIE_DOMAIN =
|
|
675
|
+
_CookieUtils.COOKIE_DOMAIN = _CookieUtils.getRootDomain();
|
|
648
676
|
var CookieUtils = _CookieUtils;
|
|
649
677
|
|
|
650
678
|
// src/services/utils/localstorage-utils.ts
|
|
@@ -782,33 +810,6 @@ var BroadcastChannelEventBus = class _BroadcastChannelEventBus {
|
|
|
782
810
|
}
|
|
783
811
|
};
|
|
784
812
|
|
|
785
|
-
// src/services/utils/url-utils.ts
|
|
786
|
-
var UrlUtils = class {
|
|
787
|
-
/**
|
|
788
|
-
* Extract subdomain from hostname or URL
|
|
789
|
-
* Example: "dashboard.cutly.io" -> "dashboard"
|
|
790
|
-
* Example: "dashboard.localhost" -> "dashboard"
|
|
791
|
-
*/
|
|
792
|
-
static getSubdomain(url) {
|
|
793
|
-
try {
|
|
794
|
-
const domain = new URL(`http://${url}`).hostname;
|
|
795
|
-
const parts = domain.split(".");
|
|
796
|
-
if (parts.length < 2 || domain === "localhost" || /^\d{1,3}(\.\d{1,3}){3}/.test(domain) || domain.startsWith(MiddlewareConfig.getBaseDomain())) {
|
|
797
|
-
return null;
|
|
798
|
-
}
|
|
799
|
-
return parts[0] || null;
|
|
800
|
-
} catch (e) {
|
|
801
|
-
return null;
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
/**
|
|
805
|
-
* Check if URL has auth-related query parameters
|
|
806
|
-
*/
|
|
807
|
-
static hasAuthParams(url) {
|
|
808
|
-
return url.includes(MiddlewareConfig.QUERY_PARAMS.AUTH_CHECKED);
|
|
809
|
-
}
|
|
810
|
-
};
|
|
811
|
-
|
|
812
813
|
// src/services/utils/cross-tab-behavior-handler.ts
|
|
813
814
|
var CrossTabBehaviorHandler = class {
|
|
814
815
|
/**
|
|
@@ -821,8 +822,8 @@ var CrossTabBehaviorHandler = class {
|
|
|
821
822
|
const pathname = window.location.pathname;
|
|
822
823
|
const subdomain = UrlUtils.getSubdomain(window.location.hostname);
|
|
823
824
|
const pageTypeMatchers = {
|
|
824
|
-
["login" /* LOGIN */]: pathname === MiddlewareConfig.
|
|
825
|
-
["dashboard" /* DASHBOARD */]: subdomain === MiddlewareConfig.
|
|
825
|
+
["/login" /* LOGIN */]: pathname === MiddlewareConfig.CONSTANTS.LOGIN_PATH,
|
|
826
|
+
["dashboard" /* DASHBOARD */]: subdomain === MiddlewareConfig.CONSTANTS.DASHBOARD_SUBDOMAIN
|
|
826
827
|
};
|
|
827
828
|
const matchedPageType = (_a = Object.entries(pageTypeMatchers).find(([, matches]) => matches)) == null ? void 0 : _a[0];
|
|
828
829
|
return matchedPageType != null ? matchedPageType : "dashboard" /* DASHBOARD */;
|
|
@@ -837,14 +838,6 @@ var CrossTabBehaviorHandler = class {
|
|
|
837
838
|
var _a, _b;
|
|
838
839
|
return (_b = (_a = CrossTabBehaviorConfig[currentPageType]) == null ? void 0 : _a[eventType]) != null ? _b : { action: "none" /* NONE */ };
|
|
839
840
|
}
|
|
840
|
-
/**
|
|
841
|
-
* Check if current route requires redirect for given event
|
|
842
|
-
* Returns PageType to redirect to, or null if no redirect needed
|
|
843
|
-
*/
|
|
844
|
-
static shouldRedirect(currentPageType, eventType) {
|
|
845
|
-
const action = this.getAction(currentPageType, eventType);
|
|
846
|
-
return action.action === "redirect" /* REDIRECT */ ? action.target : null;
|
|
847
|
-
}
|
|
848
841
|
};
|
|
849
842
|
|
|
850
843
|
// src/services/auth/manager/token-manager.ts
|
|
@@ -2376,23 +2369,8 @@ var useAuthEventBus = ({ onLoggedOut, onLoggedIn } = {}) => {
|
|
|
2376
2369
|
const handler = eventHandlers[e.type];
|
|
2377
2370
|
const action = CrossTabBehaviorHandler.getAction(currentPageType, e.type);
|
|
2378
2371
|
const actionHandlers = {
|
|
2379
|
-
["
|
|
2380
|
-
|
|
2381
|
-
if (target) {
|
|
2382
|
-
window.location.replace(target);
|
|
2383
|
-
}
|
|
2384
|
-
},
|
|
2385
|
-
["current" /* CURRENT */]: () => {
|
|
2386
|
-
const isAuthAction = e.type === "auth.logged_in" /* LoggedIn */ || e.type === "auth.logged_out" /* LoggedOut */;
|
|
2387
|
-
const hasParams = UrlUtils.hasAuthParams(window.location.href);
|
|
2388
|
-
if (isAuthAction || !hasParams) {
|
|
2389
|
-
window.location.reload();
|
|
2390
|
-
}
|
|
2391
|
-
},
|
|
2392
|
-
["modal" /* MODAL */]: () => {
|
|
2393
|
-
if (e.type === "auth.logged_in" /* LoggedIn */) {
|
|
2394
|
-
window.location.replace(window.location.href);
|
|
2395
|
-
}
|
|
2372
|
+
["reload" /* RELOAD */]: () => {
|
|
2373
|
+
window.location.replace(window.location.href);
|
|
2396
2374
|
},
|
|
2397
2375
|
["none" /* NONE */]: () => {
|
|
2398
2376
|
}
|
package/dist/middleware.mjs
CHANGED
|
@@ -22,12 +22,12 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
|
22
22
|
import { NextResponse } from "next/server";
|
|
23
23
|
|
|
24
24
|
// src/config/middleware.ts
|
|
25
|
-
var
|
|
25
|
+
var _MiddlewareConfig = class _MiddlewareConfig {
|
|
26
26
|
/**
|
|
27
27
|
* Get the base domain from environment or use default
|
|
28
28
|
*/
|
|
29
29
|
static getBaseDomain() {
|
|
30
|
-
return process.env.NEXT_PUBLIC_BASE_DOMAIN
|
|
30
|
+
return process.env.NEXT_PUBLIC_BASE_DOMAIN;
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
33
|
* Get the protocol based on environment
|
|
@@ -35,35 +35,44 @@ var MiddlewareConfig = class {
|
|
|
35
35
|
static getProtocol() {
|
|
36
36
|
return process.env.NODE_ENV === "production" ? "https" : "http";
|
|
37
37
|
}
|
|
38
|
-
/**
|
|
39
|
-
* Get the dashboard subdomain URL
|
|
40
|
-
*/
|
|
41
|
-
static getDashboardUrl(path = "") {
|
|
42
|
-
return `${this.getProtocol()}://${this.SUBDOMAINS.DASHBOARD}.${this.getBaseDomain()}${path}`;
|
|
43
|
-
}
|
|
44
38
|
};
|
|
45
|
-
//
|
|
46
|
-
|
|
47
|
-
|
|
39
|
+
// Common constants
|
|
40
|
+
_MiddlewareConfig.CONSTANTS = {
|
|
41
|
+
LOGIN_PATH: "/login",
|
|
42
|
+
DASHBOARD_SUBDOMAIN: "dashboard",
|
|
43
|
+
PUBLIC_PATH: "/public",
|
|
44
|
+
PUBLIC_API_PATH: "/api/public"
|
|
48
45
|
};
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
// Route Protection Configuration
|
|
47
|
+
// PATTERNS_TO_PROTECT: Routes that require authentication (whitelist approach recommended for security)
|
|
48
|
+
// PATTERNS_TO_EXCLUDE: Routes to explicitly exclude from protection (e.g., login page, public assets)
|
|
49
|
+
_MiddlewareConfig.PROTECTED_ROUTES = {
|
|
50
|
+
// Routes that MUST be protected
|
|
51
|
+
INCLUDE: [
|
|
52
|
+
"/"
|
|
53
|
+
// Protect everything by default (since dashboard.cutly.io/ is the root)
|
|
54
|
+
],
|
|
55
|
+
// Routes that should NEVER be protected (public)
|
|
56
|
+
EXCLUDE: [
|
|
57
|
+
_MiddlewareConfig.CONSTANTS.LOGIN_PATH,
|
|
58
|
+
_MiddlewareConfig.CONSTANTS.PUBLIC_PATH,
|
|
59
|
+
_MiddlewareConfig.CONSTANTS.PUBLIC_API_PATH
|
|
60
|
+
]
|
|
53
61
|
};
|
|
54
62
|
// HTTP methods to process
|
|
55
|
-
|
|
63
|
+
_MiddlewareConfig.ALLOWED_METHODS = ["GET", "HEAD"];
|
|
56
64
|
// Query parameters
|
|
57
|
-
|
|
65
|
+
_MiddlewareConfig.QUERY_PARAMS = {
|
|
58
66
|
LOGIN_REQUIRED: "sign_in_required",
|
|
59
67
|
AUTH_CHECKED: "auth_checked",
|
|
60
68
|
REDIRECT_URL: "redirect_url"
|
|
61
69
|
};
|
|
62
70
|
// Query parameter values
|
|
63
|
-
|
|
71
|
+
_MiddlewareConfig.QUERY_VALUES = {
|
|
64
72
|
LOGIN_REQUIRED: "true",
|
|
65
73
|
AUTH_CHECKED: "1"
|
|
66
74
|
};
|
|
75
|
+
var MiddlewareConfig = _MiddlewareConfig;
|
|
67
76
|
var middlewareMatcher = [
|
|
68
77
|
"/((?!api|_next/static|_next/image|_next/webpack-hmr|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico|css|js)$).*)"
|
|
69
78
|
];
|
|
@@ -73,18 +82,56 @@ var config = {
|
|
|
73
82
|
|
|
74
83
|
// src/services/utils/cookie-utils.ts
|
|
75
84
|
import Cookies from "js-cookie";
|
|
85
|
+
|
|
86
|
+
// src/services/utils/url-utils.ts
|
|
87
|
+
var UrlUtils = class {
|
|
88
|
+
/**
|
|
89
|
+
* Extract subdomain from hostname
|
|
90
|
+
* Example: "dashboard.cutly.io" -> "dashboard"
|
|
91
|
+
*/
|
|
92
|
+
static getSubdomain(hostname) {
|
|
93
|
+
if (!hostname || /^\d{1,3}(\.\d{1,3}){3}/.test(hostname) || hostname.startsWith(MiddlewareConfig.getBaseDomain())) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
const parts = hostname.split(".");
|
|
97
|
+
return parts.length >= 2 ? parts[0] : null;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Get root domain for cookie scope
|
|
101
|
+
* Example: "dashboard.cutly.io" -> ".cutly.io"
|
|
102
|
+
* Example: "cutly.io" -> ".cutly.io"
|
|
103
|
+
*/
|
|
104
|
+
static getRootDomain(hostname) {
|
|
105
|
+
if (!hostname || /^\d+\.\d+\.\d+\.\d+$/.test(hostname)) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
const parts = hostname.split(".");
|
|
109
|
+
if (parts.length >= 2) {
|
|
110
|
+
return `.${parts.slice(-2).join(".")}`;
|
|
111
|
+
}
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Check if URL has auth-related query parameters
|
|
116
|
+
*/
|
|
117
|
+
static hasAuthParams(url) {
|
|
118
|
+
return url.includes(MiddlewareConfig.QUERY_PARAMS.AUTH_CHECKED);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
// src/services/utils/cookie-utils.ts
|
|
76
123
|
var _CookieUtils = class _CookieUtils {
|
|
77
124
|
/**
|
|
78
|
-
* Get the access token cookie key
|
|
125
|
+
* Get the access token cookie key
|
|
79
126
|
*/
|
|
80
127
|
static getAccessTokenKey() {
|
|
81
|
-
return
|
|
128
|
+
return "auth_access_token";
|
|
82
129
|
}
|
|
83
130
|
/**
|
|
84
|
-
* Get the refresh token cookie key
|
|
131
|
+
* Get the refresh token cookie key
|
|
85
132
|
*/
|
|
86
133
|
static getRefreshTokenKey() {
|
|
87
|
-
return
|
|
134
|
+
return "auth_refresh_token";
|
|
88
135
|
}
|
|
89
136
|
/**
|
|
90
137
|
* Get root domain for subdomain support
|
|
@@ -92,26 +139,10 @@ var _CookieUtils = class _CookieUtils {
|
|
|
92
139
|
*/
|
|
93
140
|
static getRootDomain() {
|
|
94
141
|
if (typeof window === "undefined") {
|
|
95
|
-
const baseDomain = process.env.NEXT_PUBLIC_BASE_DOMAIN;
|
|
96
|
-
if (baseDomain && process.env.NODE_ENV === "production") {
|
|
97
|
-
return `.${baseDomain}`;
|
|
98
|
-
}
|
|
99
142
|
return void 0;
|
|
100
143
|
}
|
|
101
|
-
|
|
102
|
-
if (hostname === "localhost" || hostname === "127.0.0.1") {
|
|
103
|
-
return void 0;
|
|
104
|
-
}
|
|
105
|
-
if (/^\d+\.\d+\.\d+\.\d+$/.test(hostname)) {
|
|
106
|
-
return void 0;
|
|
107
|
-
}
|
|
108
|
-
const parts = hostname.split(".");
|
|
109
|
-
if (parts.length >= 2) {
|
|
110
|
-
return `.${parts.slice(-2).join(".")}`;
|
|
111
|
-
}
|
|
112
|
-
return void 0;
|
|
144
|
+
return UrlUtils.getRootDomain(window.location.hostname) || void 0;
|
|
113
145
|
}
|
|
114
|
-
// Use current domain in development
|
|
115
146
|
/**
|
|
116
147
|
* Get common cookie options
|
|
117
148
|
*/
|
|
@@ -310,7 +341,7 @@ var _CookieUtils = class _CookieUtils {
|
|
|
310
341
|
}
|
|
311
342
|
};
|
|
312
343
|
// Domain configuration - computed once
|
|
313
|
-
_CookieUtils.COOKIE_DOMAIN =
|
|
344
|
+
_CookieUtils.COOKIE_DOMAIN = _CookieUtils.getRootDomain();
|
|
314
345
|
var CookieUtils = _CookieUtils;
|
|
315
346
|
|
|
316
347
|
// src/services/utils/localstorage-utils.ts
|
|
@@ -394,32 +425,33 @@ LocalStorageUtils.USER_PROFILE_STORAGE_KEY = "user_profile_data";
|
|
|
394
425
|
LocalStorageUtils.USER_PROFILE_TIMESTAMP_KEY = "user_profile_timestamp";
|
|
395
426
|
LocalStorageUtils.DEFAULT_CACHE_DURATION = 5 * 60 * 1e3;
|
|
396
427
|
|
|
397
|
-
// src/
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
/**
|
|
417
|
-
* Check if URL has auth-related query parameters
|
|
418
|
-
*/
|
|
419
|
-
static hasAuthParams(url) {
|
|
420
|
-
return url.includes(MiddlewareConfig.QUERY_PARAMS.AUTH_CHECKED);
|
|
421
|
-
}
|
|
428
|
+
// src/config/auth-steps.tsx
|
|
429
|
+
import React2 from "react";
|
|
430
|
+
import {
|
|
431
|
+
MailOutlined,
|
|
432
|
+
LockOutlined,
|
|
433
|
+
CheckCircleOutlined
|
|
434
|
+
} from "@ant-design/icons";
|
|
435
|
+
|
|
436
|
+
// src/config/step-navigation.ts
|
|
437
|
+
var EMAIL_SUBMISSION_NAVIGATION = {
|
|
438
|
+
["login-verification" /* LOGIN_VERIFICATION */]: "verification" /* VERIFICATION */,
|
|
439
|
+
["login" /* LOGIN */]: "password" /* PASSWORD */,
|
|
440
|
+
["signup" /* SIGNUP */]: "password" /* PASSWORD */
|
|
441
|
+
};
|
|
442
|
+
var PASSWORD_SUBMISSION_NAVIGATION = {
|
|
443
|
+
VERIFIED: "verification" /* VERIFICATION */,
|
|
444
|
+
UNVERIFIED: "verification" /* VERIFICATION */
|
|
422
445
|
};
|
|
446
|
+
var VERIFICATION_SUBMISSION_NAVIGATION = {
|
|
447
|
+
SUCCESS: "verification" /* VERIFICATION */,
|
|
448
|
+
ERROR: "verification" /* VERIFICATION */
|
|
449
|
+
// Stay on verification step on error
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
// src/config/form-fields.tsx
|
|
453
|
+
import { Input } from "antd";
|
|
454
|
+
import { MailOutlined as MailOutlined2, LockOutlined as LockOutlined2, CheckCircleOutlined as CheckCircleOutlined2 } from "@ant-design/icons";
|
|
423
455
|
|
|
424
456
|
// src/services/api/endpoints.ts
|
|
425
457
|
var AUTH_ENDPOINTS = {
|
|
@@ -633,10 +665,19 @@ AuthenticationStatusContext.states = /* @__PURE__ */ new Map([
|
|
|
633
665
|
// src/middlewares/handlers/base-middleware-handler.ts
|
|
634
666
|
var BaseMiddlewareHandler = class {
|
|
635
667
|
/**
|
|
636
|
-
* Check if current
|
|
668
|
+
* Check if current route requires authentication
|
|
669
|
+
* Uses inclusive (PROTECTED_ROUTES.INCLUDE) and exclusive (PROTECTED_ROUTES.EXCLUDE) lists
|
|
637
670
|
*/
|
|
638
|
-
|
|
639
|
-
|
|
671
|
+
requiresAuthentication(pathname) {
|
|
672
|
+
const isExcluded = MiddlewareConfig.PROTECTED_ROUTES.EXCLUDE.some(
|
|
673
|
+
(route) => pathname.startsWith(route) || pathname === route
|
|
674
|
+
);
|
|
675
|
+
if (isExcluded) {
|
|
676
|
+
return false;
|
|
677
|
+
}
|
|
678
|
+
return MiddlewareConfig.PROTECTED_ROUTES.INCLUDE.some(
|
|
679
|
+
(route) => pathname.startsWith(route) || pathname === route
|
|
680
|
+
);
|
|
640
681
|
}
|
|
641
682
|
/**
|
|
642
683
|
* Check if user has both access and refresh tokens
|
|
@@ -647,11 +688,12 @@ var BaseMiddlewareHandler = class {
|
|
|
647
688
|
}
|
|
648
689
|
/**
|
|
649
690
|
* Get authentication cookie keys from environment variables
|
|
691
|
+
* Now uses CookieUtils for consistent retrieval
|
|
650
692
|
*/
|
|
651
693
|
getAuthCookieKeys() {
|
|
652
694
|
return {
|
|
653
|
-
accessTokenKey:
|
|
654
|
-
refreshTokenKey:
|
|
695
|
+
accessTokenKey: CookieUtils.getAccessTokenKey(),
|
|
696
|
+
refreshTokenKey: CookieUtils.getRefreshTokenKey()
|
|
655
697
|
};
|
|
656
698
|
}
|
|
657
699
|
/**
|
|
@@ -752,8 +794,8 @@ var MethodFilterHandler = class extends BaseMiddlewareHandler {
|
|
|
752
794
|
// src/middlewares/handlers/authentication-handler.ts
|
|
753
795
|
var AuthenticationHandler = class extends BaseMiddlewareHandler {
|
|
754
796
|
async handle(context) {
|
|
755
|
-
const { cookies,
|
|
756
|
-
if (!this.
|
|
797
|
+
const { cookies, pathname } = context;
|
|
798
|
+
if (!this.requiresAuthentication(pathname)) {
|
|
757
799
|
return this.continue();
|
|
758
800
|
}
|
|
759
801
|
const hasAuthCookies = this.hasAuthenticationCookies(cookies);
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cookie utility for managing authentication tokens with automatic SSR and client-side support
|
|
3
|
+
* Automatically chooses the right method based on environment
|
|
4
|
+
*/
|
|
5
|
+
declare class CookieUtils {
|
|
6
|
+
/**
|
|
7
|
+
* Get the access token cookie key
|
|
8
|
+
*/
|
|
9
|
+
static getAccessTokenKey(): string;
|
|
10
|
+
/**
|
|
11
|
+
* Get the refresh token cookie key
|
|
12
|
+
*/
|
|
13
|
+
static getRefreshTokenKey(): string;
|
|
14
|
+
/**
|
|
15
|
+
* Get root domain for subdomain support
|
|
16
|
+
* Must match the domain used by backend when setting cookies
|
|
17
|
+
*/
|
|
18
|
+
private static getRootDomain;
|
|
19
|
+
private static readonly COOKIE_DOMAIN;
|
|
20
|
+
/**
|
|
21
|
+
* Get common cookie options
|
|
22
|
+
*/
|
|
23
|
+
private static getCookieOptions;
|
|
24
|
+
/**
|
|
25
|
+
* Check if running on client side
|
|
26
|
+
*/
|
|
27
|
+
private static isClientSide;
|
|
28
|
+
/**
|
|
29
|
+
* Check if running on server side
|
|
30
|
+
*/
|
|
31
|
+
private static isServerSide;
|
|
32
|
+
/**
|
|
33
|
+
* Dynamically import server action for server-side operations
|
|
34
|
+
*/
|
|
35
|
+
private static getServerTokens;
|
|
36
|
+
/**
|
|
37
|
+
* Set access token in cookie (client-side only)
|
|
38
|
+
*/
|
|
39
|
+
static setAccessToken(token: string): void;
|
|
40
|
+
/**
|
|
41
|
+
* Set refresh token in cookie (client-side only)
|
|
42
|
+
*/
|
|
43
|
+
static setRefreshToken(token: string): void;
|
|
44
|
+
/**
|
|
45
|
+
* Get access token - automatically handles client/server side
|
|
46
|
+
*/
|
|
47
|
+
static getAccessToken(): Promise<string | null>;
|
|
48
|
+
/**
|
|
49
|
+
* Get refresh token - automatically handles client/server side
|
|
50
|
+
*/
|
|
51
|
+
static getRefreshToken(): Promise<string | null>;
|
|
52
|
+
/**
|
|
53
|
+
* Get both tokens - automatically handles client/server side
|
|
54
|
+
*/
|
|
55
|
+
static getTokens(): Promise<{
|
|
56
|
+
accessToken: string | null;
|
|
57
|
+
refreshToken: string | null;
|
|
58
|
+
}>;
|
|
59
|
+
/**
|
|
60
|
+
* Clear all authentication cookies (client-side only)
|
|
61
|
+
* Clears cookies from both current domain and root domain
|
|
62
|
+
*/
|
|
63
|
+
static clearAuthCookies(): void;
|
|
64
|
+
/**
|
|
65
|
+
* Check if cookies are supported/enabled (client-side only)
|
|
66
|
+
*/
|
|
67
|
+
static areCookiesEnabled(): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Get all authentication cookies - automatically handles client/server side
|
|
70
|
+
*/
|
|
71
|
+
static getAllAuthCookies(): Promise<Record<string, string>>;
|
|
72
|
+
/**
|
|
73
|
+
* Set multiple tokens at once (client-side only)
|
|
74
|
+
*/
|
|
75
|
+
static setTokens(accessToken: string, refreshToken: string): void;
|
|
76
|
+
/**
|
|
77
|
+
* Check if user has valid tokens - automatically handles client/server side
|
|
78
|
+
*/
|
|
79
|
+
static hasValidTokens(): Promise<boolean>;
|
|
80
|
+
/**
|
|
81
|
+
* Get current domain information for debugging
|
|
82
|
+
*/
|
|
83
|
+
static getDomainInfo(): Record<string, string>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export { CookieUtils };
|