1
0
mirror of https://github.com/janeczku/calibre-web synced 2026-05-07 14:11:25 +00:00

4731 Commits

Author SHA1 Message Date
Ozzie Isaacs
f4ed816f6e Fixes from testrun 2026-04-26 07:27:06 +02:00
Ozzie Isaacs
ba77f41325 Merge remote-tracking branch 'fixes/notrace' 2026-04-25 16:04:51 +02:00
Ozzie Isaacs
ea567fcbf0 Updated translation 2026-04-25 13:26:40 +02:00
Ozzie Isaacs
edb05abcbe Merge remote-tracking branch 'tmp-orphan-on-download/fix-calibredb-cover-sibling' 2026-04-25 13:25:34 +02:00
Ozzie Isaacs
46811219ca Updated Requirements 2026-04-25 13:20:25 +02:00
Ozzie Isaacs
0aab0cac73 Merge remote-tracking branch 'tmp-orphan-on-download/fix-tmp-orphan-on-download' 2026-04-25 13:13:36 +02:00
Ozzie Isaacs
3257a36892 Merge remote-tracking branch 'ko/ko-translate-update' 2026-04-25 13:11:14 +02:00
limeade23
f10b680b0e Update Korean language 2026-04-23 17:41:46 +09:00
Ozzie Isaacs
c2b1950cd5 Merge remote-tracking branch 'opds_date_update/fix-opds-atom-updated-reflects-modifications' 2026-04-20 15:55:24 +02:00
Ozzie Isaacs
00c8ff8ac4 Merge remote-tracking branch 'metadata-provider-none-crash/fix/metadata-provider-none-crash' 2026-04-20 15:49:26 +02:00
walrusec
0ca6e86177 Fix metadata search crash when ComicVine or Douban return None on error
Both comicvine.py and douban.py return None instead of [] when an HTTP
error occurs during a metadata search. The consumer in search_metadata.py
iterates the result directly, which raises TypeError: 'NoneType' object
is not iterable and crashes the server on single-threaded deployments.

Fixes #3606
2026-04-19 08:54:47 -04:00
haraldpdl
ab17992ebb fix(opds): atom:updated reflects last modification, not date added
Books.atom_timestamp returned Books.timestamp (date added), which is
set at import and never changes. OPDS clients use atom:updated to
decide whether a book has changed on the server, so cover swaps,
metadata edits, and any other post-import change were invisible to
sync clients; they would keep serving the stale cover and title
until a manual refresh.

Atom RFC 4287 defines updated as "the most recent instant in time
when an entry or feed was modified", and Calibre already tracks that
field as last_modified, bumping it on every metadata and cover edit.
Switching the property to return last_modified (with a fallback to
timestamp when last_modified is NULL) aligns Calibre-Web's behaviour
with the Atom contract.

This change only affects the OPDS feed's atom:updated element. Kobo
sync uses its own last_modified comparison path, so it is unaffected.
2026-04-19 10:51:45 +02:00
haraldpdl
570371cc82 Don't write a cover sibling per download (--dont-save-cover)
calibredb export writes <uuid>.jpg next to <uuid>.<format> by
default, leaving an unused cover image in /tmp/calibre_web for
every download that goes through do_calibre_export. The cover
file is never read by calibre-web (cover serving uses a separate
path), so it is pure waste of disk space and IO.

Pass --dont-save-cover, paired with the existing --dont-write-opf,
to skip the unwanted side-effect at the source. Verified that
none of the three do_calibre_export call sites (download via
do_download_file, email via tasks/mail.py, kepubify via
tasks/convert.py) read the cover sibling.
2026-04-18 07:27:33 +02:00
haraldpdl
674b47bdbd Remove staged download from /tmp/calibre_web after response is sent
When config_embed_metadata is enabled with config_binariesdir or
config_kepubifypath set, do_download_file stages a copy of every
downloaded book under get_temp_dir() but never removes it. A bulk
OPDS or Kobo sync can fill the host filesystem in minutes; the
effect is amplified for comic formats (CBZ/CBR), where each
staged file can run to hundreds of MB or several GB. Once the
disk fills, downloads silently 404 and a container restart does
not recover the space.

Add an after_this_request hook that removes the staged copy after
the response is sent, gated on filename == get_temp_dir() so the
non-embed and gdrive-direct paths are untouched.
2026-04-18 07:12:38 +02:00
jvoisin
fd744af75d Don't give non-admin users a full stacktrace on 500
As `traceback.format_exc()` might contain internal file paths, library versions,
function names, and variable values.
2026-04-15 23:28:27 +02:00
Ozzie Isaacs
fca580505c Fix typo 2026-04-15 20:31:40 +02:00
Ozzie Isaacs
19da54a7ae Merge remote-tracking branch 'fixes/escape_ldap' 2026-04-15 19:37:31 +02:00
Ozzie Isaacs
9c87f0fbde Merge remote-tracking branch 'fixes/fix_gdrive_md5' 2026-04-15 19:36:56 +02:00
Ozzie Isaacs
e21f943712 Merge remote-tracking branch 'fixes/oauth_relink' 2026-04-15 19:36:48 +02:00
Ozzie Isaacs
4bb553f51d Merge remote-tracking branch 'fixes/noxxe' 2026-04-15 19:35:40 +02:00
Ozzie Isaacs
0615637f58 Merge remote-tracking branch 'fixes/nodebugleak' 2026-04-15 19:33:06 +02:00
Ozzie Isaacs
a6c55deac6 Merge remote-tracking branch 'fixes/accessbp' 2026-04-15 19:31:29 +02:00
Ozzie Isaacs
2de8df7e0d Merge remote-tracking branch 'fixes/fix_kobo' 2026-04-15 19:28:55 +02:00
Ozzie Isaacs
4c1d7a9f6b Merge remote-tracking branch 'fixes/permshelf' 2026-04-15 19:28:12 +02:00
Ozzie Isaacs
9489905602 Merge remote-tracking branch 'fixes/chm' 2026-04-15 19:24:12 +02:00
Ozzie Isaacs
5e7c0c9d34 Merge remote-tracking branch 'fixes/sqlidb' 2026-04-15 19:23:01 +02:00
jvoisin
b5da0df42a Prevent SQLI via dbpath
This is reachable only by the admin users, but is still a straightforward RCE
vector, if only via SQLite's `ATTACH DATABASE` trick
2026-04-14 23:23:12 +02:00
jvoisin
0959f84fd5 Use a sane permission for the encryption key file
The typical Linux umask of 0022, meaning the encrypted file is world-readable
(-rw-r--r--). Any OS-level user on the same system can read the key and decrypt
the encrypted credentials from app.db.
2026-04-14 23:08:35 +02:00
jvoisin
84777319d7 Fix access bypass on /show/ (serve_book)
The `serve_book` function uses `get_book()` which performs no access filtering:
it simply fetches by ID. Compare with `read_book` at web.py:1562 which
correctly uses `get_filtered_book()`. The `common_filters()` function enforces
per-user tag restrictions, language restrictions, and hidden-book rules.
2026-04-14 23:05:18 +02:00
jvoisin
d85bef6c38 Don't leak credentials in debug_info
No need to dump Gmail OAuth client_secret, refresh_token, and
access_token in the debug ZIP in plaintext.
2026-04-14 22:55:08 +02:00
jvoisin
8ad9f4e3b7 Fix a dumb type condition in gdrive.py
hashlib.md5(dbpath) returns a hash object, not a hex string. Comparing a string
(md5Checksum) to a hash object with != always returns True. This means the
DB-replacement code path is always entered, allowing an attacker who sends a
forged notification (with the known static token) to trigger an arbitrary
metadata.db download from GDrive, replacing the live database.
2026-04-14 22:51:36 +02:00
jvoisin
cde3888e17 Prevent LDAP injection in bind_user>get_object_details 2026-04-14 22:35:13 +02:00
jvoisin
387678a771 Prevent OAuth relinking.
When an OAuth provider_user_id is already linked to User A, and User B
authenticates with the same OAuth identity, User B is silently logged in as
User A. This is by design for single-user OAuth, but in a multi-user
environment it means: if an attacker gains access to the same OAuth provider
account (e.g., a shared GitHub org account, or by compromising the OAuth
provider), they can log in as the linked Calibre-Web user with no password
needed.
2026-04-14 22:28:06 +02:00
jvoisin
c451daad3c Don't allow users to edit shelves they don't have permission to edit. 2026-04-14 22:25:36 +02:00
jvoisin
224915bba1 Prevent XXE in epub/fb2/goodreads API
The lxml.etree.fromstring() function use the default XML parser, which resolves
external entities because XML handling defaults in Python sucks. There is no
need for such dangerous misfeatures in calibre-web, so let's disable it.

A user able to upload epub/fb2 could add something like this to the file:

```xml
<?xml version="1.0"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<container><rootfiles><rootfile full-path="&xxe;"/></rootfiles></container>
```

and obtain the content of the `/etc/passwd` file, which is bad™.
2026-04-14 22:12:57 +02:00
jvoisin
d598054195 Fix an IDOR in kobo tokens
Authenticated users shouldn't be able to generate/delete kobo auth tokens for
other users if they're not admin.
2026-04-14 22:10:30 +02:00
Ozzie Isaacs
088778969d Better error handling on series display in basic view 2026-04-06 15:28:10 +02:00
Ozzie Isaacs
0ed4d81da2 Better error handling on order parameter for sorting of user and books table 2026-04-06 15:12:09 +02:00
Ozzie Isaacs
7c715f34dc Clean strings in comments before displaying 2026-04-03 09:01:01 +02:00
Ozzie Isaacs
00686ec1f2 Merge remote-tracking branch 'page_count/fix-series-list-view-sorts-by-name-instead-of-sort-field' 2026-03-07 10:24:58 +01:00
Ozzie Isaacs
83d331c89b Merge remote-tracking branch 'page_count/fix-kobo-prioritytimestamp-put-response' 2026-03-07 09:55:45 +01:00
Ozzie Isaacs
f6338a9fda Merge remote-tracking branch 'filename/master' 2026-03-07 09:46:16 +01:00
Ozzie Isaacs
74725b68b0 Merge remote-tracking branch 'it/patch-1' 2026-03-07 09:28:14 +01:00
mapi68
efbdd0b6e3 Update italian messages.po 2026-03-05 06:44:48 +01:00
jarynclouatre
1134f54be4 fix: series list view sorts by name instead of sort field
In series_list(), the SQLite query correctly orders results by
Series.sort, but a subsequent Python sorted() call (needed to
re-order after appending the "None" category entry) was using
Series.name as the sort key instead of Series.sort.

This caused series titles with leading articles (A, An, The) to
sort strictly alphabetically by the article rather than by the
meaningful word, e.g. "A Collins-Burke Mystery" appeared under
"A" instead of "C".

Fix by using Series.sort (with a fallback to Series.name if sort
is NULL) as the key in the Python re-sort, consistent with the
intent of the existing DB query.

Fixes #3583
2026-03-01 20:44:05 -06:00
jarynclouatre
2d4ca23d0c Kobo: include PriorityTimestamp in PUT /state response
Kobo: include PriorityTimestamp in PUT /state response
2026-03-01 18:19:40 -06:00
jarynclouatre
6157f5027c Update search_metadata.py
Fix TypeError when metadata provider returns None
2026-03-01 15:44:29 +01:00
Ozzie Isaacs
5e48a64b15 Merge remote-tracking branch 'opds-500-unauthenticated-request/fix/opds-500-unauthenticated-request' 2026-02-22 10:43:11 +01:00
Rafik Farhad
36a7ff19bc Fix AttributeError on unauthenticated OPDS requests
request_username() is used as flask-limiter's key_func for the OPDS
blueprint. The limiter evaluates key_func in a before_request handler,
before the route's auth decorator runs. When no Authorization header is
present, request.authorization is None, causing an AttributeError and
a 500 response instead of the expected 401.

Guard against None so unauthenticated requests fall back to an empty
string key, allowing the auth decorator to handle the 401 correctly.

Fixes #3592

Disclaimer: AI assisted—humans supervised.
2026-02-21 16:54:14 -06:00
Ozzie Isaacs
1b4f0d0967 Merge remote-tracking branch 'add-to-shelves-dropdown-menu/add-to-shelves-dropdown-menu' 2026-02-21 09:43:50 +01:00