Giter Club home page Giter Club logo

nitro-server's People

Contributors

consindo avatar stayradiated avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

nitro-server's Issues

Seperate sockets/routes from the rest of the app.

Sockets, Routes

- init.coffee
- controllers/
  - router.coffee
  - socket.coffee
  - validation.coffee
- routes/*.coffee

Sync, Users, Database

- controllers/
  - auth.coffee
  - connect.coffee
  - query.coffee
  - sync.coffee
  - table.coffee
  - users.coffee
- database/*.coffee
- models/*.coffee

Directory Structure

  • core/
    • index.coffee
    • config.coffee
    • server/
      • index.coffee
      • routes/
        • *.coffee
      • controllers/
        • router.coffee
        • socket.coffee
        • validation.coffee
    • app/
      • index.coffee
      • tables/
        • *.coffee
      • controllers/
        • auth.coffee
        • redis.coffee?
        • db.coffee
        • sync.coffee
        • users.coffee
      • models/
        • user.coffee

DRY up sync.coffee

It's currently very repetitive, but can be cut down by replacing duplicate code with functions.

Refactor the database

Instead of compressing tasks into a single blob, we should store them in a table called 'tasks'.

Fuzz Testing Bugs

These are the bugs found using test/fuzz.coffee.

  • Models can be created with an id of 'undefined'.
    Solution: make id a required property using xType.
  • Trying to destroy a list that has not got the tasks array set causes the server to crash.
    Solution: Make tasks a required property.
  • Creates models with non-server IDs
    Solution: Delete changes.id in sync.update.
  • Allows prefs to be created. Should only allow changes made to s0.
  • Lists can be created with a tasks property that contains task IDs that don't exist.
    Solution: Don't allow user to set tasks property that contains different contents.
  • Tasks can have listID set to a list ID that doesn't exist.
    Solution: return unless listID can be matched to a list.
  • Destroy a list that is already deleted causes the server to crash because it can't read from the tasks array.
    Solution: Check that the model exists and hasn't been deleted before doing anything else.
  • Updating task.listId creates a new list with that id (if one doesn't already exist).
  • Inbox list can be destroyed.

Organizing Tasks and Lists

Problem

When a task is created on the client, two messages are sent to the server: list.update and task.create.

list.update({
  "id": "inbox",
  "tasks": [
     "c0"
  ]
},{
  "tasks": 1390074290378
})

task.create({
  "id": "c0",
  "listId": "inbox",
  "date": 0,
  "name": "This is a new task",
  "notes": "",
  "priority": 1,
  "completed": 0
}, 1390074290379).fn(2)

The server then stores the following.

{
  "data_task": {
    "s1": {
      "id": "s1",
      "listId": "inbox",
      "date": 0,
      "name": "This is a new task",
      "notes": "",
      "priority": 1,
      "completed": 0
    }
  },
  "data_list": {
    "inbox": {
      "name": "Inbox",
      "tasks": [
        "c0",
        "s1"
      ],
      "id": "inbox"
    }
  }
}

See the problem? The inbox list has two tasks assigned to it: "c0" and "s1". But "c0" doesn't even exist!

Possible Solution 1

Whenever a list is created or updated, we loop through the tasks array and throw array any IDs that don't exist on the server.

  1. The client sends the list.update message.
  2. Server inspects the tasks property and deletes "c0" property.
  3. The client sends the task.create message.
  4. Server adds task ID to the tasks array.

Possible Solution 2

  1. The client sends the task.create message first, and then waits for the server to return the server ID.
  2. The server will automatically add the task into the list.
  3. The client will then add the task into the list, and send the list.update event.
  4. The server will then magically merge the tasks property.

Keeping Order

One of the features on the client is that you can sort tasks in order you want. We need to be able to keep this order on the server.

All The Solutions

So I think the best thing to do is just let the server manage the tasks array for each list.

Creating a task

The task.create event requires you send id and listId. The server can then check that listId exists, and will add the task id to it.

Moving a task between lists

Use task.update and set the listId to the new list id. The server can remove the task id from the old list and add it to the new one.

Destroying a task

Use task.destroy. The server can remove the task id from the list it was in.

Reordering a task

Send list.update with the tasks array.

The server willl throw array any tasks that don't exist on the server and add the tasks that aren't included. Then it will merge the order with the existing tasks array.

Deleting a list throws a foreign key constraint error

Error: ER_ROW_IS_REFERENCED_.
Cannot delete or update a parent row: a foreign key constraint fails .

SQL used to delete a list:

delete from `list` where `id` = 1

Constraint that causes the error:

Nitro.list_tasks,
CONSTRAINT `list_tasks_listid_foreign`
FOREIGN KEY (`listId`) REFERENCES `list` (`id`)

Optimize database writing

At the moment whenever anything on a user is changed, the entire user is written to the database. This can be greatly improved.

However we currently use lodash.throttle to limit writes to once per 5 seconds, so the database doesn't get thrashed during syncing. During this we lose the ability to pass arguments to the write method.

Somehow we need to keep a track of the attributes that changed between writes. So my plan is to modify lodash.throttle and keep a list of arguments that are passed to it, and then pass them all as an array to the actual write method.

Compensate for timezones

This is probably really important when dealing with realtime sync.

No idea how to implement it though.

Maybe ask the client to set their location, or somehow automatically detect which timezone they are in?

Also need to pick a timezone for the server, so we can convert it all that to do checking.

Auto Refresh is Broken

Not only is auto refresh broken, the soft reload (ui.reload is broken).
This is really important.

Rewrite websockets and sync to use SockJS

https://github.com/sockjs/sockjs-node

Should make everything faster and more secure.

Also have a new plan on how to do authentication:

  1. Client connects to server
  2. Client immediately sends a login token to the server
  3. Server starts to validate the login token
  4. Server will ignore any further messages sent by the client until the client has been authenticated
  5. If the client has not got a valid login token, then reply with an error message and kick the client
  6. If the client is valid, then return with a success message and start listening to their messages

Improve Security

  • Use login tickets that store user ids, timestamps and IP addresses as well as a secure token. http://lucumr.pocoo.org/2012/9/24/websockets-101/
  • The client must request a login ticket before connecting with websockets. Then the client sends the ticket over the socket, and the server validates it and then deletes the ticket.
  • This means we would need to store a persistent cookie. Must use HttpOnly and secure flags.
  • Hash persistant login tokens so that a database breach doesn't allow an attacker to login to any account.
  • [ ] Increase password reset tokens to at least 42 characters long.
  • [ ] Hash password reset tokens (same reason as with login tokens).
  • Use signed session tokens for authentication, like how Auth0 reccommends.
  • Generate password reset tokens by hashing known variables. Like how Ghost does it.
  • Use NewBase64 encoding for tokens instead of hex - 4x as many variants per char.
  • Rewrite part of nitro-rails to use nitro-server as an api for managing user information.
  • Throttle logins and password resets to follow OWASP best practices:
    1 failed attempt = 5 sec delay
    2 failed attempts = 15 sec delay
    3+ failed attempts = 45 sec delay

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.