tina4-python 0.1.43__tar.gz → 0.1.45__tar.gz

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.
Files changed (30) hide show
  1. {tina4_python-0.1.43 → tina4_python-0.1.45}/PKG-INFO +36 -1
  2. {tina4_python-0.1.43 → tina4_python-0.1.45}/README.md +35 -0
  3. {tina4_python-0.1.43 → tina4_python-0.1.45}/pyproject.toml +1 -1
  4. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/Auth.py +13 -0
  5. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/Router.py +16 -7
  6. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/Webserver.py +21 -5
  7. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/Constant.py +0 -0
  8. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/Debug.py +0 -0
  9. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/Env.py +0 -0
  10. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/Localization.py +0 -0
  11. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/Messages.py +0 -0
  12. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/Request.py +0 -0
  13. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/Response.py +0 -0
  14. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/Template.py +0 -0
  15. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/__init__.py +0 -0
  16. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/messages.pot +0 -0
  17. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/public/css/readme.md +0 -0
  18. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/public/favicon.ico +0 -0
  19. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/public/images/403.png +0 -0
  20. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/public/images/404.png +0 -0
  21. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/public/images/logo.png +0 -0
  22. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/public/images/readme.md +0 -0
  23. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/public/js/readme.md +0 -0
  24. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/templates/errors/403.twig +0 -0
  25. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/templates/errors/404.twig +0 -0
  26. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/templates/readme.md +0 -0
  27. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
  28. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
  29. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
  30. {tina4_python-0.1.43 → tina4_python-0.1.45}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tina4-python
3
- Version: 0.1.43
3
+ Version: 0.1.45
4
4
  Summary: Tina4Python - This is not another framework for Python
5
5
  Author: Andre van Zuydam
6
6
  Author-email: andrevanzuydam@gmail.com
@@ -169,6 +169,41 @@ Example:
169
169
  Authorization: Bearer <token>
170
170
  ```
171
171
  You can generate tokens using tina4_python.tina4_auth which takes in a payload parameter which is a dictionary:
172
+ #### Example of a post with a form, assume the route is ```/capture```
173
+
174
+ You need the following twig file in the ```src/templates``` folder called ```something.twig```
175
+
176
+ ```twig something.twig
177
+ <form method="post">
178
+ <input name="email" type="text" placeholder="Email">
179
+ <button type="submit">Send</button>
180
+ <input type="hidden" name="formToken" value="{{ token }}" >
181
+ </form>
182
+ ```
183
+
184
+ You can add the following code to ```src/routes/example.py```
185
+
186
+ ```python
187
+ # get router which renders the twig form html
188
+ @get("/capture")
189
+ async def capture_get(request, response):
190
+ # get a token to add to the form
191
+ token = tina4_python.tina4_auth.get_token({"data": {"formName": "capture"}})
192
+ html = Template.render_twig_template("somefile.twig", {"token": token})
193
+ return response(html)
194
+
195
+ # returns back to the user the form data that has been posted
196
+ @post("/capture")
197
+ async def capture_post(request, response):
198
+ return response(request.body)
199
+ ```
200
+
201
+ In your ```src/__init__.py``` add the following code
202
+
203
+ ```python
204
+ from .routes.example import *
205
+ ```
206
+ Generate tokens with the following code as per the example above, tokens carry a payload and we add an additional ```expires``` value to the token based on the env variable ```TINA4_TOKEN_LIMIT```
172
207
 
173
208
  ```python
174
209
  import tina4_python
@@ -150,6 +150,41 @@ Example:
150
150
  Authorization: Bearer <token>
151
151
  ```
152
152
  You can generate tokens using tina4_python.tina4_auth which takes in a payload parameter which is a dictionary:
153
+ #### Example of a post with a form, assume the route is ```/capture```
154
+
155
+ You need the following twig file in the ```src/templates``` folder called ```something.twig```
156
+
157
+ ```twig something.twig
158
+ <form method="post">
159
+ <input name="email" type="text" placeholder="Email">
160
+ <button type="submit">Send</button>
161
+ <input type="hidden" name="formToken" value="{{ token }}" >
162
+ </form>
163
+ ```
164
+
165
+ You can add the following code to ```src/routes/example.py```
166
+
167
+ ```python
168
+ # get router which renders the twig form html
169
+ @get("/capture")
170
+ async def capture_get(request, response):
171
+ # get a token to add to the form
172
+ token = tina4_python.tina4_auth.get_token({"data": {"formName": "capture"}})
173
+ html = Template.render_twig_template("somefile.twig", {"token": token})
174
+ return response(html)
175
+
176
+ # returns back to the user the form data that has been posted
177
+ @post("/capture")
178
+ async def capture_post(request, response):
179
+ return response(request.body)
180
+ ```
181
+
182
+ In your ```src/__init__.py``` add the following code
183
+
184
+ ```python
185
+ from .routes.example import *
186
+ ```
187
+ Generate tokens with the following code as per the example above, tokens carry a payload and we add an additional ```expires``` value to the token based on the env variable ```TINA4_TOKEN_LIMIT```
153
188
 
154
189
  ```python
155
190
  import tina4_python
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "tina4-python"
3
- version = "0.1.43"
3
+ version = "0.1.45"
4
4
  description = "Tina4Python - This is not another framework for Python"
5
5
  authors = ["Andre van Zuydam <andrevanzuydam@gmail.com>"]
6
6
  readme = "README.md"
@@ -105,6 +105,10 @@ class Auth:
105
105
 
106
106
  def get_token(self, payload_data):
107
107
  private_key = self.load_private_key()
108
+ now = datetime.datetime.now()
109
+ token_limit_minutes = os.environ.get("TINA4_TOKEN_LIMIT", 2)
110
+ expiry_time = now + datetime.timedelta(minutes=token_limit_minutes)
111
+ payload_data["expires"] = expiry_time.isoformat()
108
112
  token = jwt.encode(
109
113
  payload=payload_data,
110
114
  key=private_key,
@@ -130,6 +134,15 @@ class Auth:
130
134
  public_key = self.load_public_key()
131
135
  try:
132
136
  payload = jwt.decode(token, key=public_key, algorithms=['RS256'])
137
+ if "expires" not in payload:
138
+ return False
139
+
140
+ if "expires" in payload:
141
+ now = datetime.datetime.now()
142
+ expiry_time = datetime.datetime.fromisoformat(payload["expires"])
143
+ print("TOKEN EXPIRY", now, expiry_time)
144
+ if now > expiry_time:
145
+ return False
133
146
  except Exception:
134
147
  return False
135
148
 
@@ -61,15 +61,24 @@ class Router:
61
61
  if method in [Constant.TINA4_POST, Constant.TINA4_PUT, Constant.TINA4_PATCH, Constant.TINA4_DELETE]:
62
62
  content = Template.render_twig_template(
63
63
  "errors/403.twig", {"server": {"url": url}})
64
- # check for token in the headers
65
- if "Authorization" not in headers:
66
- return Response(content, Constant.HTTP_FORBIDDEN, Constant.TEXT_HTML)
67
64
 
68
- token = headers["Authorization"].replace("Bearer", "").strip()
69
- if not (tina4_python.tina4_auth.valid(token)):
70
- return Response(content, Constant.HTTP_FORBIDDEN, Constant.TEXT_HTML)
65
+ validated = False
66
+ # check to see if we have an auth ability
67
+ if "Authorization" in headers:
68
+ token = headers["Authorization"].replace("Bearer", "").strip()
69
+ if tina4_python.tina4_auth.valid(token):
70
+ validated = True
71
71
 
72
- # @todo add other validations here for future security
72
+ if "formToken" in request["body"]:
73
+ token = request["body"]["formToken"]
74
+ if tina4_python.tina4_auth.valid(token):
75
+ validated = True
76
+
77
+ if not validated:
78
+ return Response(content, Constant.HTTP_FORBIDDEN, Constant.TEXT_HTML)
79
+ else:
80
+ if "formToken" in request["body"]:
81
+ del request["body"]["formToken"]
73
82
 
74
83
  # default response
75
84
  result = Response("", Constant.HTTP_NOT_FOUND, Constant.TEXT_HTML)
@@ -6,6 +6,7 @@
6
6
  import asyncio
7
7
  import json
8
8
  import random
9
+ from urllib.parse import unquote
9
10
  from urllib.parse import urlparse, parse_qsl
10
11
 
11
12
  import tina4_python
@@ -26,15 +27,27 @@ class Webserver:
26
27
  async def get_content_body(self, content_length):
27
28
  # get lines of content where at the end of the request
28
29
  content = self.request_raw[-content_length:]
29
-
30
30
  try:
31
+ print("JSON", content)
31
32
  content = json.loads(content)
32
33
  except Exception as e:
33
- content = ""
34
+ # check for form body
35
+ if content != "":
36
+ body = {}
37
+ variables = content.split("&", 1)
38
+ for variable in variables:
39
+ variable = variable.split("=", 1)
40
+ body[variable[0]] = unquote(variable[1])
41
+ return body
34
42
 
35
43
  return content
36
44
 
37
45
  async def get_response(self, method):
46
+ """
47
+
48
+ :param method: GET, POST, PATCH, DELETE, PUT
49
+ :return:
50
+ """
38
51
  headers = []
39
52
  if method == "OPTIONS":
40
53
  self.send_header("Access-Control-Allow-Origin", "*", headers)
@@ -48,7 +61,10 @@ class Webserver:
48
61
  params = dict(parse_qsl(urlparse(self.path).query, keep_blank_values=True))
49
62
 
50
63
  content_length = await self.get_content_length()
51
- body = await self.get_content_body(content_length)
64
+ if method != TINA4_GET:
65
+ body = await self.get_content_body(content_length)
66
+ else:
67
+ body = None
52
68
  request = {"params": params, "body": body, "raw": self.request}
53
69
 
54
70
  tina4_python.tina4_current_request = request
@@ -143,9 +159,9 @@ class Webserver:
143
159
 
144
160
  self.method = self.request.split(" ")[0]
145
161
 
146
- initial = self.request.split("\n\n")[0]
162
+ body_parts = self.request.split("\n\n")
147
163
 
148
- self.headers = initial.split("\n")
164
+ self.headers = body_parts[0].split("\n")
149
165
 
150
166
  # parse headers into a dictionary for more efficient use
151
167
  headers_list = {}