Skip to content

Commit

Permalink
docs: finishing report and one last surprise
Browse files Browse the repository at this point in the history
  • Loading branch information
BramComyn authored Sep 22, 2024
2 parents c5b60a6 + 522b680 commit 20a0f6b
Show file tree
Hide file tree
Showing 14 changed files with 152 additions and 82 deletions.
18 changes: 9 additions & 9 deletions docs/safeguard-fetch-documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ rather than only the ``on(event, ...)`` per session or stream.

## Attack Server

This repository also contains a way to quickly initialize HTTP/1.1- and HTTP/2.0-servers for certain
This repository also contains a way to quickly initialise HTTP/1.1- and HTTP/2.0-servers for certain
malicious configurations.
The code is structured so that it is possible to expand upon this.
It is all based around the ``AttackServer`` class.
Expand All @@ -158,18 +158,18 @@ import type { Http2SecureServer } from 'node:http2'
const httpPort = 8080;
const http2SecurePort = 8443;

// Initialize an unsecured HTTP/1.1-server
// Initialise an unsecured HTTP/1.1-server
const httpServer = new AttackServer<Server>(
httpPort,
new AttackServerHttpFactory(),
[], // the initializers
[], // the initialisers
);

// Initialize a secured HTTP/2.0-server
// Initialise a secured HTTP/2.0-server
const http2Server = new AttackServer<Http2SecureServer>(
http2SecurePort,
new AttackServerHttp2SecureFactory(),
[], // the initializers
[], // the initialisers
);
```

Expand All @@ -179,13 +179,13 @@ Although the specs allow it, almost all major browsers (and even cURL)
will refuse to talk to an unsecured HTTP/2.0-server.
This was, however, included in an earlier phase of development.

To make a server attack in certain ways, the server initializer array
can be populated with ``AttackServerInitializer``s,
of which some examples are included under ``src/attack-server/attack-server-initializer``.
To make a server attack in certain ways, the server initialiser array
can be populated with ``AttackServerInitialiser``s,
of which some examples are included under ``src/attack-server/attack-server-initialiser``.

## Response Generator

Some of the ``AttackServerInitializer``s rely on instances of ``ResponseGenerator`` to
Some of the ``AttackServerInitialiser``s rely on instances of ``ResponseGenerator`` to
form the necessary ``headers`` and ``body`` objects.
There are two ``StandardResponseGenerator`` factory functions to make the distinction between HTTP/1.1 and HTTP/2.0

Expand Down
70 changes: 70 additions & 0 deletions report/final-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,73 @@ of which most of [the playgrounds](../scripts/playgrounds/) are the final result
During the first week, it was sometimes awkward getting stuck *not knowing* what to do or how to proceed.
When I noticed this, I reached out and was supported really well.
This made me very enthusiast going into the end of the first week and really allowed me to grow into this work.

## Second week: a rudimentary wrapper implementation

During my second week of working, I laid the foundations of what ultimately became the wrapper.
I started by decoupling some code I wrote for the ``infinite-server``, based on the ideas that were given to me
in our meeting and Mattermost-chats.
I also kept documenting some more details in client behavior for this specific use case,
but extended my testing and playing around to also include the case of a faulty or malicious redirect.
Ultimately, I coded the ``setContentLengthHandler``, ``setNoContentLengthHandler`` and ``setRedirectHandler``.
It was clear that this approach wasn't the most durable, so that's why I decided to ask for more feedback.
This feedback is what led to the refactoring that took me most of my week, Wednesday through to Friday.

All of this work led to the types and classes defined under ``src/handler``,
as my earlier functions got rewritten into some examples of a more generic interface for allowing
the user to attach handlers in different cases.
This made me realise that I was not directly making a wrapper, yet more some examples of how my wrapper could be used.
I would go on to fix and demonstrate this one more time in my third week.

### Perception of week 2

This week was probably the most valuable to me in terms of learning TypeScript's typing system
and how to perform some very funky things with it.
I really want to thank the people that guided me in this,
as I would have probably given up if this was some personal side project
-- which sounds very dramatic, but in fact is the truth.

I felt more comfortable in getting stuck on something,
and I felt more at home in this research-type of work.

## Third week: ``SafeguardRequester`` - a testimony to learning TypeScript

The final result of my code is the ``SafeguardRequester`` class,
with the three most important methods being:

- ``connect``
- ``request``

and their combination in

- ``connectAndRequest``

These methods allow for repeated use of the different ``ClientEventHandler``s and ``ResponseEventHandler``s
that the user can define and set through the constructor and the respective methods.

Also in the final week, I fixed broken tests and bumped the coverage for all my files to 100%,
with both integration tests and unit tests for the wrapper.
I even included a more detailed example, albeit very rudimentary, flawed and NOT FIT FOR REAL USE.
However, it is tested, shows the functionality of the wrapper and the possibilities included through its use.

In short, the wrapper makes adding a complex amount of event handlers a bit easier for the user,
yet I still believe there is more possible work and improvements to be built in the wrapper and its usage.

### Perception of the third week

The third week was a bit more difficult, as it came with a bunch of
-- in my eyes complicated -- testing,
but in the end I managed to develop a strong set of tests that cover a plethora of possible
situations. I was very happy about my results, as I could compare to myself three weeks prior
and see what improvements I had made
in terms of practical experience.

## A word of thanks

I still wish to thank everyone who helped me in achieving this code.
To me, it was my first experience I got working in my own sector.
This work managed to convince myself entirely again of why I study this field and what sparked my interest in it.
I will enter the new year as a more complete and better computer scientist.
I also wish to thank prof. Verborgh again for introducing me in Web Development
and all its interesting and complex ideas and concepts.
I yearn to returning next summer and paving my way further into the open world of software development and research.
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import type { Http2Server, IncomingHttpHeaders, ServerHttp2Stream } from 'node:http2';

import type { AttackServerInitializer, ResponseGeneratorMap } from './AttackServerInitializer';
import type { AttackServerInitialiser, ResponseGeneratorMap } from './AttackServerInitialiser';

/**
* Class for initializing HTTP/2.0 attack servers.
*
* @member responseGenerators - A map of response generators for each path.
* @method initialize - initializes the server with the necessary event listeners.
* @method initialise - initialises the server with the necessary event listeners.
*/
export class AttackServerHttp2Initializer implements AttackServerInitializer<Http2Server> {
export class AttackServerHttp2Initialiser implements AttackServerInitialiser<Http2Server> {
public constructor(
protected responseGenerators: ResponseGeneratorMap = {},
) {}

public initialize(server: Http2Server): void {
public initialise(server: Http2Server): void {
server.on('stream', (stream: ServerHttp2Stream, inboundHeaders: IncomingHttpHeaders): void => {
const path = inboundHeaders[':path'];

Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import type { Server } from 'node:http';

import { getStatusCode } from '../../util';
import type { AttackServerInitializer, ResponseGeneratorMap } from './AttackServerInitializer';
import type { AttackServerInitialiser, ResponseGeneratorMap } from './AttackServerInitialiser';

/**
* Class for initializing HTTP/1.1 attack servers.
*
* @member responseGenerators - A map of response generators for each path.
* @method initialize - initializes the server with the necessary event listeners.
* @method initialise - initialises the server with the necessary event listeners.
*/
export class AttackServerHttpInitializer implements AttackServerInitializer<Server> {
export class AttackServerHttpInitialiser implements AttackServerInitialiser<Server> {
public constructor(
protected responseGenerators: ResponseGeneratorMap = {},
) {}

public initialize(server: Server): void {
public initialise(server: Server): void {
server.on('request', (req, res): void => {
const path = req.url?.toString();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import type { ResponseGenerator } from '../../response-generator/ResponseGenerat
/**
* Interface for initializing the attack server.
*
* @method initialize - initializes the server with the necessary event listeners
* @method initialise - initialises the server with the necessary event listeners
*/
export interface AttackServerInitializer<T extends Server> {
export interface AttackServerInitialiser<T extends Server> {
/**
* Initializes a server with the necessary event listeners.
* Initialises a server with the necessary event listeners.
*
* @param server The server to be initialized.
* @param server The server to be initialised.
*/
initialize: (server: T) => void;
initialise: (server: T) => void;
}

/**
Expand Down
10 changes: 5 additions & 5 deletions src/attack-server/attack-server/AttackServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Server as HttpServer } from 'node:http';
import type { Http2Server } from 'node:http2';

import type { AttackServerFactory } from '../attack-server-factory/AttackServerFactory';
import type { AttackServerInitializer } from '../attack-server-initializer/AttackServerInitializer';
import type { AttackServerInitialiser } from '../attack-server-initialiser/AttackServerInitialiser';

/**
* An attack server for testing purposes
Expand All @@ -23,20 +23,20 @@ export class AttackServer<T extends Server> {
*
* @param port - the desired port to start the server on
* @param attackServerFactory - the factory to create the server
* @param attackServerInitializers - the initializers to initialise the server
* @param attackServerInitialisers - the initialisers to initialise the server
* @param options - options to pass to the server factory
*/
public constructor(
port: number,
attackServerFactory: AttackServerFactory<T>,
attackServerInitializers: AttackServerInitializer<T>[],
attackServerInitialisers: AttackServerInitialiser<T>[],
options?: object,
) {
this.port = port;
this.server = attackServerFactory.createServer(options ?? {});

for (const initializer of attackServerInitializers) {
initializer.initialize(this.server);
for (const initialiser of attackServerInitialisers) {
initialiser.initialise(this.server);
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,17 +64,17 @@ const HTTP_VERSION_NOT_SUPPORTED = 505;
* @returns - The status code as integer
*/
export function getStatusCode(headers: IncomingHttpHeaders | OutgoingHttpHeaders): number {
return sanitizeStatusCode(Number.parseInt(headers[':status'] as string | undefined ?? '0', 10));
return sanitiseStatusCode(Number.parseInt(headers[':status'] as string | undefined ?? '0', 10));
}

/**
* Return the correct status code to act upon as [https://www.rfc-editor.org/rfc/rfc9110.html#name-status-codes] states
*
* @param statusCode - The status code to sanitize
* @param statusCode - The status code to sanitise
*
* @returns - The sanitized status code
* @returns - The sanitised status code
*/
export function sanitizeStatusCode(statusCode: number): number {
export function sanitiseStatusCode(statusCode: number): number {
if (statusCode >= 100 && statusCode <= 199) {
return statusCode === SWITCHING_PROTOCOLS ? statusCode : 100;
}
Expand Down
12 changes: 6 additions & 6 deletions test/integration/turtle.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Http2SecureServer } from 'node:http2';

import type { ResponseGeneratorMap } from '../../src/attack-server/attack-server-initializer/AttackServerInitializer';
import type { ResponseGeneratorMap } from '../../src/attack-server/attack-server-initialiser/AttackServerInitialiser';
import { HTTP2_SERVER_PATHS, TURTLE_PATHS } from '../../src/attack-server/attackServerConstants';
import { AttackServer } from '../../src/attack-server/attack-server/AttackServer';
import { TurtleDownloader } from '../../src/turtle-downloader/TurtleDownloader';
Expand All @@ -11,8 +11,8 @@ import {
} from '../../src/attack-server/attack-server-factory/AttackServerHttp2SecureFactory';

import {
AttackServerHttp2Initializer,
} from '../../src/attack-server/attack-server-initializer/AttackServerHttp2Initializer';
AttackServerHttp2Initialiser,
} from '../../src/attack-server/attack-server-initialiser/AttackServerHttp2Initialiser';

const paths: ResponseGeneratorMap = { ...HTTP2_SERVER_PATHS, ...TURTLE_PATHS };

Expand All @@ -29,14 +29,14 @@ describe('TurtleDownloader', (): void => {
const downloader = new TurtleDownloader();

const factory = new AttackServerHttp2SecureFactory();
const initializers = [
new AttackServerHttp2Initializer(paths),
const initialisers = [
new AttackServerHttp2Initialiser(paths),
];

const server = new AttackServer<Http2SecureServer>(
port,
factory,
initializers,
initialisers,
secureServerOptions,
);

Expand Down
8 changes: 4 additions & 4 deletions test/integration/wrapper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { connect } from 'node:http2';
import { once } from 'node:events';

import { createRefuseContentLongerThanHandler } from '../../src/handler/examples/RefuseContentLengthLongerThanHandler';
import type { ResponseGeneratorMap } from '../../src/attack-server/attack-server-initializer/AttackServerInitializer';
import type { ResponseGeneratorMap } from '../../src/attack-server/attack-server-initialiser/AttackServerInitialiser';
import { createRefuseNoContentLengthHandler } from '../../src/handler/examples/RefuseNoContentLengthHandler';
import { createAllowedRedirectDetector } from '../../src/handler/examples/AllowedRedirectDetector';
import { createBannedRedirectDetector } from '../../src/handler/examples/BannedRedirectDetector';
Expand All @@ -15,8 +15,8 @@ import {
} from '../../src/attack-server/attack-server-factory/AttackServerHttp2SecureFactory';

import {
AttackServerHttp2Initializer,
} from '../../src/attack-server/attack-server-initializer/AttackServerHttp2Initializer';
AttackServerHttp2Initialiser,
} from '../../src/attack-server/attack-server-initialiser/AttackServerHttp2Initialiser';

import {
CONTENT_LENGTH_PATHS,
Expand All @@ -39,7 +39,7 @@ describe('The whole codebase', (): void => {
const server = new AttackServer(
port,
factory,
[ new AttackServerHttp2Initializer(generators) ],
[ new AttackServerHttp2Initialiser(generators) ],
secureServerOptions,
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import { PassThrough } from 'node:stream';
import type { ResponseGenerator } from '../../../../src/response-generator/ResponseGenerator';

import {
AttackServerHttp2Initializer,
} from '../../../../src/attack-server/attack-server-initializer/AttackServerHttp2Initializer';
AttackServerHttp2Initialiser,
} from '../../../../src/attack-server/attack-server-initialiser/AttackServerHttp2Initialiser';

describe('AttackServerHttp2Initializer', (): void => {
let initializer: AttackServerHttp2Initializer;
describe('AttackServerHttp2Initialiser', (): void => {
let initialiser: AttackServerHttp2Initialiser;
let responseGenerator: jest.Mocked<ResponseGenerator>;
let server: jest.Mocked<Http2Server>;
let stream: jest.Mocked<ServerHttp2Stream>;
Expand All @@ -30,13 +30,13 @@ describe('AttackServerHttp2Initializer', (): void => {
body = new PassThrough() as any;
jest.spyOn(body, 'pipe').mockImplementation();

initializer = new AttackServerHttp2Initializer({ '/': responseGenerator });
initializer.initialize(server);
initialiser = new AttackServerHttp2Initialiser({ '/': responseGenerator });
initialiser.initialise(server);
});

it('should create an instance.', (): void => {
const initializer = new AttackServerHttp2Initializer();
expect(initializer).toBeDefined();
const initialiser = new AttackServerHttp2Initialiser();
expect(initialiser).toBeDefined();
});

it('should make the server respond to known paths.', (): void => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import { PassThrough } from 'node:stream';
import type { ResponseGenerator } from '../../../../src/response-generator/ResponseGenerator';

import {
AttackServerHttpInitializer,
} from '../../../../src/attack-server/attack-server-initializer/AttackServerHttpInitializer';
AttackServerHttpInitialiser,
} from '../../../../src/attack-server/attack-server-initialiser/AttackServerHttpInitialiser';

describe('AttackServerHttpInitializer', (): void => {
let initializer: AttackServerHttpInitializer;
describe('AttackServerHttpInitialiser', (): void => {
let initialiser: AttackServerHttpInitialiser;
let responseGenerator: jest.Mocked<ResponseGenerator>;
let server: jest.Mocked<Server>;
let response: jest.Mocked<ServerResponse>;
Expand All @@ -30,13 +30,13 @@ describe('AttackServerHttpInitializer', (): void => {
body = new PassThrough() as any;
jest.spyOn(body, 'pipe').mockImplementation();

initializer = new AttackServerHttpInitializer({ '/': responseGenerator });
initializer.initialize(server);
initialiser = new AttackServerHttpInitialiser({ '/': responseGenerator });
initialiser.initialise(server);
});

it('should create an instance.', (): void => {
const initializer = new AttackServerHttpInitializer();
expect(initializer).toBeDefined();
const initialiser = new AttackServerHttpInitialiser();
expect(initialiser).toBeDefined();
});

it('should make the server respond to known paths.', (): void => {
Expand Down
Loading

0 comments on commit 20a0f6b

Please sign in to comment.