@farm.js/integration-utils 0.1.0-beta.106 → 0.1.0-beta.107

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/cookies.d.ts CHANGED
@@ -11,8 +11,10 @@ export interface RequestCookieOptions {
11
11
  domain?: string;
12
12
  expires?: Date;
13
13
  }
14
+ /** Collapse duplicate names using the first value in request-header order. */
14
15
  export declare function parseCookieHeaderMap(header: string | null): Record<string, string>;
15
16
  export declare function parseCookieHeaderList(header: string | null): ParsedCookie[];
17
+ /** Read the first matching value, consistent with core `cookies().get(name)`. */
16
18
  export declare function getCookieValue(headers: Headers, name: string): string | null;
17
19
  export declare function createRequestCookie(name: string, value: string, request: Request, options?: RequestCookieOptions): string;
18
20
  export declare function clearRequestCookie(name: string, request: Request, options?: Omit<RequestCookieOptions, "maxAge">): string;
@@ -1 +1 @@
1
- {"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../src/cookies.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,IAAI,CAAC;CAChB;AAiBD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAelF;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,YAAY,EAAE,CAK3E;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE5E;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,oBAAyB,GACjC,MAAM,CA4BR;AAED,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAM,GACjD,MAAM,CAKR"}
1
+ {"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../src/cookies.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,IAAI,CAAC;CAChB;AAED,8EAA8E;AAC9E,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASlF;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,YAAY,EAAE,CAE3E;AAED,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAK5E;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,oBAAyB,GACjC,MAAM,CA4BR;AAED,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAM,GACjD,MAAM,CAKR"}
package/dist/cookies.js CHANGED
@@ -1,39 +1,21 @@
1
- /**
2
- * Decode a cookie value, tolerating malformed percent-encoding. A request can
3
- * carry a cookie whose value is not valid UTF-8 percent-encoding (a latin-1
4
- * value from an old link, a crawler, or an attacker-planted sibling-domain
5
- * cookie); `decodeURIComponent` throws `URIError` on those. Falling back to the
6
- * raw value keeps a single bad cookie from turning every auth route into a 500.
7
- */
8
- function decodeCookieValue(value) {
9
- try {
10
- return decodeURIComponent(value);
11
- }
12
- catch {
13
- return value;
14
- }
15
- }
1
+ import { parseRequestCookieHeader } from "@farm.js/core/internal/request-cookies";
2
+ /** Collapse duplicate names using the first value in request-header order. */
16
3
  export function parseCookieHeaderMap(header) {
17
- if (!header) {
18
- return {};
4
+ const cookies = Object.create(null);
5
+ for (const cookie of parseCookieHeaderList(header)) {
6
+ if (Object.prototype.hasOwnProperty.call(cookies, cookie.name))
7
+ continue;
8
+ cookies[cookie.name] = cookie.value;
19
9
  }
20
- return Object.fromEntries(header
21
- .split(";")
22
- .map((part) => part.trim())
23
- .filter(Boolean)
24
- .map((part) => {
25
- const [key, ...rest] = part.split("=");
26
- return [key, decodeCookieValue(rest.join("="))];
27
- }));
10
+ return cookies;
28
11
  }
29
12
  export function parseCookieHeaderList(header) {
30
- return Object.entries(parseCookieHeaderMap(header)).map(([name, value]) => ({
31
- name,
32
- value,
33
- }));
13
+ return parseRequestCookieHeader(header);
34
14
  }
15
+ /** Read the first matching value, consistent with core `cookies().get(name)`. */
35
16
  export function getCookieValue(headers, name) {
36
- return parseCookieHeaderMap(headers.get("cookie"))[name] ?? null;
17
+ return (parseCookieHeaderList(headers.get("cookie")).find((cookie) => cookie.name === name)?.value ??
18
+ null);
37
19
  }
38
20
  export function createRequestCookie(name, value, request, options = {}) {
39
21
  const requestUrl = new URL(request.url);
package/dist/url.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../src/url.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,iBAAiB,CAAC,EAAE,MAAM,GAAG,MAAM,CAE9E;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,QAAQ,SAAM,GAAG,MAAM,CAgBvF;AAED,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,EAChB,iBAAiB,CAAC,EAAE,MAAM,GACzB,GAAG,CAML;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,GAAG,CAUjG;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAU1F;AAQD,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,4BAA4B,EACnC,iBAAiB,CAAC,EAAE,MAAM,GACzB;IACD,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,KAAK,MAAM,CAAC;CAClG,CAkCA"}
1
+ {"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../src/url.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,iBAAiB,CAAC,EAAE,MAAM,GAAG,MAAM,CAE9E;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,QAAQ,SAAM,GAAG,MAAM,CAWvF;AAED,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,EAChB,iBAAiB,CAAC,EAAE,MAAM,GACzB,GAAG,CAML;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,GAAG,CAUjG;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAU1F;AAiBD,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,4BAA4B,EACnC,iBAAiB,CAAC,EAAE,MAAM,GACzB;IACD,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,KAAK,MAAM,CAAC;CAClG,CAkCA"}
package/dist/url.js CHANGED
@@ -7,11 +7,7 @@ export function getReturnTo(rawValue, fallback = "/") {
7
7
  // and the URL parser treat "\" as "/") both begin with "/" yet resolve to a
8
8
  // foreign origin when passed to `new URL(returnTo, origin)`, giving an open
9
9
  // redirect after a legitimate login.
10
- if (!rawValue || !rawValue.startsWith("/")) {
11
- return fallback;
12
- }
13
- const second = rawValue[1];
14
- if (second === "/" || second === "\\") {
10
+ if (!rawValue || !isSameOriginRootRelativePath(rawValue)) {
15
11
  return fallback;
16
12
  }
17
13
  return rawValue;
@@ -45,8 +41,18 @@ export function resolveAppPath(path, label) {
45
41
  function isSameOriginRootRelativePath(value) {
46
42
  if (!value.startsWith("/"))
47
43
  return false;
48
- const second = value[1];
49
- return second !== "/" && second !== "\\";
44
+ // The URL parser removes ASCII tab, carriage return, and line feed before
45
+ // parsing. Reject them before resolution so `/\n/evil.example` cannot turn
46
+ // into the protocol-relative URL `//evil.example`.
47
+ if (/[\t\n\r]/.test(value))
48
+ return false;
49
+ const trustedOrigin = "https://farm.invalid";
50
+ try {
51
+ return new URL(value, trustedOrigin).origin === trustedOrigin;
52
+ }
53
+ catch {
54
+ return false;
55
+ }
50
56
  }
51
57
  export function resolveCallbackSettings(input, configuredBaseUrl) {
52
58
  if (input.callbackUrl) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farm.js/integration-utils",
3
- "version": "0.1.0-beta.106",
3
+ "version": "0.1.0-beta.107",
4
4
  "description": "Shared integration utilities for Farm.js",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -53,7 +53,7 @@
53
53
  "access": "public"
54
54
  },
55
55
  "dependencies": {
56
- "@farm.js/core": "0.1.0-beta.106"
56
+ "@farm.js/core": "0.1.0-beta.107"
57
57
  },
58
58
  "scripts": {
59
59
  "build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc",