2012-12-19 19:48:11 +06:00
|
|
|
#!/usr/bin/env python
|
|
|
|
# -*- coding: utf-8 -*-
|
2012-09-09 06:45:24 +06:00
|
|
|
|
|
|
|
from __future__ import with_statement
|
2012-12-19 19:48:11 +06:00
|
|
|
__license__ = 'GPL v3'
|
2009-02-26 16:42:22 +06:00
|
|
|
|
2012-12-19 19:48:11 +06:00
|
|
|
# Released under the terms of the GNU General Public Licence, version 3
|
|
|
|
# <http://www.gnu.org/licenses/>
|
2010-12-31 04:41:07 +06:00
|
|
|
|
2012-11-20 19:28:12 +06:00
|
|
|
# PLEASE DO NOT PIRATE EBOOKS!
|
2010-12-31 04:41:07 +06:00
|
|
|
|
|
|
|
# We want all authors and publishers, and eBook stores to live
|
2012-11-20 19:28:12 +06:00
|
|
|
# long and prosperous lives but at the same time we just want to
|
|
|
|
# be able to read OUR books on whatever device we want and to keep
|
2010-12-31 04:41:07 +06:00
|
|
|
# readable for a long, long time
|
|
|
|
|
2011-06-16 11:59:20 +06:00
|
|
|
# Requires Calibre version 0.7.55 or higher.
|
2010-12-31 04:41:07 +06:00
|
|
|
#
|
2012-12-19 19:48:11 +06:00
|
|
|
# All credit given to i♥cabbages for the original standalone scripts.
|
2010-12-31 04:41:07 +06:00
|
|
|
# I had the much easier job of converting them to a Calibre plugin.
|
|
|
|
#
|
|
|
|
# This plugin is meant to decrypt Adobe Digital Edition PDFs that are protected
|
|
|
|
# with Adobe's Adept encryption. It is meant to function without having to install
|
|
|
|
# any dependencies... other than having Calibre installed, of course. It will still
|
|
|
|
# work if you have Python and PyCrypto already installed, but they aren't necessary.
|
|
|
|
#
|
|
|
|
# Configuration:
|
|
|
|
# When first run, the plugin will attempt to find your Adobe Digital Editions installation
|
2012-12-19 19:48:11 +06:00
|
|
|
# (on Windows and Mac OS's). If successful, it will create one or more
|
|
|
|
# 'calibre-adeptkey<n>.der' files and save them in calibre's configuration directory.
|
|
|
|
# It will use those files on subsequent runs. If there is already a 'calibre-adeptkey*.der'
|
|
|
|
# file in the directory, the plugin won't attempt to find the ADE installation.
|
|
|
|
# So if you have ADE installed on the same machine as calibre you are ready to go.
|
2010-12-31 04:41:07 +06:00
|
|
|
#
|
2012-12-19 19:48:11 +06:00
|
|
|
# If you already have keyfiles generated with i♥cabbages' ineptkey.pyw script,
|
2010-12-31 04:41:07 +06:00
|
|
|
# you can put those keyfiles in Calibre's configuration directory. The easiest
|
|
|
|
# way to find the correct directory is to go to Calibre's Preferences page... click
|
|
|
|
# on the 'Miscellaneous' button (looks like a gear), and then click the 'Open Calibre
|
|
|
|
# configuration directory' button. Paste your keyfiles in there. Just make sure that
|
|
|
|
# they have different names and are saved with the '.der' extension (like the ineptkey
|
|
|
|
# script produces). This directory isn't touched when upgrading Calibre, so it's quite
|
|
|
|
# safe to leave them there.
|
|
|
|
#
|
|
|
|
# Since there is no Linux version of Adobe Digital Editions, Linux users will have to
|
|
|
|
# obtain a keyfile through other methods and put the file in Calibre's configuration directory.
|
|
|
|
#
|
|
|
|
# All keyfiles with a '.der' extension found in Calibre's configuration directory will
|
|
|
|
# be used to attempt to decrypt a book.
|
|
|
|
#
|
|
|
|
# ** NOTE ** There is no plugin customization data for the Inept PDF DeDRM plugin.
|
|
|
|
#
|
2009-02-26 16:42:22 +06:00
|
|
|
# Revision history:
|
2011-02-08 23:21:51 +06:00
|
|
|
# 0.1 - Initial release
|
|
|
|
# 0.1.1 - back port ineptpdf 8.4.X support for increased number of encryption methods
|
|
|
|
# 0.1.2 - back port ineptpdf 8.4.X bug fixes
|
2012-11-20 19:28:12 +06:00
|
|
|
# 0.1.3 - add in fix for improper rejection of session bookkeys with len(bookkey) = length + 1
|
2011-06-16 11:59:20 +06:00
|
|
|
# 0.1.4 - update to the new calibre plugin interface
|
2012-09-09 06:45:24 +06:00
|
|
|
# 0.1.5 - synced to ineptpdf 7.11
|
2012-11-07 19:14:25 +06:00
|
|
|
# 0.1.6 - Fix for potential problem with PyCrypto
|
|
|
|
# 0.1.7 - Fix for potential problem with ADE keys and fix possible output/unicode problem
|
2012-11-20 19:28:12 +06:00
|
|
|
# 0.1.8 - Fix for code copying error
|
2012-12-19 19:48:11 +06:00
|
|
|
# 0.1.9 - Major code change to use unaltered ineptepub.py
|
2012-11-07 19:14:25 +06:00
|
|
|
|
2009-02-26 16:42:22 +06:00
|
|
|
"""
|
2010-12-02 01:26:12 +06:00
|
|
|
Decrypts Adobe ADEPT-encrypted PDF files.
|
2009-02-26 16:42:22 +06:00
|
|
|
"""
|
|
|
|
|
2012-12-19 19:48:11 +06:00
|
|
|
PLUGIN_NAME = u"Inept PDF DeDRM"
|
|
|
|
PLUGIN_VERSION_TUPLE = (0, 1, 9)
|
|
|
|
PLUGIN_VERSION = u'.'.join([str(x) for x in PLUGIN_VERSION_TUPLE])
|
2009-02-26 16:42:22 +06:00
|
|
|
|
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
import re
|
|
|
|
|
2010-12-01 13:16:54 +06:00
|
|
|
class ADEPTError(Exception):
|
|
|
|
pass
|
|
|
|
|
2012-12-19 19:48:11 +06:00
|
|
|
from calibre.customize import FileTypePlugin
|
|
|
|
from calibre.constants import iswindows, isosx
|
2010-12-02 01:26:12 +06:00
|
|
|
|
2012-12-19 19:48:11 +06:00
|
|
|
# Wrap a stream so that output gets flushed immediately
|
|
|
|
# and also make sure that any unicode strings get
|
|
|
|
# encoded using "replace" before writing them.
|
|
|
|
class SafeUnbuffered:
|
|
|
|
def __init__(self, stream):
|
|
|
|
self.stream = stream
|
|
|
|
self.encoding = stream.encoding
|
|
|
|
if self.encoding == None:
|
|
|
|
self.encoding = "utf-8"
|
2009-01-01 20:33:12 +06:00
|
|
|
def write(self, data):
|
2012-12-19 19:48:11 +06:00
|
|
|
if isinstance(data,unicode):
|
|
|
|
data = data.encode(self.encoding,"replace")
|
|
|
|
self.stream.write(data)
|
|
|
|
self.stream.flush()
|
|
|
|
def __getattr__(self, attr):
|
|
|
|
return getattr(self.stream, attr)
|
2012-09-09 06:45:24 +06:00
|
|
|
|
2012-11-20 19:28:12 +06:00
|
|
|
|
2012-12-19 19:48:11 +06:00
|
|
|
class ADEPTError(Exception):
|
|
|
|
pass
|
2010-12-31 04:41:07 +06:00
|
|
|
|
|
|
|
class IneptPDFDeDRM(FileTypePlugin):
|
2012-12-19 19:48:11 +06:00
|
|
|
name = PLUGIN_NAME
|
|
|
|
description = u"Removes DRM from secure Adobe pdf files. Credit given to i♥cabbages for the original stand-alone scripts."
|
2010-12-31 04:41:07 +06:00
|
|
|
supported_platforms = ['linux', 'osx', 'windows']
|
2012-12-19 19:48:11 +06:00
|
|
|
author = u"DiapDealer, Apprentice Alf and i♥cabbages"
|
|
|
|
version = PLUGIN_VERSION_TUPLE
|
2011-06-16 11:59:20 +06:00
|
|
|
minimum_calibre_version = (0, 7, 55) # for the new plugin interface
|
2010-12-31 04:41:07 +06:00
|
|
|
file_types = set(['pdf'])
|
|
|
|
on_import = True
|
2012-12-19 19:48:11 +06:00
|
|
|
priority = 100
|
2012-11-20 19:28:12 +06:00
|
|
|
|
2010-12-31 04:41:07 +06:00
|
|
|
def run(self, path_to_ebook):
|
2012-11-20 19:28:12 +06:00
|
|
|
|
2012-12-19 19:48:11 +06:00
|
|
|
# make sure any unicode output gets converted safely with 'replace'
|
|
|
|
sys.stdout=SafeUnbuffered(sys.stdout)
|
|
|
|
sys.stderr=SafeUnbuffered(sys.stderr)
|
2012-11-20 19:28:12 +06:00
|
|
|
|
2012-12-19 19:48:11 +06:00
|
|
|
print u"{0} v{1}: Trying to decrypt {2}.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook))
|
2012-11-20 19:28:12 +06:00
|
|
|
|
2010-12-31 04:41:07 +06:00
|
|
|
# Load any keyfiles (*.der) included Calibre's config directory.
|
|
|
|
userkeys = []
|
|
|
|
# Find Calibre's configuration directory.
|
2012-12-19 19:48:11 +06:00
|
|
|
# self.plugin_path is passed in unicode because we defined our name in unicode
|
2010-12-31 04:41:07 +06:00
|
|
|
confpath = os.path.split(os.path.split(self.plugin_path)[0])[0]
|
2012-12-19 19:48:11 +06:00
|
|
|
print u"{0} v{1}: Calibre configuration directory = {2}".format(PLUGIN_NAME, PLUGIN_VERSION, confpath)
|
2010-12-31 04:41:07 +06:00
|
|
|
files = os.listdir(confpath)
|
2012-12-19 19:48:11 +06:00
|
|
|
filefilter = re.compile(u"\.der$", re.IGNORECASE)
|
2010-12-31 04:41:07 +06:00
|
|
|
files = filter(filefilter.search, files)
|
2012-11-07 19:14:25 +06:00
|
|
|
foundDefault = False
|
2010-12-31 04:41:07 +06:00
|
|
|
if files:
|
|
|
|
try:
|
|
|
|
for filename in files:
|
2012-12-19 19:48:11 +06:00
|
|
|
if filename[:16] == u"calibre-adeptkey":
|
2012-11-07 19:14:25 +06:00
|
|
|
foundDefault = True
|
2010-12-31 04:41:07 +06:00
|
|
|
fpath = os.path.join(confpath, filename)
|
|
|
|
with open(fpath, 'rb') as f:
|
2012-12-19 19:48:11 +06:00
|
|
|
userkeys.append([f.read(), filename])
|
|
|
|
print u"{0} v{1}: Keyfile {2} found in config folder.".format(PLUGIN_NAME, PLUGIN_VERSION, filename)
|
2010-12-31 04:41:07 +06:00
|
|
|
except IOError:
|
2012-12-19 19:48:11 +06:00
|
|
|
print u"{0} v{1}: Error reading keyfiles from config directory.".format(PLUGIN_NAME, PLUGIN_VERSION)
|
2010-12-31 04:41:07 +06:00
|
|
|
pass
|
2012-11-20 19:28:12 +06:00
|
|
|
|
2012-11-07 19:14:25 +06:00
|
|
|
if not foundDefault:
|
2010-12-31 04:41:07 +06:00
|
|
|
# Try to find key from ADE install and save the key in
|
|
|
|
# Calibre's configuration directory for future use.
|
|
|
|
if iswindows or isosx:
|
2012-12-19 19:48:11 +06:00
|
|
|
#ignore annoying future warning from key generation
|
|
|
|
import warnings
|
|
|
|
warnings.filterwarnings('ignore', category=FutureWarning)
|
|
|
|
|
2012-11-07 19:14:25 +06:00
|
|
|
# ADE key retrieval script included in respective OS folder.
|
2012-12-19 19:48:11 +06:00
|
|
|
from calibre_plugins.ineptepub.ineptkey import retrieve_keys
|
2010-12-31 04:41:07 +06:00
|
|
|
try:
|
2012-11-07 19:14:25 +06:00
|
|
|
keys = retrieve_keys()
|
|
|
|
for i,key in enumerate(keys):
|
2012-12-19 19:48:11 +06:00
|
|
|
keyname = u"calibre-adeptkey{0:d}.der".format(i)
|
|
|
|
userkeys.append([key,keyname])
|
|
|
|
keypath = os.path.join(confpath, keyname)
|
2012-11-07 19:14:25 +06:00
|
|
|
open(keypath, 'wb').write(key)
|
2012-12-19 19:48:11 +06:00
|
|
|
print u"{0} v{1}: Created keyfile {2} from ADE install.".format(PLUGIN_NAME, PLUGIN_VERSION, keyname)
|
2010-12-31 04:41:07 +06:00
|
|
|
except:
|
2012-12-19 19:48:11 +06:00
|
|
|
print u"{0} v{1}: Couldn\'t Retrieve key from ADE install.".format(PLUGIN_NAME, PLUGIN_VERSION)
|
2012-11-07 19:14:25 +06:00
|
|
|
pass
|
2009-02-26 16:42:22 +06:00
|
|
|
|
2010-12-31 04:41:07 +06:00
|
|
|
if not userkeys:
|
|
|
|
# No user keys found... bail out.
|
2012-12-19 19:48:11 +06:00
|
|
|
raise ADEPTError(u"{0} v{1}: No keys found. Check keyfile(s)/ADE install".format(PLUGIN_NAME, PLUGIN_VERSION))
|
|
|
|
return
|
2012-11-20 19:28:12 +06:00
|
|
|
|
2010-12-31 04:41:07 +06:00
|
|
|
# Attempt to decrypt pdf with each encryption key found.
|
2012-12-19 19:48:11 +06:00
|
|
|
from calibre_plugins.ineptpdf import ineptpdf
|
|
|
|
for userkeyinfo in userkeys:
|
|
|
|
print u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, userkeyinfo[1])
|
2010-12-31 04:41:07 +06:00
|
|
|
# Create a TemporaryPersistent file to work with.
|
|
|
|
of = self.temporary_file('.pdf')
|
2012-11-20 19:28:12 +06:00
|
|
|
|
2012-12-19 19:48:11 +06:00
|
|
|
# Give the user keyfile, ebook and TemporaryPersistent file to the decryptBook function.
|
|
|
|
result = ineptpdf.decryptBook(userkeyinfo[0], path_to_ebook, of.name)
|
2012-11-20 19:28:12 +06:00
|
|
|
|
2010-12-31 04:41:07 +06:00
|
|
|
# Decryption was successful return the modified PersistentTemporary
|
|
|
|
# file to Calibre's import process.
|
|
|
|
if result == 0:
|
2012-12-19 19:48:11 +06:00
|
|
|
print u"{0} v{1}: Encryption successfully removed.".format(PLUGIN_NAME, PLUGIN_VERSION)
|
|
|
|
of.close()
|
2010-12-31 04:41:07 +06:00
|
|
|
return of.name
|
|
|
|
break
|
2012-12-19 19:48:11 +06:00
|
|
|
|
|
|
|
print u"{0} v{1}: Encryption key incorrect.".format(PLUGIN_NAME, PLUGIN_VERSION)
|
|
|
|
of.close()
|
2012-11-20 19:28:12 +06:00
|
|
|
|
2010-12-31 04:41:07 +06:00
|
|
|
# Something went wrong with decryption.
|
2012-12-19 19:48:11 +06:00
|
|
|
raise ADEPTError(u"{0} v{1}: Ultimately failed to decrypt".format(PLUGIN_NAME, PLUGIN_VERSION))
|
|
|
|
return
|