├── .gitignore ├── setup.cfg ├── docs ├── _themes │ ├── flask │ │ ├── theme.conf │ │ ├── layout.html │ │ ├── relations.html │ │ └── static │ │ │ ├── small_flask.css │ │ │ └── flasky.css_t │ ├── flask_small │ │ ├── theme.conf │ │ ├── layout.html │ │ └── static │ │ │ └── flasky.css_t │ ├── README │ ├── LICENSE │ └── flask_theme_support.py ├── index.rst ├── Makefile └── conf.py ├── LICENSE.txt ├── setup.py ├── test_hashing.py ├── README.md └── flask_hashing.py /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | *.pyc 3 | build/ 4 | dist/ 5 | *.egg-info/ 6 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.md 3 | 4 | [upload_docs] 5 | upload-dir = docs/_build/html 6 | -------------------------------------------------------------------------------- /docs/_themes/flask/theme.conf: -------------------------------------------------------------------------------- 1 | [theme] 2 | inherit = basic 3 | stylesheet = flasky.css 4 | pygments_style = flask_theme_support.FlaskyStyle 5 | 6 | [options] 7 | touch_icon = 8 | -------------------------------------------------------------------------------- /docs/_themes/flask_small/theme.conf: -------------------------------------------------------------------------------- 1 | [theme] 2 | inherit = basic 3 | stylesheet = flasky.css 4 | nosidebar = true 5 | pygments_style = flask_theme_support.FlaskyStyle 6 | 7 | [options] 8 | index_logo = '' 9 | index_logo_height = 120px 10 | github_fork = '' 11 | -------------------------------------------------------------------------------- /docs/_themes/flask/layout.html: -------------------------------------------------------------------------------- 1 | {%- extends "basic/layout.html" %} 2 | {%- block extrahead %} 3 | {{ super() }} 4 | {% if theme_touch_icon %} 5 | 6 | {% endif %} 7 | 9 | {% endblock %} 10 | {%- block relbar2 %}{% endblock %} 11 | {%- block footer %} 12 |
16 | {%- endblock %} 17 | -------------------------------------------------------------------------------- /docs/_themes/flask/relations.html: -------------------------------------------------------------------------------- 1 |
19 | {% endif %}
20 | {% endblock %}
21 | {% block sidebar1 %}{% endblock %}
22 | {% block sidebar2 %}{% endblock %}
23 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Sean Beck
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/docs/_themes/README:
--------------------------------------------------------------------------------
1 | Flask Sphinx Styles
2 | ===================
3 |
4 | This repository contains sphinx styles for Flask and Flask related
5 | projects. To use this style in your Sphinx documentation, follow
6 | this guide:
7 |
8 | 1. put this folder as _themes into your docs folder. Alternatively
9 | you can also use git submodules to check out the contents there.
10 | 2. add this to your conf.py:
11 |
12 | sys.path.append(os.path.abspath('_themes'))
13 | html_theme_path = ['_themes']
14 | html_theme = 'flask'
15 |
16 | The following themes exist:
17 |
18 | - 'flask' - the standard flask documentation theme for large
19 | projects
20 | - 'flask_small' - small one-page theme. Intended to be used by
21 | very small addon libraries for flask.
22 |
23 | The following options exist for the flask_small theme:
24 |
25 | [options]
26 | index_logo = '' filename of a picture in _static
27 | to be used as replacement for the
28 | h1 in the index.rst file.
29 | index_logo_height = 120px height of the index logo
30 | github_fork = '' repository name on github for the
31 | "fork me" badge
32 |
--------------------------------------------------------------------------------
/docs/_themes/flask/static/small_flask.css:
--------------------------------------------------------------------------------
1 | /*
2 | * small_flask.css_t
3 | * ~~~~~~~~~~~~~~~~~
4 | *
5 | * :copyright: Copyright 2010 by Armin Ronacher.
6 | * :license: Flask Design License, see LICENSE for details.
7 | */
8 |
9 | body {
10 | margin: 0;
11 | padding: 20px 30px;
12 | }
13 |
14 | div.documentwrapper {
15 | float: none;
16 | background: white;
17 | }
18 |
19 | div.sphinxsidebar {
20 | display: block;
21 | float: none;
22 | width: 102.5%;
23 | margin: 50px -30px -20px -30px;
24 | padding: 10px 20px;
25 | background: #333;
26 | color: white;
27 | }
28 |
29 | div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p,
30 | div.sphinxsidebar h3 a {
31 | color: white;
32 | }
33 |
34 | div.sphinxsidebar a {
35 | color: #aaa;
36 | }
37 |
38 | div.sphinxsidebar p.logo {
39 | display: none;
40 | }
41 |
42 | div.document {
43 | width: 100%;
44 | margin: 0;
45 | }
46 |
47 | div.related {
48 | display: block;
49 | margin: 0;
50 | padding: 10px 0 20px 0;
51 | }
52 |
53 | div.related ul,
54 | div.related ul li {
55 | margin: 0;
56 | padding: 0;
57 | }
58 |
59 | div.footer {
60 | display: none;
61 | }
62 |
63 | div.bodywrapper {
64 | margin: 0;
65 | }
66 |
67 | div.body {
68 | min-height: 0;
69 | padding: 0;
70 | }
71 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | Flask-Hashing
2 | ==============
3 |
4 | .. module:: flask.ext.hashing
5 |
6 | Flask-Hashing is a Flask extension that provides an easy way to
7 | hash data and check a hash of a value against a given hash.
8 | Flask-Hashing uses `hashlib` to actually hash data.
9 |
10 | The main use case for hashing in web applications is for user
11 | passwords. But because an application may have a different need
12 | for a hash function, this extension's naming choices are not
13 | password-specific.
14 |
15 | Installation
16 | ------------
17 |
18 | Install Flask-Hashing with either of the following commands:::
19 |
20 | $ easy_install flask-hashing
21 | $ pip install flask-hashing
22 |
23 | Usage
24 | -----
25 |
26 | Initialize the extension as follows:::
27 |
28 | from flask import Flask
29 | from flask.ext.hashing import Hashing
30 |
31 | app = Flask(__name__)
32 | hashing = Hashing(app)
33 |
34 | After creating an instance of `Hashing`, we can hash data and
35 | check hashes of data as follows:::
36 |
37 | h = hashing.hash_value('secretdata', salt='abcd')
38 | if hashing.check_value(h, 'secretdata', salt='abcd'):
39 | # do some stuff because the hashes are equal
40 |
41 | And that is all there is to it!
42 |
43 | API
44 | ---
45 |
46 | .. autoclass:: flask.ext.hashing.Hashing
47 | :members:
48 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | """
2 | Flask-Hashing
3 | -------------
4 |
5 | This is a Flask extension that provides utility functions
6 | for hashing data within a Flask application.
7 |
8 | Flask-Bcrypt restricts you to using bcrypt. What if you want
9 | to use a different hash function? This extension provides access
10 | to other commonly used hash functions such as SHA256.
11 |
12 | Links
13 | -----
14 |
15 |
16 | """
17 | from setuptools import setup
18 |
19 |
20 | setup(
21 | name='Flask-Hashing',
22 | version='1.1',
23 | url='https://github.com/ThaWeatherman/flask-hashing',
24 | license='MIT',
25 | author='Sean Beck',
26 | author_email='seanmckaybeck@gmail.com',
27 | description='Easy hashing of data in Flask',
28 | long_description=__doc__,
29 | py_modules=['flask_hashing'],
30 | zip_safe=False,
31 | include_package_data=True,
32 | platforms='any',
33 | install_requires=[
34 | 'Flask'
35 | ],
36 | classifiers=[
37 | 'Environment :: Web Environment',
38 | 'Intended Audience :: Developers',
39 | 'License :: OSI Approved :: MIT License',
40 | 'Operating System :: OS Independent',
41 | 'Programming Language :: Python',
42 | 'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
43 | 'Topic :: Software Development :: Libraries :: Python Modules'
44 | ],
45 | test_suite='test_hashing'
46 | )
47 |
--------------------------------------------------------------------------------
/test_hashing.py:
--------------------------------------------------------------------------------
1 | import unittest
2 |
3 | from flask import Flask
4 | from flask.ext.hashing import Hashing
5 |
6 | class MyTest(unittest.TestCase):
7 | def setUp(self):
8 | self.app = Flask(__name__)
9 | self.app.config['HASHING_METHOD'] = 'sha256'
10 | self.h = Hashing(self.app)
11 |
12 | def test_hash_capability(self):
13 | val = 'somethingsecret'
14 | salt = 'abcd'
15 | valhash = self.h.hash_value(val, salt)
16 | self.assertTrue(self.h.check_value(valhash, val, salt))
17 | self.assertFalse(self.h.check_value(valhash, val, 'efgh'))
18 | self.assertFalse(self.h.check_value(valhash, val+'poop', salt))
19 |
20 | def test_multiple_rounds(self):
21 | self.app.config['HASHING_ROUNDS'] = 5
22 | self.h = Hashing(self.app)
23 | self.test_hash_capability()
24 |
25 | def test_different_algorithm(self):
26 | self.app.config['HASHING_METHOD'] = 'md5'
27 | self.h = Hashing(self.app)
28 | self.test_hash_capability()
29 |
30 | def test_rounds_not_int(self):
31 | self.app.config['HASHING_ROUNDS'] = 'notanint'
32 | self.assertRaises(TypeError, Hashing().init_app, self.app)
33 | self.app.config['HASHING_ROUNDS'] = 1
34 |
35 | def test_algorithm_not_valid(self):
36 | self.app.config['HASHING_METHOD'] = 'notahashalgorithm'
37 | self.assertRaises(ValueError, Hashing().init_app, self.app)
38 |
39 |
40 | if __name__ == '__main__':
41 | unittest.main()
42 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Flask-Hashing
2 |
3 | Flask-Hashing is a Flask extension that provides an easy way to
4 | hash data and check a hash of a value against a given hash.
5 | Flask-Hashing uses `hashlib` to actually hash data.
6 |
7 | This extension prevents the user from needing to worry about how
8 | to hash data. Instead, developers are provided a simple call to
9 | do any necessary hashing of data.
10 |
11 | This extension is intended to be used in place of Flask-Bcrypt,
12 | if the user so desires. Not everyone may want to use `bcrypt`
13 | for their hashing needs, and this provides a way to handle that
14 | use case.
15 |
16 | ## Installation
17 |
18 | ```
19 | $ pip install flask-hashing
20 | ```
21 |
22 | or if you don't have `pip`:
23 |
24 | ```
25 | $ easy_install flask-hashing
26 | ```
27 |
28 | ## Usage
29 |
30 | ```
31 | from flask import Flask
32 | from flask.ext.hashing import Hashing
33 |
34 | app = Flask(__name__)
35 | hashing = Hashing(app)
36 | ```
37 |
38 | After creating an instance of `Hashing`, we can hash data and
39 | check hashes of data as follows:
40 |
41 | ```
42 | h = hashing.hash_value('secretdata', salt='abcd')
43 | if hashing.check_value(h, 'secretdata', salt='abcd'):
44 | # do some stuff because the hashes are equal
45 | ```
46 |
47 | ## Tests
48 |
49 | Run
50 |
51 | ```
52 | $ python setup.py test
53 | ```
54 |
55 | or
56 |
57 | ```
58 | $ python test_hashing.py
59 | ```
60 |
61 | ## Documentation
62 |
63 | Install `sphinx` then in the `docs` directory run `make html`.
64 |
65 | You can see a live copy of the docs at [Read the Docs](http://flask-hashing.readthedocs.org/en/latest/).
66 |
--------------------------------------------------------------------------------
/docs/_themes/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2010 by Armin Ronacher.
2 |
3 | Some rights reserved.
4 |
5 | Redistribution and use in source and binary forms of the theme, with or
6 | without modification, are permitted provided that the following conditions
7 | are met:
8 |
9 | * Redistributions of source code must retain the above copyright
10 | notice, this list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above
13 | copyright notice, this list of conditions and the following
14 | disclaimer in the documentation and/or other materials provided
15 | with the distribution.
16 |
17 | * The names of the contributors may not be used to endorse or
18 | promote products derived from this software without specific
19 | prior written permission.
20 |
21 | We kindly ask you to only use these themes in an unmodified manner just
22 | for Flask and Flask-related products, not for unrelated projects. If you
23 | like the visual style and want to use it for your own projects, please
24 | consider making some larger changes to the themes (such as changing
25 | font faces, sizes, colors or margins).
26 |
27 | THIS THEME IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 | ARISING IN ANY WAY OUT OF THE USE OF THIS THEME, EVEN IF ADVISED OF THE
37 | POSSIBILITY OF SUCH DAMAGE.
38 |
--------------------------------------------------------------------------------
/docs/_themes/flask_theme_support.py:
--------------------------------------------------------------------------------
1 | # flasky extensions. flasky pygments style based on tango style
2 | from pygments.style import Style
3 | from pygments.token import Keyword, Name, Comment, String, Error, \
4 | Number, Operator, Generic, Whitespace, Punctuation, Other, Literal
5 |
6 |
7 | class FlaskyStyle(Style):
8 | background_color = "#f8f8f8"
9 | default_style = ""
10 |
11 | styles = {
12 | # No corresponding class for the following:
13 | #Text: "", # class: ''
14 | Whitespace: "underline #f8f8f8", # class: 'w'
15 | Error: "#a40000 border:#ef2929", # class: 'err'
16 | Other: "#000000", # class 'x'
17 |
18 | Comment: "italic #8f5902", # class: 'c'
19 | Comment.Preproc: "noitalic", # class: 'cp'
20 |
21 | Keyword: "bold #004461", # class: 'k'
22 | Keyword.Constant: "bold #004461", # class: 'kc'
23 | Keyword.Declaration: "bold #004461", # class: 'kd'
24 | Keyword.Namespace: "bold #004461", # class: 'kn'
25 | Keyword.Pseudo: "bold #004461", # class: 'kp'
26 | Keyword.Reserved: "bold #004461", # class: 'kr'
27 | Keyword.Type: "bold #004461", # class: 'kt'
28 |
29 | Operator: "#582800", # class: 'o'
30 | Operator.Word: "bold #004461", # class: 'ow' - like keywords
31 |
32 | Punctuation: "bold #000000", # class: 'p'
33 |
34 | # because special names such as Name.Class, Name.Function, etc.
35 | # are not recognized as such later in the parsing, we choose them
36 | # to look the same as ordinary variables.
37 | Name: "#000000", # class: 'n'
38 | Name.Attribute: "#c4a000", # class: 'na' - to be revised
39 | Name.Builtin: "#004461", # class: 'nb'
40 | Name.Builtin.Pseudo: "#3465a4", # class: 'bp'
41 | Name.Class: "#000000", # class: 'nc' - to be revised
42 | Name.Constant: "#000000", # class: 'no' - to be revised
43 | Name.Decorator: "#888", # class: 'nd' - to be revised
44 | Name.Entity: "#ce5c00", # class: 'ni'
45 | Name.Exception: "bold #cc0000", # class: 'ne'
46 | Name.Function: "#000000", # class: 'nf'
47 | Name.Property: "#000000", # class: 'py'
48 | Name.Label: "#f57900", # class: 'nl'
49 | Name.Namespace: "#000000", # class: 'nn' - to be revised
50 | Name.Other: "#000000", # class: 'nx'
51 | Name.Tag: "bold #004461", # class: 'nt' - like a keyword
52 | Name.Variable: "#000000", # class: 'nv' - to be revised
53 | Name.Variable.Class: "#000000", # class: 'vc' - to be revised
54 | Name.Variable.Global: "#000000", # class: 'vg' - to be revised
55 | Name.Variable.Instance: "#000000", # class: 'vi' - to be revised
56 |
57 | Number: "#990000", # class: 'm'
58 |
59 | Literal: "#000000", # class: 'l'
60 | Literal.Date: "#000000", # class: 'ld'
61 |
62 | String: "#4e9a06", # class: 's'
63 | String.Backtick: "#4e9a06", # class: 'sb'
64 | String.Char: "#4e9a06", # class: 'sc'
65 | String.Doc: "italic #8f5902", # class: 'sd' - like a comment
66 | String.Double: "#4e9a06", # class: 's2'
67 | String.Escape: "#4e9a06", # class: 'se'
68 | String.Heredoc: "#4e9a06", # class: 'sh'
69 | String.Interpol: "#4e9a06", # class: 'si'
70 | String.Other: "#4e9a06", # class: 'sx'
71 | String.Regex: "#4e9a06", # class: 'sr'
72 | String.Single: "#4e9a06", # class: 's1'
73 | String.Symbol: "#4e9a06", # class: 'ss'
74 |
75 | Generic: "#000000", # class: 'g'
76 | Generic.Deleted: "#a40000", # class: 'gd'
77 | Generic.Emph: "italic #000000", # class: 'ge'
78 | Generic.Error: "#ef2929", # class: 'gr'
79 | Generic.Heading: "bold #000080", # class: 'gh'
80 | Generic.Inserted: "#00A000", # class: 'gi'
81 | Generic.Output: "#888", # class: 'go'
82 | Generic.Prompt: "#745334", # class: 'gp'
83 | Generic.Strong: "bold #000000", # class: 'gs'
84 | Generic.Subheading: "bold #800080", # class: 'gu'
85 | Generic.Traceback: "bold #a40000", # class: 'gt'
86 | }
87 |
--------------------------------------------------------------------------------
/flask_hashing.py:
--------------------------------------------------------------------------------
1 | '''
2 | Flask-Hashing
3 | -------------
4 |
5 | An extension providing easy hashing using the ``hashlib`` module.
6 | '''
7 | import hashlib
8 | try:
9 | from hashlib import algorithms as algs
10 | except ImportError:
11 | from hashlib import algorithms_available as algs
12 | from sys import version_info
13 |
14 |
15 | VER = version_info[0]
16 |
17 |
18 | class Hashing(object):
19 | '''An extension that provides easy hashing and comparing of hashes to a
20 | Flask application. This extension uses the standard library ``hashlib``
21 | to allow access to any available hash functions on the system via OpenSSL,
22 | depending on your version of Python in use.
23 | The ``hashlib`` module guarantees access to ``md5``, ``sha1``, ``sha224``,
24 | ``sha256``, ``sha384``, and ``sha512``.
25 |
26 | To begin using this extension you must first wrap the application.::
27 |
28 | from flask import Flask
29 | from flask.ext.hashing import Hashing
30 |
31 | app = Flask(__name__)
32 | hashing = Hashing(app)
33 |
34 | If you prefer to use the factory pattern you can also use :class: as follows:::
35 |
36 | from flask import Flask
37 | from flask.ext.hashing import Hashing
38 |
39 | hashing = Hashing()
40 | # do some stuff
41 | app = create_app()
42 | hashing.init_app(app)
43 |
44 | If you would like to customize your instance of :class:, you may specify values
45 | for HASHING_METHOD and HASHING_ROUNDS in the Flask application configuration.
46 | HASHING_METHOD defaults to ``sha256`` and HASHING_ROUNDS defaults to 1. If you
47 | are using anything less than Python 2.7.9 you will only have the guaranteed
48 | functions provided by ``hashlib``. Python 2.7.9 or higher allows access to OpenSSL
49 | hash functions. The name you supply to HASHING_METHOD must be valid to ``hashlib``.
50 | To get a list of valid names, supply a random string to HASHING_METHOD and check
51 | the output when initializing your application (it raises and exception), or check
52 | ``hashlib.algorithms`` for Python 2.7.8 or less, or ``hashlib.algorithms_available``
53 | if using Python 2.7.9+.
54 | '''
55 | algorithm = 'sha256'
56 | rounds = 1
57 |
58 | def __init__(self, app=None):
59 | if app is not None:
60 | self.init_app(app)
61 |
62 | def init_app(self, app):
63 | '''Initializes the Flask application with this extension. It grabs
64 | the necessary configuration values from ``app.config``, those being
65 | HASHING_METHOD and HASHING_ROUNDS. HASHING_METHOD defaults to ``sha256``
66 | but can be any one of ``hashlib.algorithms``. HASHING_ROUNDS specifies
67 | the number of times to hash the input with the specified algorithm.
68 | This defaults to 1.
69 |
70 | :param app: Flask application object
71 | '''
72 | self.algorithm = app.config.get('HASHING_METHOD', 'sha256')
73 | if self.algorithm not in algs:
74 | raise ValueError('{} not one of {}'.format(self.algorithm, algs))
75 | self.rounds = app.config.get('HASHING_ROUNDS', 1)
76 | if not isinstance(self.rounds, int):
77 | raise TypeError('HASHING_ROUNDS must be type int')
78 |
79 | def hash_value(self, value, salt=''):
80 | '''Hashes the specified value combined with the specified salt.
81 | The hash is done HASHING_ROUNDS times as specified by the application
82 | configuration.
83 |
84 | An example usage of :class:``hash_value`` would be::
85 |
86 | val_hash = hashing.hash_value('mysecretdata', salt='abcd')
87 | # save to a db or check against known hash
88 |
89 | :param value: The value we want hashed
90 | :param salt: The salt to use when generating the hash of ``value``. Default is ''.
91 | :return: The resulting hash as a string
92 | :rtype: str
93 | '''
94 | def hashit(value, salt):
95 | h = hashlib.new(self.algorithm)
96 | tgt = salt+value
97 | h.update(tgt)
98 | return h.hexdigest()
99 |
100 | def fix_unicode(value):
101 | if VER < 3 and isinstance(value, unicode):
102 | value = str(value)
103 | elif VER >= 3 and isinstance(value, str):
104 | value = str.encode(value)
105 | return value
106 |
107 | salt = fix_unicode(salt)
108 | for i in range(self.rounds):
109 | value = fix_unicode(value)
110 | value = hashit(value, salt)
111 | return value
112 |
113 | def check_value(self, value_hash, value, salt=''):
114 | '''Checks the specified hash value against the hash of the provided
115 | salt and value.
116 |
117 | An example usage of :class:`check_value` would be::
118 |
119 | val_hash = hashing.hash_value('mysecretdata', salt='abcd')
120 | if hashing.check_value(val_hash, 'mysecretdata', salt='abcd'):
121 | # do something special
122 |
123 | :param value_hash: The hash value to check against
124 | :param value: The value we want hashed to compare
125 | :param salt: The salt to use when generating the hash of ``value``. Default is ''.
126 | :return: True if equal, False otherwise
127 | :rtype: bool
128 | '''
129 | h = self.hash_value(value, salt=salt)
130 | return h == value_hash
131 |
--------------------------------------------------------------------------------
/docs/_themes/flask_small/static/flasky.css_t:
--------------------------------------------------------------------------------
1 | /*
2 | * flasky.css_t
3 | * ~~~~~~~~~~~~
4 | *
5 | * Sphinx stylesheet -- flasky theme based on nature theme.
6 | *
7 | * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
8 | * :license: BSD, see LICENSE for details.
9 | *
10 | */
11 |
12 | @import url("basic.css");
13 |
14 | /* -- page layout ----------------------------------------------------------- */
15 |
16 | body {
17 | font-family: 'Georgia', serif;
18 | font-size: 17px;
19 | color: #000;
20 | background: white;
21 | margin: 0;
22 | padding: 0;
23 | }
24 |
25 | div.documentwrapper {
26 | float: left;
27 | width: 100%;
28 | }
29 |
30 | div.bodywrapper {
31 | margin: 40px auto 0 auto;
32 | width: 700px;
33 | }
34 |
35 | hr {
36 | border: 1px solid #B1B4B6;
37 | }
38 |
39 | div.body {
40 | background-color: #ffffff;
41 | color: #3E4349;
42 | padding: 0 30px 30px 30px;
43 | }
44 |
45 | img.floatingflask {
46 | padding: 0 0 10px 10px;
47 | float: right;
48 | }
49 |
50 | div.footer {
51 | text-align: right;
52 | color: #888;
53 | padding: 10px;
54 | font-size: 14px;
55 | width: 650px;
56 | margin: 0 auto 40px auto;
57 | }
58 |
59 | div.footer a {
60 | color: #888;
61 | text-decoration: underline;
62 | }
63 |
64 | div.related {
65 | line-height: 32px;
66 | color: #888;
67 | }
68 |
69 | div.related ul {
70 | padding: 0 0 0 10px;
71 | }
72 |
73 | div.related a {
74 | color: #444;
75 | }
76 |
77 | /* -- body styles ----------------------------------------------------------- */
78 |
79 | a {
80 | color: #004B6B;
81 | text-decoration: underline;
82 | }
83 |
84 | a:hover {
85 | color: #6D4100;
86 | text-decoration: underline;
87 | }
88 |
89 | div.body {
90 | padding-bottom: 40px; /* saved for footer */
91 | }
92 |
93 | div.body h1,
94 | div.body h2,
95 | div.body h3,
96 | div.body h4,
97 | div.body h5,
98 | div.body h6 {
99 | font-family: 'Garamond', 'Georgia', serif;
100 | font-weight: normal;
101 | margin: 30px 0px 10px 0px;
102 | padding: 0;
103 | }
104 |
105 | {% if theme_index_logo %}
106 | div.indexwrapper h1 {
107 | text-indent: -999999px;
108 | background: url({{ theme_index_logo }}) no-repeat center center;
109 | height: {{ theme_index_logo_height }};
110 | }
111 | {% endif %}
112 |
113 | div.body h2 { font-size: 180%; }
114 | div.body h3 { font-size: 150%; }
115 | div.body h4 { font-size: 130%; }
116 | div.body h5 { font-size: 100%; }
117 | div.body h6 { font-size: 100%; }
118 |
119 | a.headerlink {
120 | color: white;
121 | padding: 0 4px;
122 | text-decoration: none;
123 | }
124 |
125 | a.headerlink:hover {
126 | color: #444;
127 | background: #eaeaea;
128 | }
129 |
130 | div.body p, div.body dd, div.body li {
131 | line-height: 1.4em;
132 | }
133 |
134 | div.admonition {
135 | background: #fafafa;
136 | margin: 20px -30px;
137 | padding: 10px 30px;
138 | border-top: 1px solid #ccc;
139 | border-bottom: 1px solid #ccc;
140 | }
141 |
142 | div.admonition p.admonition-title {
143 | font-family: 'Garamond', 'Georgia', serif;
144 | font-weight: normal;
145 | font-size: 24px;
146 | margin: 0 0 10px 0;
147 | padding: 0;
148 | line-height: 1;
149 | }
150 |
151 | div.admonition p.last {
152 | margin-bottom: 0;
153 | }
154 |
155 | div.highlight{
156 | background-color: white;
157 | }
158 |
159 | dt:target, .highlight {
160 | background: #FAF3E8;
161 | }
162 |
163 | div.note {
164 | background-color: #eee;
165 | border: 1px solid #ccc;
166 | }
167 |
168 | div.seealso {
169 | background-color: #ffc;
170 | border: 1px solid #ff6;
171 | }
172 |
173 | div.topic {
174 | background-color: #eee;
175 | }
176 |
177 | div.warning {
178 | background-color: #ffe4e4;
179 | border: 1px solid #f66;
180 | }
181 |
182 | p.admonition-title {
183 | display: inline;
184 | }
185 |
186 | p.admonition-title:after {
187 | content: ":";
188 | }
189 |
190 | pre, tt {
191 | font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
192 | font-size: 0.85em;
193 | }
194 |
195 | img.screenshot {
196 | }
197 |
198 | tt.descname, tt.descclassname {
199 | font-size: 0.95em;
200 | }
201 |
202 | tt.descname {
203 | padding-right: 0.08em;
204 | }
205 |
206 | img.screenshot {
207 | -moz-box-shadow: 2px 2px 4px #eee;
208 | -webkit-box-shadow: 2px 2px 4px #eee;
209 | box-shadow: 2px 2px 4px #eee;
210 | }
211 |
212 | table.docutils {
213 | border: 1px solid #888;
214 | -moz-box-shadow: 2px 2px 4px #eee;
215 | -webkit-box-shadow: 2px 2px 4px #eee;
216 | box-shadow: 2px 2px 4px #eee;
217 | }
218 |
219 | table.docutils td, table.docutils th {
220 | border: 1px solid #888;
221 | padding: 0.25em 0.7em;
222 | }
223 |
224 | table.field-list, table.footnote {
225 | border: none;
226 | -moz-box-shadow: none;
227 | -webkit-box-shadow: none;
228 | box-shadow: none;
229 | }
230 |
231 | table.footnote {
232 | margin: 15px 0;
233 | width: 100%;
234 | border: 1px solid #eee;
235 | }
236 |
237 | table.field-list th {
238 | padding: 0 0.8em 0 0;
239 | }
240 |
241 | table.field-list td {
242 | padding: 0;
243 | }
244 |
245 | table.footnote td {
246 | padding: 0.5em;
247 | }
248 |
249 | dl {
250 | margin: 0;
251 | padding: 0;
252 | }
253 |
254 | dl dd {
255 | margin-left: 30px;
256 | }
257 |
258 | pre {
259 | padding: 0;
260 | margin: 15px -30px;
261 | padding: 8px;
262 | line-height: 1.3em;
263 | padding: 7px 30px;
264 | background: #eee;
265 | border-radius: 2px;
266 | -moz-border-radius: 2px;
267 | -webkit-border-radius: 2px;
268 | }
269 |
270 | dl pre {
271 | margin-left: -60px;
272 | padding-left: 60px;
273 | }
274 |
275 | tt {
276 | background-color: #ecf0f3;
277 | color: #222;
278 | /* padding: 1px 2px; */
279 | }
280 |
281 | tt.xref, a tt {
282 | background-color: #FBFBFB;
283 | }
284 |
285 | a:hover tt {
286 | background: #EEE;
287 | }
288 |
--------------------------------------------------------------------------------
/docs/_themes/flask/static/flasky.css_t:
--------------------------------------------------------------------------------
1 | /*
2 | * flasky.css_t
3 | * ~~~~~~~~~~~~
4 | *
5 | * :copyright: Copyright 2010 by Armin Ronacher.
6 | * :license: Flask Design License, see LICENSE for details.
7 | */
8 |
9 | {% set page_width = '940px' %}
10 | {% set sidebar_width = '220px' %}
11 |
12 | @import url("basic.css");
13 |
14 | /* -- page layout ----------------------------------------------------------- */
15 |
16 | body {
17 | font-family: 'Georgia', serif;
18 | font-size: 17px;
19 | background-color: white;
20 | color: #000;
21 | margin: 0;
22 | padding: 0;
23 | }
24 |
25 | div.document {
26 | width: {{ page_width }};
27 | margin: 30px auto 0 auto;
28 | }
29 |
30 | div.documentwrapper {
31 | float: left;
32 | width: 100%;
33 | }
34 |
35 | div.bodywrapper {
36 | margin: 0 0 0 {{ sidebar_width }};
37 | }
38 |
39 | div.sphinxsidebar {
40 | width: {{ sidebar_width }};
41 | }
42 |
43 | hr {
44 | border: 1px solid #B1B4B6;
45 | }
46 |
47 | div.body {
48 | background-color: #ffffff;
49 | color: #3E4349;
50 | padding: 0 30px 0 30px;
51 | }
52 |
53 | img.floatingflask {
54 | padding: 0 0 10px 10px;
55 | float: right;
56 | }
57 |
58 | div.footer {
59 | width: {{ page_width }};
60 | margin: 20px auto 30px auto;
61 | font-size: 14px;
62 | color: #888;
63 | text-align: right;
64 | }
65 |
66 | div.footer a {
67 | color: #888;
68 | }
69 |
70 | div.related {
71 | display: none;
72 | }
73 |
74 | div.sphinxsidebar a {
75 | color: #444;
76 | text-decoration: none;
77 | border-bottom: 1px dotted #999;
78 | }
79 |
80 | div.sphinxsidebar a:hover {
81 | border-bottom: 1px solid #999;
82 | }
83 |
84 | div.sphinxsidebar {
85 | font-size: 14px;
86 | line-height: 1.5;
87 | }
88 |
89 | div.sphinxsidebarwrapper {
90 | padding: 18px 10px;
91 | }
92 |
93 | div.sphinxsidebarwrapper p.logo {
94 | padding: 0 0 20px 0;
95 | margin: 0;
96 | text-align: center;
97 | }
98 |
99 | div.sphinxsidebar h3,
100 | div.sphinxsidebar h4 {
101 | font-family: 'Garamond', 'Georgia', serif;
102 | color: #444;
103 | font-size: 24px;
104 | font-weight: normal;
105 | margin: 0 0 5px 0;
106 | padding: 0;
107 | }
108 |
109 | div.sphinxsidebar h4 {
110 | font-size: 20px;
111 | }
112 |
113 | div.sphinxsidebar h3 a {
114 | color: #444;
115 | }
116 |
117 | div.sphinxsidebar p.logo a,
118 | div.sphinxsidebar h3 a,
119 | div.sphinxsidebar p.logo a:hover,
120 | div.sphinxsidebar h3 a:hover {
121 | border: none;
122 | }
123 |
124 | div.sphinxsidebar p {
125 | color: #555;
126 | margin: 10px 0;
127 | }
128 |
129 | div.sphinxsidebar ul {
130 | margin: 10px 0;
131 | padding: 0;
132 | color: #000;
133 | }
134 |
135 | div.sphinxsidebar input {
136 | border: 1px solid #ccc;
137 | font-family: 'Georgia', serif;
138 | font-size: 1em;
139 | }
140 |
141 | /* -- body styles ----------------------------------------------------------- */
142 |
143 | a {
144 | color: #004B6B;
145 | text-decoration: underline;
146 | }
147 |
148 | a:hover {
149 | color: #6D4100;
150 | text-decoration: underline;
151 | }
152 |
153 | div.body h1,
154 | div.body h2,
155 | div.body h3,
156 | div.body h4,
157 | div.body h5,
158 | div.body h6 {
159 | font-family: 'Garamond', 'Georgia', serif;
160 | font-weight: normal;
161 | margin: 30px 0px 10px 0px;
162 | padding: 0;
163 | }
164 |
165 | div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; }
166 | div.body h2 { font-size: 180%; }
167 | div.body h3 { font-size: 150%; }
168 | div.body h4 { font-size: 130%; }
169 | div.body h5 { font-size: 100%; }
170 | div.body h6 { font-size: 100%; }
171 |
172 | a.headerlink {
173 | color: #ddd;
174 | padding: 0 4px;
175 | text-decoration: none;
176 | }
177 |
178 | a.headerlink:hover {
179 | color: #444;
180 | background: #eaeaea;
181 | }
182 |
183 | div.body p, div.body dd, div.body li {
184 | line-height: 1.4em;
185 | }
186 |
187 | div.admonition {
188 | background: #fafafa;
189 | margin: 20px -30px;
190 | padding: 10px 30px;
191 | border-top: 1px solid #ccc;
192 | border-bottom: 1px solid #ccc;
193 | }
194 |
195 | div.admonition tt.xref, div.admonition a tt {
196 | border-bottom: 1px solid #fafafa;
197 | }
198 |
199 | dd div.admonition {
200 | margin-left: -60px;
201 | padding-left: 60px;
202 | }
203 |
204 | div.admonition p.admonition-title {
205 | font-family: 'Garamond', 'Georgia', serif;
206 | font-weight: normal;
207 | font-size: 24px;
208 | margin: 0 0 10px 0;
209 | padding: 0;
210 | line-height: 1;
211 | }
212 |
213 | div.admonition p.last {
214 | margin-bottom: 0;
215 | }
216 |
217 | div.highlight {
218 | background-color: white;
219 | }
220 |
221 | dt:target, .highlight {
222 | background: #FAF3E8;
223 | }
224 |
225 | div.note {
226 | background-color: #eee;
227 | border: 1px solid #ccc;
228 | }
229 |
230 | div.seealso {
231 | background-color: #ffc;
232 | border: 1px solid #ff6;
233 | }
234 |
235 | div.topic {
236 | background-color: #eee;
237 | }
238 |
239 | p.admonition-title {
240 | display: inline;
241 | }
242 |
243 | p.admonition-title:after {
244 | content: ":";
245 | }
246 |
247 | pre, tt {
248 | font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
249 | font-size: 0.9em;
250 | }
251 |
252 | img.screenshot {
253 | }
254 |
255 | tt.descname, tt.descclassname {
256 | font-size: 0.95em;
257 | }
258 |
259 | tt.descname {
260 | padding-right: 0.08em;
261 | }
262 |
263 | img.screenshot {
264 | -moz-box-shadow: 2px 2px 4px #eee;
265 | -webkit-box-shadow: 2px 2px 4px #eee;
266 | box-shadow: 2px 2px 4px #eee;
267 | }
268 |
269 | table.docutils {
270 | border: 1px solid #888;
271 | -moz-box-shadow: 2px 2px 4px #eee;
272 | -webkit-box-shadow: 2px 2px 4px #eee;
273 | box-shadow: 2px 2px 4px #eee;
274 | }
275 |
276 | table.docutils td, table.docutils th {
277 | border: 1px solid #888;
278 | padding: 0.25em 0.7em;
279 | }
280 |
281 | table.field-list, table.footnote {
282 | border: none;
283 | -moz-box-shadow: none;
284 | -webkit-box-shadow: none;
285 | box-shadow: none;
286 | }
287 |
288 | table.footnote {
289 | margin: 15px 0;
290 | width: 100%;
291 | border: 1px solid #eee;
292 | background: #fdfdfd;
293 | font-size: 0.9em;
294 | }
295 |
296 | table.footnote + table.footnote {
297 | margin-top: -15px;
298 | border-top: none;
299 | }
300 |
301 | table.field-list th {
302 | padding: 0 0.8em 0 0;
303 | }
304 |
305 | table.field-list td {
306 | padding: 0;
307 | }
308 |
309 | table.footnote td.label {
310 | width: 0px;
311 | padding: 0.3em 0 0.3em 0.5em;
312 | }
313 |
314 | table.footnote td {
315 | padding: 0.3em 0.5em;
316 | }
317 |
318 | dl {
319 | margin: 0;
320 | padding: 0;
321 | }
322 |
323 | dl dd {
324 | margin-left: 30px;
325 | }
326 |
327 | blockquote {
328 | margin: 0 0 0 30px;
329 | padding: 0;
330 | }
331 |
332 | ul, ol {
333 | margin: 10px 0 10px 30px;
334 | padding: 0;
335 | }
336 |
337 | pre {
338 | background: #eee;
339 | padding: 7px 30px;
340 | margin: 15px -30px;
341 | line-height: 1.3em;
342 | }
343 |
344 | dl pre, blockquote pre, li pre {
345 | margin-left: -60px;
346 | padding-left: 60px;
347 | }
348 |
349 | dl dl pre {
350 | margin-left: -90px;
351 | padding-left: 90px;
352 | }
353 |
354 | tt {
355 | background-color: #ecf0f3;
356 | color: #222;
357 | /* padding: 1px 2px; */
358 | }
359 |
360 | tt.xref, a tt {
361 | background-color: #FBFBFB;
362 | border-bottom: 1px solid white;
363 | }
364 |
365 | a.reference {
366 | text-decoration: none;
367 | border-bottom: 1px dotted #004B6B;
368 | }
369 |
370 | a.reference:hover {
371 | border-bottom: 1px solid #6D4100;
372 | }
373 |
374 | a.footnote-reference {
375 | text-decoration: none;
376 | font-size: 0.7em;
377 | vertical-align: top;
378 | border-bottom: 1px dotted #004B6B;
379 | }
380 |
381 | a.footnote-reference:hover {
382 | border-bottom: 1px solid #6D4100;
383 | }
384 |
385 | a:hover tt {
386 | background: #EEE;
387 | }
388 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | PAPER =
8 | BUILDDIR = _build
9 |
10 | # User-friendly check for sphinx-build
11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
13 | endif
14 |
15 | # Internal variables.
16 | PAPEROPT_a4 = -D latex_paper_size=a4
17 | PAPEROPT_letter = -D latex_paper_size=letter
18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
19 | # the i18n builder cannot share the environment and doctrees with the others
20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
21 |
22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext
23 |
24 | help:
25 | @echo "Please use \`make