@stacksjs/browser 0.70.182 → 0.70.184
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.
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
/**
|
|
3
|
+
* Read the CSRF token the server planted, or null when there is none.
|
|
4
|
+
*
|
|
5
|
+
* Returns null rather than throwing outside a browser so server-side rendering
|
|
6
|
+
* and tests can call this freely.
|
|
7
|
+
*/
|
|
8
|
+
export declare function readCsrfToken(cookieSource?: string): string | null;
|
|
9
|
+
/**
|
|
10
|
+
* Add the CSRF header to a set of request headers.
|
|
11
|
+
*
|
|
12
|
+
* A bearer token already exempts the request server-side, so the header is
|
|
13
|
+
* only added when there is a cookie to echo. Existing values win: an explicit
|
|
14
|
+
* caller-supplied token is never overwritten.
|
|
15
|
+
*/
|
|
16
|
+
export declare function withCsrfHeader(headers?: Record<string, string>, cookieSource?: string): Record<string, string>;
|
|
17
|
+
/**
|
|
18
|
+
* CSRF token plumbing for browser requests.
|
|
19
|
+
*
|
|
20
|
+
* The framework's CSRF middleware is default-on for unsafe methods and uses a
|
|
21
|
+
* stateless double-submit cookie: the server sets a non-HttpOnly
|
|
22
|
+
* `X-CSRF-Token` cookie on safe responses, and the client is expected to echo
|
|
23
|
+
* that value back in the `X-CSRF-Token` header. Nothing in the browser package
|
|
24
|
+
* did the echoing, so every cookie-authenticated POST the framework itself
|
|
25
|
+
* issues — login, register, logout — came back 403 "CSRF token mismatch" on a
|
|
26
|
+
* stock install.
|
|
27
|
+
*/
|
|
28
|
+
/** Cookie (and header) name the CSRF middleware issues and checks. */
|
|
29
|
+
export declare const CSRF_COOKIE_NAME: 'X-CSRF-Token';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export const CSRF_COOKIE_NAME = "X-CSRF-Token";
|
|
2
|
+
export function readCsrfToken(cookieSource) {
|
|
3
|
+
const raw = cookieSource ?? (typeof document < "u" ? document.cookie : "");
|
|
4
|
+
if (!raw)
|
|
5
|
+
return null;
|
|
6
|
+
for (const part of raw.split(";")) {
|
|
7
|
+
const separator = part.indexOf("=");
|
|
8
|
+
if (separator === -1)
|
|
9
|
+
continue;
|
|
10
|
+
if (part.slice(0, separator).trim() !== CSRF_COOKIE_NAME)
|
|
11
|
+
continue;
|
|
12
|
+
const value = part.slice(separator + 1).trim();
|
|
13
|
+
return value ? decodeURIComponent(value) : null;
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
export function withCsrfHeader(headers = {}, cookieSource) {
|
|
18
|
+
if (headers[CSRF_COOKIE_NAME])
|
|
19
|
+
return headers;
|
|
20
|
+
const token = readCsrfToken(cookieSource);
|
|
21
|
+
if (!token)
|
|
22
|
+
return headers;
|
|
23
|
+
return { ...headers, [CSRF_COOKIE_NAME]: token };
|
|
24
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useStorage } from "@stacksjs/composables";
|
|
2
2
|
import { ref } from "@stacksjs/stx";
|
|
3
|
+
import { withCsrfHeader } from "./csrf";
|
|
3
4
|
const token = useStorage("token", ""), stacksConfig = globalThis.__STACKS_CONFIG__ || {}, baseUrl = stacksConfig.API_URL || (typeof window < "u" ? window.location.origin : `http://localhost:${process.env.PORT_API || "3008"}`), user = ref(null), isAuthenticated = ref(!1);
|
|
4
5
|
export function useAuth() {
|
|
5
6
|
async function fetchAuthUser() {
|
|
@@ -44,9 +45,10 @@ export function useAuth() {
|
|
|
44
45
|
async function register(user) {
|
|
45
46
|
const url = `${baseUrl}/register`, data = await (await fetch(url, {
|
|
46
47
|
method: "POST",
|
|
47
|
-
|
|
48
|
+
credentials: "same-origin",
|
|
49
|
+
headers: withCsrfHeader({
|
|
48
50
|
"Content-Type": "application/json"
|
|
49
|
-
},
|
|
51
|
+
}),
|
|
50
52
|
body: JSON.stringify(user)
|
|
51
53
|
})).json();
|
|
52
54
|
if (isRegisterError(data))
|
|
@@ -67,9 +69,10 @@ export function useAuth() {
|
|
|
67
69
|
try {
|
|
68
70
|
const url = `${baseUrl}/login`, response = await fetch(url, {
|
|
69
71
|
method: "POST",
|
|
70
|
-
|
|
72
|
+
credentials: "same-origin",
|
|
73
|
+
headers: withCsrfHeader({
|
|
71
74
|
"Content-Type": "application/json"
|
|
72
|
-
},
|
|
75
|
+
}),
|
|
73
76
|
body: JSON.stringify(user)
|
|
74
77
|
});
|
|
75
78
|
if (!response.ok) {
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/browser",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.70.
|
|
5
|
+
"version": "0.70.184",
|
|
6
6
|
"description": "Stacks core frontend/browser functionalities.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"prepublishOnly": "bun run build"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@stacksjs/composables": "0.70.
|
|
55
|
+
"@stacksjs/composables": "0.70.184",
|
|
56
56
|
"@stacksjs/stx": "^0.2.100",
|
|
57
57
|
"bun-query-builder": "^0.1.59",
|
|
58
58
|
"magic-regexp": "^0.11.0"
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"better-dx": "^0.2.17",
|
|
70
|
-
"@stacksjs/utils": "0.70.
|
|
70
|
+
"@stacksjs/utils": "0.70.184",
|
|
71
71
|
"@stripe/stripe-js": "^9.10.0"
|
|
72
72
|
}
|
|
73
73
|
}
|