Foreword

This course, in a nutshell, is a shit show. We are being tested on the most irrelevant crap - details we don't ever need to remember as webdevs (hello MDN Web Docs) and API-specific shit from Express!

Then they expect you to be able to compile badly-written JavaScript in your head after they teach it to you in ~4 weeks. Don't even get me started on the project. The education quality here is laughable. Students will not take away any skills from this course.

Here I'll outline some important information you should know for the exams. Do note that a lot of the material is simplified as I focus on how to answer the exam, not to provide actual webdev knowledge. Please tweet any suggestions/requests to @kevincharm. You can also submit a PR on the github repo.

If anyone important is reading this; contact me. I am keen to teach CSE1500 next year (trade for ECs or waive my tuition) because students paying >EUR10k deserve better education than this.

JavaScript

JavaSkrrrt

Classes & Modules

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public int getAge() {
        return this.age;
    }

    public void birthday() {
        this.age = this.age + 1;
    }
}

// Then this class can be instantiated with:
Person person = new Person("Kevin", 42);
// and you can invoke instance methods like:
person.birthday();
// and get the age like this:
int age = person.getAge();

Above is an example class in Java.

  • We can't get access to name because it's private and has no getter!
    • Therefore we say that name is encapsulated.
  • There are multiple ways to write this class in JavaScript. Below we go through some examples of how to write this equivalent class in JavaScript.

Prototype Pattern

// This is the constructor:
function Person(name, age) {
    this.name = name
    this.age = age
}

// These are *instance* methods;
// meaning they have access to `this` (itself).
Person.prototype.getAge = function () {
    return this.age
}

Person.prototype.birthday = function () {
    this.age = this.age + 1
}

// Then this "class" can be instantiated with:
var person = new Person('Kevin', 42)
// and you can invoke instance methods like:
person.birthday()

// and get the age like this:
var age = person.getAge()
// OR
var age = person.age

// ...and this is also works!
var name = person.name
  • This is called the prototype pattern.
  • It does not support encapsulation, because we are able to access any of its attributes, including name.

Module Pattern

function Person(name, age) {
    var name = name
    var age = age

    function getAge() {
        return age
    }

    function birthday() {
        age = age + 1
    }

    // Tricks to watch out for:
    // Usually, with the module pattern, we don't need to use `this` as in other patterns!

    // With the module pattern,
    // we _explicitly return_ what we want to expose (make public):
    return {
        getAge: getAge,
        birthday: birthday
    }
}

// We create the instance like so (notice the lack of `new`):
var person = Person('Kevin', 42)
// Then we can do
person.birthday()
// and
var age = person.getAge()
// but we cannot access name! So it's encapsulated :)
  • This is called the module pattern (or a factory, but I don't think we use that name in this course).
  • Allows encapsulation. (name is not accessible; so therefore it is "private")

Event Loop

Asynchronous, Synchronous, Blocking, Non-blocking

Synchronous

  • Synchronous -> blocking.
    • Events will be executed one after the other, sequentially, in order.

Example with synchronous version of the readFile function:

// Here, the program waits until the file is read.
// Then the contents of the file are assigned to the `contents` variable.
var contents = fs.readFileSync("file.txt")

// This will now print the contents of the file:
console.log(contents)

Asynchronous

  • Asynchronous -> non-blocking.
    • Events will happen in parallel, and the order is not guaranteed.
    • Accepts callback functions that get called when the event is finished.

Example with asynchronous version of the readFile function:

var contents

// Here, the program does NOT wait until the file is read.
// The `fs.readFile` function returns *immediately*!
// Note how `readFile` accepts a callback - this is what gets called
// when it is finished reading.
fs.readFile("file.txt", function (err, fileContents) {
    // This function is run AFTER the file reading is done, some time in the future.
    // We don't know when.
    contents = fileContents
})

// At this point, the file reading is not done yet, so contents will still be empty!
console.log(contents)

The order in which the operations happen in this script are as follows:

  1. Line 30: fs.readFile
  2. Line 37: console.log
  3. Line 33: contents = fileContents

Functions

Functions can be declared in 2 different ways.

Function Declaration

  • Function declarations are hoisted.
    • Hoisted means that it is "pulled up" to the top of the current scope.
    • This means you can call it before it's declared.
sayHello('Kevin') // this works!

function sayHello(name) {
    console.log('Hello, ' + name)
}

Function Expression

  • Function expressions are functions which are assigned to a variable.
  • They are NOT hoisted.
    • This means you can not call it before it is declared.
sayHello('Kevin') // this will throw an error!

var sayHello = function (name) {
    console.log('Hello' + name)
}

Objects

Accessing properties

var person1 = {
    name: 'Kevin',
    age: 69,
    background: {
        nationality: 'Australian'
    }
}

// These are valid ways to access these objects' properties:

// The standard dot-notation
var name = person1.name
var age = person1.age
var nationality = person1.background.nationality


// Bracket notation
var name = person1['name']
// This is usually what it's used for:
var AGE_PROPERTY = 'age'
var age = person1[AGE_PROPERTY]

// A mix of both:
var nationality = person1['background'].nationality

Modules

This is a common trick question that appears in the exams.

Exporting a plain object

// Exporting a plain object.
// Any code that `requires` this will share the same object.
module.exports = {
    name: 'Kevin',
    age: 42
}
// Also valid, equivalent to above
module.exports.name = 'Kevin'
module.exports.age = 42

Exporting a function that returns an object

// Exporting a function that returns an object
// Any code that `requires` and calls this will
// get a NEW object every time.
module.exports = function () {
    return {
        name: 'Kevin',
        age: 42
    }
}

// Also watch out with this one, you need to require it like this:
var foo1 = require('foo')()
console.log(foo1.name) // prints 'Kevin'

// This is NOT valid and will return a function instead of an object
var foo2 = require('foo')
console.log(foo2.name) // undefined!

Express

Middlewares

var app = require('express')()

app.use(function (req, res, next) {
    console.log('first middleware!')

    // call the next middleware in the chain
    next()
})

app.use(function (req, res, next) {
    console.log('second middleware!')

    // call the next middleware in the chain
    next()
})

app.use(function (req, res, next) {
    console.log('third middleware!')

    // end the response
    res.end()
})

The code above illustrates a middleware chain.

  • Middlewares are declared by passing a callback function into app.use
  • Order of declaration of middlewares is important.
var app = require('express')()

app.get('/action', function (req, res) {
    console.log('action route')
    res.end()
})

app.post('/user', function (req, res) {
    console.log('user route')
    res.end()
})

// Now the following middleware will be called before a request
// is routed to any of the routes above.
app.use(function (req, res, next) {
    console.log('first middleware!')

    // call the next middleware in the chain
    // in this case, it goes to either
    // - the GET /action handler, or
    // - the POST /user handler
    next()
})

EJS vs Ajax

  • EJS is a templating language used in Express.
    • This allows the server to insert data dynamically into templates that are basically HTML.
    • This means data can be inserted before the webpage is returned to the browser.
  • Ajax is a way for webpages that are already loaded on the browser to make HTTP requests.
    • This means that existing webpages can make HTTP requests, then use those responses to insert new data into itself.
    • This also means more HTTP requests as the webpage first needs to be requested.

CSS

Cascading Swagsheets

Selectors

Descendant

main h1 {
    background-color: red;
}

This matches any h1 element that is a child, grandchild, great grandchild, etc of any main element.

<main>
    <h1>
        <!-- Matches, this h1 will have a red background -->
        Kevin loves croissants!
    </h1>
</main>

<main>
    <article>
        <h1>
            <!-- Matches, this h1 will have a red background -->
            Kevin loves croissants!
        </h1>
    </article>
</main>

Child

main > h1 {
    background-color: red;
}

This matches any h1 element that is a direct child of any main element.

<main>
    <h1>
        <!-- Matches, this h1 will have a red background -->
        Kevin loves croissants!
    </h1>
</main>

<main>
    <article>
        <h1>
            <!-- Does not match, this h1 will not have a red background -->
            Kevin loves croissants!
        </h1>
    </article>
</main>

Multiple Selectors

Don't get this confused with the other two. The key here is the comma.

main, h1 {
    background-color: red;
}

This matches any element that is a main or a h1.

<main>
    <h1>
        <!-- Matches, this h1 will have a red background -->
        Kevin loves croissants!
    </h1>
</main>

<main>
    <article>
        <h1>
            <!-- Matches, this h1 will have a red background -->
            Kevin loves croissants!
        </h1>
    </article>
</main>

<h1>
    <!-- Matches, this h1 will have a red background -->
    Kevin loves croissants!
</h1>

HTTP

Hypertext Transfer Protocol. Remember that HTTP version 1.1 is still the most widely used protocol.

URL

Anatomy of a URL

<protocol>://<hostname>:<port>/<path>?<query_params>

<protocol> required

  • http
  • https
  • ftp (probably don't need to know this one, also heaps more)

<hostname> required

  • localhost
  • google.com
  • tudelft.nl
  • cse1500.sendcroissants.me
  • really.long.and.nested.subdomains.co.uk

<port> optional

  • 80 (this is the default port when no port is specified)
  • 3000
  • 5000
  • ...and any other integer from 0 to 65535

<path> optional

  • login
  • calendar/january/31
  • ...it's a path. You know what a path is.

<query_params> optional

key=value pairs separated by &, comes after the ?. Usually used for sending data in a GET request since GET requests can't send content in the body.

  • username=kevin
  • username=kevin&token=fdfa8e7cc4b3
    • this is basically like sending this in the body:
      {
          "username":"kevin",
          "token":"fdfa8e7cc4b3"
      }
      

Examples

# Ordinary URL, note the <port> is missing, so it defaults to 80
https://google.com

# Pointing to computer's own address, note the port is specified as 3000
# Also note it has a query string with some data.
http://localhost:3000/register?username=kevin&password=yeet

Status Codes

Here I'll list the important ones you should know. For everything else, there is HTTP Cats.

200

The 200s are success codes. It means your GET request was successful, or your POST request was successful and a new account was created, etc.

  • 200 OK
  • 201 Created - usually after a POST

300

The 300s are all about redirection. It's still a success, just means that the resource has moved somewhere else.

  • 301 Moved permanently
  • 302 Found - usually a temporary redirect

400

The 400s are about bad requests. Anything 400 or higher is an error.

  • 400 Bad request
  • 401 Unauthorized - usually when you aren't logged in or you haven't supplied some Authorization header
  • 403 Forbidden - you're logged in/authenticated, but you don't have access (maybe the route is only for admins)
  • 404 Not found

500

The 500s are about server errors.

  • 500 Internal server error - some error occurred on the server.

Request Methods

Don't get tricked, remember these names! Some trick names they might use are UPDATE instead of PUT or REMOVE instead of DELETE. BE CAREFUL!!!

You should always think of requests as <method> <path>. These always go together. Example:

  • GET /users/42
  • POST /register
  • PUT /settings

GET

A GET request can not contain a body (you can't send some JSON with it) so it should only be used to retrieve data. HOWEVER! You can still send data in the query string. So technically a GET request can do everything the other methods can.

HEAD

A subset of GET. The request looks the same, but in the response, you only get the headers back, with no response body.

POST

Should be used for sending data to the server, because you can attach things to the request body: JSON, a file, etc.

PUT & PATCH

Should be used for updating data. You can attach stuff to the request body.

DELETE

Should be used for deleting data. You can attach stuff to the request body.

Security

CSRF, XSS, etc.

CSRF, XSS, etc

CSRF (Cross-site Request Forgery)

CSRF is when a malicious site uses your authenticated session to inject data to the server using your account. They key to remembering this is the word Forgery; like when you forged your mum's signature in high school so you could skip school and hang out in the city.

How to prevent CSRF attacks on your server/app

  • Make sure your sessions expire.
  • Reauthenticate your users often.
    • Example 1: ask them to login again from time to time
    • Example 2: add a CAPTCHA

XSS (Cross-site Scripting)

XSS is when a malicious site injects scripts to your server, but does not strictly need authenticated sessions.

Example: Users are able to post comments on the site. A malicious user posts a comment containing the following content:

<script>alert('lol')</script>

Once posted, the server displays the comment as it is, without sanitising it. Now when other users see this comment, they will get a rude message box saying "lol".

How to prevent XSS attacks on your server/app

  • Make sure any user-inputted data is sanitised/escaped.
    • When displaying user-inputted data such as comments, always sanitise inputs before rendering them.
    • ELI5: Sanitising means making the code into a plain string so that it can't be executed by a browser.

Indirect Secure Object Reference

This is, for example, when you are able to manipulate a URL to get access to another user's settings page with sensitive information.

For example:

  1. Your user settings page is at http://tudelft.nl/users/42/settings
  2. Then you try changing the URL to http://tudelft.nl/users/69/settings
  3. Surprisingly, you are able to see some other person's settings page and see their personal details such as home address, phone number, etc.
  4. This is indirect because there is no link that lets you do this, but you have to play around with the URL.
  5. This is supposed to be a secure object because it contains sensitive information like home address.
  6. The reference to this object is the user id (42 and 69).

How to prevent Indirect Secure Object Reference access

  • Protect your routes with authentication.
  • Don't use sequential numbers as IDs. For example, you could use a UUID that looks like 123e4567-e89b-12d3-a456-426655440000, which is random and unguessable.

Bonus: CSRF vs XSS

Quora: What is the difference between XSS and CSRF from their execution perspective?

DoS

DoS stands for Denial of Service. This is when an attacker prevents your server from receiving packets.

Some ways to DoS

  • Overload the server with so much traffic that it stops being able to process requests.
  • Block packets/requests from reaching the server.

Encoding vs Encryption

¡MUY IMPORTANTE!

Encoding is NOT the same as encryption. Don't get tricked!!!

Encryption DOES provide security.

Encoding DOES NOT provide security.

¡MUY IMPORTANTE!

Encoding

When you encode something, it is possible to decode it back easily. For example, you may encode some text containing Chinese characters into Base64 so that it can be sent over HTTP. This can then be decoded back on the other end easily. Therefore, it provides no security!

Encryption

When you encrypt something, it is either impossible to decrypt it or you will require a key to decrypt it.

Example 1: Passwords are usually encrypted with an algorithm like bcrypt, which means it cannot be decrypted back.

Example 2: When using HTTPS, data is encrypted before being sent. There is a public key and a private key. The private key is used to encrypt the data, then the public key can be used to decrypt the data.