stack/packages/stack-shared/src/utils/http.tsx
devin-ai-integration[bot] 9a76d10c2a
[DEVIN: Konsti] Add in-source unit tests to stack-shared utilities (#485)
* Add in-source unit tests to stack-shared utilities

Co-Authored-By: Konstantin Wohlwend <n2d4xc@gmail.com>

* Fix type checking and linting issues

Co-Authored-By: Konstantin Wohlwend <n2d4xc@gmail.com>

* Fix lint errors in results.tsx

Co-Authored-By: Konstantin Wohlwend <n2d4xc@gmail.com>

* Fix remaining lint errors in results.tsx

Co-Authored-By: Konstantin Wohlwend <n2d4xc@gmail.com>

* Fix lint warnings in results.tsx

Co-Authored-By: Konstantin Wohlwend <n2d4xc@gmail.com>

* Fix wait function mocking in results.tsx

Co-Authored-By: Konstantin Wohlwend <n2d4xc@gmail.com>

* Fix retry function test in results.tsx

Co-Authored-By: Konstantin Wohlwend <n2d4xc@gmail.com>

* Fix React.forwardRef mock in react.tsx test

Co-Authored-By: Konstantin Wohlwend <n2d4xc@gmail.com>

* Fix trailing spaces in react.tsx and results.tsx

Co-Authored-By: Konstantin Wohlwend <n2d4xc@gmail.com>

* Revert to DependenciesMap and wrap rejected promise in ignoreUnhandledRejection

Co-Authored-By: Konstantin Wohlwend <n2d4xc@gmail.com>

* Fix

* Revert changes to known-errors.tsx constructor

Co-Authored-By: Konstantin Wohlwend <n2d4xc@gmail.com>

* Make rotateRight call rotateLeft per review feedback

Co-Authored-By: Konstantin Wohlwend <n2d4xc@gmail.com>

* Remove redundant @ts-expect-error directive in known-errors.tsx

Co-Authored-By: Konstantin Wohlwend <n2d4xc@gmail.com>

* Fix import order in promises.tsx

Co-Authored-By: Konstantin Wohlwend <n2d4xc@gmail.com>

* Fix

* Fix CI failures: add back @ts-expect-error in known-errors.tsx and revert mapResult implementation in results.tsx

Co-Authored-By: Konstantin Wohlwend <n2d4xc@gmail.com>

* Remove unused @ts-expect-error directive in known-errors.tsx

Co-Authored-By: Konstantin Wohlwend <n2d4xc@gmail.com>

* Add back @ts-expect-error directive with explanation in known-errors.tsx

Co-Authored-By: Konstantin Wohlwend <n2d4xc@gmail.com>

* Change @ts-expect-error to @ts-ignore in known-errors.tsx

Co-Authored-By: Konstantin Wohlwend <n2d4xc@gmail.com>

* be honest

* vocabulary

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Konstantin Wohlwend <n2d4xc@gmail.com>
2025-02-28 01:47:37 +00:00

92 lines
3.1 KiB
TypeScript

import { decodeBase64, encodeBase64, isBase64 } from "./bytes";
export const HTTP_METHODS = {
"GET": {
safe: true,
idempotent: true,
},
"POST": {
safe: false,
idempotent: false,
},
"PUT": {
safe: false,
idempotent: true,
},
"DELETE": {
safe: false,
idempotent: true,
},
"PATCH": {
safe: false,
idempotent: false,
},
"OPTIONS": {
safe: true,
idempotent: true,
},
"HEAD": {
safe: true,
idempotent: true,
},
"TRACE": {
safe: true,
idempotent: true,
},
"CONNECT": {
safe: false,
idempotent: false,
},
} as const;
export type HttpMethod = keyof typeof HTTP_METHODS;
export function decodeBasicAuthorizationHeader(value: string): [string, string] | null {
const [type, encoded, ...rest] = value.split(' ');
if (rest.length > 0) return null;
if (!encoded) return null;
if (type !== 'Basic') return null;
if (!isBase64(encoded)) return null;
const decoded = new TextDecoder().decode(decodeBase64(encoded));
const split = decoded.split(':');
return [split[0], split.slice(1).join(':')];
}
import.meta.vitest?.test("decodeBasicAuthorizationHeader", ({ expect }) => {
// Test with valid Basic Authorization header
const username = "user";
const password = "pass";
const encoded = encodeBasicAuthorizationHeader(username, password);
expect(decodeBasicAuthorizationHeader(encoded)).toEqual([username, password]);
// Test with password containing colons
const complexPassword = "pass:with:colons";
const encodedComplex = encodeBasicAuthorizationHeader(username, complexPassword);
expect(decodeBasicAuthorizationHeader(encodedComplex)).toEqual([username, complexPassword]);
// Test with invalid headers
expect(decodeBasicAuthorizationHeader("NotBasic dXNlcjpwYXNz")).toBe(null); // Wrong type
expect(decodeBasicAuthorizationHeader("Basic")).toBe(null); // Missing encoded part
expect(decodeBasicAuthorizationHeader("Basic not-base64")).toBe(null); // Not base64
expect(decodeBasicAuthorizationHeader("Basic dXNlcjpwYXNz extra")).toBe(null); // Extra parts
});
export function encodeBasicAuthorizationHeader(id: string, password: string): string {
if (id.includes(':')) throw new Error("Basic authorization header id cannot contain ':'");
return `Basic ${encodeBase64(new TextEncoder().encode(`${id}:${password}`))}`;
}
import.meta.vitest?.test("encodeBasicAuthorizationHeader", ({ expect }) => {
// Test with simple username and password
const encoded = encodeBasicAuthorizationHeader("user", "pass");
expect(encoded).toMatch(/^Basic [A-Za-z0-9+/=]+$/); // Should start with "Basic " followed by base64
// Test with empty password
const encodedEmptyPass = encodeBasicAuthorizationHeader("user", "");
expect(encodedEmptyPass).toMatch(/^Basic [A-Za-z0-9+/=]+$/);
// Test with password containing special characters
const encodedSpecialChars = encodeBasicAuthorizationHeader("user", "p@ss!w0rd");
expect(encodedSpecialChars).toMatch(/^Basic [A-Za-z0-9+/=]+$/);
// Test with username containing colon should throw
expect(() => encodeBasicAuthorizationHeader("user:name", "pass")).toThrow();
});