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

merge dev into main #8

Merged
merged 3 commits into from
Sep 29, 2024
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
23 changes: 10 additions & 13 deletions .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: CI
name: CI/CD

on:
push:
Expand All @@ -13,19 +13,16 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up pnpm
uses: pnpm/action-setup@v4
- name: Set up bun
uses: oven-sh/setup-bun@v2
with:
version: 9.11.0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
cache: 'pnpm'
bun-version: 1.1.29

- name: Install dependencies
run: pnpm install --frozen-lockfile
run: bun install --frozen-lockfile

- name: Run lint
run: bun lint

- name: Run linter
run: pnpm lint && pnpm build
- name: Run build
run: bun run build
18 changes: 6 additions & 12 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Publish
on:
workflow_run:
workflows: [Lint]
workflows: [CI/CD]
branches: [main]
types: [completed]

Expand All @@ -19,25 +19,19 @@ jobs:
- name: Checkout
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4
- name: Set up bun
uses: oven-sh/setup-bun@v2
with:
version: 9.11.0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
cache: 'pnpm'
bun-version: 1.1.29

- name: Install Dependencies
run: pnpm install --frozen-lockfile
run: bun install --frozen-lockfile

- name: Create Release Pull Request or Publish
id: changesets
uses: changesets/action@v1
with:
publish: pnpm run release
publish: bun release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
node_modules
dist
.vercel
.vercel
bun.lockb
.turbo
32 changes: 30 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

Secure your [sveltekit](https://kit.svelte.dev/) app using [http response headers](https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html)

[![Lint](https://github.com/IslamZaoui/securekit/actions/workflows/lint.yaml/badge.svg)](https://github.com/IslamZaoui/securekit/actions/workflows/lint.yaml)
[![npm](https://img.shields.io/npm/v/%40islamzaoui%2Fsecurekit)](https://www.npmjs.com/package/@islamzaoui/securekit)
[![CI/CD](https://github.com/IslamZaoui/securekit/actions/workflows/lint.yaml/badge.svg)](https://github.com/IslamZaoui/securekit/actions/workflows/lint.yaml)
[![NPM](https://img.shields.io/npm/v/%40islamzaoui%2Fsecurekit)](https://www.npmjs.com/package/@islamzaoui/securekit)
[![Issues](https://img.shields.io/github/issues/IslamZaoui/securekit)](https://github.com/IslamZaoui/securekit/issues)
[![License](https://img.shields.io/github/license/IslamZaoui/securekit)](https://github.com/IslamZaoui/securekit/blob/main/LICENSE)

Expand All @@ -19,6 +19,8 @@ you can also use other package managers like [pnpm](https://pnpm.io/) or [yarn](

### default headers

this will add the default headers to the response, this will be enough to get your website A grade in [security headers](https://securityheaders.com/)

```ts
// src/hooks.server.ts
import { securityHeaders } from '@islamzaoui/securekit';
Expand All @@ -28,6 +30,8 @@ export const handle = securityHeaders().handle;

### with custom headers

you can customize the headers you want to set, and override any of the headers available in response headers.

```ts
// src/hooks.server.ts
import { securityHeaders } from '@islamzaoui/securekit';
Expand All @@ -46,6 +50,8 @@ export const handle = securityHeaders({

### with multiple handles

you can use [sequence](https://kit.svelte.dev/docs/modules#sveltejs-kit-hooks) to sequencing other handles with `securityHeaders`.

```ts
// src/hooks.server.ts
import { securityHeaders } from '@islamzaoui/securekit';
Expand All @@ -61,10 +67,32 @@ export const handle = sequence(
);
```

### delete headers

set the value to `null` to delete the header.

```ts
// src/hooks.server.ts
import { securityHeaders } from '@islamzaoui/securekit';

export const handle = securityHeaders({
headers: {
'Access-Control-Allow-Origin': 'https://yoursite.com',
'x-sveltekit-page': null, // this will be deleted
},
});
```

## Content Security Policy header

your can use `csp` option in `securityHeaders` to set the `Content-Security-Policy` header directives.

**Note**:

- `config.csp` directives will override any existing directives in the `Content-Security-Policy` header.

- `config.csp` directives will extend the existing directives in [svelte.config.js](https://kit.svelte.dev/docs/configuration#csp)

```ts
// src/hooks.server.ts
import { securityHeaders } from '@islamzaoui/securekit';
Expand Down
9 changes: 4 additions & 5 deletions apps/demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,25 @@
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check . && eslint .",
"format": "prettier --write .",
"postinstall": "cd ../../packages/securekit && pnpm run build"
"format": "prettier --write ."
},
"devDependencies": {
"@sveltejs/adapter-vercel": "^5.4.4",
"@sveltejs/kit": "catalog:default",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"@types/eslint": "^9.6.0",
"autoprefixer": "^10.4.20",
"eslint": "^9.0.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.36.0",
"globals": "^15.0.0",
"prettier": "catalog:default",
"prettier": "^3.1.1",
"prettier-plugin-svelte": "^3.1.2",
"prettier-plugin-tailwindcss": "^0.6.5",
"svelte": "^4.2.7",
"svelte-check": "^3.6.0",
"tailwindcss": "^3.4.9",
"typescript": "catalog:default",
"typescript": "^5.0.0",
"typescript-eslint": "^8.0.0",
"vite": "^5.0.3"
},
Expand Down
9 changes: 5 additions & 4 deletions apps/demo/src/hooks.server.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { dev } from '$app/environment';
import { rules, securityHeaders } from '@islamzaoui/securekit';
import { securityHeaders, rules } from '@islamzaoui/securekit';

const origin = dev ? 'http://localhost:5173' : 'https://securekit-demo.vercel.app';

export const handle = securityHeaders({
headers: {
...rules.defaultHeaders,
'Access-Control-Allow-Origin': origin
'Access-Control-Allow-Origin': origin,
'x-sveltekit-page': null
},
csp: {
directives: {
Expand All @@ -21,9 +22,9 @@ export const handle = securityHeaders({
'manifest-src': ["'self'"],
'media-src': ["'self'", 'data:'],
'object-src': ["'none'"],
'style-src': ["'self'", "'unsafe-inline'"],
'style-src': ["'self'"],
'default-src': ["'self'", origin],
'script-src': ["'self'", "'unsafe-inline'"],
'script-src': ["'self'"],
'worker-src': ["'self'"]
}
},
Expand Down
8 changes: 7 additions & 1 deletion apps/demo/svelte.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ const config = {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter()
adapter: adapter(),
csp: {
mode: 'auto',
directives: {
'default-src': ["'self'"]
}
}
}
};

Expand Down
17 changes: 9 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@
"name": "monorepo",
"private": true,
"scripts": {
"build": "pnpm run -r build",
"dev": "pnpm run -r --parallel --stream dev",
"release": "pnpm run -r build && changeset publish",
"lint": "prettier --check \"**/*.{json,md}\" && pnpm run -r lint",
"format": "prettier --write \"**/*.{json,md}\" && pnpm run -r format"
"build": "turbo run build",
"dev": "turbo run dev",
"release": "turbo run build && changeset publish",
"lint": "prettier --check \"**/*.{json,md}\" && turbo run lint",
"format": "prettier --write \"**/*.{json,md}\" && turbo run format"
},
"workspaces": [
"packages/*",
"apps/*"
],
"devDependencies": {
"@changesets/cli": "catalog:default",
"prettier": "catalog:default"
"@changesets/cli": "^2.27.8",
"prettier": "^3.1.1",
"turbo": "^2.1.2"
},
"packageManager": "[email protected]"
"packageManager": "[email protected]"
}
8 changes: 4 additions & 4 deletions packages/securekit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@
"license": "MIT",
"description": "Secure your sveltekit app using http response security headers",
"devDependencies": {
"prettier": "catalog:default",
"tsup": "catalog:default",
"typescript": "catalog:default"
"prettier": "^3.1.1",
"tsup": "^8.3.0",
"typescript": "^5.0.0"
},
"peerDependencies": {
"@sveltejs/kit": "catalog:default"
"@sveltejs/kit": "^2.0.0"
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HTTPResponseHeaders } from './types/http';
import { HTTPResponseHeaders } from '../types/http';

const defaultHeaders: HTTPResponseHeaders = {
'X-Frame-Options': 'DENY',
Expand All @@ -7,7 +7,7 @@ const defaultHeaders: HTTPResponseHeaders = {
'Permissions-Policy': 'geolocation=(), camera=(), microphone=()',
};

export const rules = {
export default {
/**
* Default headers for secure headers.
* @example
Expand Down
62 changes: 3 additions & 59 deletions packages/securekit/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,59 +1,3 @@
import { Handle } from '@sveltejs/kit';
import { Config } from './types';
import { normalizeCspValue, normalizeHeaderValue } from './utils';
import { rules } from './headers';

/**
* sets HTTP response security headers based on the provided configuration.
*
* @param {Config} [config] - Configuration object for secure headers.
* @param {Object} [config.headers] - Custom headers to set.
* @param {boolean} [config.debug] - Enables debug logging if true.
* @param {Object} [config.csp] - Content Security Policy directives.
* @returns {Object} An object containing the handle function to process requests.
*/
export const securityHeaders = (
config: Config = {
headers: {
...rules.defaultHeaders,
},
debug: false,
csp: undefined,
},
) => {
const headers = new Map<string, string>();

if (config?.headers) {
Object.entries(config.headers).forEach(([key, value]) => {
value && headers.set(key, normalizeHeaderValue(value));
});
}

if (config?.csp) {
const cspDirectives = Object.entries(config.csp.directives)
.map(([key, value]) => `${key} ${normalizeCspValue(value)}`)
.join('; ');
headers.set('Content-Security-Policy', cspDirectives);
}

const handle: Handle = async ({ event, resolve }) => {
if (config?.debug) {
console.log(
'[DEBUG] securekit Headers:',
JSON.stringify(Object.fromEntries(headers), null, 2),
);
}

const response = await resolve(event);

headers.forEach((value, key) => {
response.headers.set(key, value);
});

return response;
};

return { handle };
};

export { rules } from './headers';
export { securityHeaders } from './securityHeaders';
export { default as rules } from './constants/rules';
export * from './types';
Loading