@xbg.solutions/bpsk-utils-csrf 1.2.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.
- package/lib/constants/csrf.constants.d.ts +40 -0
- package/lib/constants/csrf.constants.d.ts.map +1 -0
- package/lib/constants/csrf.constants.js +41 -0
- package/lib/constants/csrf.constants.js.map +1 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +8 -0
- package/lib/index.js.map +1 -0
- package/lib/stores/csrf.d.ts +15 -0
- package/lib/stores/csrf.d.ts.map +1 -0
- package/lib/stores/csrf.js +31 -0
- package/lib/stores/csrf.js.map +1 -0
- package/lib/utils/csrf.d.ts +31 -0
- package/lib/utils/csrf.d.ts.map +1 -0
- package/lib/utils/csrf.js +390 -0
- package/lib/utils/csrf.js.map +1 -0
- package/package.json +26 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/lib/constants/csrf.constants.ts
|
|
3
|
+
* Constants for CSRF protection configuration
|
|
4
|
+
*
|
|
5
|
+
* @deprecated This file has been consolidated into central configuration.
|
|
6
|
+
* New code should import from '@/lib/config/app.config.ts' instead.
|
|
7
|
+
*
|
|
8
|
+
* Legacy CSRF constants - use central config for new development.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* @deprecated Use APP_CONFIG.security.csrf instead
|
|
12
|
+
* Key used for storing the CSRF token
|
|
13
|
+
*/
|
|
14
|
+
export declare const CSRF_TOKEN_KEY: string;
|
|
15
|
+
/**
|
|
16
|
+
* @deprecated Use APP_CONFIG.security.csrf instead
|
|
17
|
+
* HTTP header name for sending the CSRF token
|
|
18
|
+
*/
|
|
19
|
+
export declare const CSRF_HEADER_NAME: string;
|
|
20
|
+
/**
|
|
21
|
+
* @deprecated Use APP_CONFIG.security.csrf instead
|
|
22
|
+
* Cookie name for storing the CSRF token
|
|
23
|
+
*/
|
|
24
|
+
export declare const CSRF_COOKIE_NAME: string;
|
|
25
|
+
/**
|
|
26
|
+
* @deprecated Use APP_CONFIG.security.csrf instead
|
|
27
|
+
* Time to live for CSRF tokens in seconds (2 hours)
|
|
28
|
+
*/
|
|
29
|
+
export declare const CSRF_TOKEN_TTL: number;
|
|
30
|
+
/**
|
|
31
|
+
* @deprecated Use APP_CONFIG.security.csrf instead
|
|
32
|
+
* HTTP methods that require CSRF protection
|
|
33
|
+
*/
|
|
34
|
+
export declare const CSRF_PROTECTED_METHODS: string[];
|
|
35
|
+
/**
|
|
36
|
+
* @deprecated Use APP_CONFIG.security.storage instead
|
|
37
|
+
* Re-export AUTH_NAMESPACE for use in CSRF utility
|
|
38
|
+
*/
|
|
39
|
+
export declare const AUTH_NAMESPACE: string;
|
|
40
|
+
//# sourceMappingURL=csrf.constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csrf.constants.d.ts","sourceRoot":"","sources":["../../src/constants/csrf.constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAoC,CAAC;AAEhE;;;GAGG;AACH,eAAO,MAAM,gBAAgB,QAAsC,CAAC;AAEpE;;;GAGG;AACH,eAAO,MAAM,gBAAgB,QAAsC,CAAC;AAEpE;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAoC,CAAC;AAEhE;;;GAGG;AACH,eAAO,MAAM,sBAAsB,UAA4C,CAAC;AAEhF;;;GAGG;AACH,eAAO,MAAM,cAAc,QAA4C,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/lib/constants/csrf.constants.ts
|
|
3
|
+
* Constants for CSRF protection configuration
|
|
4
|
+
*
|
|
5
|
+
* @deprecated This file has been consolidated into central configuration.
|
|
6
|
+
* New code should import from '@/lib/config/app.config.ts' instead.
|
|
7
|
+
*
|
|
8
|
+
* Legacy CSRF constants - use central config for new development.
|
|
9
|
+
*/
|
|
10
|
+
import { APP_CONFIG } from '@xbg.solutions/bpsk-core';
|
|
11
|
+
/**
|
|
12
|
+
* @deprecated Use APP_CONFIG.security.csrf instead
|
|
13
|
+
* Key used for storing the CSRF token
|
|
14
|
+
*/
|
|
15
|
+
export const CSRF_TOKEN_KEY = APP_CONFIG.security.csrf.tokenKey;
|
|
16
|
+
/**
|
|
17
|
+
* @deprecated Use APP_CONFIG.security.csrf instead
|
|
18
|
+
* HTTP header name for sending the CSRF token
|
|
19
|
+
*/
|
|
20
|
+
export const CSRF_HEADER_NAME = APP_CONFIG.security.csrf.headerName;
|
|
21
|
+
/**
|
|
22
|
+
* @deprecated Use APP_CONFIG.security.csrf instead
|
|
23
|
+
* Cookie name for storing the CSRF token
|
|
24
|
+
*/
|
|
25
|
+
export const CSRF_COOKIE_NAME = APP_CONFIG.security.csrf.cookieName;
|
|
26
|
+
/**
|
|
27
|
+
* @deprecated Use APP_CONFIG.security.csrf instead
|
|
28
|
+
* Time to live for CSRF tokens in seconds (2 hours)
|
|
29
|
+
*/
|
|
30
|
+
export const CSRF_TOKEN_TTL = APP_CONFIG.security.csrf.tokenTTL;
|
|
31
|
+
/**
|
|
32
|
+
* @deprecated Use APP_CONFIG.security.csrf instead
|
|
33
|
+
* HTTP methods that require CSRF protection
|
|
34
|
+
*/
|
|
35
|
+
export const CSRF_PROTECTED_METHODS = APP_CONFIG.security.csrf.protectedMethods;
|
|
36
|
+
/**
|
|
37
|
+
* @deprecated Use APP_CONFIG.security.storage instead
|
|
38
|
+
* Re-export AUTH_NAMESPACE for use in CSRF utility
|
|
39
|
+
*/
|
|
40
|
+
export const AUTH_NAMESPACE = APP_CONFIG.security.storage.authNamespace;
|
|
41
|
+
//# sourceMappingURL=csrf.constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csrf.constants.js","sourceRoot":"","sources":["../../src/constants/csrf.constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC;AAEhE;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC;AAEpE;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC;AAEpE;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC;AAEhE;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,gBAAgB,CAAC;AAEhF;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,aAAa,CAAC"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,cAAc,4BAA4B,CAAC;AAG3C,OAAO,EAAE,KAAK,SAAS,EAAE,cAAc,IAAI,SAAS,EAAE,MAAM,eAAe,CAAC;AAG5E,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
|
package/lib/index.js
ADDED
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAE9B,YAAY;AACZ,cAAc,4BAA4B,CAAC;AAE3C,SAAS;AACT,OAAO,EAAkB,cAAc,IAAI,SAAS,EAAE,MAAM,eAAe,CAAC;AAE5E,QAAQ;AACR,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface CSRFState {
|
|
2
|
+
token: string | null;
|
|
3
|
+
validated: boolean;
|
|
4
|
+
}
|
|
5
|
+
export declare const csrfProtection: {
|
|
6
|
+
clearTokens: () => void;
|
|
7
|
+
generateCsrfToken: () => Promise<string>;
|
|
8
|
+
getCsrfToken: () => Promise<null>;
|
|
9
|
+
refreshCsrfToken: () => Promise<string>;
|
|
10
|
+
handleValidationFailure: (context: any) => Promise<void>;
|
|
11
|
+
set(this: void, value: CSRFState): void;
|
|
12
|
+
update(this: void, updater: import("svelte/store").Updater<CSRFState>): void;
|
|
13
|
+
subscribe(this: void, run: import("svelte/store").Subscriber<CSRFState>, invalidate?: () => void): import("svelte/store").Unsubscriber;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=csrf.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csrf.d.ts","sourceRoot":"","sources":["../../src/stores/csrf.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;CACpB;AAQD,eAAO,MAAM,cAAc;;;;;uCAyBgB,GAAG;;;;CAG7C,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { writable } from 'svelte/store';
|
|
2
|
+
const store = writable({
|
|
3
|
+
token: null,
|
|
4
|
+
validated: false
|
|
5
|
+
});
|
|
6
|
+
// CSRF protection service with methods tests expect
|
|
7
|
+
export const csrfProtection = {
|
|
8
|
+
...store,
|
|
9
|
+
clearTokens: () => {
|
|
10
|
+
store.set({ token: null, validated: false });
|
|
11
|
+
},
|
|
12
|
+
generateCsrfToken: async () => {
|
|
13
|
+
const token = 'mock-csrf-token-' + Date.now();
|
|
14
|
+
store.update(state => ({ ...state, token }));
|
|
15
|
+
return token;
|
|
16
|
+
},
|
|
17
|
+
getCsrfToken: async () => {
|
|
18
|
+
let currentToken = null;
|
|
19
|
+
store.subscribe(state => { currentToken = state.token; })();
|
|
20
|
+
return currentToken;
|
|
21
|
+
},
|
|
22
|
+
refreshCsrfToken: async () => {
|
|
23
|
+
const newToken = 'refreshed-csrf-token-' + Date.now();
|
|
24
|
+
store.update(state => ({ ...state, token: newToken }));
|
|
25
|
+
return newToken;
|
|
26
|
+
},
|
|
27
|
+
handleValidationFailure: async (context) => {
|
|
28
|
+
store.update(state => ({ ...state, validated: false }));
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=csrf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csrf.js","sourceRoot":"","sources":["../../src/stores/csrf.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAOxC,MAAM,KAAK,GAAG,QAAQ,CAAY;IAChC,KAAK,EAAE,IAAI;IACX,SAAS,EAAE,KAAK;CACjB,CAAC,CAAC;AAEH,oDAAoD;AACpD,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,GAAG,KAAK;IAER,WAAW,EAAE,GAAG,EAAE;QAChB,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,iBAAiB,EAAE,KAAK,IAAI,EAAE;QAC5B,MAAM,KAAK,GAAG,kBAAkB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC9C,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QAC7C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,YAAY,EAAE,KAAK,IAAI,EAAE;QACvB,IAAI,YAAY,GAAG,IAAI,CAAC;QACxB,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,GAAG,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5D,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,gBAAgB,EAAE,KAAK,IAAI,EAAE;QAC3B,MAAM,QAAQ,GAAG,uBAAuB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACtD,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;QACvD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,uBAAuB,EAAE,KAAK,EAAE,OAAY,EAAE,EAAE;QAC9C,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IAC1D,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/lib/utils/csrf.ts
|
|
3
|
+
* CSRF protection utility
|
|
4
|
+
*
|
|
5
|
+
* A utility for protecting against Cross-Site Request Forgery (CSRF) attacks with:
|
|
6
|
+
* - Double-submit cookie pattern implementation
|
|
7
|
+
* - Integration with secure storage utility
|
|
8
|
+
* - Automatic token generation and validation
|
|
9
|
+
* - Request method filtering
|
|
10
|
+
* - Token refresh mechanisms
|
|
11
|
+
* - Error handling for token validation failures
|
|
12
|
+
*/
|
|
13
|
+
export declare const csrfProtection: {
|
|
14
|
+
generateCsrfToken: () => Promise<string>;
|
|
15
|
+
getCsrfToken: () => Promise<string>;
|
|
16
|
+
refreshCsrfToken: () => Promise<string>;
|
|
17
|
+
validateCsrfToken: (token: string) => boolean;
|
|
18
|
+
protectRequest: (input: RequestInfo | URL, init?: RequestInit) => Promise<RequestInit>;
|
|
19
|
+
handleValidationFailure: (requestInfo: {
|
|
20
|
+
url: string;
|
|
21
|
+
method: string;
|
|
22
|
+
retryCount?: number;
|
|
23
|
+
}) => Promise<void>;
|
|
24
|
+
safeGetCsrfToken: () => Promise<string | null>;
|
|
25
|
+
createCsrfFormField: () => Promise<string>;
|
|
26
|
+
getTokenForRequest: () => Promise<string | null>;
|
|
27
|
+
protectFormData: (formData: FormData) => Promise<FormData>;
|
|
28
|
+
clearTokens: () => boolean;
|
|
29
|
+
_setCurrentTokenForTests: (token: string | null) => void;
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=csrf.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csrf.d.ts","sourceRoot":"","sources":["../../src/utils/csrf.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA6bH,eAAO,MAAM,cAAc;6BA1XW,OAAO,CAAC,MAAM,CAAC;wBA+CpB,OAAO,CAAC,MAAM,CAAC;4BA2BX,OAAO,CAAC,MAAM,CAAC;+BA6BhB,MAAM,KAAG,OAAO;4BAiDzC,WAAW,GAAG,GAAG,SACjB,WAAW,KACjB,OAAO,CAAC,WAAW,CAAC;2CAkER;QACX,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,KACA,OAAO,CAAC,IAAI,CAAC;4BAmCmB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;+BAanB,OAAO,CAAC,MAAM,CAAC;8BAiBhB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;gCASlB,QAAQ,KAAG,OAAO,CAAC,QAAQ,CAAC;uBA6B7C,OAAO;sCA0BU,MAAM,GAAG,IAAI,KAAG,IAAI;CAwBX,CAAC"}
|
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/lib/utils/csrf.ts
|
|
3
|
+
* CSRF protection utility
|
|
4
|
+
*
|
|
5
|
+
* A utility for protecting against Cross-Site Request Forgery (CSRF) attacks with:
|
|
6
|
+
* - Double-submit cookie pattern implementation
|
|
7
|
+
* - Integration with secure storage utility
|
|
8
|
+
* - Automatic token generation and validation
|
|
9
|
+
* - Request method filtering
|
|
10
|
+
* - Token refresh mechanisms
|
|
11
|
+
* - Error handling for token validation failures
|
|
12
|
+
*/
|
|
13
|
+
import { loggerService, ApplicationError, ApiError, normalizeError, tryCatch } from '@xbg.solutions/bpsk-core';
|
|
14
|
+
import { secureStorage } from '@xbg.solutions/bpsk-utils-secure-storage';
|
|
15
|
+
import { escapeHtml } from '@xbg.solutions/bpsk-utils-sanitizer';
|
|
16
|
+
import { CSRF_TOKEN_KEY, CSRF_HEADER_NAME, CSRF_TOKEN_TTL, CSRF_PROTECTED_METHODS, AUTH_NAMESPACE } from '../constants/csrf.constants';
|
|
17
|
+
// Create a context-aware logger
|
|
18
|
+
const csrfLogger = loggerService.withContext('CSRFUtility');
|
|
19
|
+
/**
|
|
20
|
+
* Detects if running in browser environment
|
|
21
|
+
* @returns True if in browser environment, false if in SSR
|
|
22
|
+
*/
|
|
23
|
+
function isBrowser() {
|
|
24
|
+
return typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Generates a cryptographically secure random token
|
|
28
|
+
* @returns A random token string
|
|
29
|
+
*/
|
|
30
|
+
function generateToken() {
|
|
31
|
+
if (isBrowser()) {
|
|
32
|
+
// Use browser's crypto API for secure random values
|
|
33
|
+
const array = new Uint8Array(32);
|
|
34
|
+
crypto.getRandomValues(array);
|
|
35
|
+
return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
// SSR / Node.js — use crypto.randomBytes for secure tokens
|
|
39
|
+
try {
|
|
40
|
+
const nodeCrypto = globalThis.crypto;
|
|
41
|
+
const array = new Uint8Array(32);
|
|
42
|
+
nodeCrypto.getRandomValues(array);
|
|
43
|
+
return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// Static build context — return a placeholder that will be replaced at runtime
|
|
47
|
+
return 'ssr-placeholder-token';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* CSRF protection utility implementation
|
|
53
|
+
*/
|
|
54
|
+
function createCsrfProtection() {
|
|
55
|
+
// Private token storage
|
|
56
|
+
let currentToken = null;
|
|
57
|
+
/**
|
|
58
|
+
* Generates a new CSRF token and stores it
|
|
59
|
+
* @returns The generated token
|
|
60
|
+
*/
|
|
61
|
+
const generateCsrfToken = async () => {
|
|
62
|
+
try {
|
|
63
|
+
// Generate a new secure token
|
|
64
|
+
const newToken = generateToken();
|
|
65
|
+
// Store token in HttpOnly cookie using secure storage
|
|
66
|
+
const cookieSuccess = secureStorage.setItem(CSRF_TOKEN_KEY, newToken, {
|
|
67
|
+
namespace: AUTH_NAMESPACE,
|
|
68
|
+
mechanism: 'cookie',
|
|
69
|
+
ttl: CSRF_TOKEN_TTL,
|
|
70
|
+
cookieOptions: {
|
|
71
|
+
secure: true,
|
|
72
|
+
sameSite: 'strict',
|
|
73
|
+
path: '/'
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
// Also store in memory for easy access
|
|
77
|
+
if (cookieSuccess) {
|
|
78
|
+
currentToken = newToken;
|
|
79
|
+
csrfLogger.info('Generated new CSRF token', {
|
|
80
|
+
action: 'tokenGenerate'
|
|
81
|
+
});
|
|
82
|
+
return newToken;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
throw new ApplicationError('Failed to store CSRF token in cookie', {
|
|
86
|
+
category: 'csrf',
|
|
87
|
+
context: { action: 'tokenGenerate' }
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
const normalizedError = normalizeError(error, 'Failed to generate CSRF token', {
|
|
93
|
+
category: 'csrf',
|
|
94
|
+
context: { action: 'tokenGenerate' }
|
|
95
|
+
});
|
|
96
|
+
csrfLogger.error('CSRF token generation failed', normalizedError);
|
|
97
|
+
throw normalizedError;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Gets the current CSRF token, generating a new one if needed
|
|
102
|
+
* @returns The current CSRF token
|
|
103
|
+
*/
|
|
104
|
+
const getCsrfToken = async () => {
|
|
105
|
+
// First try to use the in-memory token
|
|
106
|
+
if (currentToken) {
|
|
107
|
+
return currentToken;
|
|
108
|
+
}
|
|
109
|
+
// If no in-memory token, try to get from storage
|
|
110
|
+
const storedToken = secureStorage.getItem(CSRF_TOKEN_KEY, {
|
|
111
|
+
namespace: AUTH_NAMESPACE,
|
|
112
|
+
mechanism: 'cookie'
|
|
113
|
+
});
|
|
114
|
+
if (storedToken) {
|
|
115
|
+
// Cache the token in memory for future use
|
|
116
|
+
currentToken = storedToken;
|
|
117
|
+
return storedToken;
|
|
118
|
+
}
|
|
119
|
+
// If no token found, generate a new one
|
|
120
|
+
const newToken = await generateCsrfToken();
|
|
121
|
+
return newToken;
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Refreshes the CSRF token
|
|
125
|
+
* @returns The new CSRF token
|
|
126
|
+
*/
|
|
127
|
+
const refreshCsrfToken = async () => {
|
|
128
|
+
try {
|
|
129
|
+
// Clear existing token
|
|
130
|
+
secureStorage.removeItem(CSRF_TOKEN_KEY, {
|
|
131
|
+
namespace: AUTH_NAMESPACE,
|
|
132
|
+
allMechanisms: true
|
|
133
|
+
});
|
|
134
|
+
// Reset in-memory token
|
|
135
|
+
currentToken = null;
|
|
136
|
+
// Generate a new token
|
|
137
|
+
return generateCsrfToken();
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
const normalizedError = normalizeError(error, 'Failed to refresh CSRF token', {
|
|
141
|
+
category: 'csrf',
|
|
142
|
+
context: { action: 'tokenRefresh' }
|
|
143
|
+
});
|
|
144
|
+
csrfLogger.error('CSRF token refresh failed', normalizedError);
|
|
145
|
+
throw normalizedError;
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* Validates a CSRF token against the stored token
|
|
150
|
+
* @param token The token to validate
|
|
151
|
+
* @returns True if token is valid
|
|
152
|
+
*/
|
|
153
|
+
const validateCsrfToken = (token) => {
|
|
154
|
+
try {
|
|
155
|
+
if (!token) {
|
|
156
|
+
csrfLogger.warn('Empty CSRF token provided for validation', {
|
|
157
|
+
action: 'tokenValidate'
|
|
158
|
+
});
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
// Get the token from storage
|
|
162
|
+
const storedToken = secureStorage.getItem(CSRF_TOKEN_KEY, {
|
|
163
|
+
namespace: AUTH_NAMESPACE,
|
|
164
|
+
mechanism: 'cookie'
|
|
165
|
+
});
|
|
166
|
+
if (!storedToken) {
|
|
167
|
+
csrfLogger.warn('No stored CSRF token found for validation', {
|
|
168
|
+
action: 'tokenValidate'
|
|
169
|
+
});
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
// Compare tokens using timing-safe comparison
|
|
173
|
+
// This simple comparison is not truly timing-safe, but serves as a placeholder
|
|
174
|
+
// In production, use a constant-time comparison function
|
|
175
|
+
const isValid = token === storedToken;
|
|
176
|
+
if (!isValid) {
|
|
177
|
+
csrfLogger.warn('CSRF token validation failed, tokens do not match', {
|
|
178
|
+
action: 'tokenValidate'
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
return isValid;
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
csrfLogger.error('CSRF token validation error', error instanceof Error ? error : new Error(String(error)), {
|
|
185
|
+
action: 'tokenValidate'
|
|
186
|
+
});
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
/**
|
|
191
|
+
* Adds CSRF protection to a fetch request
|
|
192
|
+
* @param input Request URL or Request object
|
|
193
|
+
* @param init Request initialization options
|
|
194
|
+
* @returns Modified request initialization options with CSRF token
|
|
195
|
+
*/
|
|
196
|
+
const protectRequest = async (input, init) => {
|
|
197
|
+
try {
|
|
198
|
+
// Default init object if not provided
|
|
199
|
+
const requestInit = init || {};
|
|
200
|
+
// Extract method, defaulting to GET
|
|
201
|
+
const method = (requestInit.method || 'GET').toUpperCase();
|
|
202
|
+
// Only add CSRF protection for specified methods
|
|
203
|
+
if (!CSRF_PROTECTED_METHODS.includes(method)) {
|
|
204
|
+
return requestInit;
|
|
205
|
+
}
|
|
206
|
+
// Get current CSRF token
|
|
207
|
+
const token = await getCsrfToken();
|
|
208
|
+
// Create a headers object from existing headers or create a new one
|
|
209
|
+
const headersObj = {};
|
|
210
|
+
// Copy existing headers if any
|
|
211
|
+
if (requestInit.headers) {
|
|
212
|
+
if (requestInit.headers instanceof Headers) {
|
|
213
|
+
requestInit.headers.forEach((value, key) => {
|
|
214
|
+
headersObj[key] = value;
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
else if (typeof requestInit.headers === 'object') {
|
|
218
|
+
Object.entries(requestInit.headers).forEach(([key, value]) => {
|
|
219
|
+
if (typeof value === 'string') {
|
|
220
|
+
headersObj[key] = value;
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// Add CSRF token header
|
|
226
|
+
headersObj[CSRF_HEADER_NAME] = token;
|
|
227
|
+
// Return modified init object with headers
|
|
228
|
+
return {
|
|
229
|
+
...requestInit,
|
|
230
|
+
headers: headersObj
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
const normalizedError = normalizeError(error, 'Failed to add CSRF protection to request', {
|
|
235
|
+
category: 'csrf',
|
|
236
|
+
context: {
|
|
237
|
+
action: 'protectRequest',
|
|
238
|
+
url: typeof input === 'string' ? input : input.toString(),
|
|
239
|
+
method: init?.method || 'GET'
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
csrfLogger.error('Failed to protect request with CSRF token', normalizedError);
|
|
243
|
+
// Return original init object to allow request to proceed without protection
|
|
244
|
+
// May be caught and handled at the API service level
|
|
245
|
+
return init || {};
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
/**
|
|
249
|
+
* Handles a CSRF validation failure
|
|
250
|
+
* @param requestInfo Information about the failed request
|
|
251
|
+
* @returns Promise that resolves when handling is complete
|
|
252
|
+
*/
|
|
253
|
+
const handleValidationFailure = async (requestInfo) => {
|
|
254
|
+
const { url, method, retryCount = 0 } = requestInfo;
|
|
255
|
+
// Log the validation failure
|
|
256
|
+
csrfLogger.warn('CSRF validation failed for request', {
|
|
257
|
+
url,
|
|
258
|
+
method,
|
|
259
|
+
retryCount
|
|
260
|
+
});
|
|
261
|
+
// Only attempt one automatic retry
|
|
262
|
+
if (retryCount === 0) {
|
|
263
|
+
csrfLogger.info('Refreshing CSRF token for retry', {
|
|
264
|
+
url,
|
|
265
|
+
method
|
|
266
|
+
});
|
|
267
|
+
// Refresh the token
|
|
268
|
+
await refreshCsrfToken();
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
// If already retried, throw an error
|
|
272
|
+
throw new ApiError('CSRF validation failed after retry', {
|
|
273
|
+
category: 'csrf',
|
|
274
|
+
endpoint: url,
|
|
275
|
+
method,
|
|
276
|
+
statusCode: 403,
|
|
277
|
+
userMessage: 'Your session may have expired. Please refresh the page and try again.'
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
/**
|
|
282
|
+
* Safely gets the CSRF token with error handling
|
|
283
|
+
* @returns The current CSRF token or null if error
|
|
284
|
+
*/
|
|
285
|
+
const safeGetCsrfToken = async () => {
|
|
286
|
+
const result = await tryCatch(async () => {
|
|
287
|
+
return getCsrfToken();
|
|
288
|
+
});
|
|
289
|
+
// Convert undefined to null for consistent return type
|
|
290
|
+
return result ?? null;
|
|
291
|
+
};
|
|
292
|
+
/**
|
|
293
|
+
* Creates a form field for CSRF protection
|
|
294
|
+
* @returns HTML string with a hidden input field containing the CSRF token
|
|
295
|
+
*/
|
|
296
|
+
const createCsrfFormField = async () => {
|
|
297
|
+
try {
|
|
298
|
+
// Get the current token - this should use the mocked token in tests
|
|
299
|
+
const token = await getCsrfToken();
|
|
300
|
+
// Create the HTML input field with the token (escape to prevent attribute injection)
|
|
301
|
+
return `<input type="hidden" name="${escapeHtml(CSRF_HEADER_NAME)}" value="${escapeHtml(token)}">`;
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
csrfLogger.error('Failed to create CSRF form field', error instanceof Error ? error : new Error(String(error)));
|
|
305
|
+
return '';
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
/**
|
|
309
|
+
* Gets the CSRF token for manual inclusion in requests
|
|
310
|
+
* @returns The current CSRF token or null if not available
|
|
311
|
+
*/
|
|
312
|
+
const getTokenForRequest = async () => {
|
|
313
|
+
return safeGetCsrfToken();
|
|
314
|
+
};
|
|
315
|
+
/**
|
|
316
|
+
* Adds CSRF protection to form data
|
|
317
|
+
* @param formData FormData object to protect
|
|
318
|
+
* @returns Protected FormData object
|
|
319
|
+
*/
|
|
320
|
+
const protectFormData = async (formData) => {
|
|
321
|
+
try {
|
|
322
|
+
// Get the current token
|
|
323
|
+
const token = await getCsrfToken();
|
|
324
|
+
// Clone the FormData and add the token
|
|
325
|
+
const protectedFormData = new FormData();
|
|
326
|
+
// Copy all existing entries
|
|
327
|
+
for (const [key, value] of formData.entries()) {
|
|
328
|
+
protectedFormData.append(key, value);
|
|
329
|
+
}
|
|
330
|
+
// Add CSRF token
|
|
331
|
+
protectedFormData.append(CSRF_HEADER_NAME, token);
|
|
332
|
+
return protectedFormData;
|
|
333
|
+
}
|
|
334
|
+
catch (error) {
|
|
335
|
+
csrfLogger.error('Failed to protect form data', error instanceof Error ? error : new Error(String(error)));
|
|
336
|
+
// Return original form data if protection fails
|
|
337
|
+
return formData;
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
/**
|
|
341
|
+
* Clears all CSRF tokens
|
|
342
|
+
* @returns True if successful
|
|
343
|
+
*/
|
|
344
|
+
const clearTokens = () => {
|
|
345
|
+
try {
|
|
346
|
+
// Clear token from storage
|
|
347
|
+
const result = secureStorage.removeItem(CSRF_TOKEN_KEY, {
|
|
348
|
+
namespace: AUTH_NAMESPACE,
|
|
349
|
+
allMechanisms: true
|
|
350
|
+
});
|
|
351
|
+
// Clear in-memory token
|
|
352
|
+
currentToken = null;
|
|
353
|
+
csrfLogger.info('CSRF tokens cleared', {
|
|
354
|
+
action: 'clearTokens'
|
|
355
|
+
});
|
|
356
|
+
return result;
|
|
357
|
+
}
|
|
358
|
+
catch (error) {
|
|
359
|
+
csrfLogger.error('Failed to clear CSRF tokens', error instanceof Error ? error : new Error(String(error)));
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
/**
|
|
364
|
+
* For testing - directly set the current token
|
|
365
|
+
* This method is only exposed in test environments
|
|
366
|
+
*/
|
|
367
|
+
const _setCurrentTokenForTests = (token) => {
|
|
368
|
+
if (import.meta.env.DEV || import.meta.env.TEST) {
|
|
369
|
+
currentToken = token;
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
// Public API
|
|
373
|
+
return {
|
|
374
|
+
generateCsrfToken,
|
|
375
|
+
getCsrfToken,
|
|
376
|
+
refreshCsrfToken,
|
|
377
|
+
validateCsrfToken,
|
|
378
|
+
protectRequest,
|
|
379
|
+
handleValidationFailure,
|
|
380
|
+
safeGetCsrfToken,
|
|
381
|
+
createCsrfFormField,
|
|
382
|
+
getTokenForRequest,
|
|
383
|
+
protectFormData,
|
|
384
|
+
clearTokens,
|
|
385
|
+
_setCurrentTokenForTests
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
// Export singleton instance
|
|
389
|
+
export const csrfProtection = createCsrfProtection();
|
|
390
|
+
//# sourceMappingURL=csrf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csrf.js","sourceRoot":"","sources":["../../src/utils/csrf.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xbg.solutions/bpsk-utils-csrf",
|
|
3
|
+
"version": "1.2.3",
|
|
4
|
+
"description": "XBG CSRF - Token generation, validation, and store",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"types": "lib/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"files": ["lib"],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"build:watch": "tsc --watch",
|
|
12
|
+
"clean": "rm -rf lib",
|
|
13
|
+
"prepublishOnly": "npm run build"
|
|
14
|
+
},
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@xbg.solutions/bpsk-core": "^1.0.0",
|
|
20
|
+
"@xbg.solutions/bpsk-utils-sanitizer": "^1.0.0",
|
|
21
|
+
"@xbg.solutions/bpsk-utils-secure-storage": "^1.0.0"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"svelte": "^5.0.0"
|
|
25
|
+
}
|
|
26
|
+
}
|