Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redirect Response, Add Auth Factory, jwt improvements #51

Merged
merged 6 commits into from
Oct 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -177,4 +177,5 @@ bun.lockb
.DS_Store

.vscode
.npmrc
.npmrc
.history
4 changes: 2 additions & 2 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as dataGen from "./modules/data-gen";
import * as deploy from "./modules/deploy";
import * as fetcher from "./modules/fetcher";
import * as filesFolders from "./modules/files-folders";
import * as hash from "./modules/hash";
import * as auth from "./modules/auth";
import * as htmlody from "./modules/htmlody";
import * as jwt from "./modules/jwt";
import * as logger from "./modules/logger";
Expand All @@ -25,7 +25,7 @@ export {
deploy,
fetcher,
filesFolders,
hash,
auth,
htmlody,
jwt,
logger,
Expand Down
1 change: 0 additions & 1 deletion jwt-tokens.json

This file was deleted.

1 change: 1 addition & 0 deletions modules/auth/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Auth Module
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, expect, test } from "bun:test";
import { createNonSecureHashFactory } from "./non-secure-hash-factory";
import { createNonSecureHashFactory } from "./hash-factory";

describe("NonSecureHashFactory", () => {
const factory = createNonSecureHashFactory();
Expand Down
File renamed without changes.
9 changes: 9 additions & 0 deletions modules/auth/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export { createNonSecureHashFactory } from "./hash-factory";
export { createSecureHashFactory } from "./secure-hash-factory";

export {
createSecurityToken,
createToken,
getTokenExpireEpoch,
verifyToken
} from "./security-token";
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
type SecureHashConfig = {
export type SecureHashConfig = {
algorithm: "bcrypt";
memoryCost?: number;
timeCost?: number;
Expand Down
68 changes: 68 additions & 0 deletions modules/auth/security-token.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { describe, it } from "bun:test";
import { expect } from "bun:test";
import {
getTokenExpireEpoch,
createToken,
verifyToken,
createSecurityToken,
} from ".";

describe("Token Utilities", () => {
describe("getTokenExpireEpoch", () => {
it("should return the correct expiration epoch", () => {
const date = new Date("2023-10-26T12:00:00Z");
const tokenValidTimeSec = 3600; // 1 hour in seconds
const expected = date.getTime() + tokenValidTimeSec * 1000; // convert seconds to milliseconds
const result = getTokenExpireEpoch(date, tokenValidTimeSec);

// Diagnostics
console.log("Original Date Epoch:", date.getTime());
console.log(
"Token Valid Time in Milliseconds:",
tokenValidTimeSec * 1000
);
console.log("Expected:", expected);
console.log("Received:", result);

expect(result).toEqual(expected);
});
});
describe("verifyToken", () => {
it("should verify the token correctly", async () => {
const salt = "randomSalt";
const originalString = "testToken";
const hashedToken = await createToken(originalString, salt);
const isVerified = await verifyToken(originalString, salt, hashedToken);
expect(isVerified).toBe(true);
});
});

describe("createToken", () => {
it("should create a hashed token", async () => {
const salt = "randomSalt";
const originalString = "testToken";
const hashedToken = await createToken(originalString, salt);
expect(hashedToken).toBeTruthy();
expect(hashedToken).not.toEqual(originalString); // Ensure the hashed token is not the same as the original string
});
});

describe("createSecurityToken", () => {
it("should create a security token with default expiration time", async () => {


const result = await createSecurityToken(5000);
expect(result.securityToken).toBeTruthy();
expect(result.tokenId).toBeTruthy();
expect(result.tokenExpireEpoch).toBeGreaterThan(Date.now());
});

it("should create a security token with specified expiration time", async () => {
const currentTime = new Date();
const tokenValidTime = 60 * 15; // 15 minutes
const result = await createSecurityToken(tokenValidTime, currentTime);
const expectedExpiration = currentTime.getTime() + (tokenValidTime * 1000);
expect(result.tokenExpireEpoch).toBeCloseTo(expectedExpiration, -2); // -2 is for a precision of 10 milliseconds
});
});
});
58 changes: 58 additions & 0 deletions modules/auth/security-token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { v7 as uuid } from "mod/uuid";

export const getTokenExpireEpoch = (date: Date, tokenValidTimeSec: number) => {
const expireEpoch = date.getTime() + tokenValidTimeSec * 1000;

console.log(
"Inside getTokenExpireEpoch:",
date.getTime(),
tokenValidTimeSec,
expireEpoch
);

return expireEpoch;
};

export async function verifyToken(
tokenString: string,
salt: string,
storedHash: string
) {
const fullPassword = tokenString + salt;
const isMatch = await Bun.password.verify(fullPassword, storedHash);

return isMatch;
}

export async function createToken(string: string, salt: string) {
const fullPassword = string + salt;
return await Bun.password.hash(fullPassword, {
algorithm: "argon2id",
memoryCost: 65536,
timeCost: 3,
});
}

export const createSecurityToken = async (
tokenValidTime: number,
currentDate?: Date
) => {
const salt = uuid();
const { uuid: tokenId, timestamp } = uuid({
returnTimestamp: true,
dateTime: currentDate,
});

console.log("createSecurityToken Timestamp:", currentDate, timestamp);

console.log(currentDate?.getTime(), timestamp.getTime());

const securityToken = await createToken(tokenId, salt);
const tokenExpireEpoch = getTokenExpireEpoch(timestamp, tokenValidTime);

return {
securityToken,
tokenId,
tokenExpireEpoch,
};
};
3 changes: 0 additions & 3 deletions modules/hash/README.md

This file was deleted.

3 changes: 0 additions & 3 deletions modules/hash/index.ts

This file was deleted.

48 changes: 17 additions & 31 deletions modules/htmlody/html-factory.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { describe, expect, it } from "bun:test";
import { CRNode } from ".";
import { cc } from "./css-engine";
import { htmlFactory } from "./html-factory";
import { pageGenerator } from "./html-factory";
import type { JsonHtmlNodeMap } from "./html-type-engine";
import { htmlBody } from "./html-type-engine.test";

Expand All @@ -22,66 +22,55 @@ describe("htmlFactory", () => {
};

it("renders basic elements correctly", () => {
const factory = htmlFactory(mockHeadConfig, mockBodyConfig, {
pageTitle: "Test Page",
});
const htmlOut = factory.getHtmlOut();
const factory = pageGenerator(mockHeadConfig);
const htmlOut = factory.buildHtml(mockBodyConfig);

expect(htmlOut).toContain('<div class="bg-blue-500">');
expect(htmlOut).toContain("Test Content");
expect(htmlOut).toContain("</div>");
});

it("renders attributes correctly", () => {
const factory = htmlFactory(mockHeadConfig, mockBodyConfig, {
pageTitle: "Test Page",
});
const htmlOut = factory.getHtmlOut();
const factory = pageGenerator(mockHeadConfig);
const htmlOut = factory.buildHtml(mockBodyConfig);

expect(htmlOut).toContain('class="bg-blue-500"');
});

it("renders nested children correctly", () => {
const factory = htmlFactory(mockHeadConfig, mockBodyConfig, {
pageTitle: "Test Page",
});
const htmlOut = factory.getHtmlOut();
const factory = pageGenerator(mockHeadConfig);
const htmlOut = factory.buildHtml(mockBodyConfig);

expect(htmlOut).toContain("<span>");
expect(htmlOut).toContain("Child Content");
expect(htmlOut).toContain("</span>");
});

it("handles optional configurations correctly", () => {
const factory = htmlFactory(mockHeadConfig, mockBodyConfig, {
pageTitle: "Test Page",
useTailwind: true,
const factory = pageGenerator(mockHeadConfig, {
useHtmx: true,
});
const htmlOut = factory.getHtmlOut();
const htmlOut = factory.buildHtml(mockBodyConfig);

expect(htmlOut).toContain(
'<script src="https://cdn.tailwindcss.com"></script>'
);
expect(htmlOut).toContain(
'<script src="https://unpkg.com/htmx.org"></script>'
);
});
});

const createPageFactory = () => {
return htmlFactory({ title: "My Title" }, htmlBody, {
pageTitle: "My Page",
// tailwindConfig,
useHtmx: true,
useTailwind: true,
});
return pageGenerator(
{ title: "My Title" },
{
useHtmx: true,
}
);
};

describe("htmlFactory", () => {
it("renders complete HTML structure based on provided config", () => {
const factory = createPageFactory();
const htmlOut = factory.getHtmlOut();
const htmlOut = factory.buildHtml(htmlBody);

expect(htmlOut).toContain(
'<h1 class="bg-blue-500" id="title-id">Hello World</h1>'
Expand All @@ -97,11 +86,8 @@ describe("htmlFactory", () => {

it("includes optional configurations like Tailwind and htmx", () => {
const factory = createPageFactory();
const htmlOut = factory.getHtmlOut();
const htmlOut = factory.buildHtml(htmlBody);

expect(htmlOut).toContain(
'<script src="https://cdn.tailwindcss.com"></script>'
);
expect(htmlOut).toContain(
'<script src="https://unpkg.com/htmx.org"></script>'
);
Expand Down
Loading