summaryrefslogtreecommitdiffstats
path: root/module/web
diff options
context:
space:
mode:
Diffstat (limited to 'module/web')
-rw-r--r--module/web/api_app.py6
-rw-r--r--module/web/json_app.py113
-rw-r--r--module/web/pyload_app.py127
-rw-r--r--module/web/templates/default/admin.html50
-rw-r--r--module/web/templates/default/base.html4
-rw-r--r--module/web/utils.py61
-rw-r--r--module/web/webinterface.py1
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: