pyramid-csrf-multi-scheme 1.0.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyramid_csrf_multi_scheme/__init__.py +189 -0
- pyramid_csrf_multi_scheme/debugtoolbar/__init__.py +8 -0
- pyramid_csrf_multi_scheme/debugtoolbar/panels/__init__.py +0 -0
- pyramid_csrf_multi_scheme/debugtoolbar/panels/csrf_multi_scheme.py +116 -0
- pyramid_csrf_multi_scheme/debugtoolbar/panels/templates/csrf_multi_scheme.dbtmako +34 -0
- pyramid_csrf_multi_scheme-1.0.0.dist-info/METADATA +110 -0
- pyramid_csrf_multi_scheme-1.0.0.dist-info/RECORD +10 -0
- pyramid_csrf_multi_scheme-1.0.0.dist-info/WHEEL +6 -0
- pyramid_csrf_multi_scheme-1.0.0.dist-info/licenses/LICENSE.txt +40 -0
- pyramid_csrf_multi_scheme-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# stdlib
|
|
2
|
+
import sys
|
|
3
|
+
import uuid
|
|
4
|
+
|
|
5
|
+
# pypi
|
|
6
|
+
from pyramid.interfaces import ICSRFStoragePolicy
|
|
7
|
+
from pyramid.request import Request
|
|
8
|
+
from pyramid.util import strings_differ
|
|
9
|
+
from pyramid.util import SimpleSerializer
|
|
10
|
+
from webob.cookies import CookieProfile
|
|
11
|
+
from webob.response import Response
|
|
12
|
+
from zope.interface import implementer
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# ==============================================================================
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
__VERSION__ = "1.0.0"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# ------------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
"""
|
|
25
|
+
The following functions are taken from Pyramid directly.
|
|
26
|
+
|
|
27
|
+
* `pyramid.compat.bytes_`
|
|
28
|
+
* `pyramid.compat.text_`
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
text_type = unicode if (sys.version_info[0] == 2) else str
|
|
32
|
+
binary_type = str if (sys.version_info[0] == 2) else bytes
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def text_(s, encoding="latin-1", errors="strict"):
|
|
36
|
+
"""If ``s`` is an instance of ``binary_type``, return
|
|
37
|
+
``s.decode(encoding, errors)``, otherwise return ``s``"""
|
|
38
|
+
if isinstance(s, binary_type):
|
|
39
|
+
return s.decode(encoding, errors)
|
|
40
|
+
return s
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def bytes_(s, encoding="latin-1", errors="strict"):
|
|
44
|
+
"""If ``s`` is an instance of ``text_type``, return
|
|
45
|
+
``s.encode(encoding, errors)``, otherwise return ``s``"""
|
|
46
|
+
if isinstance(s, text_type):
|
|
47
|
+
return s.encode(encoding, errors)
|
|
48
|
+
return s
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# ==============================================================================
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@implementer(ICSRFStoragePolicy)
|
|
55
|
+
class DualCookieCSRFStoragePolicy(object):
|
|
56
|
+
"""
|
|
57
|
+
A re-implementation of ``pyramid.csrf.CookieCSRFStoragePolicy``.
|
|
58
|
+
This policy runs separate csrf tokens on http and https connections.
|
|
59
|
+
|
|
60
|
+
If the connection is https:
|
|
61
|
+
expiring the csrf will expire the http and https
|
|
62
|
+
only the https csrf will be consulted
|
|
63
|
+
|
|
64
|
+
If the connection is http:
|
|
65
|
+
expiring the csrf will expire the http
|
|
66
|
+
only the http csrf will be consulted
|
|
67
|
+
|
|
68
|
+
last synced to pyramid: 1.10.4
|
|
69
|
+
|
|
70
|
+
NOTE: this does not support a ``secure`` argument
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
_token_factory = staticmethod(lambda: text_(uuid.uuid4().hex))
|
|
74
|
+
|
|
75
|
+
def __init__(
|
|
76
|
+
self,
|
|
77
|
+
cookie_name_secure="csrf_https",
|
|
78
|
+
cookie_name_http="csrf_http",
|
|
79
|
+
secure=None,
|
|
80
|
+
httponly=False,
|
|
81
|
+
domain=None,
|
|
82
|
+
max_age=None,
|
|
83
|
+
path="/",
|
|
84
|
+
samesite="Lax",
|
|
85
|
+
):
|
|
86
|
+
if secure is not None:
|
|
87
|
+
raise ValueError(
|
|
88
|
+
"`DualCookieCSRFStoragePolicy` does not support "
|
|
89
|
+
"the `secure` argument."
|
|
90
|
+
)
|
|
91
|
+
serializer = SimpleSerializer()
|
|
92
|
+
self.cookie_name_secure = cookie_name_secure
|
|
93
|
+
self.cookie_name_http = cookie_name_http
|
|
94
|
+
self.cookie_profile_secure = CookieProfile(
|
|
95
|
+
cookie_name=cookie_name_secure,
|
|
96
|
+
secure=True,
|
|
97
|
+
max_age=max_age,
|
|
98
|
+
httponly=httponly,
|
|
99
|
+
path=path,
|
|
100
|
+
domains=[domain],
|
|
101
|
+
serializer=serializer,
|
|
102
|
+
samesite=samesite,
|
|
103
|
+
)
|
|
104
|
+
self.cookie_profile_http = CookieProfile(
|
|
105
|
+
cookie_name=cookie_name_http,
|
|
106
|
+
secure=False,
|
|
107
|
+
max_age=max_age,
|
|
108
|
+
httponly=httponly,
|
|
109
|
+
path=path,
|
|
110
|
+
domains=[domain],
|
|
111
|
+
serializer=serializer,
|
|
112
|
+
samesite=samesite,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def cookie_profile(self):
|
|
117
|
+
"""
|
|
118
|
+
Returns the active cookie profile for the request's scheme.
|
|
119
|
+
"""
|
|
120
|
+
raise ValueError(
|
|
121
|
+
"`DualCookieCSRFStoragePolicy` supports access "
|
|
122
|
+
"via the attributes `.cookie_profile_secure` and "
|
|
123
|
+
"via the attributes `.cookie_profile_http`. The "
|
|
124
|
+
"attribute `.cookie_profile` is not supported."
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
def new_csrf_token(self, request):
|
|
128
|
+
# type: (Request) -> str
|
|
129
|
+
"""Rotate the HTTP token and also the HTTPS token on secure requests."""
|
|
130
|
+
|
|
131
|
+
def _issue_token(cookie_name, profile):
|
|
132
|
+
# type: (str, CookieProfile) -> str
|
|
133
|
+
"""Store a fresh token and schedule its response cookie."""
|
|
134
|
+
token = self._token_factory()
|
|
135
|
+
request.cookies[cookie_name] = token
|
|
136
|
+
|
|
137
|
+
def _set_cookie(request, response):
|
|
138
|
+
# type: (Request, Response) -> None
|
|
139
|
+
profile.set_cookies(response, token)
|
|
140
|
+
|
|
141
|
+
request.add_response_callback(_set_cookie)
|
|
142
|
+
return token
|
|
143
|
+
|
|
144
|
+
token_http = _issue_token(self.cookie_name_http, self.cookie_profile_http)
|
|
145
|
+
if request.scheme == "https":
|
|
146
|
+
return _issue_token(self.cookie_name_secure, self.cookie_profile_secure)
|
|
147
|
+
return token_http
|
|
148
|
+
|
|
149
|
+
def get_csrf_token(self, request):
|
|
150
|
+
"""
|
|
151
|
+
Returns the currently active CSRF token by checking the cookies
|
|
152
|
+
sent with the current request.
|
|
153
|
+
"""
|
|
154
|
+
if request.scheme == "https":
|
|
155
|
+
# only consult the secure cookie
|
|
156
|
+
bound_cookies = self.cookie_profile_secure.bind(request)
|
|
157
|
+
else:
|
|
158
|
+
# the only accessible cookie is http insecure
|
|
159
|
+
bound_cookies = self.cookie_profile_http.bind(request)
|
|
160
|
+
token = bound_cookies.get_value()
|
|
161
|
+
if not token:
|
|
162
|
+
token = self.new_csrf_token(request)
|
|
163
|
+
return token
|
|
164
|
+
|
|
165
|
+
def check_csrf_token(self, request, supplied_token):
|
|
166
|
+
# type: (Request, object) -> bool
|
|
167
|
+
"""Check a text or byte token using Pyramid's timing-safe comparison."""
|
|
168
|
+
if not isinstance(supplied_token, (text_type, binary_type)):
|
|
169
|
+
return False
|
|
170
|
+
try:
|
|
171
|
+
supplied_bytes = bytes_(supplied_token)
|
|
172
|
+
except UnicodeEncodeError:
|
|
173
|
+
return False
|
|
174
|
+
expected_token = self.get_csrf_token(request)
|
|
175
|
+
return not strings_differ(bytes_(expected_token), supplied_bytes)
|
|
176
|
+
|
|
177
|
+
def get_csrf_token_scheme(self, request, scheme):
|
|
178
|
+
"""this is a utility for testing"""
|
|
179
|
+
if scheme not in ("https", "http"):
|
|
180
|
+
raise ValueError("unknown scheme")
|
|
181
|
+
if scheme == "https":
|
|
182
|
+
if request.scheme != "https":
|
|
183
|
+
return None
|
|
184
|
+
bound_cookies = self.cookie_profile_secure.bind(request)
|
|
185
|
+
token = bound_cookies.get_value()
|
|
186
|
+
return token
|
|
187
|
+
bound_cookies = self.cookie_profile_http.bind(request)
|
|
188
|
+
token = bound_cookies.get_value()
|
|
189
|
+
return token
|
|
File without changes
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
from pyramid_debugtoolbar.panels import DebugPanel
|
|
2
|
+
|
|
3
|
+
from pyramid.interfaces import ICSRFStoragePolicy
|
|
4
|
+
from ... import DualCookieCSRFStoragePolicy
|
|
5
|
+
|
|
6
|
+
_ = lambda x: x
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class CSRFMultiSchemeDebugPanel(DebugPanel):
|
|
10
|
+
"""
|
|
11
|
+
Sample debug panel
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
name = "CSRFMultiScheme"
|
|
15
|
+
has_content = None
|
|
16
|
+
template = "pyramid_csrf_multi_scheme.debugtoolbar.panels:templates/csrf_multi_scheme.dbtmako"
|
|
17
|
+
|
|
18
|
+
# only query the policy once
|
|
19
|
+
_policy = None
|
|
20
|
+
|
|
21
|
+
# stash
|
|
22
|
+
_cookie_names = None
|
|
23
|
+
|
|
24
|
+
response = None # we may never have a response
|
|
25
|
+
|
|
26
|
+
def __init__(self, request):
|
|
27
|
+
|
|
28
|
+
self.data = {
|
|
29
|
+
"request_data": {
|
|
30
|
+
"cookie_secure": {"in": None, "out": None, "cookie_name": None},
|
|
31
|
+
"cookie_http": {"in": None, "out": None, "cookie_name": None},
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
policy = request.registry.queryUtility(ICSRFStoragePolicy)
|
|
35
|
+
if isinstance(policy, DualCookieCSRFStoragePolicy):
|
|
36
|
+
self._policy = policy
|
|
37
|
+
self._cookie_names = [policy.cookie_name_secure, policy.cookie_name_http]
|
|
38
|
+
|
|
39
|
+
self.has_content = True
|
|
40
|
+
|
|
41
|
+
self.data["request_data"]["cookie_secure"]["in"] = request.cookies.get(
|
|
42
|
+
policy.cookie_name_secure
|
|
43
|
+
)
|
|
44
|
+
self.data["request_data"]["cookie_secure"][
|
|
45
|
+
"cookie_name"
|
|
46
|
+
] = policy.cookie_name_secure
|
|
47
|
+
|
|
48
|
+
self.data["request_data"]["cookie_http"]["in"] = request.cookies.get(
|
|
49
|
+
policy.cookie_name_http
|
|
50
|
+
)
|
|
51
|
+
self.data["request_data"]["cookie_http"][
|
|
52
|
+
"cookie_name"
|
|
53
|
+
] = policy.cookie_name_http
|
|
54
|
+
|
|
55
|
+
# `process_response` fires before the set_cookie callbacks, so use this hack...
|
|
56
|
+
def finished_callback(request):
|
|
57
|
+
self._process_response_deferred()
|
|
58
|
+
|
|
59
|
+
request.add_finished_callback(finished_callback)
|
|
60
|
+
|
|
61
|
+
def process_response(self, response):
|
|
62
|
+
"""`
|
|
63
|
+
process_response` fires before the set_cookie callbacks
|
|
64
|
+
so we use a hack from pyramid_debugtoolbar's HeaderDebugPanel
|
|
65
|
+
|
|
66
|
+
1. `__init__()` sets a callback to `_process_response_deferred()`
|
|
67
|
+
2. `process_response()` stashes the response
|
|
68
|
+
3. `_process_response_deferred` has the headers
|
|
69
|
+
"""
|
|
70
|
+
self.response = response
|
|
71
|
+
|
|
72
|
+
def _process_response_deferred(self):
|
|
73
|
+
"""
|
|
74
|
+
`process_response` fires before the set_cookie callbacks
|
|
75
|
+
so we use a hack from pyramid_debugtoolbar's HeaderDebugPanel
|
|
76
|
+
"""
|
|
77
|
+
if self.response is not None:
|
|
78
|
+
cookies = [i for i in self.response.headerlist if i[0] == "Set-Cookie"]
|
|
79
|
+
# [('Set-Cookie', 'ci_ss_ck=eXrTEtumW4Jal3FyEXtkJijofCAyOnayzGQiPG7IAjukycfE; Domain=.dev.example.com; Path=/'),
|
|
80
|
+
# ('Set-Cookie', 'ci_s_ck=iG6dqE5mff_iR2Y95o5eENuVdC; Domain=.dev.example.com; Path=/')
|
|
81
|
+
# ]
|
|
82
|
+
for ck in cookies:
|
|
83
|
+
try:
|
|
84
|
+
ck_parts = ck[1].split(";")
|
|
85
|
+
(ck_name, ck_value) = ck_parts[0].split(
|
|
86
|
+
"=", 1
|
|
87
|
+
) # maxsplit 1, because the value could be an encoding with == as a right pad
|
|
88
|
+
if ck_name in self._cookie_names:
|
|
89
|
+
if (
|
|
90
|
+
ck_name
|
|
91
|
+
== self.data["request_data"]["cookie_secure"]["cookie_name"]
|
|
92
|
+
):
|
|
93
|
+
self.data["request_data"]["cookie_secure"]["out"] = ck_value
|
|
94
|
+
elif (
|
|
95
|
+
ck_name
|
|
96
|
+
== self.data["request_data"]["cookie_http"]["cookie_name"]
|
|
97
|
+
):
|
|
98
|
+
self.data["request_data"]["cookie_http"]["out"] = ck_value
|
|
99
|
+
except Exception as exc:
|
|
100
|
+
# TODO: logging
|
|
101
|
+
pass
|
|
102
|
+
|
|
103
|
+
@property
|
|
104
|
+
def nav_title(self):
|
|
105
|
+
return _(self.name)
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def title(self):
|
|
109
|
+
return _(self.name)
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def url(self):
|
|
113
|
+
return ""
|
|
114
|
+
|
|
115
|
+
def render_content(self, request):
|
|
116
|
+
return DebugPanel.render_content(self, request)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<%!
|
|
2
|
+
def coded_value(val):
|
|
3
|
+
if val:
|
|
4
|
+
return "<code>%s</code>" % val
|
|
5
|
+
return ''
|
|
6
|
+
%>
|
|
7
|
+
|
|
8
|
+
<table class="table table-striped table-condensed">
|
|
9
|
+
<thead>
|
|
10
|
+
<tr>
|
|
11
|
+
<th>cookie_type</th>
|
|
12
|
+
<th>cookie_secure</th>
|
|
13
|
+
<th>cookie_http</th>
|
|
14
|
+
</tr>
|
|
15
|
+
</thead>
|
|
16
|
+
<tbody>
|
|
17
|
+
<tr>
|
|
18
|
+
<th>cookie_name</th>
|
|
19
|
+
<td><code>${request_data['cookie_secure']['cookie_name']}</code></td>
|
|
20
|
+
<td><code>${request_data['cookie_http']['cookie_name']}</code></td>
|
|
21
|
+
</tr>
|
|
22
|
+
<tr>
|
|
23
|
+
<th>request</th>
|
|
24
|
+
<td>${coded_value(request_data['cookie_secure']['in'])|n}</td>
|
|
25
|
+
<td>${coded_value(request_data['cookie_http']['in'])|n}</td>
|
|
26
|
+
</tr>
|
|
27
|
+
<tr>
|
|
28
|
+
<th>response</th>
|
|
29
|
+
<td>${coded_value(request_data['cookie_secure']['out'])|n}</td>
|
|
30
|
+
<td>${coded_value(request_data['cookie_http']['out'])|n}</td>
|
|
31
|
+
</tr>
|
|
32
|
+
</tbody>
|
|
33
|
+
</table>
|
|
34
|
+
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyramid_csrf_multi_scheme
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Provides for creating independent csrf tokens for the http and https schemes
|
|
5
|
+
Home-page: https://github.com/jvanasco/pyramid_csrf_multi_scheme
|
|
6
|
+
Author: Jonathan Vanasco
|
|
7
|
+
Author-email: jvanasco@2xlp.com
|
|
8
|
+
License: BSD-derived (http://www.repoze.org/LICENSE.txt)
|
|
9
|
+
Keywords: web,pyramid,csrf
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Framework :: Pyramid
|
|
12
|
+
Classifier: Programming Language :: Python :: 2.7
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.5
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
25
|
+
Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7
|
|
26
|
+
Description-Content-Type: text/x-rst
|
|
27
|
+
License-File: LICENSE.txt
|
|
28
|
+
Requires-Dist: pyramid>=1.10.4
|
|
29
|
+
Requires-Dist: setuptools<82; python_version >= "3.7" and python_version < "3.10"
|
|
30
|
+
Provides-Extra: testing
|
|
31
|
+
Requires-Dist: coverage; extra == "testing"
|
|
32
|
+
Requires-Dist: pytest; extra == "testing"
|
|
33
|
+
Requires-Dist: pyramid_debugtoolbar>=4.0.0; extra == "testing"
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
pyramid_csrf_multi_scheme
|
|
37
|
+
=========================
|
|
38
|
+
|
|
39
|
+
.. image:: https://github.com/jvanasco/pyramid_csrf_multi_scheme/workflows/Python%20package/badge.svg
|
|
40
|
+
:alt: Build Status
|
|
41
|
+
|
|
42
|
+
This package enables two separate cookie tokens on each request, bound to the scheme:
|
|
43
|
+
|
|
44
|
+
* a SECURE HTTPS only cookie
|
|
45
|
+
* a mixed-use insecure http token (which is also available on https).
|
|
46
|
+
|
|
47
|
+
If the current scheme is `HTTPS`:
|
|
48
|
+
|
|
49
|
+
* only the SECURE HTTPS token will be considered
|
|
50
|
+
* HOWEVER calls to generate a new token will reset both the SECURE HTTPS and the
|
|
51
|
+
insecure http tokens.
|
|
52
|
+
|
|
53
|
+
If the current scheme is `insecure http`:
|
|
54
|
+
|
|
55
|
+
* the SECURE HTTPS tokens are ignored as they are not even available, and only the
|
|
56
|
+
insecure http token is considered.
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
Python Versions
|
|
60
|
+
---------------
|
|
61
|
+
|
|
62
|
+
This package is currently supported under Python2.7 and 3.8; other 3.x versions may work.
|
|
63
|
+
|
|
64
|
+
This package should work on Pyramid1.x and 2.x
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
Why?
|
|
68
|
+
----
|
|
69
|
+
|
|
70
|
+
If an application supports both `HTTP` and `HTTPS` endpoints, this package simplifies
|
|
71
|
+
isolating the CSRF data from both.
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
Is this necessary?
|
|
75
|
+
------------------
|
|
76
|
+
|
|
77
|
+
I'm not sure, but have decided to err on the side of caution.
|
|
78
|
+
|
|
79
|
+
HTTP traffic is sent in plaintext and capable of being intercepted by a
|
|
80
|
+
man-in-the-middle or network packet sniffing.
|
|
81
|
+
|
|
82
|
+
It seems plausible that someone might read a csrf token via HTTP and use that
|
|
83
|
+
in attempts to compromise HTTPS endpoints in a mixed use environment.
|
|
84
|
+
|
|
85
|
+
A better option is to only use HTTPS tokens and forms - but that is not
|
|
86
|
+
always an option.
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
debugtoolbar support!
|
|
90
|
+
---------------------
|
|
91
|
+
|
|
92
|
+
just add to your `ENVIRONMENT.ini` file, or similar application configuration.
|
|
93
|
+
|
|
94
|
+
.. code-block:: python
|
|
95
|
+
|
|
96
|
+
debugtoolbar.includes = pyramid_csrf_multi_scheme.debugtoolbar
|
|
97
|
+
|
|
98
|
+
Tthe debugtoolbar will now have a `CSRFMultiScheme` panel that has the following info:
|
|
99
|
+
|
|
100
|
+
* configuration info on the cookie names
|
|
101
|
+
* incoming request csrf values
|
|
102
|
+
* outgoing response csrf values
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
License
|
|
106
|
+
-------
|
|
107
|
+
|
|
108
|
+
Most of this is just code lightly edited from Pyramid, and
|
|
109
|
+
therefore available under Pyramid's licensing terms.
|
|
110
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
pyramid_csrf_multi_scheme/__init__.py,sha256=hg1nrVe51ZXv23T0RsnrgxHSfUGMpr9tsomMDrUUOjg,6187
|
|
2
|
+
pyramid_csrf_multi_scheme/debugtoolbar/__init__.py,sha256=y-09Tp_6atpkVbdJKYlXBRNJU5Id0H9S1GyLWkASj1E,187
|
|
3
|
+
pyramid_csrf_multi_scheme/debugtoolbar/panels/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
pyramid_csrf_multi_scheme/debugtoolbar/panels/csrf_multi_scheme.py,sha256=V8vP7emxqTWwJ8WrNVjzpmRdTVMRMsRoSvZWeZ-SCDI,4130
|
|
5
|
+
pyramid_csrf_multi_scheme/debugtoolbar/panels/templates/csrf_multi_scheme.dbtmako,sha256=LHQSj8Sfv57fEpVkp-e1eTlZY6w3k9NOW72Mz1x0KLk,792
|
|
6
|
+
pyramid_csrf_multi_scheme-1.0.0.dist-info/licenses/LICENSE.txt,sha256=GiTI_rOhwQPIHLvhwbVxVrBcpi3Q-9vC0iqWjPHJeXE,1850
|
|
7
|
+
pyramid_csrf_multi_scheme-1.0.0.dist-info/METADATA,sha256=RmCVoxDd1Qv0jolfidWruZfsC-jXAvI20n4e-5Wj414,3562
|
|
8
|
+
pyramid_csrf_multi_scheme-1.0.0.dist-info/WHEEL,sha256=Uvlg2aNlEKdilsyFSJt1QX5me0eEbCjQzR3nZeFkvy4,109
|
|
9
|
+
pyramid_csrf_multi_scheme-1.0.0.dist-info/top_level.txt,sha256=B88icNON_eQZtw45b_Ajo1m5Xos3YgI6WC-QNLoMB8w,26
|
|
10
|
+
pyramid_csrf_multi_scheme-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
The majority of the code in Pyramid is supplied under this license:
|
|
2
|
+
|
|
3
|
+
A copyright notice accompanies this license document that identifies
|
|
4
|
+
the copyright holders.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are
|
|
8
|
+
met:
|
|
9
|
+
|
|
10
|
+
1. Redistributions in source code must retain the accompanying
|
|
11
|
+
copyright notice, this list of conditions, and the following
|
|
12
|
+
disclaimer.
|
|
13
|
+
|
|
14
|
+
2. Redistributions in binary form must reproduce the accompanying
|
|
15
|
+
copyright notice, this list of conditions, and the following
|
|
16
|
+
disclaimer in the documentation and/or other materials provided
|
|
17
|
+
with the distribution.
|
|
18
|
+
|
|
19
|
+
3. Names of the copyright holders must not be used to endorse or
|
|
20
|
+
promote products derived from this software without prior
|
|
21
|
+
written permission from the copyright holders.
|
|
22
|
+
|
|
23
|
+
4. If any files are modified, you must cause the modified files to
|
|
24
|
+
carry prominent notices stating that you changed the files and
|
|
25
|
+
the date of any change.
|
|
26
|
+
|
|
27
|
+
Disclaimer
|
|
28
|
+
|
|
29
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND
|
|
30
|
+
ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
31
|
+
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
32
|
+
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
33
|
+
HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
34
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
|
35
|
+
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
36
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
37
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
|
38
|
+
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
|
39
|
+
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
40
|
+
SUCH DAMAGE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pyramid_csrf_multi_scheme
|