tools v5.6

This commit is contained in:
Apprentice Alf
2013-01-19 14:50:57 +00:00
parent 602ff30b3a
commit c23b903420
51 changed files with 4335 additions and 1071 deletions

View File

@@ -1,13 +1,19 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# DeDRM.pyw, version 5.5.3
# DeDRM.pyw, version 5.6
# By some_updates and Apprentice Alf
import sys
import os, os.path
sys.path.append(os.path.join(sys.path[0],"lib"))
os.environ['PYTHONIOENCODING'] = "utf-8"
import sys, os
import codecs
from argv_utils import add_cp65001_codec, set_utf8_default_encoding, utf8_argv
add_cp65001_codec()
set_utf8_default_encoding()
import shutil
import Tkinter
@@ -16,15 +22,35 @@ import Tkconstants
import tkFileDialog
from scrolltextwidget import ScrolledText
from activitybar import ActivityBar
import subprocess
from subprocess import Popen, PIPE, STDOUT
import subasyncio
from subasyncio import Process
import re
import simpleprefs
from Queue import Full
from Queue import Empty
from multiprocessing import Process, Queue
__version__ = '5.5.3'
from scriptinterface import decryptepub, decryptpdb, decryptpdf, decryptk4mobi
# Wrap a stream so that output gets flushed immediately
# and appended to shared queue
class QueuedStream:
def __init__(self, stream, q):
self.stream = stream
self.encoding = stream.encoding
self.q = q
if self.encoding == None:
self.encoding = "utf-8"
def write(self, data):
if isinstance(data,unicode):
data = data.encode(self.encoding,"replace")
self.q.put(data)
# self.stream.write(data)
# self.stream.flush()
def __getattr__(self, attr):
return getattr(self.stream, attr)
__version__ = '5.6'
class DrmException(Exception):
pass
@@ -35,6 +61,7 @@ class MainApp(Tk):
self.withdraw()
self.dnd = dnd
self.apphome = apphome
# preference settings
# [dictionary key, file in preferences directory where info is stored]
description = [ ['pids' , 'pidlist.txt' ],
@@ -152,7 +179,7 @@ class PrefsDialog(Toplevel):
self.pidnums.set(self.prefs_array['pids'])
self.pidinfo.grid(row=3, column=1, sticky=sticky)
Tkinter.Label(body, text='eInk Kindle Serial Number list\n(16 characters, first character B, comma separated)').grid(row=4, sticky=Tkconstants.E)
Tkinter.Label(body, text='eInk Kindle Serial Number list\n(16 characters, comma separated)').grid(row=4, sticky=Tkconstants.E)
self.sernums = Tkinter.StringVar()
self.serinfo = Tkinter.Entry(body, width=50, textvariable=self.sernums)
if 'serials' in self.prefs_array:
@@ -327,10 +354,11 @@ class ConvDialog(Toplevel):
self.filenames = filenames
self.interval = 50
self.p2 = None
self.q = Queue()
self.running = 'inactive'
self.numgood = 0
self.numbad = 0
self.log = u""
self.log = ''
self.status = Tkinter.Label(self, text='DeDRM processing...')
self.status.pack(fill=Tkconstants.X, expand=1)
body = Tkinter.Frame(self)
@@ -378,16 +406,18 @@ class ConvDialog(Toplevel):
if len(self.filenames) > 0:
filename = self.filenames.pop(0)
if filename == None:
msg = u"\nComplete: Successes: {0}, Failures: {1}\n".format(self.numgood,self.numbad)
msg = '\nComplete: '
msg += 'Successes: %d, ' % self.numgood
msg += 'Failures: %d\n' % self.numbad
self.showCmdOutput(msg)
if self.numbad == 0:
self.after(2000,self.conversion_done())
logfile = os.path.join(rscpath,'dedrm.log')
file(logfile,'w').write(self.log.encode('utf8'))
file(logfile,'wb').write(self.log)
return
infile = filename
bname = os.path.basename(infile)
msg = u"Processing: {0} ... ".format(bname)
msg = 'Processing: ' + bname + ' ... '
self.log += msg
self.showCmdOutput(msg)
outdir = os.path.dirname(filename)
@@ -399,9 +429,9 @@ class ConvDialog(Toplevel):
if rv == 0:
self.bar.start()
self.running = 'active'
self.processPipe()
self.processQueue()
else:
msg = u"Unknown File: {0}\n".format(bname)
msg = 'Unknown File: ' + bname + '\n'
self.log += msg
self.showCmdOutput(msg)
self.numbad += 1
@@ -410,7 +440,7 @@ class ConvDialog(Toplevel):
# kill any still running subprocess
self.running = 'stopped'
if self.p2 != None:
if (self.p2.wait('nowait') == None):
if (self.p2.exitcode == None):
self.p2.terminate()
self.conversion_done()
@@ -426,130 +456,127 @@ class ConvDialog(Toplevel):
# read from subprocess pipe without blocking
# invoked every interval via the widget "after"
# option being used, so need to reset it for the next time
def processPipe(self):
def processQueue(self):
if self.p2 == None:
# nothing to wait for so just return
return
poll = self.p2.wait('nowait')
poll = self.p2.exitcode
if poll != None:
self.bar.stop()
if poll == 0:
msg = u"\nSuccess\n"
msg = 'Success\n'
self.numgood += 1
text = self.p2.read().decode('utf8')
text += self.p2.readerr().decode('utf8')
done = False
text = ''
while not done:
try:
data = self.q.get_nowait()
text += data
except Empty:
done = True
pass
self.log += text
self.log += msg
else:
msg = u"\nFailed\n"
text = self.p2.read().decode('utf8')
text += self.p2.readerr().decode('utf8')
msg += text
self.numbad += 1
if poll != 0:
msg = 'Failed\n'
done = False
text = ''
while not done:
try:
data = self.q.get_nowait()
text += data
except Empty:
done = True
pass
msg += '\n'
self.log += text
self.log += msg
self.numbad += 1
self.p2.join()
self.showCmdOutput(msg)
self.p2 = None
self.running = 'inactive'
self.after(50,self.processBooks)
return
try:
text = self.q.get_nowait()
except Empty:
text = ''
pass
if text != '':
self.log += text
# make sure we get invoked again by event loop after interval
self.stext.after(self.interval,self.processPipe)
self.stext.after(self.interval,self.processQueue)
return
def decrypt_ebook(self, infile, outdir, rscpath):
apphome = self.apphome
q = self.q
rv = 1
name, ext = os.path.splitext(os.path.basename(infile))
ext = ext.lower()
if ext == '.epub':
self.p2 = processEPUB(apphome, infile, outdir, rscpath)
self.p2 = Process(target=processEPUB, args=(q, infile, outdir, rscpath))
self.p2.start()
return 0
if ext == '.pdb':
self.p2 = processPDB(apphome, infile, outdir, rscpath)
self.p2 = Process(target=processPDB, args=(q, infile, outdir, rscpath))
self.p2.start()
return 0
if ext in ['.azw', '.azw1', '.azw3', '.azw4', '.prc', '.mobi', '.tpz']:
self.p2 = processK4MOBI(apphome, infile, outdir, rscpath)
self.p2 = Process(target=processK4MOBI,args=(q, infile, outdir, rscpath))
self.p2.start()
return 0
if ext == '.pdf':
self.p2 = processPDF(apphome, infile, outdir, rscpath)
self.p2 = Process(target=processPDF, args=(q, infile, outdir, rscpath))
self.p2.start()
return 0
return rv
# run as a subprocess via pipes and collect stdout, stderr, and return value
def runit(apphome, ncmd, nparms):
pengine = sys.executable
if pengine is None or pengine == '':
pengine = 'python'
pengine = os.path.normpath(pengine)
cmdline = pengine + ' "' + os.path.join(apphome, ncmd) + '" '
# if sys.platform.startswith('win'):
# search_path = os.environ['PATH']
# search_path = search_path.lower()
# if search_path.find('python') < 0:
# # if no python hope that win registry finds what is associated with py extension
# cmdline = pengine + ' "' + os.path.join(apphome, ncmd) + '" '
cmdline += nparms
cmdline = cmdline.encode(sys.getfilesystemencoding())
p2 = subasyncio.Process(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False, env = os.environ)
return p2
# child process starts here
def processK4MOBI(q, infile, outdir, rscpath):
add_cp65001_codec()
set_utf8_default_encoding()
sys.stdout = QueuedStream(sys.stdout, q)
sys.stderr = QueuedStream(sys.stderr, q)
rv = decryptk4mobi(infile, outdir, rscpath)
sys.exit(rv)
def processK4MOBI(apphome, infile, outdir, rscpath):
cmd = os.path.join('lib','k4mobidedrm.py')
parms = ''
pidnums = ''
pidspath = os.path.join(rscpath,'pidlist.txt')
if os.path.exists(pidspath):
pidnums = file(pidspath,'r').read()
pidnums = pidnums.rstrip(os.linesep)
if pidnums != '':
parms += '-p "' + pidnums + '" '
serialnums = ''
serialnumspath = os.path.join(rscpath,'seriallist.txt')
if os.path.exists(serialnumspath):
serialnums = file(serialnumspath,'r').read()
serialnums = serialnums.rstrip(os.linesep)
if serialnums != '':
parms += '-s "' + serialnums + '" '
# child process starts here
def processPDF(q, infile, outdir, rscpath):
add_cp65001_codec()
set_utf8_default_encoding()
sys.stdout = QueuedStream(sys.stdout, q)
sys.stderr = QueuedStream(sys.stderr, q)
rv = decryptpdf(infile, outdir, rscpath)
sys.exit(rv)
files = os.listdir(rscpath)
filefilter = re.compile("\.info$|\.kinf$", re.IGNORECASE)
files = filter(filefilter.search, files)
if files:
for filename in files:
dpath = os.path.join(rscpath,filename)
parms += '-k "' + dpath + '" '
parms += '"' + infile +'" "' + outdir + '"'
p2 = runit(apphome, cmd, parms)
return p2
# child process starts here
def processEPUB(q, infile, outdir, rscpath):
add_cp65001_codec()
set_utf8_default_encoding()
sys.stdout = QueuedStream(sys.stdout, q)
sys.stderr = QueuedStream(sys.stderr, q)
rv = decryptepub(infile, outdir, rscpath)
sys.exit(rv)
def processPDF(apphome, infile, outdir, rscpath):
cmd = os.path.join('lib','decryptpdf.py')
parms = '"' + infile + '" "' + outdir + '" "' + rscpath + '"'
p2 = runit(apphome, cmd, parms)
return p2
def processEPUB(apphome, infile, outdir, rscpath):
# invoke routine to check both Adept and Barnes and Noble
cmd = os.path.join('lib','decryptepub.py')
parms = '"' + infile + '" "' + outdir + '" "' + rscpath + '"'
p2 = runit(apphome, cmd, parms)
return p2
def processPDB(apphome, infile, outdir, rscpath):
cmd = os.path.join('lib','decryptpdb.py')
parms = '"' + infile + '" "' + outdir + '" "' + rscpath + '"'
p2 = runit(apphome, cmd, parms)
return p2
# child process starts here
def processPDB(q, infile, outdir, rscpath):
add_cp65001_codec()
set_utf8_default_encoding()
sys.stdout = QueuedStream(sys.stdout, q)
sys.stderr = QueuedStream(sys.stderr, q)
rv = decryptpdb(infile, outdir, rscpath)
sys.exit(rv)
def main(argv=sys.argv):
apphome = os.path.dirname(sys.argv[0])
def main(argv=utf8_argv()):
apphome = os.path.dirname(argv[0])
apphome = os.path.abspath(apphome)
# windows may pass a spurious quoted null string as argv[1] from bat file
# simply work around this until we can figure out a better way to handle things
if len(argv) == 2:
if sys.platform.startswith('win') and len(argv) == 2:
temp = argv[1]
temp = temp.strip('"')
temp = temp.strip()
@@ -563,11 +590,10 @@ def main(argv=sys.argv):
else : # processing books via drag and drop
dnd = True
# build a list of the files to be processed
# note all filenames and paths have been utf-8 encoded
infilelst = argv[1:]
filenames = []
for infile in infilelst:
infile = infile.decode(sys.getfilesystemencoding())
print infile
infile = infile.replace('"','')
infile = os.path.abspath(infile)
if os.path.isdir(infile):

View File

@@ -34,10 +34,14 @@ def _load_libalfcrypto():
else:
name_of_lib = 'libalfcrypto64.so'
# hard code to local location for libalfcrypto
libalfcrypto = os.path.join(sys.path[0],name_of_lib)
if not os.path.isfile(libalfcrypto):
raise Exception('libalfcrypto not found')
libalfcrypto = os.path.join(sys.path[0], 'lib', name_of_lib)
if not os.path.isfile(libalfcrypto):
libalfcrypto = os.path.join('.',name_of_lib)
if not os.path.isfile(libalfcrypto):
raise Exception('libalfcrypto not found at %s' % libalfcrypto)
libalfcrypto = CDLL(libalfcrypto)

View File

@@ -0,0 +1,92 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys, os
import locale
import codecs
# get sys.argv arguments and encode them into utf-8
def utf8_argv():
if sys.platform.startswith('win'):
# Versions 2.x of Python don't support Unicode in sys.argv on
# Windows, with the underlying Windows API instead replacing multi-byte
# characters with '?'. So use shell32.GetCommandLineArgvW to get sys.argv
# as a list of Unicode strings and encode them as utf-8
from ctypes import POINTER, byref, cdll, c_int, windll
from ctypes.wintypes import LPCWSTR, LPWSTR
GetCommandLineW = cdll.kernel32.GetCommandLineW
GetCommandLineW.argtypes = []
GetCommandLineW.restype = LPCWSTR
CommandLineToArgvW = windll.shell32.CommandLineToArgvW
CommandLineToArgvW.argtypes = [LPCWSTR, POINTER(c_int)]
CommandLineToArgvW.restype = POINTER(LPWSTR)
cmd = GetCommandLineW()
argc = c_int(0)
argv = CommandLineToArgvW(cmd, byref(argc))
if argc.value > 0:
# Remove Python executable and commands if present
start = argc.value - len(sys.argv)
return [argv[i].encode('utf-8') for i in
xrange(start, argc.value)]
# this should never happen
return None
else:
argv = []
argvencoding = sys.stdin.encoding
if argvencoding == None:
argvencoding = sys.getfilesystemencoding()
if argvencoding == None:
argvencoding = 'utf-8'
for arg in sys.argv:
if type(arg) == unicode:
argv.append(arg.encode('utf-8'))
else:
argv.append(arg.decode(argvencoding).encode('utf-8'))
return argv
def add_cp65001_codec():
try:
codecs.lookup('cp65001')
except LookupError:
codecs.register(
lambda name: name == 'cp65001' and codecs.lookup('utf-8') or None)
return
def set_utf8_default_encoding():
if sys.getdefaultencoding() == 'utf-8':
return
# Regenerate setdefaultencoding.
reload(sys)
sys.setdefaultencoding('utf-8')
for attr in dir(locale):
if attr[0:3] != 'LC_':
continue
aref = getattr(locale, attr)
try:
locale.setlocale(aref, '')
except locale.Error:
continue
try:
lang = locale.getlocale(aref)[0]
except (TypeError, ValueError):
continue
if lang:
try:
locale.setlocale(aref, (lang, 'UTF-8'))
except locale.Error:
os.environ[attr] = lang + '.UTF-8'
try:
locale.setlocale(locale.LC_ALL, '')
except locale.Error:
pass
return

View File

@@ -255,13 +255,15 @@ class PageParser(object):
'empty_text_region' : (1, 'snippets', 1, 0),
'img' : (1, 'snippets', 1, 0),
'img.x' : (1, 'scalar_number', 0, 0),
'img.y' : (1, 'scalar_number', 0, 0),
'img.h' : (1, 'scalar_number', 0, 0),
'img.w' : (1, 'scalar_number', 0, 0),
'img.src' : (1, 'scalar_number', 0, 0),
'img.color_src' : (1, 'scalar_number', 0, 0),
'img' : (1, 'snippets', 1, 0),
'img.x' : (1, 'scalar_number', 0, 0),
'img.y' : (1, 'scalar_number', 0, 0),
'img.h' : (1, 'scalar_number', 0, 0),
'img.w' : (1, 'scalar_number', 0, 0),
'img.src' : (1, 'scalar_number', 0, 0),
'img.color_src' : (1, 'scalar_number', 0, 0),
'img.gridBeginCenter' : (1, 'scalar_number', 0, 0),
'img.gridEndCenter' : (1, 'scalar_number', 0, 0),
'paragraph' : (1, 'snippets', 1, 0),
'paragraph.class' : (1, 'scalar_text', 0, 0),
@@ -307,6 +309,7 @@ class PageParser(object):
'span.gridEndCenter' : (1, 'scalar_number', 0, 0),
'extratokens' : (1, 'snippets', 1, 0),
'extratokens.class' : (1, 'scalar_text', 0, 0),
'extratokens.type' : (1, 'scalar_text', 0, 0),
'extratokens.firstGlyph' : (1, 'scalar_number', 0, 0),
'extratokens.lastGlyph' : (1, 'scalar_number', 0, 0),

View File

@@ -1,88 +0,0 @@
#!/usr/bin/env python
# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
class Unbuffered:
def __init__(self, stream):
self.stream = stream
def write(self, data):
self.stream.write(data)
self.stream.flush()
def __getattr__(self, attr):
return getattr(self.stream, attr)
import sys
sys.stdout=Unbuffered(sys.stdout)
import os
import ineptepub
import ignobleepub
import zipfix
import re
def main(argv=sys.argv):
args = argv[1:]
if len(args) != 3:
return -1
infile = args[0]
outdir = args[1]
rscpath = args[2]
errlog = ''
# first fix the epub to make sure we do not get errors
name, ext = os.path.splitext(os.path.basename(infile))
bpath = os.path.dirname(infile)
zippath = os.path.join(bpath,name + '_temp.zip')
rv = zipfix.repairBook(infile, zippath)
if rv != 0:
print "Error while trying to fix epub"
return rv
# determine a good name for the output file
outfile = os.path.join(outdir, name + '_nodrm.epub')
rv = 1
# first try with the Adobe adept epub
# try with any keyfiles (*.der) in the rscpath
files = os.listdir(rscpath)
filefilter = re.compile("\.der$", re.IGNORECASE)
files = filter(filefilter.search, files)
if files:
for filename in files:
keypath = os.path.join(rscpath, filename)
try:
rv = ineptepub.decryptBook(keypath, zippath, outfile)
if rv == 0:
break
except Exception, e:
errlog += str(e)
rv = 1
pass
if rv == 0:
os.remove(zippath)
return 0
# still no luck
# now try with ignoble epub
# try with any keyfiles (*.b64) in the rscpath
files = os.listdir(rscpath)
filefilter = re.compile("\.b64$", re.IGNORECASE)
files = filter(filefilter.search, files)
if files:
for filename in files:
keypath = os.path.join(rscpath, filename)
try:
rv = ignobleepub.decryptBook(keypath, zippath, outfile)
if rv == 0:
break
except Exception, e:
errlog += str(e)
rv = 1
pass
os.remove(zippath)
if rv != 0:
print errlog
return rv
if __name__ == "__main__":
sys.exit(main())

View File

@@ -1,45 +0,0 @@
#!/usr/bin/env python
# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
class Unbuffered:
def __init__(self, stream):
self.stream = stream
def write(self, data):
self.stream.write(data)
self.stream.flush()
def __getattr__(self, attr):
return getattr(self.stream, attr)
import sys
sys.stdout=Unbuffered(sys.stdout)
import os
import erdr2pml
def main(argv=sys.argv):
args = argv[1:]
if len(args) != 3:
return -1
infile = args[0]
outdir = args[1]
rscpath = args[2]
rv = 1
socialpath = os.path.join(rscpath,'sdrmlist.txt')
if os.path.exists(socialpath):
keydata = file(socialpath,'r').read()
keydata = keydata.rstrip(os.linesep)
ar = keydata.split(',')
for i in ar:
try:
name, cc8 = i.split(':')
except ValueError:
print ' Error parsing user supplied social drm data.'
return 1
rv = erdr2pml.decryptBook(infile, outdir, True, erdr2pml.getuser_key(name, cc8) )
if rv == 0:
break
return rv
if __name__ == "__main__":
sys.exit(main())

View File

@@ -1,54 +0,0 @@
#!/usr/bin/env python
# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
class Unbuffered:
def __init__(self, stream):
self.stream = stream
def write(self, data):
self.stream.write(data)
self.stream.flush()
def __getattr__(self, attr):
return getattr(self.stream, attr)
import sys
sys.stdout=Unbuffered(sys.stdout)
import os
import re
import ineptpdf
def main(argv=sys.argv):
args = argv[1:]
if len(args) != 3:
return -1
infile = args[0]
outdir = args[1]
rscpath = args[2]
errlog = ''
rv = 1
# determine a good name for the output file
name, ext = os.path.splitext(os.path.basename(infile))
outfile = os.path.join(outdir, name + '_nodrm.pdf')
# try with any keyfiles (*.der) in the rscpath
files = os.listdir(rscpath)
filefilter = re.compile("\.der$", re.IGNORECASE)
files = filter(filefilter.search, files)
if files:
for filename in files:
keypath = os.path.join(rscpath, filename)
try:
rv = ineptpdf.decryptBook(keypath, infile, outfile)
if rv == 0:
break
except Exception, e:
errlog += str(e)
rv = 1
pass
if rv != 0:
print errlog
return rv
if __name__ == "__main__":
sys.exit(main())

View File

@@ -387,10 +387,14 @@ class DocParser(object):
ws_last = int(argres)
elif name.endswith('word.class'):
(cname, space) = argres.split('-',1)
if space == '' : space = '0'
if (cname == 'spaceafter') and (int(space) > 0) :
word_class = 'sa'
# we only handle spaceafter word class
try:
(cname, space) = argres.split('-',1)
if space == '' : space = '0'
if (cname == 'spaceafter') and (int(space) > 0) :
word_class = 'sa'
except:
pass
elif name.endswith('word.img.src'):
result.append(('img' + word_class, int(argres)))

View File

@@ -117,7 +117,7 @@ class Dictionary(object):
self.pos = val
return self.stable[self.pos]
else:
print "Error - %d outside of string table limits" % val
print "Error: %d outside of string table limits" % val
raise TpzDRMError('outside or string table limits')
# sys.exit(-1)
def getSize(self):

View File

@@ -3,7 +3,7 @@
from __future__ import with_statement
# ignobleepub.pyw, version 3.6
# ignobleepub.pyw, version 3.7
# Copyright © 2009-2010 by i♥cabbages
# Released under the terms of the GNU General Public Licence, version 3
@@ -26,18 +26,19 @@ from __future__ import with_statement
# 2 - Added OS X support by using OpenSSL when available
# 3 - screen out improper key lengths to prevent segfaults on Linux
# 3.1 - Allow Windows versions of libcrypto to be found
# 3.2 - add support for encoding to 'utf-8' when building up list of files to cecrypt from encryption.xml
# 3.3 - On Windows try PyCrypto first and OpenSSL next
# 3.4 - Modify interace to allow use with import
# 3.2 - add support for encoding to 'utf-8' when building up list of files to decrypt from encryption.xml
# 3.3 - On Windows try PyCrypto first, OpenSSL next
# 3.4 - Modify interface to allow use with import
# 3.5 - Fix for potential problem with PyCrypto
# 3.6 - Revised to allow use in calibre plugins to eliminate need for duplicate code
# 3.7 - Tweaked to match ineptepub more closely
"""
Decrypt Barnes & Noble encrypted ePub books.
"""
__license__ = 'GPL v3'
__version__ = "3.6"
__version__ = "3.7"
import sys
import os
@@ -254,18 +255,17 @@ def ignobleBook(inpath):
return True
return False
# return error code and error message duple
def decryptBook(keyb64, inpath, outpath):
if AES is None:
# 1 means don't try again
return (1, u"PyCrypto or OpenSSL must be installed.")
raise IGNOBLEError(u"PyCrypto or OpenSSL must be installed.")
key = keyb64.decode('base64')[:16]
aes = AES(key)
with closing(ZipFile(open(inpath, 'rb'))) as inf:
namelist = set(inf.namelist())
if 'META-INF/rights.xml' not in namelist or \
'META-INF/encryption.xml' not in namelist:
return (1, u"Not a secure Barnes & Noble ePub.")
print u"{0:s} is DRM-free.".format(os.path.basename(inpath))
return 1
for name in META_NAMES:
namelist.remove(name)
try:
@@ -274,7 +274,8 @@ def decryptBook(keyb64, inpath, outpath):
expr = './/%s' % (adept('encryptedKey'),)
bookkey = ''.join(rights.findtext(expr))
if len(bookkey) != 64:
return (1, u"Not a secure Barnes & Noble ePub.")
print u"{0:s} is not a secure Barnes & Noble ePub.".format(os.path.basename(inpath))
return 1
bookkey = aes.decrypt(bookkey.decode('base64'))
bookkey = bookkey[:-ord(bookkey[-1])]
encryption = inf.read('META-INF/encryption.xml')
@@ -286,21 +287,23 @@ def decryptBook(keyb64, inpath, outpath):
for path in namelist:
data = inf.read(path)
outf.writestr(path, decryptor.decrypt(path, data))
except Exception, e:
return (2, u"{0}.".format(e.args[0]))
return (0, u"Success")
except:
print u"Could not decrypt {0:s} because of an exception:\n{1:s}".format(os.path.basename(inpath), traceback.format_exc())
return 2
return 0
def cli_main(argv=unicode_argv()):
progname = os.path.basename(argv[0])
if len(argv) != 4:
print u"usage: {0} <keyfile.der> <inbook.epub> <outbook.epub>".format(progname)
print u"usage: {0} <keyfile.b64> <inbook.epub> <outbook.epub>".format(progname)
return 1
keypath, inpath, outpath = argv[1:]
userkey = open(keypath,'rb').read()
result = decryptBook(userkey, inpath, outpath)
print result[1]
return result[0]
if result == 0:
print u"Successfully decrypted {0:s} as {1:s}".format(os.path.basename(inpath),os.path.basename(outpath))
return result
def gui_main():
import Tkinter
@@ -399,10 +402,10 @@ def gui_main():
except Exception, e:
self.status['text'] = u"Error: {0}".format(e.args[0])
return
if decrypt_status[0] == 0:
if decrypt_status == 0:
self.status['text'] = u"File successfully decrypted"
else:
self.status['text'] = decrypt_status[1]
self.status['text'] = u"The was an error decrypting the file."
root = Tkinter.Tk()
root.title(u"Barnes & Noble ePub Decrypter v.{0}".format(__version__))

View File

@@ -1,4 +1,4 @@
#! /usr/bin/python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import with_statement
@@ -542,7 +542,7 @@ def gui_main():
try:
decrypt_status = decryptBook(userkey, inpath, outpath)
except Exception, e:
self.status['text'] = u"Error; {0}".format(e)
self.status['text'] = u"Error: {0}".format(e.args[0])
return
if decrypt_status == 0:
self.status['text'] = u"File successfully decrypted"

View File

@@ -50,8 +50,9 @@ from __future__ import with_statement
# 4.7 - Added timing reports, and changed search for Mac key files
# 4.8 - Much better unicode handling, matching the updated inept and ignoble scripts
# - Moved back into plugin, __init__ in plugin now only contains plugin code.
# 4.9 - Missed some invalid characters in cleanup_name
__version__ = '4.8'
__version__ = '4.9'
import sys, os, re
@@ -144,7 +145,7 @@ def unicode_argv():
# and with some (heavily edited) code from Paul Durrant's kindlenamer.py
def cleanup_name(name):
# substitute filename unfriendly characters
name = name.replace(u"<",u"[").replace(u">",u"]").replace(u" : ",u" ").replace(u": ",u" ").replace(u":",u"").replace(u"/",u"_").replace(u"\\",u"_").replace(u"|",u"_").replace(u"\"",u"\'")
name = name.replace(u"<",u"[").replace(u">",u"]").replace(u" : ",u" ").replace(u": ",u" ").replace(u":",u"").replace(u"/",u"_").replace(u"\\",u"_").replace(u"|",u"_").replace(u"\"",u"\'").replace(u"*",u"_").replace(u"?",u"")
# delete control characters
name = u"".join(char for char in name if ord(char)>=32)
# white space to single space, delete leading and trailing while space
@@ -220,6 +221,7 @@ def decryptBook(infile, outdir, kInfoFiles, serials, pids):
book = GetDecryptedBook(infile, kInfoFiles, serials, pids, starttime)
except Exception, e:
print u"Error decrypting book after {1:.1f} seconds: {0}".format(e.args[0],time.time()-starttime)
traceback.print_exc()
return 1
# if we're saving to the same folder as the original, use file name_
@@ -246,6 +248,7 @@ def decryptBook(infile, outdir, kInfoFiles, serials, pids):
# remove internal temporary directory of Topaz pieces
book.cleanup()
return 0
def usage(progname):

View File

@@ -0,0 +1,153 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
import sys
import os
import re
import ineptepub
import ignobleepub
import zipfix
import ineptpdf
import erdr2pml
import k4mobidedrm
def decryptepub(infile, outdir, rscpath):
errlog = ''
# first fix the epub to make sure we do not get errors
name, ext = os.path.splitext(os.path.basename(infile))
bpath = os.path.dirname(infile)
zippath = os.path.join(bpath,name + '_temp.zip')
rv = zipfix.repairBook(infile, zippath)
if rv != 0:
print "Error while trying to fix epub"
return rv
# determine a good name for the output file
outfile = os.path.join(outdir, name + '_nodrm.epub')
rv = 1
# first try with the Adobe adept epub
# try with any keyfiles (*.der) in the rscpath
files = os.listdir(rscpath)
filefilter = re.compile("\.der$", re.IGNORECASE)
files = filter(filefilter.search, files)
if files:
for filename in files:
keypath = os.path.join(rscpath, filename)
userkey = open(keypath,'rb').read()
try:
rv = ineptepub.decryptBook(userkey, zippath, outfile)
if rv == 0:
break
except Exception, e:
errlog += str(e)
rv = 1
pass
if rv == 0:
os.remove(zippath)
return 0
# still no luck
# now try with ignoble epub
# try with any keyfiles (*.b64) in the rscpath
files = os.listdir(rscpath)
filefilter = re.compile("\.b64$", re.IGNORECASE)
files = filter(filefilter.search, files)
if files:
for filename in files:
keypath = os.path.join(rscpath, filename)
userkey = open(keypath,'rb').read()
try:
rv = ignobleepub.decryptBook(userkey, zippath, outfile)
if rv == 0:
break
except Exception, e:
errlog += str(e)
rv = 1
pass
os.remove(zippath)
if rv != 0:
print errlog
return rv
def decryptpdf(infile, outdir, rscpath):
errlog = ''
rv = 1
# determine a good name for the output file
name, ext = os.path.splitext(os.path.basename(infile))
outfile = os.path.join(outdir, name + '_nodrm.pdf')
# try with any keyfiles (*.der) in the rscpath
files = os.listdir(rscpath)
filefilter = re.compile("\.der$", re.IGNORECASE)
files = filter(filefilter.search, files)
if files:
for filename in files:
keypath = os.path.join(rscpath, filename)
userkey = open(keypath,'rb').read()
try:
rv = ineptpdf.decryptBook(userkey, infile, outfile)
if rv == 0:
break
except Exception, e:
errlog += str(e)
rv = 1
pass
if rv != 0:
print errlog
return rv
def decryptpdb(infile, outdir, rscpath):
outname = os.path.splitext(os.path.basename(infile))[0] + ".pmlz"
outpath = os.path.join(outdir, outname)
rv = 1
socialpath = os.path.join(rscpath,'sdrmlist.txt')
if os.path.exists(socialpath):
keydata = file(socialpath,'r').read()
keydata = keydata.rstrip(os.linesep)
ar = keydata.split(',')
for i in ar:
try:
name, cc8 = i.split(':')
except ValueError:
print ' Error parsing user supplied social drm data.'
return 1
rv = erdr2pml.decryptBook(infile, outpath, True, erdr2pml.getuser_key(name, cc8))
if rv == 0:
break
return rv
def decryptk4mobi(infile, outdir, rscpath):
rv = 1
pidnums = []
pidspath = os.path.join(rscpath,'pidlist.txt')
if os.path.exists(pidspath):
pidstr = file(pidspath,'r').read()
pidstr = pidstr.rstrip(os.linesep)
pidstr = pidstr.strip()
if pidstr != '':
pidnums = pidstr.split(',')
serialnums = []
serialnumspath = os.path.join(rscpath,'seriallist.txt')
if os.path.exists(serialnumspath):
serialstr = file(serialnumspath,'r').read()
serialstr = serialstr.rstrip(os.linesep)
serialstr = serialstr.strip()
if serialstr != '':
serialnums = serialstr.split(',')
kInfoFiles = []
files = os.listdir(rscpath)
filefilter = re.compile("\.info$|\.kinf$", re.IGNORECASE)
files = filter(filefilter.search, files)
if files:
for filename in files:
dpath = os.path.join(rscpath,filename)
kInfoFiles.append(dpath)
rv = k4mobidedrm.decryptBook(infile, outdir, kInfoFiles, serialnums, pidnums)
return rv

View File

@@ -1,7 +1,7 @@
ReadMe_DeDRM_v5.5.3_WinApp
ReadMe_DeDRM_v5.6_WinApp
========================
DeDRM_v5.5.3_WinApp is a pure python drag and drop application that allows users to drag and drop ebooks or folders of ebooks onto the DeDRM_Drop_Target to have the DRM removed. It repackages all the "tools" python software in one easy to use program that remembers preferences and settings.
DeDRM_v5.6_WinApp is a pure python drag and drop application that allows users to drag and drop ebooks or folders of ebooks onto the DeDRM_Drop_Target to have the DRM removed. It repackages all the "tools" python software in one easy to use program that remembers preferences and settings.
It will work without manual configuration for Kindle for PC ebooks and Adobe Adept epub and pdf ebooks.
@@ -23,9 +23,9 @@ Installation
0. If you don't already have a correct version of Python and PyCrypto installed, follow the "Installing Python on Windows" and "Installing PyCrypto on Windows" sections below before continuing.
1. Drag the DeDRM_5.5.3 folder from tools_v5.5.3/DeDRM_Applications/Windows to your "My Documents" folder.
1. Drag the DeDRM_5.6 folder from tools_v5.6/DeDRM_Applications/Windows to your "My Documents" folder.
2. Open the DeDRM_5.5.3 folder you've just dragged, and make a short-cut of the DeDRM_Drop_Target.bat file (right-click/Create Shortcut). Drag the shortcut file onto your Desktop.
2. Open the DeDRM_5.6 folder you've just dragged, and make a short-cut of the DeDRM_Drop_Target.bat file (right-click/Create Shortcut). Drag the shortcut file onto your Desktop.
3. To set the preferences simply double-click on your just created short-cut.