From cf11444a417ffc3d34e899dd835a018057eef42f Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 18 May 2017 15:11:11 +0530 Subject: [PATCH] Apply per library restrictions to all endpoints (I hope) --- src/calibre/srv/ajax.py | 9 +++++---- src/calibre/srv/books.py | 9 +++++---- src/calibre/srv/cdb.py | 4 +++- src/calibre/srv/code.py | 4 ++-- src/calibre/srv/content.py | 2 +- src/calibre/srv/opds.py | 6 +++--- 6 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/calibre/srv/ajax.py b/src/calibre/srv/ajax.py index 7768651c82..83ad6766e0 100644 --- a/src/calibre/srv/ajax.py +++ b/src/calibre/srv/ajax.py @@ -168,7 +168,7 @@ def book(ctx, rd, book_id, library_id): book_id = None except Exception: book_id = None - if book_id is None or not db.has_id(book_id): + if book_id is None or not ctx.has_id(rd, db, book_id): raise HTTPNotFound('Book with id %r does not exist' % oid) category_urls = rd.query.get('category_urls', 'true').lower() device_compatible = rd.query.get('device_compatible', 'false').lower() @@ -216,8 +216,9 @@ def books(ctx, rd, library_id): device_compatible = rd.query.get('device_compatible', 'false').lower() == 'true' device_for_template = rd.query.get('device_for_template', None) ans = {} + allowed_book_ids = ctx.allowed_book_ids(rd, db) for book_id in ids: - if not db.has_id(book_id): + if book_id not in allowed_book_ids: ans[book_id] = None continue data, lm = book_to_json( @@ -483,7 +484,7 @@ def books_in(ctx, rd, encoded_category, encoded_item, library_id): raise HTTPNotFound('%s is not a valid sort field'%sort) if dname in ('allbooks', 'newest'): - ids = db.all_book_ids() + ids = ctx.allowed_book_ids(rd, db) elif dname == 'search': try: ids = ctx.search(rd, db, 'search:"%s"'%ditem) @@ -497,7 +498,7 @@ def books_in(ctx, rd, encoded_category, encoded_item, library_id): if dname == 'news': dname = 'tags' - ids = db.get_books_for_category(dname, cid) + ids = db.get_books_for_category(dname, cid) & ctx.allowed_book_ids(rd, db) ids = db.multisort(fields=[(sfield, sort_order == 'asc')], ids_to_sort=ids) total_num = len(ids) diff --git a/src/calibre/srv/books.py b/src/calibre/srv/books.py index 70252688c2..e8d7545f06 100644 --- a/src/calibre/srv/books.py +++ b/src/calibre/srv/books.py @@ -130,7 +130,7 @@ def book_manifest(ctx, rd, book_id, fmt): force_reload = rd.query.get('force_reload') == '1' if plugin_for_input_format(fmt) is None: raise HTTPNotFound('The format %s cannot be viewed' % fmt.upper()) - if not db.has_id(book_id): + if not ctx.has_id(rd, db, book_id): raise HTTPNotFound('No book with id: %s in library: %s' % (book_id, library_id)) with db.safe_read_lock: fm = db.format_metadata(book_id, fmt) @@ -166,7 +166,7 @@ def book_manifest(ctx, rd, book_id, fmt): @endpoint('/book-file/{book_id}/{fmt}/{size}/{mtime}/{+name}', types={'book_id':int, 'size':int, 'mtime':int}) def book_file(ctx, rd, book_id, fmt, size, mtime, name): db, library_id = get_library_data(ctx, rd)[:2] - if not db.has_id(book_id): + if not ctx.has_id(rd, db, book_id): raise HTTPNotFound('No book with id: %s in library: %s' % (book_id, library_id)) bhash = book_hash(db.library_id, book_id, fmt, size, mtime) base = abspath(os.path.join(books_cache_dir(), 'f')) @@ -190,13 +190,14 @@ def get_last_read_position(ctx, rd, library_id, which): db = get_db(ctx, rd, library_id) user = rd.username or None ans = {} + allowed_book_ids = ctx.allowed_book_ids(rd, db) for item in which.split('_'): book_id, fmt = item.partition('-')[::2] try: book_id = int(book_id) except Exception: continue - if not db.has_id(book_id): + if book_id not in allowed_book_ids: continue key = '{}:{}'.format(book_id, fmt) ans[key] = db.get_last_read_positions(book_id, fmt, user) @@ -207,7 +208,7 @@ def get_last_read_position(ctx, rd, library_id, which): def set_last_read_position(ctx, rd, library_id, book_id, fmt): db = get_db(ctx, rd, library_id) user = rd.username or None - if not db.has_id(book_id): + if not ctx.has_id(rd, db, book_id): raise HTTPNotFound('No book with id {} found'.format(book_id)) try: data = jsonlib.load(rd.request_body_file) diff --git a/src/calibre/srv/cdb.py b/src/calibre/srv/cdb.py index 56e4b20ab3..f2f9b20b59 100644 --- a/src/calibre/srv/cdb.py +++ b/src/calibre/srv/cdb.py @@ -8,7 +8,7 @@ from functools import partial from calibre import as_unicode from calibre.db.cli import module_for_cmd -from calibre.srv.errors import HTTPBadRequest, HTTPNotFound +from calibre.srv.errors import HTTPBadRequest, HTTPNotFound, HTTPForbidden from calibre.srv.routes import endpoint, msgpack_or_json from calibre.srv.utils import get_library_data from calibre.utils.serialize import MSGPACK_MIME, json_loads, msgpack_loads @@ -38,6 +38,8 @@ def cdb_run(ctx, rd, which, version): except Exception: raise HTTPBadRequest('args are not valid encoded data') db = get_library_data(ctx, rd, strict_library_id=True)[0] + if ctx.restriction_for(rd, db): + raise HTTPForbidden('Cannot use the command-line db interface with a user who has per library restrictions') if getattr(m, 'needs_srv_ctx', False): args = [ctx] + list(args) try: diff --git a/src/calibre/srv/code.py b/src/calibre/srv/code.py index 81f591835a..2b72f2cf5f 100644 --- a/src/calibre/srv/code.py +++ b/src/calibre/srv/code.py @@ -312,9 +312,9 @@ def book_metadata(ctx, rd, book_id): raise HTTPNotFound(_('No book with id: {} in library: {}').format(book_id, library_id)) if not book_id: - all_ids = db.books_in_virtual_library(vl) if vl else db.all_book_ids() + all_ids = ctx.allowed_book_ids(rd, db) book_id = random.choice(tuple(all_ids)) - elif not db.has_id(book_id): + elif not ctx.has_id(rd, db, book_id): notfound() data = book_as_json(db, book_id) if data is None: diff --git a/src/calibre/srv/content.py b/src/calibre/srv/content.py index 2fe64f7933..8f732e6da8 100644 --- a/src/calibre/srv/content.py +++ b/src/calibre/srv/content.py @@ -280,7 +280,7 @@ def get(ctx, rd, what, book_id, library_id): if db is None: raise HTTPNotFound('Library %r not found' % library_id) with db.safe_read_lock: - if not db.has_id(book_id): + if not ctx.has_id(rd, db, book_id): raise HTTPNotFound('Book with id %r does not exist' % book_id) library_id = db.server_library_id # in case library_id was None if what == 'thumb': diff --git a/src/calibre/srv/opds.py b/src/calibre/srv/opds.py index 944513e469..eed260f4e3 100644 --- a/src/calibre/srv/opds.py +++ b/src/calibre/srv/opds.py @@ -367,8 +367,8 @@ class RequestContext(object): ans += '?' + urlencode(q) return ans - def all_book_ids(self): - return self.db.all_book_ids() + def allowed_book_ids(self): + return self.ctx.allowed_book_ids(self.rd, self.db) @property def outheaders(self): @@ -414,7 +414,7 @@ def get_all_books(rc, which, page_url, up_url, offset=0): ascending = which == 'title' feed_title = {'newest':_('Newest'), 'title': _('Title')}.get(which, which) feed_title = default_feed_title + ' :: ' + _('By %s') % feed_title - ids = rc.all_book_ids() + ids = rc.allowed_book_ids() return get_acquisition_feed(rc, ids, offset, page_url, up_url, id_='calibre-all:'+sort, sort_by=sort, ascending=ascending, feed_title=feed_title)