Skip to content

Commit

Permalink
Merge pull request #6 from jagaapple/feature/add-readme
Browse files Browse the repository at this point in the history
# New Features
- Add a readme


# Changes and Fixes
- Fix to return undefined when not enabling optional rules
- Use a CSP rule in the example project
- Modify English
  • Loading branch information
jagaapple authored Dec 4, 2019
2 parents 6783dd5 + fffc1c7 commit c2e3204
Show file tree
Hide file tree
Showing 9 changed files with 495 additions and 26 deletions.
433 changes: 433 additions & 0 deletions README.md

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions example/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ import withSecureHeaders from "next-secure-headers";
class Application extends App {}

export default withSecureHeaders({
contentSecurityPolicy: {
directives: {
defaultSrc: "'self'",
styleSrc: ["'self'", "https://stackpath.bootstrapcdn.com"],
},
},
forceHTTPSRedirect: [true, { maxAge: 60 * 60 * 24 * 4, includeSubDomains: true }],
referrerPolicy: "same-origin",
})(Application);
12 changes: 7 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ type Options = Partial<{
/**
* This is to set "Content-Security-Policy" or "Content-Security-Policy-Report-Only" header and it's to prevent to load and
* execute non-allowed resources.
* If you give true to `reportOnly` , this sets "Content-Security-Policy-Report-Only" to value instead of
* "Content-Security-Policy".
*/
contentSecurityPolicy: rules.ContentSecurityPolicyOption;
/**
Expand All @@ -16,13 +18,13 @@ type Options = Partial<{
/**
* This is to set "Strict-Transport-Security (HSTS)" header and it's to prevent man-in-the-middle attacks during redirects from HTTP to HTTPS.
* To enable this is highly recommended if you use HTTPS (SSL) on your servers.
* By default, this is set two years (63,072,000 seconds) as `max-age` .
* By default, this sets `max-age` to two years (63,072,000 seconds).
* @default [true, { maxAge: 63072000 }]
*/
forceHTTPSRedirect: rules.ForceHTTPSRedirectOption;
/**
* This is to set "X-Frame-Options" header and it's to prevent clickjacking attacks.
* `"deny"` is highly recommendeed if you doesn't use frame elements such as `iframe` .
* `"deny"` is highly recommended if you don't use frame elements such as `iframe` .
* @default "deny"
*/
frameGuard: rules.FrameGuardOption;
Expand All @@ -43,9 +45,9 @@ type Options = Partial<{
referrerPolicy: rules.ReferrerPolicyOption;
/**
* This is to set "X-XSS-Protection" header and it's to prevent XSS attacks.
* If you specify `"sanitize"` , this sets `"1"` to the header and browsers will sanitize unsafe area.
* If you specify `"block-rendering"` , this sets `"1; mode=block"` to the header and browsers will block rendering a page.
* "X-XSS-Protection" blocks many XSS attacks, but Contents Security Policy is recommended to use comapred to this.
* If you specify `"sanitize"` , this sets the header to `"1"` and browsers will sanitize unsafe area.
* If you specify `"block-rendering"` , this sets the header to `"1; mode=block"` and browsers will block rendering a page.
* "X-XSS-Protection" blocks many XSS attacks, but Content Security Policy is recommended to use compared to this.
* @default "sanitize"
*/
xssProtection: rules.XSSProtectionOption;
Expand Down
4 changes: 2 additions & 2 deletions src/rules/content-security-policy.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ describe("createContentSecurityPolicyOptionHeaderValue", () => {

it('should join directive strings using "; "', () => {
fetchDirectiveToStringConverterMock.mockReturnValue("dummy-value-1");
documentDirectiveToStringConverterMock.mockReturnValue("dummy-value-2");
documentDirectiveToStringConverterMock.mockReturnValue("");
reportingDirectiveToStringConverterMock.mockReturnValue("dummy-value-3");

expect(
Expand All @@ -123,7 +123,7 @@ describe("createContentSecurityPolicyOptionHeaderValue", () => {
documentDirectiveToStringConverterMock,
reportingDirectiveToStringConverterMock,
),
).toBe("dummy-value-1; dummy-value-2; dummy-value-3");
).toBe("dummy-value-1; dummy-value-3");
});
});
});
Expand Down
4 changes: 3 additions & 1 deletion src/rules/content-security-policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,9 @@ export const createContentSecurityPolicyOptionHeaderValue = (
fetchDirectiveToStringConverter(option.directives),
documentDirectiveToStringConverter(option.directives),
reportingDirectiveToStringConverter(option.directives),
].join(directiveValueSepartor);
]
.filter((string) => string.length > 0)
.join(directiveValueSepartor);
};

export const createContentSecurityPolicyHeader = (
Expand Down
43 changes: 29 additions & 14 deletions src/rules/expect-ct.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,40 @@ import { encodeStrictURI } from "./shared";
import { createExpectCTHeader, createExpectCTHeaderValue } from "./expect-ct";

describe("createExpectCTHeader", () => {
let headerValueCreatorMock: jest.Mock<
ReturnType<typeof createExpectCTHeaderValue>,
Parameters<typeof createExpectCTHeaderValue>
>;
beforeAll(() => {
headerValueCreatorMock = jest.fn(createExpectCTHeaderValue);
context("when giving undefined", () => {
it("should return undefined", () => {
expect(createExpectCTHeader()).toBeUndefined();
});
});

it('should return "Expect-CT" as object\'s "name" property', () => {
expect(createExpectCTHeader(undefined, headerValueCreatorMock)).toHaveProperty("name", "Expect-CT");
context("when giving false", () => {
it("should return undefined", () => {
expect(createExpectCTHeader(false)).toBeUndefined();
});
});

it('should call the second argument function and return a value from the function as object\'s "value" property', () => {
const dummyOption: Parameters<typeof createExpectCTHeader>[0] = undefined;
const dummyValue = "dummy-value";
headerValueCreatorMock.mockReturnValue(dummyValue);
context("when giving an object", () => {
const dummyOption: Parameters<typeof createExpectCTHeader>[0] = [true, { maxAge: 123 }];

expect(createExpectCTHeader(dummyOption, headerValueCreatorMock)).toHaveProperty("value", dummyValue);
expect(headerValueCreatorMock).toBeCalledWith(dummyOption);
let headerValueCreatorMock: jest.Mock<
ReturnType<typeof createExpectCTHeaderValue>,
Parameters<typeof createExpectCTHeaderValue>
>;
beforeAll(() => {
headerValueCreatorMock = jest.fn(createExpectCTHeaderValue);
});

it('should return "Expect-CT" as object\'s "name" property', () => {
expect(createExpectCTHeader(dummyOption, headerValueCreatorMock)).toHaveProperty("name", "Expect-CT");
});

it('should call the second argument function and return a value from the function as object\'s "value" property', () => {
const dummyValue = "dummy-value";
headerValueCreatorMock.mockReturnValue(dummyValue);

expect(createExpectCTHeader(dummyOption, headerValueCreatorMock)).toHaveProperty("value", dummyValue);
expect(headerValueCreatorMock).toBeCalledWith(dummyOption);
});
});
});

Expand Down
5 changes: 4 additions & 1 deletion src/rules/expect-ct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ export const createExpectCTHeaderValue = (option?: ExpectCTOption, strictURIEnco
export const createExpectCTHeader = (
option?: ExpectCTOption,
headerValueCreator = createExpectCTHeaderValue,
): ResponseHeader => {
): ResponseHeader | undefined => {
if (option == undefined) return;
if (option === false) return;

const value = headerValueCreator(option);

return { name: headerName, value };
Expand Down
13 changes: 10 additions & 3 deletions src/rules/referrer-policy.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@ describe("createReferrerPolicyHeader", () => {
});
});

context("when giving not undefined", () => {
context("when giving false", () => {
it("should return undefined", () => {
expect(createReferrerPolicyHeader(false)).toBeUndefined();
});
});

context("when giving an object", () => {
const dummyOption: Parameters<typeof createReferrerPolicyHeader>[0] = "same-origin";

let headerValueCreatorMock: jest.Mock<
ReturnType<typeof createReferrerPolicyHeaderValue>,
Parameters<typeof createReferrerPolicyHeaderValue>
Expand All @@ -17,11 +25,10 @@ describe("createReferrerPolicyHeader", () => {
});

it('should return "Referrer-Policy" as object\'s "name" property', () => {
expect(createReferrerPolicyHeader("no-referrer", headerValueCreatorMock)).toHaveProperty("name", "Referrer-Policy");
expect(createReferrerPolicyHeader(dummyOption, headerValueCreatorMock)).toHaveProperty("name", "Referrer-Policy");
});

it('should call the second argument function and return a value from the function as object\'s "value" property', () => {
const dummyOption: Parameters<typeof createReferrerPolicyHeader>[0] = "no-referrer";
const dummyValue = "dummy-value";
headerValueCreatorMock.mockReturnValue(dummyValue);

Expand Down
1 change: 1 addition & 0 deletions src/rules/referrer-policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const createReferrerPolicyHeader = (
headerValueCreator = createReferrerPolicyHeaderValue,
): ResponseHeader | undefined => {
if (option == undefined) return;
if (option === false) return;

const value = headerValueCreator(option);

Expand Down

0 comments on commit c2e3204

Please sign in to comment.