Skip to content

Commit

Permalink
add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ematipico committed Apr 8, 2024
1 parent 61a85c1 commit 01b39be
Show file tree
Hide file tree
Showing 5 changed files with 242 additions and 1 deletion.
3 changes: 2 additions & 1 deletion packages/astro/src/core/app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ export class App {
* @private
*/
#createPipeline(streaming = false) {
if (this.#manifest.csrfProtection) {
console.log(this.#manifest);
if (this.#manifest.csrfProtection?.origin === true) {
this.#manifest.middleware = sequence(
this.#createOriginCheckMiddleware(),
this.#manifest.middleware
Expand Down
188 changes: 188 additions & 0 deletions packages/astro/test/csrf-protection.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
import { before, describe, it } from 'node:test';
import { loadFixture } from './test-utils.js';
import testAdapter from './test-adapter.js';
import assert from 'node:assert/strict';

describe('CSRF origin check', () => {
let app;

before(async () => {
const fixture = await loadFixture({
root: './fixtures/csrf-check-origin/',
adapter: testAdapter(),
});
await fixture.build();
app = await fixture.loadTestAdapterApp();
});

it("return 403 when the origin doesn't match and calling a POST", async () => {
let request;
let response;
request = new Request('http://example.com/api/', {
headers: { origin: 'http://loreum.com', 'content-type': 'multipart/form-data' },
method: 'POST',
});
response = await app.render(request);
assert.equal(response.status, 403);

request = new Request('http://example.com/api/', {
headers: { origin: 'http://loreum.com', 'content-type': 'application/x-www-form-urlencoded' },
method: 'POST',
});
response = await app.render(request);
assert.equal(response.status, 403);

request = new Request('http://example.com/api/', {
headers: { origin: 'http://loreum.com', 'content-type': 'text/plain' },
method: 'POST',
});
response = await app.render(request);
assert.equal(response.status, 403);
});

it("return 403 when the origin doesn't match and calling a PUT", async () => {
let request;
let response;
request = new Request('http://example.com/api/', {
headers: { origin: 'http://loreum.com', 'content-type': 'multipart/form-data' },
method: 'PUT',
});
response = await app.render(request);
assert.equal(response.status, 403);

request = new Request('http://example.com/api/', {
headers: { origin: 'http://loreum.com', 'content-type': 'application/x-www-form-urlencoded' },
method: 'PUT',
});
response = await app.render(request);
assert.equal(response.status, 403);

request = new Request('http://example.com/api/', {
headers: { origin: 'http://loreum.com', 'content-type': 'text/plain' },
method: 'PUT',
});
response = await app.render(request);
assert.equal(response.status, 403);
});

it("return 403 when the origin doesn't match and calling a DELETE", async () => {
let request;
let response;
request = new Request('http://example.com/api/', {
headers: { origin: 'http://loreum.com', 'content-type': 'multipart/form-data' },
method: 'DELETE',
});
response = await app.render(request);
assert.equal(response.status, 403);

request = new Request('http://example.com/api/', {
headers: { origin: 'http://loreum.com', 'content-type': 'application/x-www-form-urlencoded' },
method: 'DELETE',
});
response = await app.render(request);
assert.equal(response.status, 403);

request = new Request('http://example.com/api/', {
headers: { origin: 'http://loreum.com', 'content-type': 'text/plain' },
method: 'DELETE',
});
response = await app.render(request);
assert.equal(response.status, 403);
});

it("return 403 when the origin doesn't match and calling a PATCH", async () => {
let request;
let response;
request = new Request('http://example.com/api/', {
headers: { origin: 'http://loreum.com', 'content-type': 'multipart/form-data' },
method: 'PATCH',
});
response = await app.render(request);
assert.equal(response.status, 403);

request = new Request('http://example.com/api/', {
headers: { origin: 'http://loreum.com', 'content-type': 'application/x-www-form-urlencoded' },
method: 'PATCH',
});
response = await app.render(request);
assert.equal(response.status, 403);

request = new Request('http://example.com/api/', {
headers: { origin: 'http://loreum.com', 'content-type': 'text/plain' },
method: 'PATCH',
});
response = await app.render(request);
assert.equal(response.status, 403);
});

it("return a 200 when the origin doesn't match but calling a GET", async () => {
let request;
let response;
request = new Request('http://example.com/api/', {
headers: { origin: 'http://loreum.com', 'content-type': 'multipart/form-data' },
method: 'GET',
});
response = await app.render(request);
assert.equal(response.status, 200);
assert.deepEqual(await response.json(), {
something: 'true',
});

request = new Request('http://example.com/api/', {
headers: { origin: 'http://loreum.com', 'content-type': 'application/x-www-form-urlencoded' },
method: 'GET',
});
response = await app.render(request);
assert.equal(response.status, 200);
assert.deepEqual(await response.json(), {
something: 'true',
});

request = new Request('http://example.com/api/', {
headers: { origin: 'http://loreum.com', 'content-type': 'text/plain' },
method: 'GET',
});
response = await app.render(request);
assert.equal(response.status, 200);
assert.deepEqual(await response.json(), {
something: 'true',
});
});

it('return 200 when calling POST/PUT/DELETE/PATCH with the correct origin', async () => {
let request;
let response;
request = new Request('http://example.com/api/', {
headers: { origin: 'http://example.com', 'content-type': 'multipart/form-data' },
method: 'POST',
});
response = await app.render(request);
assert.equal(response.status, 200);
assert.deepEqual(await response.json(), {
something: 'true',
});

request = new Request('http://example.com/api/', {
headers: {
origin: 'http://example.com',
'content-type': 'application/x-www-form-urlencoded',
},
method: 'PUT',
});
response = await app.render(request);
assert.equal(response.status, 200);
assert.deepEqual(await response.json(), {
something: 'true',
});

request = new Request('http://example.com/api/', {
headers: { origin: 'http://example.com', 'content-type': 'text/plain' },
method: 'PATCH',
});
response = await app.render(request);
assert.equal(response.status, 200);
assert.deepEqual(await response.json(), {
something: 'true',
});
});
});
15 changes: 15 additions & 0 deletions packages/astro/test/fixtures/csrf-check-origin/astro.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { defineConfig } from 'astro/config';

// https://astro.build/config
export default defineConfig({
output: "server",
security: {
csrfProtection: {
origin: true
}
},
experimental: {
csrfProtection: true
}
});

8 changes: 8 additions & 0 deletions packages/astro/test/fixtures/csrf-check-origin/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "@test/csrf",
"version": "0.0.0",
"private": true,
"dependencies": {
"astro": "workspace:*"
}
}
29 changes: 29 additions & 0 deletions packages/astro/test/fixtures/csrf-check-origin/src/pages/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export const GET = () => {
return Response.json({
something: 'true',
});
};

export const POST = () => {
return Response.json({
something: 'true',
});
};

export const PUT = () => {
return Response.json({
something: 'true',
});
};

export const DELETE = () => {
return Response.json({
something: 'true',
});
};

export const PATCH = () => {
return Response.json({
something: 'true',
});
};

0 comments on commit 01b39be

Please sign in to comment.