Skip to content

Commit

Permalink
hash factory, cookie factory, jwt factories
Browse files Browse the repository at this point in the history
  • Loading branch information
brandon-schabel committed Jul 20, 2023
1 parent 3478885 commit e0fb414
Show file tree
Hide file tree
Showing 12 changed files with 276 additions and 9 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Are you overwhelmed by countless options and dependencies? Embrace the simplicit
## Alpha Software
Please use at your own risk, this is alpha software and is still very much in the early stages and the APIs are **guranteed** to change.

This project is

## Key Highlights

- **Zero Dependencies**: Our goal is to build this toolkit with no extra dependencies so your apps stay lean and fast, relying solely on Bun itself.
Expand Down
18 changes: 15 additions & 3 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
export { createCliFactory } from "./modules/cli-factory";
export {
createClientCookieFactory,
createServerCookieFactory
} from "./modules/cookie-factory";
export { createErrorHandlerFactory } from "./modules/error-handler-factory/create-error-handler-factory";
export { defaultErrorHandler } from "./modules/error-handler-factory/default-error-handler";
export * from "./modules/fetch-factory/create-fetch-factory";
export { createFileFactory } from "./modules/files-factory";
export {
createNonSecureHashFactory,
createSecureHashFactory
} from "./modules/hash-factory";
export { createHIDKeyboardFactory } from "./modules/hid-emulators/keyboard-hid-factory";
export {
jwtClientSideFactory,
jwtServerSideFactory
} from "./modules/jwt-factory";
export * from "./modules/logger-factory";
export { createLoggerFactory } from "./modules/logger-factory/create-logger-factory";
export { createServerFactory } from "./modules/server-factory";
export {
createSqliteFactory,
createTableQuery,
createTableQuery
} from "./modules/sqlite-factory";
export { createHTMLProcessor } from "./modules/text-processing/html-factory";
export { createMarkdownProcessor } from "./modules/text-processing/markdown-factory";
export { createValidatorFactory } from "./modules/validation-factory";
export { createHIDKeyboardFactory } from "./modules/hid-emulators/keyboard-hid-factory";
export {jwtClientSideFactory, jwtServerSideFactory} from './modules/jwt-factory'

65 changes: 65 additions & 0 deletions modules/cookie-factory/cookie-factory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
## Client-Side:

1. **Set Cookie:** A method that accepts a cookie name, value, and optional settings (like max-age, path, domain, secure, and http-only) as parameters and sets the cookie on the client.

2. **Get Cookie:** A method that accepts a cookie name as a parameter and retrieves its value from the client.

3. **Delete Cookie:** A method that accepts a cookie name as a parameter and removes it from the client.

4. **Check Cookie:** A method that accepts a cookie name as a parameter and checks if the cookie exists on the client.

## Server-Side:

1. **Set Cookie:** A similar method to the client-side's set cookie method but sets the cookie on the server response. This will require access to the response object from the server.

2. **Get Cookie:** A method that accepts a cookie name as a parameter and retrieves its value from the server request. This will require access to the request object from the server.

3. **Delete Cookie:** A similar method to the client-side's delete cookie method but deletes the cookie on the server. This will require access to the response object from the server.

4. **Check Cookie:** A method that accepts a cookie name as a parameter and checks if the cookie exists on the server request. This will require access to the request object from the server.

Here's a brief overview of how the code for these might look:

```typescript
export const cookieFactory = () => {
// Client-side methods.
const setCookieClient = (name: string, value: string, options?: CookieOptions) => { ... };
const getCookieClient = (name: string) => { ... };
const deleteCookieClient = (name: string) => { ... };
const checkCookieClient = (name: string) => { ... };

// Server-side methods.
const setCookieServer = (res: Response, name: string, value: string, options?: CookieOptions) => { ... };
const getCookieServer = (req: Request, name: string) => { ... };
const deleteCookieServer = (res: Response, name: string) => { ... };
const checkCookieServer = (req: Request, name: string) => { ... };

return {
setCookieClient,
getCookieClient,
deleteCookieClient,
checkCookieClient,
setCookieServer,
getCookieServer,
deleteCookieServer,
checkCookieServer,
};
};

// Cookie options type for TypeScript.
type CookieOptions = {
maxAge?: number;
path?: string;
domain?: string;
secure?: boolean;
httpOnly?: boolean;
};
```

Remember to replace the `{ ... }` with the actual logic of each function. For client-side methods, you'll be manipulating `document.cookie`. For server-side methods, you'll be manipulating the `req.cookies` and `res.cookie` objects (assuming Express.js or similar server framework).

Please note that on the server side, you need to ensure you have middleware in place to handle cookies. In Express.js, for example, this would be the `cookie-parser` middleware.

For the server-side `setCookieServer` and `deleteCookieServer` methods, you will need to provide the `res` (response) object as an argument to the function. This is because these methods need to modify the HTTP response headers to set or delete cookies. For `getCookieServer` and `checkCookieServer`, you will need to provide the `req` (request) object to access the cookies sent by the client in the HTTP request headers.

Keep in mind, while storing JWTs in cookies, it's good practice to set the `httpOnly` flag to prevent client-side JavaScript from accessing the cookie. This helps mitigate certain types of cross-site scripting (XSS) attacks.
69 changes: 69 additions & 0 deletions modules/cookie-factory/create-client-side-cookie-factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
export function createClientCookieFactory() {
const setCookie = (
name: string,
value: string,
options: CookieOptions = {}
) => {
let cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(
value
)}`;

if (options.maxAge) {
cookieString += `; max-age=${options.maxAge}`;
}

if (options.path) {
cookieString += `; path=${options.path}`;
}

if (options.domain) {
cookieString += `; domain=${options.domain}`;
}

if (options.secure) {
cookieString += `; secure`;
}

if (options.httpOnly) {
cookieString += `; httpOnly`;
}

document.cookie = cookieString;
};

const getCookie = (name: string) => {
const cookieArr = document.cookie.split("; ");

for (let i = 0; i < cookieArr.length; i++) {
const cookiePair = cookieArr[i].split("=");
if (name == decodeURIComponent(cookiePair[0])) {
return decodeURIComponent(cookiePair[1]);
}
}

return null;
};

const deleteCookie = (name: string) => {
setCookie(name, "", { maxAge: -1 });
};

const checkCookie = (name: string) => {
return getCookie(name) !== null;
};

return {
setCookie,
getCookie,
deleteCookie,
checkCookie,
};
}

type CookieOptions = {
maxAge?: number;
path?: string;
domain?: string;
secure?: boolean;
httpOnly?: boolean;
};
2 changes: 2 additions & 0 deletions modules/cookie-factory/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { createClientCookieFactory } from "./create-client-side-cookie-factory";
export { createServerCookieFactory } from "./server-side-cookie-factory";
80 changes: 80 additions & 0 deletions modules/cookie-factory/server-side-cookie-factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
export function createServerCookieFactory() {
const setCookie = (
res: Response,
name: string,
value: string,
options: CookieOptions = {}
) => {
let cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(
value
)}`;

if (options.maxAge) {
cookieString += `; Max-Age=${options.maxAge}`;
}

if (options.path) {
cookieString += `; Path=${options.path}`;
}

if (options.domain) {
cookieString += `; Domain=${options.domain}`;
}

if (options.secure) {
cookieString += `; Secure`;
}

if (options.httpOnly) {
cookieString += `; HttpOnly`;
}

if (options.sameSite) {
cookieString += `; SameSite=${options.sameSite}`;
}

// For HTTP/2, multiple Set-Cookie headers are allowed
res.headers.append("Set-Cookie", cookieString);
};

const getCookie = (req: Request, name: string) => {
const cookies = parseCookies(req.headers.get("Cookie") || "");
return cookies[name];
};

const deleteCookie = (res: Response, name: string) => {
setCookie(res, name, "", { maxAge: -1 });
};

const checkCookie = (req: Request, name: string) => {
return getCookie(req, name) !== undefined;
};

return {
setCookie,
getCookie,
deleteCookie,
checkCookie,
};
}

type CookieOptions = {
maxAge?: number;
path?: string;
domain?: string;
secure?: boolean;
httpOnly?: boolean;
sameSite?: "Strict" | "Lax" | "None";
};

function parseCookies(cookiesString: string) {
const cookies: { [name: string]: string } = {};
const pairs = cookiesString.split(";");

pairs.forEach((pair) => {
const [name, ...rest] = pair.split("=");
cookies[name.trim()] = rest.join("=").trim();
});

return cookies;
}
12 changes: 8 additions & 4 deletions modules/files-factory/files-folder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export function findAppRoot(startingPath: string): string | null | undefined {
export const saveResultToFile = async (
filePath: string,
content: string
): Promise<void> | undefined => {
): Promise<void | undefined> => {
try {
await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
await fs.promises.writeFile(filePath, content);
Expand All @@ -89,13 +89,17 @@ export const readFilesContents = (
}
};


type FileFactoryOptions = {
baseDirectory: string;
errorHandler: ReturnType<typeof createErrorHandlerFactory<any, BaseError<any>>>;
errorHandler: ReturnType<
typeof createErrorHandlerFactory<any, BaseError<any>>
>;
};

export function createFileFactory({ baseDirectory, errorHandler }: FileFactoryOptions) {
export function createFileFactory({
baseDirectory,
errorHandler,
}: FileFactoryOptions) {
const getFullPath = (filePath: string) => path.join(baseDirectory, filePath);

const updateFiles = async (filePaths: string[], data: string) => {
Expand Down
File renamed without changes.
3 changes: 3 additions & 0 deletions modules/hash-factory/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { createNonSecureHashFactory } from "./non-secure-hash-factory";
export { createSecureHashFactory } from "./secure-hash-factory";

30 changes: 30 additions & 0 deletions modules/hash-factory/non-secure-hash-factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
type NonSecureHashAlgorithm =
| "wyhash"
| "crc32"
| "adler32"
| "cityHash32"
| "cityHash64"
| "murmur32v3"
| "murmur64v2";

export function createNonSecureHashFactory() {
const hash = (
data: string | ArrayBuffer | SharedArrayBuffer,
seed?: number
) => {
return Bun.hash(data, seed);
};

const hashWithAlgorithm = (
algorithm: NonSecureHashAlgorithm,
data: string | ArrayBuffer | SharedArrayBuffer,
seed?: number
) => {
return Bun.hash[algorithm](data, seed);
};

return {
hash,
hashWithAlgorithm,
};
}
2 changes: 1 addition & 1 deletion modules/hash-factory/secure-hash-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ type SecureHashConfig = {
cost?: number;
};

function createSecureHasher() {
export function createSecureHashFactory() {
const hashPassword = async (
password: string,
config: SecureHashConfig = {
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"compilerOptions": {
"lib": ["ESNext"],
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"module": "esnext",
"target": "esnext",
"moduleResolution": "bundler",
Expand Down

0 comments on commit e0fb414

Please sign in to comment.