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

chore: dependency bump #45

Merged
merged 4 commits into from
Dec 16, 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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ number;
request: Request,
response: Response,
overwrite?: boolean, // Set to true to force a new token to be generated
validateOnReuse?: boolean // Set to false to generate a new token if token re-use is invalid
validateOnReuse?: boolean, // Set to false to generate a new token if token re-use is invalid
) => string;
```

Expand Down
2 changes: 1 addition & 1 deletion example/complete/src/index.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
Expand Down
2 changes: 1 addition & 1 deletion example/complete/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ app.post(
res.json({
protected_endpoint: "form processed successfully",
});
}
},
);

// Try with a HTTP client (is not protected from a CSRF attack)
Expand Down
941 changes: 440 additions & 501 deletions package-lock.json

Large diffs are not rendered by default.

30 changes: 15 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,26 +48,26 @@
"tokens"
],
"devDependencies": {
"@types/chai": "^4.3.4",
"@types/cookie": "^0.5.1",
"@types/cookie-parser": "^1.4.3",
"@types/cookie-signature": "^1.1.0",
"@types/express": "^4.17.17",
"@types/http-errors": "^2.0.1",
"@types/mocha": "^10.0.1",
"@types/chai": "^4.3.11",
"@types/cookie": "^0.6.0",
"@types/cookie-parser": "^1.4.6",
"@types/cookie-signature": "^1.1.2",
"@types/express": "^4.17.21",
"@types/http-errors": "^2.0.4",
"@types/mocha": "^10.0.6",
"@types/node": "^18.15.8",
"@typescript-eslint/eslint-plugin": "^5.56.0",
"@typescript-eslint/parser": "^5.56.0",
"chai": "^4.3.7",
"cookie": "^0.5.0",
"@typescript-eslint/eslint-plugin": "^6.14.0",
"@typescript-eslint/parser": "^6.14.0",
"chai": "^4.3.10",
"cookie": "^0.6.0",
"cookie-parser": "^1.4.6",
"cookie-signature": "^1.2.1",
"eslint": "^8.45.0",
"eslint": "^8.56.0",
"mocha": "^10.2.0",
"prettier": "^2.8.7",
"prettier": "^3.1.1",
"standard-version": "^9.5.0",
"ts-node": "^10.9.1",
"typescript": "^5.0.2"
"ts-node": "^10.9.2",
"typescript": "^5.3.3"
},
"dependencies": {
"http-errors": "^2.0.0"
Expand Down
21 changes: 10 additions & 11 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export type DoubleCsrfConfigOptions = Partial<DoubleCsrfConfig> & {
export type doubleCsrfProtection = (
req: Request,
res: Response,
next: NextFunction
next: NextFunction,
) => void;
export type RequestMethod =
| "GET"
Expand All @@ -38,26 +38,25 @@ export type RequestMethod =
| "DELETE"
| "CONNECT"
| "OPTIONS"
| "TRACE"
| "PATCH";
| "TRACE";
export type CsrfIgnoredMethods = Array<RequestMethod>;
export type CsrfRequestValidator = (req: Request) => boolean;
export type CsrfTokenAndHashPairValidator = (
token: string,
hash: string,
possibleSecrets: Array<string>
possibleSecrets: Array<string>,
) => boolean;
export type CsrfCookieSetter = (
res: Response,
name: string,
value: string,
options: DoubleCsrfCookieOptions
options: DoubleCsrfCookieOptions,
) => void;
export type CsrfTokenCreator = (
req: Request,
res: Response,
ovewrite?: boolean,
validateOnReuse?: boolean
validateOnReuse?: boolean,
) => string;

export interface DoubleCsrfConfig {
Expand Down Expand Up @@ -198,7 +197,7 @@ export function doubleCsrf({
const generateTokenAndHash = (
req: Request,
overwrite: boolean,
validateOnReuse: boolean
validateOnReuse: boolean,
) => {
const getSecretResult = getSecret(req);
const possibleSecrets = Array.isArray(getSecretResult)
Expand Down Expand Up @@ -242,12 +241,12 @@ export function doubleCsrf({
req: Request,
res: Response,
overwrite = false,
validateOnReuse = true
validateOnReuse = true,
) => {
const { csrfToken, csrfTokenHash } = generateTokenAndHash(
req,
overwrite,
validateOnReuse
validateOnReuse,
);
const cookieContent = `${csrfToken}|${csrfTokenHash}`;
res.cookie(cookieName, cookieContent, { ...cookieOptions, httpOnly: true });
Expand All @@ -262,7 +261,7 @@ export function doubleCsrf({
const validateTokenAndHashPair: CsrfTokenAndHashPairValidator = (
token,
hash,
possibleSecrets
possibleSecrets,
) => {
if (typeof token !== "string" || typeof hash !== "string") return false;

Expand Down Expand Up @@ -297,7 +296,7 @@ export function doubleCsrf({
validateTokenAndHashPair(
csrfTokenFromRequest,
csrfTokenHash,
possibleSecrets
possibleSecrets,
)
);
};
Expand Down
55 changes: 25 additions & 30 deletions src/tests/doublecsrf.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,41 +77,45 @@ describe("csrf-csrf token-rotation", () => {

it("should be valid with 1 matching secret", () => {
assert.isTrue(
generateMocksWithMultipleSecrets(SECRET1).validateRequest(mockRequest)
generateMocksWithMultipleSecrets(SECRET1).validateRequest(mockRequest),
);
});

it("should be valid with 1/1 matching secret in array", () => {
assert.isTrue(
generateMocksWithMultipleSecrets([SECRET1]).validateRequest(mockRequest)
generateMocksWithMultipleSecrets([SECRET1]).validateRequest(
mockRequest,
),
);
});

it("should be valid with 1/2 matching secrets in array, first secret matches", () => {
assert.isTrue(
generateMocksWithMultipleSecrets([SECRET1, SECRET2]).validateRequest(
mockRequest
)
mockRequest,
),
);
});

it("should be valid with 1/2 matching secrets in array, second secret matches", () => {
assert.isTrue(
generateMocksWithMultipleSecrets([SECRET2, SECRET1]).validateRequest(
mockRequest
)
mockRequest,
),
);
});

it("should be invalid with 0/1 matching secret in array", () => {
assert.isFalse(
generateMocksWithMultipleSecrets([SECRET2]).validateRequest(mockRequest)
generateMocksWithMultipleSecrets([SECRET2]).validateRequest(
mockRequest,
),
);
});

it("should be invalid with 0/2 matching secrets in array", () => {
assert.isFalse(
generateMocksWithMultipleSecrets(SECRET2).validateRequest(mockRequest)
generateMocksWithMultipleSecrets(SECRET2).validateRequest(mockRequest),
);
});

Expand All @@ -121,7 +125,7 @@ describe("csrf-csrf token-rotation", () => {
"invalid0",
"invalid1",
"invalid2",
]).validateRequest(mockRequest)
]).validateRequest(mockRequest),
);
});
});
Expand All @@ -130,32 +134,23 @@ describe("csrf-csrf token-rotation", () => {
"should generate tokens correctly, simulating token rotations",
() => {
const getEmptyResponse = () => {
const { mockResponse, mockRequest } = generateMocks();
const { mockResponse } = generateMocks();
return mockResponse;
};

const {
validateRequest: validateRequestWithSecret1,
generateToken: generateTokenWithSecret1,
} = generateMocksWithMultipleSecrets(SECRET1);
const { validateRequest: validateRequestWithSecret1 } =
generateMocksWithMultipleSecrets(SECRET1);

const {
validateRequest: validateRequestWithSecret2,
generateToken: generateTokenWithSecret2,
} = generateMocksWithMultipleSecrets(SECRET2);
const { validateRequest: validateRequestWithSecret2 } =
generateMocksWithMultipleSecrets(SECRET2);

const {
validateRequest: validateRequestWithSecret1And2,
generateToken: generateTokenWithSecret1And2,
} = generateMocksWithMultipleSecrets([SECRET1, SECRET2]);
const { generateToken: generateTokenWithSecret1And2 } =
generateMocksWithMultipleSecrets([SECRET1, SECRET2]);

const {
validateRequest: validateRequestWithSecret2And1,
generateToken: generateTokenWithSecret2And1,
} = generateMocksWithMultipleSecrets([SECRET2, SECRET1]);
const { generateToken: generateTokenWithSecret2And1 } =
generateMocksWithMultipleSecrets([SECRET2, SECRET1]);

it("should reuse existing token on request with SECRET1, while current is [SECRET1, SECRET2]", () => {
//
const { mockRequest } = generateMocksWithMultipleSecrets(SECRET1);
const mockResponse = getEmptyResponse();

Expand Down Expand Up @@ -197,7 +192,7 @@ describe("csrf-csrf token-rotation", () => {
const token = generateTokenWithSecret1And2(
mockRequest,
mockResponse,
true
true,
);

attachResponseValuesToRequest({
Expand All @@ -220,7 +215,7 @@ describe("csrf-csrf token-rotation", () => {
const token = generateTokenWithSecret2And1(
mockRequest,
mockResponse,
true
true,
);

attachResponseValuesToRequest({
Expand All @@ -234,6 +229,6 @@ describe("csrf-csrf token-rotation", () => {
assert.isTrue(validateRequestWithSecret2(mockRequest));
assert.isFalse(validateRequestWithSecret1(mockRequest));
});
}
},
);
});
Loading
Loading