Giter VIP home page Giter VIP logo

pegasus's Introduction

Pegasus

Documentation Status Build Status

About

a whiteboard collaboration app whose aim is to enable/facilitate realtime sharing of ideas in the form of components (for example: text, images, code, etc) that can be pieced together and edited by several people in a live session, and exported at any time.

At this point in time (v0.1.0), the only component available is text, along with the sidebar chat (which is available to everyone, edit privileges or not).

The plan is to add components, and features (like exporting the board as text instead of image), gradually, until the project reaches its initial purpose (stated above).

This project was part of the second edition of Learn IT, Girl, and would not have been possible without the continuous mentorship, support, and tolerance of 'newbie' questions courtesy of @daniel-j-h.

Rules, Installation, and Docs

All relevant info about that can be found here.

Contributing

This is something I built to learn, so you're welcome to do the same as well. Issues (everything I want to do next) are reported here but feel free to report new issues/improvements and if all looks good, work on them.

I added the Hacktoberfest label to some issues I think would be good for beginners (like me!) or generally more understandable (some of the other issues are missing context, I think) but again feel free to pick anything you want to work on and let me know.

What you have to do:

  • Fork the repo.
  • Create a branch. Work on it.
  • Create a PR here with all the details/reference to the issue it solves.

Here's a great article with more details for absolute beginners.

pegasus's People

Contributors

daniel-j-h avatar mariamrf avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar  avatar

pegasus's Issues

Argument parsing

Familiarize yourself with the argument parsing features in the argparse module.

Implement a small script that takes an IP address (with 127.0.0.1 as default) and a port (with 5000 as default). The script should be callable with

./arguments 127.0.0.1 5000

and

./arguments

printing both the IP address and the port and showing the help description when called with

./arguments -h

or

./arguments --help

Rationale: our server application needs to "bind" to a host and port (in this case localhost, and 5000 is arbitrary), so that we can access it inside the browser by means of http://127.0.0.1:5000.

Password hashing

Preamble

I will show how the current password set up might be not sufficient and how it can be improved. It's not a heavy bug but it somehow shows what could possibly go wrong when deploying web application and may help you to a rough idea how a security calculation may look like.

Problem description

Currently werkzeug's generate_password_hash is used to generate salted password hashes. This results in the following configuration:

  • Key derivation function: PBKDF2 (ref)
  • Hash algorithm: SHA1 (ref)
  • Iteration count: 1000 (ref)

Now let's assume that a uneducated user may only choose a alpha-numeric password of the length 8 which are 8 characters from the following set: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.

Now the main question is: how long does it take to recover a password from a salted hash? To do so, we first need to calculate how many hash operations are required on average to find a match (just by bruteforcing it, wordlist-based attacks may be even faster). This characters set for a simple password contains 62 characters and therefore there are 62^8 possible combinations. If you multiply this by the 1000 (because of the iteration count) and divide it by 2 (to calculate the number of hash operations you need to do on average to recover a password) you get ~1.09e17 required hash operations.

Now how long does it take to do that many hash operations? Take a look at oclhashcat. I'm kinda evil and assume that the attacker is equipped with a full-blown PC3 setup (which currently is "Ubuntu 14.04, 64 bit ForceWare 346.29, 8x NVidia Titan X, stock core clock, oclHashcat v1.36") and therefore can execute 37336 Mh/s (read: MegaHashes per second = 1000*1000 hashes per second). Doing the math this gives us ~2.92e6 seconds or <34 days.

Now why is this a problem? First of all, this is the current available hardware setup. In 1 or 2 years, this might be up to 5 times faster (pushing it down to <7 days). This is also the time you need to consider software is running and not updated (sad real world though). It may not sound like a huge deal to crack one single password of one single user of a whiteboard platform, but this password may be used for other more important websites as well. So imagine the following (artificial) example: A politician is using the whiteboard software and because he/she isn't that smart uses the same password as for the twitter account. Now the enemy party contracts a black hat hacker to break into the database which is used by Pegasus (this is mostly not your fault but may be a incompetent administrator or a zero day exploit) to crack the password and can use it to spread wrong information (like "all black people are bad!") right before the upcoming election. Even though the victim can claim that he/she got hacked, the effect on the election results will be huge.

Solution (for now)

generate_password_hash as a method parameter which can be used to tune the password hashing process. So the iteration count and the hash function can be exchanged. I would suggest the following:

  • Hash algorithm: sha512
  • Iteration count: 10'000 (slightly depending on your expected server load, but even 100'000 may work)

So the method parameter will be 'pbkdf2:sha512:10000'. That increases the average cracking time to 1.5 years.

Solution (for later)

The Secure Hash Algorithm (SHA) family was never designed to be a secure password hasher. Instead they should be fast, non-invertible, and collision free. That's why you need to run that many iterations of the same algorithm to get a nearly useable password hasher. Also the design of the SHA family allows them to be executed by GPUs and FPGAs (and that's the main problem here: you won't be able to crack the password that quickly by using a normal CPU). That this misuse of the SHA algorithms is a security problem got recognized some years ago and international experts start developing a new hash algorithm especially designed for hashing passwords (and other secrets). The result: argon2. There exist a semi-great Python wrapper which I also use for one of my projects in two variants (weak => not for passwords but other data, strong => for passwords).

Remove an Invited Email From Board

For the creator, add an option in the Invited Users modal to delete/remove an invited user entirely. Right now, they can only change a person's editing privileges.

Split functionality into modules

Currently you have all the "business logic" in the pegasus.py file. What you normally do is split logical parts into their own modules. For example views.py module for all of your views (functions that run on a specific route endpoint) and an errorhandlers.py module for custom error handlers. You then hoist your app in the __init__.py file, import both modules and register them with your Flask app like this:

routes = [
    ('/', views.index, ['GET', 'POST']),
    ...]

for rule, view, methods in routes:
    app.add_url_rule(rule, view_func=view, methods=methods)

handlers = [
    (400, errorhandlers.bad_request),
    (401, errorhandlers.unauthorized),
    (404, errorhandlers.page_not_found),
    (403, errorhandlers.page_forbidden),
    (410, errorhandlers.page_gone),
    (500, errorhandlers.not_found),
]

for errno, handler in handlers:
    app.register_error_handler(errno, handler)

The logical structure can be something similar to: views.py for all of your view functions, models.py for classes that abstract away entities and how you store and query them in your database, and then other modules as needs be, e.g. a decorators.py with helpers such as http://flask.pocoo.org/docs/0.10/patterns/viewdecorators/#templating-decorator (good time to learn about decorators!).

Your view.py then could look similar to this:

@templated('index.html')
def index():
    return dict(userName='someUser')

Virtual environment

Read up about pyvenv and its predecessor virtualenv.

Then create a local "isolated sandbox" for this project, e.g. .env (and put it on the .gitignore since we do not want the environment to be indexed by Git; while we're at it, read up about why putting *.py[cod] files on the gitignore is a good idea, too):

pyvenv-3.4 .env

(It could be that you have to install a package from your Ubuntu package manager for that like python3-virtualenv)

Now every time you start a new shell and want to work on this project, you "activate" the local environment via:

. .env/bin/activate

(read up on bash and what the . (source) operator does).

Your prompt should now look like:

(.env) daniel@x1c /t/app>

signalling that you are "inside" that local environment. Why is this useful? Imagine having several projects, with each one depending on a different version of say Flask. If you install dependencies globally, you would have a bad time. Local environments solve this by keeping dependencies local to the project.

Now read up about Python's package manager pip (already comes with pyvenv), and install Flask into your local environment:

(.env) daniel@x1c /t/app> pip install flask

Github Issues as Tasks

Let's use Github issues / tickets as tasks. You can close an issue if it's no longer actionable / resolved.

Feel free to create a few meaningful labels and maybe some milestones. Also feel free to create tickets yourself for tasks you want to work on later or are up for discussion.

Separate the front-end js in the show-board.html file

Some of the JavaScript logic in the show-board page is inline, and it needs to be separated into another file. The thing is, though, some of the variables in the JS are rendered as part of the template, so those need to be put into consideration while moving the code.

FYI: There's an existing dependency - JSGlue - that already helps with rendering the urls and is included in the layout everywhere.

Optional: learn about SQLAlchemy

Currently you hard-code SQL query strings (as prepared statements, ๐Ÿ‘ for that) and you're using the sqlite module to work with your database.

There is this really neat abstraction layer called SQLAlchemy that let's you define your models (e.g. a User class) and then you get a Python interface for inserting them into a database, modifying, querying them, and more.

This has the benefit that 1/ you are no longer bound to SQLite but later you could use PostgreSQL (or even Oracle..) by simply changing a single line (the db connection string) and 2/ you don't have to hard code the SQL query strings.

Take a look at the wonderful Quickstart section here: http://flask-sqlalchemy.pocoo.org

Using SQLAlchemy is optional since it's not strictly needed, but most Flask apps with a database layer use it for convenience. And once you learned a bit about SQLAlchemy you can use it in other projects that have nothing to do with web apps, too! For example, I used it yesterday to store and cache reviews on disk. This is the model for it:

https://github.com/daniel-j-h/classyshoes/blob/ec2c574fc718e3978aa5cb86022544d18347b569/classyshoes/db.py

and here is how you can query all reviews then:

https://github.com/daniel-j-h/classyshoes/blob/ec2c574fc718e3978aa5cb86022544d18347b569/classyshoes/semantics.py#L44

(Come to think of it maybe take a look at the project itself to see a few tricks you can re-use here. It should be readable and only a few hours of work went into it, so it should be still small enough)

If you take a look at the SQLAlchemy docs or the Quickstart section above you can see there are ways to filter, join, group and limit --- these Python functions simply generate SQL for the database you connect to, so you still have to know SQL to use and understand it :P.

Implement an HTTP Server

Take a look at Python's http.server/http.cookie and implement a small HTTP server, preferably configurable from the command line using argparse.

Optimize for Mobile/Touch Devices

  • Doubletap/dblclick events (to edit text for example) are not working (well) on mobile. TRIED: jQuery Finger. Did not go as planned.
  • Top menu for owner needs to be in an offcanvas menu/list.
  • As positions of elements are in pixels from top/left, elements appear differently on different screen sizes. Convert to a relative unit.
  • Save image as.

Ground Zero

  • Sketch a general look for the UI/the main template.
  • Create a directory for the app (inside the current directory) with basic functionality (db schema per the doc, home page, login)
  • Create the templates for the basic views (profile, board, new board)

Custom Context Manager

Implement your own context manager as an example for timing commands:
Entering the scope sets a variable t0 = now(), leaving the scope prints now() - t0.

Finish the basic text chat app

  • Edit profile and board info (title, done_at) for the user/creator.
  • Chat box only available for people who can participate (creators + users with an 'edit' invite)
  • List of boards a user has been invited to.
  • Real-time messaging in the board through a polling solution (recursive/timed ajax GET request for the board contents/chat bits).

Non-Implementation Tasks

  • Documentation: read up on docstrings, maybe you can get ReadTheDocs
    integration to work
  • Unit tests: investigate how to test your backend business logic
  • Interface tests: investigate in techniques to test the UI
  • Continuous Integration: Travis CI is pretty good, maybe let tests ^
    automatically run there
  • "Marketing": polish up the Readme **and the docstring structure,**what this project tries to solve, and at the end how to get started with it (db setup? installing requirements?
    Maybe create a Github Page for the project (either pushing to gh-pages
    branch or more easily use the generator at Repo. -> Settings -> Github
    pages).
  • Landing page for the project.
  • Get the project deployed on Red Hat's OpenShift (or Heroku,
    ...)

Simple Flask App

Follow the Flask quickstart docs, and create a simple app in flask, making use of routing, and Jinja2 templates, as a stepping stone towards the actual project.

Learn about httpie

Now is also the perfect time to learn some basic tools such as: wget,
curl, httpie, e.g. to see only the response headers without the actual
content you can do:

wget -S --spider localhost:5000

(read the wget manual via "man wget")

wget and curl are usually installed by default on almost all
distributions, but they are also quite old (alomost 20 years for curl)
and not intuitive to use. There is httpie (Ubuntu package is called
httpie but installs a binary called http) which is more user friendly
and has great documentation.

If you provide custom error handler, provide them for all meaningful errors

Currently you only provide a custom error handler for error code 401 (ref). It makes sense to provide custom error handlers for the errors outlined in #10.

You can define handlers like this (with a corresponding template):

def page_not_found(e):
    return render_template('errorhandler.html', errorcode=404, errormessage='Not Found'), 404

(see the docs about what you have to return)

or encapsulate it into a function and then dispatch to it from your error handlers:

def render_error(errorcode, errormessage):
    return render_template('errorhandler.html', errorcode=errorcode, errormessage=errormessage), errorcode


def not_found(e):
    return render_error(500, 'Internal Error')

def unauthorized(e):
    flash('Unauthorized!', 'warning')
    return redirect(url_for('login'))

(the last one is to show you that you don't have to return an error code every time)

Docs for the front-end work

Docs currently available only cover the backend functions, but not the front-end architecture, which is an integral part of this project, so the currently available docs need to be edited to include the js logic. Everything should be explained in the code comments, though.

Tuples

Learn about Python's tuples, then take a look at collections.namedtuple, play around with it, and think about why, when, and how to use a namedtuple over a plain one.

Wrap SQL Code in Context Manager

"wrap your SQL code in a contextmanager which encloses your code and calls "commit" at the end or "rollback" on error (in which case you can e.g. catch the exception and "flash" the user a warning based on the exception type)."
Ref.

Properly append scripts to baselayout scripts section

Currently your layout template contains a scripts section:

https://github.com/blaringsilence/pegasus/blob/c48fe1e5577116f0d88e2b51451afb05ebc05b69/pegasus/templates/layout.html#L98-L102

but your register template simply puts the script behind its form:

https://github.com/blaringsilence/pegasus/blob/c48fe1e5577116f0d88e2b51451afb05ebc05b69/pegasus/templates/register.html#L30-L106

The following allows you do do what you intended. In your layout, wrap everything script related in a Jinja2 block at the end of the document, let's name it "scripts":

{% block scripts %}
..
{% endblock scripts %}

In templates inheriting from layout (e.g. the register template) put scripts in a separate block (name it "scripts" here, too) and then call the super() function.

{% block scripts %}
{{ super() }}
...
{% endblock scripts %}

This makes sure you first get all the scripts from the layout template at the end of of your document, and then you get the scripts from the register template appended.

(By the way, you can do the same for other logical sections in your layout html when it could make sense for a inheriting template to customize or append something to it, e.g. a css block in case only specific templates need some css)

Confirm Email Before Participating Without Invite Code

Right now, if someone is invited to a board, they can access it either through the invite link or through any account with the email invited. To solve this, only give access to board to the person who created it, anyone with the appropriate invite link, and anyone logged in, on the invite list, and their email has been confirmed.

Ability to Add, Edit, & Position Text Elements on The Board

  • Add new text elements, store them to the database, make them draggable.
  • Sanitize text/don't allow HTML.
  • Save positions on "stop" (of drag) and update them in everyone's sessions accordingly.
  • group "get" function to 1) Query all changes since update_date of last fetched element. 2) Update DOM according to "type" of board_content object.
  • Divide api board_component function into smaller functions (one for GET, one or several for POST)
  • Ability to edit text.
  • Ability to delete it.
  • Ability to re-initialize all elements based on type and position.
  • Reset permissions so that everyone can access the chat but only edit-level permissions and higher (owner) can access the canvas.
  • Lock/Unlock board while someone is editing it/after they're done/certain timeout. (maybe adjust the timeout/remove it later so only people who are online, with permission and with an edit request/are actively editing can lock the board)
  • Allow user control over some layout settings (font size, etc)
  • Change how textareas look (create and edit)

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.