diff options
Diffstat (limited to 'module/web')
-rw-r--r-- | module/web/api_app.py | 6 | ||||
-rw-r--r-- | module/web/json_app.py | 113 | ||||
-rw-r--r-- | module/web/pyload_app.py | 127 | ||||
-rw-r--r-- | module/web/templates/default/admin.html | 50 | ||||
-rw-r--r-- | module/web/templates/default/base.html | 4 | ||||
-rw-r--r-- | module/web/utils.py | 61 | ||||
-rw-r--r-- | module/web/webinterface.py | 1 |
7 files changed, 101 insertions, 261 deletions
diff --git a/module/web/api_app.py b/module/web/api_app.py index 32b128e6a..156922d6a 100644 --- a/module/web/api_app.py +++ b/module/web/api_app.py @@ -14,7 +14,6 @@ from utils import toDict, set_session from webinterface import PYLOAD from module.common.json_layer import json_dumps -from module.database.UserDatabase import ROLE try: from ast import literal_eval @@ -46,9 +45,12 @@ def call_api(func, args=""): if 'session' in request.POST: s = s.get_by_id(request.POST['session']) - if not s or not s.get("authenticated", False) or s.get("role", -1) != ROLE.ADMIN: + if not s or not s.get("authenticated", False): return HTTPError(401, json_dumps("Unauthorized")) + if not PYLOAD.isAuthorized(func, {"role": s["role"], "permission": s["perms"]}): + return HTTPError(403, json_dumps("Forbidden")) + args = args.split("/")[1:] kwargs = {} diff --git a/module/web/json_app.py b/module/web/json_app.py index 0573eff77..6d50525bb 100644 --- a/module/web/json_app.py +++ b/module/web/json_app.py @@ -31,7 +31,7 @@ def get_sort_key(item): @route("/json/status") @route("/json/status", method="POST") -@login_required('see_downloads') +@login_required('LIST') def status(): try: status = toDict(PYLOAD.statusServer()) @@ -43,7 +43,7 @@ def status(): @route("/json/links") @route("/json/links", method="POST") -@login_required('see_downloads') +@login_required('LIST') def links(): try: links = [toDict(x) for x in PYLOAD.statusDownloads()] @@ -69,7 +69,7 @@ def links(): @route("/json/queue") -@login_required('see_downloads') +@login_required('LIST') def queue(): print "/json/queue" try: @@ -80,7 +80,7 @@ def queue(): @route("/json/pause") -@login_required('status') +@login_required('STATUS') def pause(): try: return PYLOAD.pauseServer() @@ -90,7 +90,7 @@ def pause(): @route("/json/unpause") -@login_required('status') +@login_required('STATUS') def unpause(): try: return PYLOAD.unpauseServer() @@ -100,7 +100,7 @@ def unpause(): @route("/json/cancel") -@login_required('status') +@login_required('STATUS') def cancel(): try: return PYLOAD.stopAllDownloads() @@ -109,7 +109,7 @@ def cancel(): @route("/json/packages") -@login_required('see_downloads') +@login_required('LIST') def packages(): print "/json/packages" try: @@ -128,7 +128,7 @@ def packages(): @route("/json/package/:id") @validate(id=int) -@login_required('see_downloads') +@login_required('LIST') def package(id): try: data = toDict(PYLOAD.getPackageData(id)) @@ -163,7 +163,7 @@ def package(id): @route("/json/package_order/:ids") -@login_required('add') +@login_required('ADD') def package_order(ids): try: pid, pos = ids.split("|") @@ -175,7 +175,7 @@ def package_order(ids): @route("/json/link/:id") @validate(id=int) -@login_required('see_downloads') +@login_required('LIST') def link(id): print "/json/link/%d" % id try: @@ -187,7 +187,7 @@ def link(id): @route("/json/remove_link/:id") @validate(id=int) -@login_required('delete') +@login_required('DELETE') def remove_link(id): try: PYLOAD.deleteFiles([id]) @@ -198,7 +198,7 @@ def remove_link(id): @route("/json/restart_link/:id") @validate(id=int) -@login_required('add') +@login_required('ADD') def restart_link(id): try: PYLOAD.restartFile(id) @@ -209,7 +209,7 @@ def restart_link(id): @route("/json/abort_link/:id") @validate(id=int) -@login_required('delete') +@login_required('DELETE') def abort_link(id): try: PYLOAD.stopDownloads([id]) @@ -219,7 +219,7 @@ def abort_link(id): @route("/json/link_order/:ids") -@login_required('add') +@login_required('ADD') def link_order(ids): try: pid, pos = ids.split("|") @@ -231,7 +231,7 @@ def link_order(ids): @route("/json/add_package") @route("/json/add_package", method="POST") -@login_required('add') +@login_required('ADD') def add_package(): name = request.forms.get("add_name", "New Package").strip() queue = int(request.forms['add_dest']) @@ -267,7 +267,7 @@ def add_package(): @route("/json/remove_package/:id") @validate(id=int) -@login_required('delete') +@login_required('DELETE') def remove_package(id): try: PYLOAD.deletePackages([id]) @@ -278,7 +278,7 @@ def remove_package(id): @route("/json/restart_package/:id") @validate(id=int) -@login_required('add') +@login_required('MODIFY') def restart_package(id): try: PYLOAD.restartPackage(id) @@ -290,7 +290,7 @@ def restart_package(id): @route("/json/move_package/:dest/:id") @validate(dest=int, id=int) -@login_required('add') +@login_required('MODIFY') def move_package(dest, id): try: PYLOAD.movePackage(dest, id) @@ -300,7 +300,7 @@ def move_package(dest, id): @route("/json/edit_package", method="POST") -@login_required('add') +@login_required('MODIFY') def edit_package(): try: id = int(request.forms.get("pack_id")) @@ -317,7 +317,7 @@ def edit_package(): @route("/json/set_captcha") @route("/json/set_captcha", method="POST") -@login_required('add') +@login_required('ADD') def set_captcha(): if request.environ.get('REQUEST_METHOD', "GET") == "POST": try: @@ -336,13 +336,13 @@ def set_captcha(): @route("/json/delete_finished") -@login_required('delete') +@login_required('DELETE') def delete_finished(): return {"del": PYLOAD.deleteFinished()} @route("/json/restart_failed") -@login_required('delete') +@login_required('MODIFY') def restart_failed(): restart = PYLOAD.restartFailed() @@ -351,7 +351,7 @@ def restart_failed(): @route("/json/load_config/:category/:section") -@login_required("settings") +@login_required("SETTINGS") def load_config(category, section): conf = None if category == "general": @@ -371,7 +371,7 @@ def load_config(category, section): @route("/json/save_config/:category", method="POST") -@login_required("settings") +@login_required("SETTINGS") def save_config(category): for key, value in request.POST.iteritems(): try: @@ -385,7 +385,7 @@ def save_config(category): @route("/json/add_account", method="POST") -@login_required("settings") +@login_required("ACCOUNTS") def add_account(): login = request.POST["account_login"] password = request.POST["account_password"] @@ -395,7 +395,7 @@ def add_account(): @route("/json/update_accounts", method="POST") -@login_required("settings") +@login_required("ACCOUNTS") def update_accounts(): deleted = [] #dont update deleted accs or they will be created again @@ -428,64 +428,3 @@ def change_password(): if not PYLOAD.changePassword(user, oldpw, newpw): print "Wrong password" return HTTPError() - -#@route("/json/filemanager/rename", method="POST") -#@login_required('filemanager') -def rename_dir(): - try: - path = decode(request.forms.get("path")) - old_name = path + "/" + decode(request.forms.get("old_name")) - new_name = path + "/" + decode(request.forms.get("new_name")) - - try: - #check if file exists - os.rename(old_name, new_name) - except Exception, e: - return {"response": "fail", "error": str(e) + "\n" + old_name + " => " + new_name} - - return {"response": "success"} - - except: - return HTTPError() - - -#@route("/json/filemanager/delete", method="POST") -#@login_required('filemanager') -def delete_dir(): - try: - try: - path = decode(request.forms.get("path")) - name = decode(request.forms.get("name")) - shutil.rmtree(path + "/" + name) - except Exception, e: - return {"response": "fail", "error": str(e) + "\n" + path + "/" + name} - - return {"response": "success"} - - except: - return HTTPError() - - -#@route("/json/filemanager/mkdir", method="POST") -#@login_required('filemanager') -def make_dir(): - try: - path = decode(request.forms.get("path")) - name = decode(request.forms.get("name")) - try: - #i = 1 - #full_name = path + "/" + name - #while os.path.exists(full_name) - # full_name = full_name + i - # i = i + 1 - # - #os.mkdir(full_name) - - os.mkdir(path + "/" + name) - except Exception, e: - return {"response": "fail", "error": str(e) + "\nUnable to create directory: " + path + "/" + name} - - return {"response": "success", "path": path, "name": name} - - except: - return HTTPError() diff --git a/module/web/pyload_app.py b/module/web/pyload_app.py index 49568baad..553eeaa57 100644 --- a/module/web/pyload_app.py +++ b/module/web/pyload_app.py @@ -32,11 +32,11 @@ from bottle import route, static_file, request, response, redirect, HTTPError, e from webinterface import PYLOAD, PYLOAD_DIR, PROJECT_DIR, SETUP from utils import render_to_response, parse_permissions, parse_userdata, \ - login_required, get_permission, set_permission, toDict, set_session + login_required, get_permission, set_permission, permlist, toDict, set_session from filters import relpath, unquotepath -from module.utils import formatSize, decode, fs_decode +from module.utils import formatSize, fs_decode # Helper @@ -132,7 +132,7 @@ def logout(): @route("/") @route("/home") -@login_required("see_downloads") +@login_required("LIST") def home(): try: res = [toDict(x) for x in PYLOAD.statusDownloads()] @@ -149,7 +149,7 @@ def home(): @route("/queue") -@login_required("see_downloads") +@login_required("LIST") def queue(): queue = PYLOAD.getQueue() @@ -159,7 +159,7 @@ def queue(): @route("/collector") -@login_required('see_downloads') +@login_required('LIST') def collector(): queue = PYLOAD.getCollector() @@ -169,7 +169,7 @@ def collector(): @route("/downloads") -@login_required('download') +@login_required('DOWNLOAD') def downloads(): root = fs_decode(PYLOAD.getConfigValue("general", "download_folder")) @@ -205,7 +205,7 @@ def downloads(): @route("/downloads/get/:path#.+#") -@login_required("download") +@login_required("DOWNLOAD") def get_download(path): path = unquote(path) #@TODO some files can not be downloaded @@ -221,64 +221,9 @@ def get_download(path): return HTTPError(404, "File not Found.") -#@route("/filemanager") -#@login_required('filemanager') -def filemanager(): - root = PYLOAD.getConfigValue("general", "download_folder") - - if not isdir(root): - return base([_('Download directory not found.')]) - - root_node = {'name': '/', - 'path': root, - 'files': [], - 'folders': [] - } - - for item in sorted(listdir(root)): - if isdir(join(root, item)): - root_node['folders'].append(iterate_over_dir(root, item)) - elif isfile(join(root, item)): - f = { - 'name': decode(item), - 'path': root - } - root_node['files'].append(f) - - return render_to_response('filemanager.html', {'root': root_node}, [pre_processor]) - - -def iterate_over_dir(root, dir): - out = { - 'name': decode(dir), - 'path': root, - 'files': [], - 'folders': [] - } - for item in sorted(listdir(join(root, dir))): - subroot = join(root, dir) - if isdir(join(subroot, item)): - out['folders'].append(iterate_over_dir(subroot, item)) - elif isfile(join(subroot, item)): - f = { - 'name': decode(item), - 'path': subroot - } - out['files'].append(f) - - return out - - -#@route("/filemanager/get_dir", "POST") -#@login_required('filemanager') -def folder(): - path = request.forms.get("path").decode("utf8", "ignore") - name = request.forms.get("name").decode("utf8", "ignore") - return render_to_response('folder.html', {'path': path, 'name': name}, [pre_processor]) - @route("/settings") -@login_required('settings') +@login_required('SETTINGS') def config(): conf = PYLOAD.getConfig() plugin = PYLOAD.getPluginConfig() @@ -327,7 +272,7 @@ def config(): @route("/package_ui.js") -@login_required('see_downloads') +@login_required('LIST') def package_ui(): response.headers['Expires'] = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(time.time() + 60 * 60 * 24 * 7)) @@ -336,7 +281,7 @@ def package_ui(): @route("/filemanager_ui.js") -@login_required('see_downloads') +@login_required('LIST') def package_ui(): response.headers['Expires'] = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(time.time() + 60 * 60 * 24 * 7)) @@ -348,7 +293,7 @@ def package_ui(): @route("/pathchooser") @route("/filechooser/:file#.+#") @route("/pathchooser/:path#.+#") -@login_required('status') +@login_required('STATUS') def path(file="", path=""): if file: type = "file" @@ -438,7 +383,7 @@ def path(file="", path=""): @route("/logs", method="POST") @route("/logs/:item") @route("/logs/:item", method="POST") -@login_required('status') +@login_required('STATUS') def logs(item=-1): s = request.environ.get('beaker.session') @@ -523,14 +468,17 @@ def logs(item=-1): @route("/admin") @route("/admin", method="POST") -@login_required("is_admin") +@login_required("ADMIN") def admin(): user = PYLOAD.getAllUserData() + perms = permlist() + for data in user.itervalues(): data["perms"] = {} get_permission(data["perms"], data["permission"]) data["perms"]["admin"] = True if data["role"] is 0 else False + s = request.environ.get('beaker.session') if request.environ.get('REQUEST_METHOD', "GET") == "POST": for name in user: @@ -541,46 +489,19 @@ def admin(): user[name]["role"] = 1 user[name]["perms"]["admin"] = False - if request.POST.get("%s|add" % name, False): - user[name]["perms"]["add"] = True - else: - user[name]["perms"]["add"] = False - - if request.POST.get("%s|delete" % name, False): - user[name]["perms"]["delete"] = True - else: - user[name]["perms"]["delete"] = False - - if request.POST.get("%s|status" % name, False): - user[name]["perms"]["status"] = True - else: - user[name]["perms"]["status"] = False - - if request.POST.get("%s|see_downloads" % name, False): - user[name]["perms"]["see_downloads"] = True - else: - user[name]["perms"]["see_downloads"] = False - - if request.POST.get("%s|download" % name, False): - user[name]["perms"]["download"] = True - else: - user[name]["perms"]["download"] = False - - if request.POST.get("%s|settings" % name, False): - user[name]["perms"]["settings"] = True - else: - user[name]["perms"]["settings"] = False - - if request.POST.get("%s|filemanager" % name, False): - user[name]["perms"]["filemanager"] = True - else: - user[name]["perms"]["filemanager"] = False + # set all perms to false + for perm in perms: + user[name]["perms"][perm] = False + + + for perm in request.POST.getall("%s|perms" % name): + user[name]["perms"][perm] = True user[name]["permission"] = set_permission(user[name]["perms"]) PYLOAD.setUserPermission(name, user[name]["permission"], user[name]["role"]) - return render_to_response("admin.html", {"users": user}, [pre_processor]) + return render_to_response("admin.html", {"users": user, "permlist": perms}, [pre_processor]) @route("/setup") diff --git a/module/web/templates/default/admin.html b/module/web/templates/default/admin.html index 7b9a8b32d..96c5e7ef3 100644 --- a/module/web/templates/default/admin.html +++ b/module/web/templates/default/admin.html @@ -72,9 +72,8 @@ {% block content %} - {{ _("Note: You can only change permissions for webinterface.") }} {{ _("To add user or change passwords use:") }} <b>python pyLoadCore.py -u</b><br> - {{ _("Important: Admin user have always all permissions! Only Admin user can use other clients like CLI and GUI.") }} + {{ _("Important: Admin user have always all permissions!") }} <form action="" method="POST"> <table class="settable wide"> @@ -89,48 +88,27 @@ {{ _("Admin") }} </th> <th> - {{ _("Add downloads") }} - </th> - <th> - {{ _("Delete downloads") }} - </th> - <th> - {{ _("Change server status") }} - </th> - <th> - {{ _("See queue/collector") }} - </th> - <th> - {{ _("Download from webinterface") }} - </th> - <th> - {{ _("Change settings") }} - </th> - <th> - {{ _("Filemanager") }} + {{ _("Permissions") }} </th> </thead> - {% for name, data in users.iteritems ( ) %} + {% for name, data in users.iteritems() %} <tr> <td>{{ name }}</td> <td><a class="change_password" href="#" id="change_pw|{{name}}">{{ _("change") }}</a></td> <td><input name="{{ name }}|admin" type="checkbox" {% if data.perms.admin %} checked="True" {% endif %}"></td> - <td><input name="{{ name }}|add" type="checkbox" {% if data.perms.add %} checked="True" {% endif %} - "></td> - <td><input name="{{ name }}|delete" type="checkbox" {% if data.perms.delete %} - checked="True" {% endif %}"></td> - <td><input name="{{ name }}|status" type="checkbox" {% if data.perms.status %} - checked="True" {% endif %}"></td> - <td><input name="{{ name }}|see_downloads" type="checkbox" {% if data.perms.see_downloads %} - checked="True" {% endif %}"></td> - <td><input name="{{ name }}|download" type="checkbox" {% if data.perms.download %} - checked="True" {% endif %}"></td> - <td><input name="{{ name }}|settings" type="checkbox" {% if data.perms.settings %} - checked="True" {% endif %}"></td> - <td><input name="{{ name }}|filemanager" type="checkbox" {% if data.perms.filemanager %} - checked="True" {% endif %}"></td> + <td> + <select multiple="multiple" size="{{ permlist|length }}" name="{{ name }}|perms"> + {% for perm in permlist %} + {% if data.perms|getitem(perm) %} + <option selected="selected">{{ perm }}</option> + {% else %} + <option>{{ perm }}</option> + {% endif %} + {% endfor %} + </select> + </td> </tr> {% endfor %} diff --git a/module/web/templates/default/base.html b/module/web/templates/default/base.html index 4057d320c..2987cf081 100644 --- a/module/web/templates/default/base.html +++ b/module/web/templates/default/base.html @@ -257,7 +257,7 @@ function AddBox(){ <div style="clear:both;"></div>
</div>
-{% if perms.status %}
+{% if perms.STATUS %}
<ul id="page-actions2">
<li id="action_play"><a href="#" class="action play" accesskey="o" rel="nofollow">{{_("Start")}}</a></li>
<li id="action_stop"><a href="#" class="action stop" accesskey="o" rel="nofollow">{{_("Stop")}}</a></li>
@@ -266,7 +266,7 @@ function AddBox(){ </ul>
{% endif %}
-{% if perms.see_downloads %}
+{% if perms.LIST %}
<ul id="page-actions">
<li><span class="time">{{_("Download:")}}</span><a id="time" style=" background-color: {% if status.download %}#8ffc25{% else %} #fc6e26{% endif %}; padding-left: 0cm; padding-right: 0.1cm; "> {% if status.download %}{{_("on")}}{% else %}{{_("off")}}{% endif %}</a></li>
<li><span class="reconnect">{{_("Reconnect:")}}</span><a id="reconnect" style=" background-color: {% if status.reconnect %}#8ffc25{% else %} #fc6e26{% endif %}; padding-left: 0cm; padding-right: 0.1cm; "> {% if status.reconnect %}{{_("on")}}{% else %}{{_("off")}}{% endif %}</a></li>
diff --git a/module/web/utils.py b/module/web/utils.py index 39ddb361f..a89c87558 100644 --- a/module/web/utils.py +++ b/module/web/utils.py @@ -20,7 +20,7 @@ from bottle import request, HTTPError, redirect, ServerAdapter from webinterface import env, TEMPLATE -from module.database.UserDatabase import has_permission, PERMS, ROLE +from module.Api import has_permission, PERMS, ROLE def render_to_response(name, args={}, proc=[]): for p in proc: @@ -29,15 +29,11 @@ def render_to_response(name, args={}, proc=[]): t = env.get_template(TEMPLATE + "/" + name) return t.render(**args) + def parse_permissions(session): - perms = {"add": False, - "delete": False, - "status": False, - "see_downloads": False, - "download" : False, - "filemanager" : False, - "settings": False, - "is_admin": False} + perms = dict([(x, False) for x in dir(PERMS) if not x.startswith("_")]) + perms["ADMIN"] = False + perms["is_admin"] = False if not session.get("authenticated", False): return perms @@ -53,31 +49,31 @@ def parse_permissions(session): return perms +def permlist(): + return [x for x in dir(PERMS) if not x.startswith("_") and x != "ALL"] + + def get_permission(perms, p): - perms["add"] = has_permission(p, PERMS.ADD) - perms["delete"] = has_permission(p, PERMS.DELETE) - perms["status"] = has_permission(p, PERMS.STATUS) - perms["see_downloads"] = has_permission(p, PERMS.SEE_DOWNLOADS) - perms["download"] = has_permission(p, PERMS.DOWNLOAD) - perms["settings"] = has_permission(p, PERMS.SETTINGS) - perms["accounts"] = has_permission(p, PERMS.ACCOUNTS) + """Returns a dict with permission key + + :param perms: dictionary + :param p: bits + """ + for name in permlist(): + perms[name] = has_permission(p, getattr(PERMS, name)) + def set_permission(perms): + """generates permission bits from dictionary + + :param perms: dict + """ permission = 0 - if perms["add"]: - permission |= PERMS.ADD - if perms["delete"]: - permission |= PERMS.DELETE - if perms["status"]: - permission |= PERMS.STATUS - if perms["see_downloads"]: - permission |= PERMS.SEE_DOWNLOADS - if perms["download"]: - permission |= PERMS.DOWNLOAD - if perms["settings"]: - permission |= PERMS.SETTINGS - if perms["accounts"]: - permission |= PERMS.ACCOUNTS + for name in dir(PERMS): + if name.startswith("_"): continue + + if name in perms and perms[name]: + permission |= getattr(PERMS, name) return permission @@ -94,11 +90,13 @@ def set_session(request, info): return s + def parse_userdata(session): return {"name": session.get("name", "Anonymous"), "is_admin": True if session.get("role", 1) == 0 else False, "is_authenticated": session.get("authenticated", False)} + def login_required(perm=None): def _dec(func): def _view(*args, **kwargs): @@ -123,14 +121,15 @@ def login_required(perm=None): return _dec + def toDict(obj): ret = {} for att in obj.__slots__: ret[att] = getattr(obj, att) return ret -class CherryPyWSGI(ServerAdapter): +class CherryPyWSGI(ServerAdapter): def run(self, handler): from wsgiserver import CherryPyWSGIServer diff --git a/module/web/webinterface.py b/module/web/webinterface.py index f6ad35138..8f814715f 100644 --- a/module/web/webinterface.py +++ b/module/web/webinterface.py @@ -89,6 +89,7 @@ env.filters["path_make_absolute"] = path_make_absolute env.filters["decode"] = decode env.filters["type"] = lambda x: str(type(x)) env.filters["formatsize"] = formatSize +env.filters["getitem"] = lambda x,y: x.__getitem__(y) if PREFIX: env.filters["url"] = lambda x: x else: |