pluginserver 0.5.6__tar.gz → 0.6.0__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.
- {pluginserver-0.5.6/pluginserver.egg-info → pluginserver-0.6.0}/PKG-INFO +1 -1
- pluginserver-0.6.0/README.md +8 -0
- {pluginserver-0.5.6 → pluginserver-0.6.0}/plugincore/baseplugin.py +29 -2
- {pluginserver-0.5.6 → pluginserver-0.6.0}/plugincore/pserv.py +62 -9
- {pluginserver-0.5.6 → pluginserver-0.6.0/pluginserver.egg-info}/PKG-INFO +1 -1
- {pluginserver-0.5.6 → pluginserver-0.6.0}/setup.py +1 -1
- pluginserver-0.5.6/README.md +0 -11
- {pluginserver-0.5.6 → pluginserver-0.6.0}/LICENSE.txt +0 -0
- {pluginserver-0.5.6 → pluginserver-0.6.0}/MANIFEST.in +0 -0
- {pluginserver-0.5.6 → pluginserver-0.6.0}/plugincore/__init__.py +0 -0
- {pluginserver-0.5.6 → pluginserver-0.6.0}/plugincore/configfile.py +0 -0
- {pluginserver-0.5.6 → pluginserver-0.6.0}/plugincore/cors.py +0 -0
- {pluginserver-0.5.6 → pluginserver-0.6.0}/plugincore/pluginmanager.py +0 -0
- {pluginserver-0.5.6 → pluginserver-0.6.0}/pluginserver.egg-info/SOURCES.txt +0 -0
- {pluginserver-0.5.6 → pluginserver-0.6.0}/pluginserver.egg-info/dependency_links.txt +0 -0
- {pluginserver-0.5.6 → pluginserver-0.6.0}/pluginserver.egg-info/entry_points.txt +0 -0
- {pluginserver-0.5.6 → pluginserver-0.6.0}/pluginserver.egg-info/requires.txt +0 -0
- {pluginserver-0.5.6 → pluginserver-0.6.0}/pluginserver.egg-info/top_level.txt +0 -0
- {pluginserver-0.5.6 → pluginserver-0.6.0}/setup.cfg +0 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Plugin Server
|
|
2
|
+
|
|
3
|
+
Plugin Server is a python script and library to manage a REST-like API server utilizing a plugin system to handle requests to API routes. It is built upon Python async and aiohttp.
|
|
4
|
+
|
|
5
|
+
# Installing Plugin Server
|
|
6
|
+
Please see the [Installation Instructions](https://pluginserver.readthedocs.io/en/latest/Install.html) for details.
|
|
7
|
+
|
|
8
|
+
Please see the [Project Documentation](https://pluginserver.readthedocs.io/) for information on usage, configuration and more.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from aiohttp import web
|
|
2
|
+
import base64
|
|
2
3
|
|
|
3
4
|
class BasePlugin:
|
|
4
5
|
"""
|
|
@@ -27,9 +28,35 @@ class BasePlugin:
|
|
|
27
28
|
self.args = dict(kwargs)
|
|
28
29
|
|
|
29
30
|
def _check_auth(self,data):
|
|
30
|
-
|
|
31
|
+
toktype = 'Undefined'
|
|
32
|
+
def get_token(data):
|
|
33
|
+
nonlocal toktype
|
|
34
|
+
headers = data.get('request_headers', {})
|
|
35
|
+
auth_header = headers.get('Authorization')
|
|
36
|
+
if auth_header and auth_header.startswith('Bearer '):
|
|
37
|
+
toktype = 'token'
|
|
38
|
+
return auth_header.split(' ', 1)[1].strip()
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
def get_custom_header_token(data):
|
|
42
|
+
nonlocal toktype
|
|
43
|
+
headers = data.get('request_headers', {})
|
|
44
|
+
custom_header = headers.get('X-Custom-Auth')
|
|
45
|
+
toktype = 'custom'
|
|
46
|
+
if custom_header:
|
|
47
|
+
return custom_header.strip()
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
def get_user_token(data):
|
|
51
|
+
nonlocal toktype
|
|
52
|
+
token = data.get('apikey')
|
|
53
|
+
if token:
|
|
54
|
+
toktype='userdata'
|
|
55
|
+
return token
|
|
56
|
+
user_key = get_token(data) or get_custom_header_token(data) or get_user_token(data)
|
|
57
|
+
print(f"_check_auth: type: {toktype} {self._auth_type} apikey {self._apikey}, args {data}")
|
|
58
|
+
|
|
31
59
|
if self._auth_type:
|
|
32
|
-
user_key = data.get('apikey')
|
|
33
60
|
#print(f"Checking {user_key}")
|
|
34
61
|
if not user_key:
|
|
35
62
|
#print("Returning false")
|
|
@@ -90,12 +90,43 @@ def main():
|
|
|
90
90
|
|
|
91
91
|
# --- Auth Helper ---
|
|
92
92
|
def check_auth(data, config):
|
|
93
|
+
toktype = 'Undefined'
|
|
94
|
+
def get_token(data):
|
|
95
|
+
nonlocal toktype
|
|
96
|
+
headers = data.get('request_headers', {})
|
|
97
|
+
auth_header = headers.get('Authorization')
|
|
98
|
+
if auth_header and auth_header.startswith('Bearer '):
|
|
99
|
+
toktype = 'token'
|
|
100
|
+
return auth_header.split(' ', 1)[1].strip()
|
|
101
|
+
return None
|
|
102
|
+
|
|
103
|
+
def get_custom_header_token(data):
|
|
104
|
+
nonlocal toktype
|
|
105
|
+
headers = data.get('request_headers', {})
|
|
106
|
+
custom_header = headers.get('X-Custom-Auth')
|
|
107
|
+
toktype = 'custom'
|
|
108
|
+
if custom_header:
|
|
109
|
+
return custom_header.strip()
|
|
110
|
+
return None
|
|
111
|
+
|
|
112
|
+
def get_user_token(data):
|
|
113
|
+
nonlocal toktype
|
|
114
|
+
token = data.get('apikey')
|
|
115
|
+
if token:
|
|
116
|
+
toktype='userdata'
|
|
117
|
+
return token
|
|
93
118
|
try:
|
|
94
119
|
expected = config.auth.apikey
|
|
95
120
|
except AttributeError:
|
|
96
|
-
|
|
97
|
-
provided = data
|
|
98
|
-
|
|
121
|
+
return True
|
|
122
|
+
provided = get_token(data) or get_custom_header_token(data) or get_user_token(data)
|
|
123
|
+
#print(f"pserv:check_auth: provided/expected: {provided}/{expected}")
|
|
124
|
+
if not provided:
|
|
125
|
+
print("Returning false")
|
|
126
|
+
return False
|
|
127
|
+
auth_ok = expected == provided
|
|
128
|
+
#print("Returning {auth_ok}")
|
|
129
|
+
return auth_ok
|
|
99
130
|
|
|
100
131
|
# --- Plugin Request Handler ---
|
|
101
132
|
def register_plugin_route(plugin_id, instance, config):
|
|
@@ -125,16 +156,31 @@ def register_plugin_route(plugin_id, instance, config):
|
|
|
125
156
|
|
|
126
157
|
# --- Control Routes ---
|
|
127
158
|
def register_control_routes(config):
|
|
128
|
-
|
|
159
|
+
print("Registering Control Routes")
|
|
160
|
+
@routes.route('*','/plugins')
|
|
129
161
|
async def plugin_list(request):
|
|
130
|
-
data =
|
|
162
|
+
data = {}
|
|
163
|
+
if request.method == 'POST' and request.can_read_body:
|
|
164
|
+
try:
|
|
165
|
+
data.update(await request.json())
|
|
166
|
+
except Exception:
|
|
167
|
+
pass
|
|
168
|
+
data.update(request.query)
|
|
169
|
+
data['request_headers'] = dict(request.headers)
|
|
131
170
|
if not check_auth(data, config):
|
|
132
171
|
return web.json_response({'error': 'unauthorized'}, status=403)
|
|
133
172
|
return corsobj.apply_headers(web.json_response({'loaded_plugins': list(manager.plugins.keys())}),request)
|
|
134
173
|
|
|
135
|
-
@routes.
|
|
174
|
+
@routes.route('*','/reload/{plugin_id}')
|
|
136
175
|
async def reload_plugin(request):
|
|
137
|
-
data =
|
|
176
|
+
data = {}
|
|
177
|
+
if request.method == 'POST' and request.can_read_body:
|
|
178
|
+
try:
|
|
179
|
+
data.update(await request.json())
|
|
180
|
+
except Exception:
|
|
181
|
+
pass
|
|
182
|
+
data.update(request.query)
|
|
183
|
+
data['request_headers'] = dict(request.headers)
|
|
138
184
|
if not check_auth(data, config):
|
|
139
185
|
return corsobj.apply_headers(web.json_response({'error': 'unauthorized'}, status=403),request)
|
|
140
186
|
|
|
@@ -144,9 +190,16 @@ def register_control_routes(config):
|
|
|
144
190
|
return corsobj.apply_headers(web.json_response({'reloaded': pid, 'success': success}),request)
|
|
145
191
|
return corsobj.apply_headers(web.json_response({'error': f'Plugin "{pid}" not found'}, status=404),request)
|
|
146
192
|
|
|
147
|
-
@routes.
|
|
193
|
+
@routes.route('*', '/reload/all')
|
|
148
194
|
async def reload_all(request):
|
|
149
|
-
data =
|
|
195
|
+
data = {}
|
|
196
|
+
if request.method == 'POST' and request.can_read_body:
|
|
197
|
+
try:
|
|
198
|
+
data.update(await request.json())
|
|
199
|
+
except Exception:
|
|
200
|
+
pass
|
|
201
|
+
data.update(request.query)
|
|
202
|
+
data['request_headers'] = dict(request.headers)
|
|
150
203
|
if not check_auth(data, config):
|
|
151
204
|
return corsobj.apply_headers(web.json_response({'error': 'unauthorized'}, status=403),request)
|
|
152
205
|
manager.load_plugins()
|
pluginserver-0.5.6/README.md
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
# Plugin Server
|
|
2
|
-
|
|
3
|
-
This server implements an API server using rest-like API routes. The server is implemented
|
|
4
|
-
in Python using aiohttp.
|
|
5
|
-
|
|
6
|
-
This relatively simplistic RESTapi servers use routes to determine the request handler when a request
|
|
7
|
-
is made. A route is simply the ‘tail’ of the web address being requested.
|
|
8
|
-
Think of a web address like `https://server.domain.tld/tail`. The tail portion is the route.
|
|
9
|
-
|
|
10
|
-
Please see the documentation at [https://pluginserver.readthedocs.io](https://pluginserver.readthedocs.io/en/latest/).
|
|
11
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|