tools v5.4

This commit is contained in:
Apprentice Alf
2012-11-07 13:14:25 +00:00
parent 0028027f71
commit 0dcd18d524
119 changed files with 13790 additions and 8140 deletions

View File

@@ -1,4 +1,7 @@
#! /usr/bin/python
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import with_statement
# ineptepub_plugin.py
# Released under the terms of the GNU General Public Licence, version 3 or
@@ -50,12 +53,16 @@
# 0.1.5 - update zipfix to handle out of position mimetypes
# 0.1.6 - update zipfix to handle completely missing mimetype files
# 0.1.7 - update to new calibre plugin interface
# 0.1.8 - Fix for potential problem with PyCrypto
# 0.1.9 - Fix for potential problem with ADE keys and fix possible output/unicode problem
"""
Decrypt Adobe ADEPT-encrypted EPUB books.
"""
from __future__ import with_statement
PLUGIN_NAME = 'Inept Epub DeDRM'
PLUGIN_VERSION_TUPLE = (0, 1, 9)
PLUGIN_VERSION = '.'.join([str(x) for x in PLUGIN_VERSION_TUPLE])
__license__ = 'GPL v3'
@@ -89,7 +96,7 @@ def _load_crypto_libcrypto():
else:
libcrypto = find_library('crypto')
if libcrypto is None:
raise ADEPTError('libcrypto not found')
raise ADEPTError('%s Plugin v%s: libcrypto not found' % (PLUGIN_NAME, PLUGIN_VERSION))
libcrypto = CDLL(libcrypto)
RSA_NO_PADDING = 3
@@ -262,7 +269,7 @@ def _load_crypto_pycrypto():
class AES(object):
def __init__(self, key):
self._aes = _AES.new(key, _AES.MODE_CBC)
self._aes = _AES.new(key, _AES.MODE_CBC, '\x00'*16)
def decrypt(self, data):
return self._aes.decrypt(data)
@@ -369,18 +376,29 @@ from calibre.customize import FileTypePlugin
from calibre.constants import iswindows, isosx
class IneptDeDRM(FileTypePlugin):
name = 'Inept Epub DeDRM'
name = PLUGIN_NAME
description = 'Removes DRM from secure Adobe epub files. \
Credit given to I <3 Cabbages for the original stand-alone scripts.'
supported_platforms = ['linux', 'osx', 'windows']
author = 'DiapDealer'
version = (0, 1, 7)
version = PLUGIN_VERSION_TUPLE
minimum_calibre_version = (0, 7, 55) # Compiled python libraries cannot be imported in earlier versions.
file_types = set(['epub'])
on_import = True
priority = 100
def run(self, path_to_ebook):
from calibre_plugins.ineptepub import outputfix
if sys.stdout.encoding == None:
sys.stdout = outputfix.getwriter('utf-8')(sys.stdout)
else:
sys.stdout = outputfix.getwriter(sys.stdout.encoding)(sys.stdout)
if sys.stderr.encoding == None:
sys.stderr = outputfix.getwriter('utf-8')(sys.stderr)
else:
sys.stderr = outputfix.getwriter(sys.stderr.encoding)(sys.stderr)
global AES
global RSA
@@ -400,10 +418,13 @@ class IneptDeDRM(FileTypePlugin):
files = os.listdir(confpath)
filefilter = re.compile("\.der$", re.IGNORECASE)
files = filter(filefilter.search, files)
foundDefault = False
if files:
try:
for filename in files:
if filename[:16] == 'calibre-adeptkey':
foundDefault = True
fpath = os.path.join(confpath, filename)
with open(fpath, 'rb') as f:
userkeys.append(f.read())
@@ -411,22 +432,23 @@ class IneptDeDRM(FileTypePlugin):
except IOError:
print 'IneptEpub: Error reading keyfiles from config directory.'
pass
else:
if not foundDefault:
# Try to find key from ADE install and save the key in
# Calibre's configuration directory for future use.
if iswindows or isosx:
# ADE key retrieval script included in respective OS folder.
from calibre_plugins.ineptepub.ade_key import retrieve_key
from calibre_plugins.ineptepub.ineptkey import retrieve_keys
try:
keydata = retrieve_key()
userkeys.append(keydata)
keypath = os.path.join(confpath, 'calibre-adeptkey.der')
with open(keypath, 'wb') as f:
f.write(keydata)
print 'IneptEpub: Created keyfile from ADE install.'
keys = retrieve_keys()
for i,key in enumerate(keys):
userkeys.append(key)
keypath = os.path.join(confpath, 'calibre-adeptkey{0:d}.der'.format(i))
open(keypath, 'wb').write(key)
print 'IneptEpub: Created keyfile %s from ADE install.' % keypath
except:
print 'IneptEpub: Couldn\'t Retrieve key from ADE install.'
pass
print 'IneptEpub: Couldn\'t Retrieve key from ADE install.'
pass
if not userkeys:
# No user keys found... bail out.
@@ -440,9 +462,11 @@ class IneptDeDRM(FileTypePlugin):
from calibre_plugins.ineptepub import zipfix
inf = self.temporary_file('.epub')
try:
print '%s Plugin: Verifying zip archive integrity.' % PLUGIN_NAME
fr = zipfix.fixZip(path_to_ebook, inf.name)
fr.fix()
except Exception, e:
print '%s Plugin: unforeseen zip archive issue.' % PLUGIN_NAME
raise Exception(e)
return
of = self.temporary_file('.epub')

View File

@@ -1,17 +1,59 @@
#!/usr/bin/env python
#! /usr/bin/python
# -*- coding: utf-8 -*-
from __future__ import with_statement
# ineptkey.pyw, version 5.6
# Copyright © 2009-2010 i♥cabbages
# Released under the terms of the GNU General Public Licence, version 3 or
# later. <http://www.gnu.org/licenses/>
# Windows users: Before running this program, you must first install Python 2.6
# from <http://www.python.org/download/> and PyCrypto from
# <http://www.voidspace.org.uk/python/modules.shtml#pycrypto> (make certain
# to install the version for Python 2.6). Then save this script file as
# ineptkey.pyw and double-click on it to run it. It will create a file named
# adeptkey.der in the same directory. This is your ADEPT user key.
#
# Mac OS X users: Save this script file as ineptkey.pyw. You can run this
# program from the command line (pythonw ineptkey.pyw) or by double-clicking
# it when it has been associated with PythonLauncher. It will create a file
# named adeptkey.der in the same directory. This is your ADEPT user key.
# Revision history:
# 1 - Initial release, for Adobe Digital Editions 1.7
# 2 - Better algorithm for finding pLK; improved error handling
# 3 - Rename to INEPT
# 4 - Series of changes by joblack (and others?) --
# 4.1 - quick beta fix for ADE 1.7.2 (anon)
# 4.2 - added old 1.7.1 processing
# 4.3 - better key search
# 4.4 - Make it working on 64-bit Python
# 5 - Clean up and improve 4.x changes;
# Clean up and merge OS X support by unknown
# 5.1 - add support for using OpenSSL on Windows in place of PyCrypto
# 5.2 - added support for output of key to a particular file
# 5.3 - On Windows try PyCrypto first, OpenSSL next
# 5.4 - Modify interface to allow use of import
# 5.5 - Fix for potential problem with PyCrypto
# 5.6 - Revise to allow use in Plugins to eliminate need for duplicate code
"""
Retrieve Adobe ADEPT user key.
"""
from __future__ import with_statement
__license__ = 'GPL v3'
import sys
import os
import struct
from calibre.constants import iswindows, isosx
try:
from calibre.constants import iswindows, isosx
except:
iswindows = sys.platform.startswith('win')
isosx = sys.platform.startswith('darwin')
class ADEPTError(Exception):
pass
@@ -72,7 +114,7 @@ if iswindows:
from Crypto.Cipher import AES as _AES
class AES(object):
def __init__(self, key):
self._aes = _AES.new(key, _AES.MODE_CBC)
self._aes = _AES.new(key, _AES.MODE_CBC, '\x00'*16)
def decrypt(self, data):
return self._aes.decrypt(data)
return AES
@@ -254,13 +296,9 @@ if iswindows:
return CryptUnprotectData
CryptUnprotectData = CryptUnprotectData()
def retrieve_key():
def retrieve_keys():
if AES is None:
tkMessageBox.showerror(
"ADEPT Key",
"This script requires PyCrypto or OpenSSL which must be installed "
"separately. Read the top-of-script comment for details.")
return False
raise ADEPTError("PyCrypto or OpenSSL must be installed")
root = GetSystemDirectory().split('\\')[0] + '\\'
serial = GetVolumeSerialNumber(root)
vendor = cpuid0()
@@ -275,6 +313,7 @@ if iswindows:
device = winreg.QueryValueEx(regkey, 'key')[0]
keykey = CryptUnprotectData(device, entropy)
userkey = None
keys = []
try:
plkroot = winreg.OpenKey(cuser, PRIVATE_LICENCE_KEY_PATH)
except WindowsError:
@@ -296,19 +335,17 @@ if iswindows:
if ktype != 'privateLicenseKey':
continue
userkey = winreg.QueryValueEx(plkkey, 'value')[0]
break
if userkey is not None:
break
if userkey is None:
userkey = userkey.decode('base64')
aes = AES(keykey)
userkey = aes.decrypt(userkey)
userkey = userkey[26:-ord(userkey[-1])]
keys.append(userkey)
if len(keys) == 0:
raise ADEPTError('Could not locate privateLicenseKey')
userkey = userkey.decode('base64')
aes = AES(keykey)
userkey = aes.decrypt(userkey)
userkey = userkey[26:-ord(userkey[-1])]
return userkey
else:
return keys
elif isosx:
import xml.etree.ElementTree as etree
import subprocess
@@ -332,8 +369,8 @@ else:
if os.path.exists(ActDatPath):
return ActDatPath
return None
def retrieve_key():
def retrieve_keys():
actpath = findActivationDat()
if actpath is None:
raise ADEPTError("Could not locate ADE activation")
@@ -343,4 +380,78 @@ else:
userkey = tree.findtext(expr)
userkey = userkey.decode('base64')
userkey = userkey[26:]
return userkey
return [userkey]
else:
def retrieve_keys(keypath):
raise ADEPTError("This script only supports Windows and Mac OS X.")
return []
def retrieve_key(keypath):
keys = retrieve_keys()
with open(keypath, 'wb') as f:
f.write(keys[0])
return True
def extractKeyfile(keypath):
try:
success = retrieve_key(keypath)
except ADEPTError, e:
print "Key generation Error: " + str(e)
return 1
except Exception, e:
print "General Error: " + str(e)
return 1
if not success:
return 1
return 0
def cli_main(argv=sys.argv):
keypath = argv[1]
return extractKeyfile(keypath)
def main(argv=sys.argv):
import Tkinter
import Tkconstants
import tkMessageBox
import traceback
class ExceptionDialog(Tkinter.Frame):
def __init__(self, root, text):
Tkinter.Frame.__init__(self, root, border=5)
label = Tkinter.Label(self, text="Unexpected error:",
anchor=Tkconstants.W, justify=Tkconstants.LEFT)
label.pack(fill=Tkconstants.X, expand=0)
self.text = Tkinter.Text(self)
self.text.pack(fill=Tkconstants.BOTH, expand=1)
self.text.insert(Tkconstants.END, text)
root = Tkinter.Tk()
root.withdraw()
progname = os.path.basename(argv[0])
keypath = os.path.abspath("adeptkey.der")
success = False
try:
success = retrieve_key(keypath)
except ADEPTError, e:
tkMessageBox.showerror("ADEPT Key", "Error: " + str(e))
except Exception:
root.wm_state('normal')
root.title('ADEPT Key')
text = traceback.format_exc()
ExceptionDialog(root, text).pack(fill=Tkconstants.BOTH, expand=1)
root.mainloop()
if not success:
return 1
tkMessageBox.showinfo(
"ADEPT Key", "Key successfully retrieved to %s" % (keypath))
return 0
if __name__ == '__main__':
if len(sys.argv) > 1:
sys.exit(cli_main())
sys.exit(main())

View File

@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
#
# Adapted and simplified from the kitchen project
#
# Kitchen Project Copyright (c) 2012 Red Hat, Inc.
#
# kitchen is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# kitchen is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with kitchen; if not, see <http://www.gnu.org/licenses/>
#
# Authors:
# Toshio Kuratomi <toshio@fedoraproject.org>
# Seth Vidal
#
# Portions of code taken from yum/i18n.py and
# python-fedora: fedora/textutils.py
import codecs
# returns a char string unchanged
# returns a unicode string converted to a char string of the passed encoding
# return the empty string for anything else
def getwriter(encoding):
class _StreamWriter(codecs.StreamWriter):
def __init__(self, stream):
codecs.StreamWriter.__init__(self, stream, 'replace')
def encode(self, msg, errors='replace'):
if isinstance(msg, basestring):
if isinstance(msg, str):
return (msg, len(msg))
return (msg.encode(self.encoding, 'replace'), len(msg))
return ('',0)
_StreamWriter.encoding = encoding
return _StreamWriter

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
import sys
import zlib
import zipfile
import zipfilerugged
import os
import os.path
import getopt
@@ -15,7 +15,7 @@ _FILENAME_OFFSET = 30
_MAX_SIZE = 64 * 1024
_MIMETYPE = 'application/epub+zip'
class ZipInfo(zipfile.ZipInfo):
class ZipInfo(zipfilerugged.ZipInfo):
def __init__(self, *args, **kwargs):
if 'compress_type' in kwargs:
compress_type = kwargs.pop('compress_type')
@@ -27,11 +27,11 @@ class fixZip:
self.ztype = 'zip'
if zinput.lower().find('.epub') >= 0 :
self.ztype = 'epub'
self.inzip = zipfile.ZipFile(zinput,'r')
self.outzip = zipfile.ZipFile(zoutput,'w')
self.inzip = zipfilerugged.ZipFile(zinput,'r')
self.outzip = zipfilerugged.ZipFile(zoutput,'w')
# open the input zip for reading only as a raw file
self.bzf = file(zinput,'rb')
self.bzf = file(zinput,'rb')
def getlocalname(self, zi):
local_header_offset = zi.header_offset
self.bzf.seek(local_header_offset + _FILENAME_LEN_OFFSET)
@@ -76,17 +76,17 @@ class fixZip:
data = None
# if not compressed we are good to go
if zi.compress_type == zipfile.ZIP_STORED:
if zi.compress_type == zipfilerugged.ZIP_STORED:
data = self.bzf.read(zi.file_size)
# if compressed we must decompress it using zlib
if zi.compress_type == zipfile.ZIP_DEFLATED:
if zi.compress_type == zipfilerugged.ZIP_DEFLATED:
cmpdata = self.bzf.read(zi.compress_size)
data = self.uncompress(cmpdata)
return data
def fix(self):
# get the zipinfo for each member of the input archive
@@ -95,7 +95,7 @@ class fixZip:
# if epub write mimetype file first, with no compression
if self.ztype == 'epub':
nzinfo = ZipInfo('mimetype', compress_type=zipfile.ZIP_STORED)
nzinfo = ZipInfo('mimetype', compress_type=zipfilerugged.ZIP_STORED)
self.outzip.writestr(nzinfo, _MIMETYPE)
# write the rest of the files
@@ -103,9 +103,9 @@ class fixZip:
if zinfo.filename != "mimetype" or self.ztype == '.zip':
data = None
nzinfo = zinfo
try:
try:
data = self.inzip.read(zinfo.filename)
except zipfile.BadZipfile or zipfile.error:
except zipfilerugged.BadZipfile or zipfilerugged.error:
local_name = self.getlocalname(zinfo)
data = self.getfiledata(zinfo)
nzinfo.filename = local_name
@@ -126,7 +126,7 @@ def usage():
inputzip is the source zipfile to fix
outputzip is the fixed zip archive
"""
def repairBook(infile, outfile):
if not os.path.exists(infile):
@@ -152,5 +152,3 @@ def main(argv=sys.argv):
if __name__ == '__main__' :
sys.exit(main())