mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
EPUB Output: Fix converting a document with obfuscated fonts to EPUB 3 not working. Fixes #1990185 [Private bug](https://bugs.launchpad.net/calibre/+bug/1990185)
This commit is contained in:
parent
1f13e36547
commit
19cb5117f0
@ -257,11 +257,11 @@ class EPUBOutput(OutputFormatPlugin):
|
|||||||
opf = [x for x in os.listdir(tdir) if x.endswith('.opf')][0]
|
opf = [x for x in os.listdir(tdir) if x.endswith('.opf')][0]
|
||||||
self.condense_ncx([os.path.join(tdir, x) for x in os.listdir(tdir)
|
self.condense_ncx([os.path.join(tdir, x) for x in os.listdir(tdir)
|
||||||
if x.endswith('.ncx')][0])
|
if x.endswith('.ncx')][0])
|
||||||
if self.opts.epub_version == '3':
|
|
||||||
self.upgrade_to_epub3(tdir, opf)
|
|
||||||
encryption = None
|
encryption = None
|
||||||
if encrypted_fonts:
|
if encrypted_fonts:
|
||||||
encryption = self.encrypt_fonts(encrypted_fonts, tdir, uuid)
|
encryption = self.encrypt_fonts(encrypted_fonts, tdir, uuid)
|
||||||
|
if self.opts.epub_version == '3':
|
||||||
|
encryption = self.upgrade_to_epub3(tdir, opf, encryption)
|
||||||
|
|
||||||
from calibre.ebooks.epub import initialize_container
|
from calibre.ebooks.epub import initialize_container
|
||||||
with initialize_container(output_path, os.path.basename(opf),
|
with initialize_container(output_path, os.path.basename(opf),
|
||||||
@ -284,7 +284,7 @@ class EPUBOutput(OutputFormatPlugin):
|
|||||||
zf.extractall(path=opts.extract_to)
|
zf.extractall(path=opts.extract_to)
|
||||||
self.log.info('EPUB extracted to', opts.extract_to)
|
self.log.info('EPUB extracted to', opts.extract_to)
|
||||||
|
|
||||||
def upgrade_to_epub3(self, tdir, opf):
|
def upgrade_to_epub3(self, tdir, opf, encryption=None):
|
||||||
self.log.info('Upgrading to EPUB 3...')
|
self.log.info('Upgrading to EPUB 3...')
|
||||||
from calibre.ebooks.epub import simple_container_xml
|
from calibre.ebooks.epub import simple_container_xml
|
||||||
from calibre.ebooks.oeb.polish.cover import fix_conversion_titlepage_links_in_nav
|
from calibre.ebooks.oeb.polish.cover import fix_conversion_titlepage_links_in_nav
|
||||||
@ -294,6 +294,9 @@ class EPUBOutput(OutputFormatPlugin):
|
|||||||
pass
|
pass
|
||||||
with open(os.path.join(tdir, 'META-INF', 'container.xml'), 'wb') as f:
|
with open(os.path.join(tdir, 'META-INF', 'container.xml'), 'wb') as f:
|
||||||
f.write(simple_container_xml(os.path.basename(opf)).encode('utf-8'))
|
f.write(simple_container_xml(os.path.basename(opf)).encode('utf-8'))
|
||||||
|
if encryption is not None:
|
||||||
|
with open(os.path.join(tdir, 'META-INF', 'encryption.xml'), 'wb') as ef:
|
||||||
|
ef.write(as_bytes(encryption))
|
||||||
from calibre.ebooks.oeb.polish.container import EpubContainer
|
from calibre.ebooks.oeb.polish.container import EpubContainer
|
||||||
container = EpubContainer(tdir, self.log)
|
container = EpubContainer(tdir, self.log)
|
||||||
from calibre.ebooks.oeb.polish.upgrade import epub_2_to_3
|
from calibre.ebooks.oeb.polish.upgrade import epub_2_to_3
|
||||||
@ -304,10 +307,14 @@ class EPUBOutput(OutputFormatPlugin):
|
|||||||
fix_conversion_titlepage_links_in_nav(container)
|
fix_conversion_titlepage_links_in_nav(container)
|
||||||
container.commit()
|
container.commit()
|
||||||
os.remove(f.name)
|
os.remove(f.name)
|
||||||
|
if encryption is not None:
|
||||||
|
encryption = open(ef.name, 'rb').read()
|
||||||
|
os.remove(ef.name)
|
||||||
try:
|
try:
|
||||||
os.rmdir(os.path.join(tdir, 'META-INF'))
|
os.rmdir(os.path.join(tdir, 'META-INF'))
|
||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
|
return encryption
|
||||||
|
|
||||||
def encrypt_fonts(self, uris, tdir, uuid): # {{{
|
def encrypt_fonts(self, uris, tdir, uuid): # {{{
|
||||||
from polyglot.binary import from_hex_bytes
|
from polyglot.binary import from_hex_bytes
|
||||||
|
@ -1283,24 +1283,7 @@ class EpubContainer(Container):
|
|||||||
self.dirty('META-INF/encryption.xml')
|
self.dirty('META-INF/encryption.xml')
|
||||||
super().remove_item(name, remove_from_guide=remove_from_guide)
|
super().remove_item(name, remove_from_guide=remove_from_guide)
|
||||||
|
|
||||||
def process_encryption(self):
|
def read_raw_unique_identifier(self):
|
||||||
fonts = {}
|
|
||||||
enc = self.parsed('META-INF/encryption.xml')
|
|
||||||
for em in enc.xpath('//*[local-name()="EncryptionMethod" and @Algorithm]'):
|
|
||||||
alg = em.get('Algorithm')
|
|
||||||
if alg not in {ADOBE_OBFUSCATION, IDPF_OBFUSCATION}:
|
|
||||||
raise DRMError()
|
|
||||||
try:
|
|
||||||
cr = em.getparent().xpath('descendant::*[local-name()="CipherReference" and @URI]')[0]
|
|
||||||
except (IndexError, ValueError, KeyError):
|
|
||||||
continue
|
|
||||||
name = self.href_to_name(cr.get('URI'))
|
|
||||||
path = self.name_path_map.get(name, None)
|
|
||||||
if path is not None:
|
|
||||||
fonts[name] = alg
|
|
||||||
if not fonts:
|
|
||||||
return
|
|
||||||
|
|
||||||
package_id = raw_unique_identifier = idpf_key = None
|
package_id = raw_unique_identifier = idpf_key = None
|
||||||
for attrib, val in iteritems(self.opf.attrib):
|
for attrib, val in iteritems(self.opf.attrib):
|
||||||
if attrib.endswith('unique-identifier'):
|
if attrib.endswith('unique-identifier'):
|
||||||
@ -1315,6 +1298,32 @@ class EpubContainer(Container):
|
|||||||
idpf_key = raw_unique_identifier
|
idpf_key = raw_unique_identifier
|
||||||
idpf_key = re.sub('[\u0020\u0009\u000d\u000a]', '', idpf_key)
|
idpf_key = re.sub('[\u0020\u0009\u000d\u000a]', '', idpf_key)
|
||||||
idpf_key = hashlib.sha1(idpf_key.encode('utf-8')).digest()
|
idpf_key = hashlib.sha1(idpf_key.encode('utf-8')).digest()
|
||||||
|
return package_id, raw_unique_identifier, idpf_key
|
||||||
|
|
||||||
|
def iter_encryption_entries(self):
|
||||||
|
if 'META-INF/encryption.xml' in self.name_path_map:
|
||||||
|
enc = self.parsed('META-INF/encryption.xml')
|
||||||
|
for em in enc.xpath('//*[local-name()="EncryptionMethod" and @Algorithm]'):
|
||||||
|
try:
|
||||||
|
cr = em.getparent().xpath('descendant::*[local-name()="CipherReference" and @URI]')[0]
|
||||||
|
except Exception:
|
||||||
|
cr = None
|
||||||
|
yield em, cr
|
||||||
|
|
||||||
|
def process_encryption(self):
|
||||||
|
fonts = {}
|
||||||
|
for em, cr in self.iter_encryption_entries():
|
||||||
|
alg = em.get('Algorithm')
|
||||||
|
if alg not in {ADOBE_OBFUSCATION, IDPF_OBFUSCATION}:
|
||||||
|
raise DRMError()
|
||||||
|
if cr is None:
|
||||||
|
continue
|
||||||
|
name = self.href_to_name(cr.get('URI'))
|
||||||
|
path = self.name_path_map.get(name, None)
|
||||||
|
if path is not None:
|
||||||
|
fonts[name] = alg
|
||||||
|
|
||||||
|
package_id, raw_unique_identifier, idpf_key = self.read_raw_unique_identifier()
|
||||||
key = None
|
key = None
|
||||||
for item in self.opf_xpath('//*[local-name()="metadata"]/*'
|
for item in self.opf_xpath('//*[local-name()="metadata"]/*'
|
||||||
'[local-name()="identifier"]'):
|
'[local-name()="identifier"]'):
|
||||||
|
@ -4,14 +4,19 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from calibre.ebooks.conversion.plugins.epub_input import (
|
||||||
|
ADOBE_OBFUSCATION, IDPF_OBFUSCATION
|
||||||
|
)
|
||||||
|
from calibre.ebooks.metadata.opf3 import XPath
|
||||||
from calibre.ebooks.metadata.opf_2_to_3 import upgrade_metadata
|
from calibre.ebooks.metadata.opf_2_to_3 import upgrade_metadata
|
||||||
from calibre.ebooks.oeb.base import EPUB_NS, OEB_DOCS, xpath
|
from calibre.ebooks.oeb.base import DC, EPUB_NS, OEB_DOCS, xpath
|
||||||
from calibre.ebooks.oeb.parse_utils import ensure_namespace_prefixes
|
from calibre.ebooks.oeb.parse_utils import ensure_namespace_prefixes
|
||||||
from calibre.ebooks.oeb.polish.utils import OEB_FONTS
|
|
||||||
from calibre.ebooks.oeb.polish.opf import get_book_language
|
from calibre.ebooks.oeb.polish.opf import get_book_language
|
||||||
from calibre.ebooks.oeb.polish.toc import (
|
from calibre.ebooks.oeb.polish.toc import (
|
||||||
commit_nav_toc, find_existing_ncx_toc, get_landmarks, get_toc
|
commit_nav_toc, find_existing_ncx_toc, get_landmarks, get_toc
|
||||||
)
|
)
|
||||||
|
from calibre.ebooks.oeb.polish.utils import OEB_FONTS
|
||||||
|
from calibre.utils.short_uuid import uuid4
|
||||||
|
|
||||||
|
|
||||||
def add_properties(item, *props):
|
def add_properties(item, *props):
|
||||||
@ -31,6 +36,38 @@ def fix_font_mime_types(container):
|
|||||||
return changed
|
return changed
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_obfuscated_fonts(container):
|
||||||
|
if not container.obfuscated_fonts:
|
||||||
|
return
|
||||||
|
name_to_elem_map = {}
|
||||||
|
for em, cr in container.iter_encryption_entries():
|
||||||
|
alg = em.get('Algorithm')
|
||||||
|
if cr is None or alg not in {ADOBE_OBFUSCATION, IDPF_OBFUSCATION}:
|
||||||
|
continue
|
||||||
|
name = container.href_to_name(cr.get('URI'))
|
||||||
|
name_to_elem_map[name] = em, cr
|
||||||
|
package_id, raw_unique_identifier, idpf_key = container.read_raw_unique_identifier()
|
||||||
|
if not idpf_key:
|
||||||
|
if not package_id:
|
||||||
|
package_id = uuid4()
|
||||||
|
container.opf.set('unique-identifier', package_id)
|
||||||
|
metadata = XPath('./opf:metadata')(container.opf)[0]
|
||||||
|
ident = metadata.makeelement(DC('identifier'))
|
||||||
|
ident.text = uuid4()
|
||||||
|
metadata.append(ident)
|
||||||
|
package_id, raw_unique_identifier, idpf_key = container.read_raw_unique_identifier()
|
||||||
|
for name in tuple(container.obfuscated_fonts):
|
||||||
|
try:
|
||||||
|
em, cr = name_to_elem_map[name]
|
||||||
|
except KeyError:
|
||||||
|
container.obfuscated_fonts.pop(name)
|
||||||
|
continue
|
||||||
|
em.set('Algorithm', IDPF_OBFUSCATION)
|
||||||
|
cr.set('URI', container.name_to_href(name))
|
||||||
|
container.obfuscated_fonts[name] = (IDPF_OBFUSCATION, idpf_key)
|
||||||
|
container.commit_item('META-INF/encryption.xml')
|
||||||
|
|
||||||
|
|
||||||
def collect_properties(container):
|
def collect_properties(container):
|
||||||
for item in container.opf_xpath('//opf:manifest/opf:item[@href and @media-type]'):
|
for item in container.opf_xpath('//opf:manifest/opf:item[@href and @media-type]'):
|
||||||
mt = item.get('media-type') or ''
|
mt = item.get('media-type') or ''
|
||||||
@ -128,6 +165,7 @@ def epub_2_to_3(container, report, previous_nav=None, remove_ncx=True):
|
|||||||
container.opf.set('version', '3.0')
|
container.opf.set('version', '3.0')
|
||||||
if fix_font_mime_types(container):
|
if fix_font_mime_types(container):
|
||||||
container.refresh_mime_map()
|
container.refresh_mime_map()
|
||||||
|
migrate_obfuscated_fonts(container)
|
||||||
container.dirty(container.opf_name)
|
container.dirty(container.opf_name)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user