tools v5.4.1
This commit is contained in:
@@ -1,4 +1,8 @@
|
||||
<html>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
|
||||
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
|
||||
<head>
|
||||
<title>Ignoble Epub DeDRM Plugin Configuration</title>
|
||||
@@ -7,10 +11,10 @@
|
||||
<body>
|
||||
|
||||
<h1>Ignoble Epub DeDRM Plugin</h1>
|
||||
<h3>(version 0.2.3)</h3>
|
||||
<h3>(version 0.2.4)</h3>
|
||||
<h3> For additional help read the <a href="http://apprenticealf.wordpress.com/2011/01/17/frequently-asked-questions-about-the-drm-removal-tools/" target="_blank">FAQ</a> on <a href="http://apprenticealf.wordpress.com" target="_blank">Apprentice Alf's Blog</a> and ask questions in the comments section of the <a href="http://apprenticealf.wordpress.com/2012/09/10/drm-removal-tools-for-ebooks/" target="_blank">first post</a>.</h3>
|
||||
|
||||
<p>All credit given to I <3 Cabbages for the original standalone scripts (I had the much easier job of converting them to a calibre plugin).</p>
|
||||
<p>All credit given to I ♥ Cabbages for the original standalone scripts (I had the much easier job of converting them to a calibre plugin).</p>
|
||||
|
||||
<p>This plugin is meant to decrypt Barnes & Noble ePubs 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.</p>
|
||||
|
||||
@@ -83,6 +87,8 @@
|
||||
0.2.1 - an updated/modified zipfix.py and included zipfilerugged.py
|
||||
0.2.2 - added in potential fixes from 0.1.7 that had been missed.
|
||||
0.2.3 - fixed possible output/unicode problem
|
||||
0.2.4 - ditched nearly hopeless caselessStrCmp method in favor of uStrCmp.
|
||||
- added ability to rename existing keys.
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import with_statement
|
||||
__license__ = 'GPL v3'
|
||||
@@ -11,7 +12,7 @@ __docformat__ = 'restructuredtext en'
|
||||
#
|
||||
# Requires Calibre version 0.7.55 or higher.
|
||||
#
|
||||
# All credit given to I <3 Cabbages for the original standalone scripts.
|
||||
# All credit given to I ♥ Cabbages for the original standalone scripts.
|
||||
# I had the much easier job of converting them to Calibre a plugin.
|
||||
#
|
||||
# This plugin is meant to decrypt Barnes & Noble Epubs that are protected
|
||||
@@ -40,13 +41,15 @@ __docformat__ = 'restructuredtext en'
|
||||
# 0.2.1 - an updated/modified zipfix.py and included zipfilerugged.py
|
||||
# 0.2.2 - added in potential fixes from 0.1.7 that had been missed.
|
||||
# 0.2.3 - fixed possible output/unicode problem
|
||||
# 0.2.4 - ditched nearly hopeless caselessStrCmp method in favor of uStrCmp.
|
||||
# - added ability to rename existing keys.
|
||||
|
||||
"""
|
||||
Decrypt Barnes & Noble ADEPT encrypted EPUB books.
|
||||
"""
|
||||
|
||||
PLUGIN_NAME = 'Ignoble Epub DeDRM'
|
||||
PLUGIN_VERSION_TUPLE = (0, 2, 3)
|
||||
PLUGIN_VERSION_TUPLE = (0, 2, 4)
|
||||
PLUGIN_VERSION = '.'.join([str(x) for x in PLUGIN_VERSION_TUPLE])
|
||||
# Include an html helpfile in the plugin's zipfile with the following name.
|
||||
RESOURCE_NAME = PLUGIN_NAME + '_Help.htm'
|
||||
@@ -225,7 +228,7 @@ from calibre.gui2 import is_ok_to_use_qt
|
||||
|
||||
class IgnobleDeDRM(FileTypePlugin):
|
||||
name = PLUGIN_NAME
|
||||
description = 'Removes DRM from secure Barnes & Noble epub files. Credit given to I <3 Cabbages for the original stand-alone scripts.'
|
||||
description = 'Removes DRM from secure Barnes & Noble epub files. Credit given to I ♥ Cabbages for the original stand-alone scripts.'
|
||||
supported_platforms = ['linux', 'osx', 'windows']
|
||||
author = 'DiapDealer'
|
||||
version = PLUGIN_VERSION_TUPLE
|
||||
@@ -258,10 +261,12 @@ class IgnobleDeDRM(FileTypePlugin):
|
||||
import calibre_plugins.ignoble_epub.config as cfg
|
||||
if not cfg.prefs['configured']:
|
||||
titlemsg = '%s v%s' % (PLUGIN_NAME, PLUGIN_VERSION)
|
||||
errmsg = 'Plugin not configured! Decryption unsuccessful.\n' + \
|
||||
'\nThis may be the first time you\'ve used this plugin\n' + \
|
||||
'(or the first time since upgrading this plugin).\n' + \
|
||||
'\nYou\'ll need to open the customization dialog (Preferences->Plugins->File type plugins).'
|
||||
errmsg = titlemsg + ' not (properly) configured!\n' + \
|
||||
'\nThis may be the first time you\'ve used this plugin' + \
|
||||
' (or the first time since upgrading this plugin).' + \
|
||||
' You\'ll need to open the customization dialog (Preferences->Plugins->File type plugins)' + \
|
||||
' and follow the instructions there.\n' + \
|
||||
'\nIf you don\'t use the ' + PLUGIN_NAME + ' plugin, you should disable or uninstall it.'
|
||||
if is_ok_to_use_qt():
|
||||
from PyQt4.Qt import QMessageBox
|
||||
d = QMessageBox(QMessageBox.Warning, titlemsg, errmsg )
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
|
||||
from __future__ import with_statement
|
||||
__license__ = 'GPL v3'
|
||||
@@ -21,8 +22,8 @@ from calibre.utils.config import dynamic, config_dir, JSONConfig
|
||||
from calibre_plugins.ignoble_epub.__init__ import PLUGIN_NAME, PLUGIN_VERSION
|
||||
from calibre_plugins.ignoble_epub.__init__ import RESOURCE_NAME as help_file_name
|
||||
from calibre_plugins.ignoble_epub.utilities import (_load_crypto, normalize_name,
|
||||
generate_keyfile, caselessStrCmp, AddKeyDialog,
|
||||
DETAILED_MESSAGE, parseCustString)
|
||||
generate_keyfile, uStrCmp, DETAILED_MESSAGE, parseCustString)
|
||||
from calibre_plugins.ignoble_epub.dialogs import AddKeyDialog, RenameKeyDialog
|
||||
|
||||
JSON_NAME = PLUGIN_NAME.strip().lower().replace(' ', '_')
|
||||
JSON_PATH = 'plugins/' + JSON_NAME + '.json'
|
||||
@@ -135,6 +136,12 @@ class ConfigWidget(QWidget):
|
||||
self._delete_key_button.setIcon(QIcon(I('list_remove.png')))
|
||||
self._delete_key_button.clicked.connect(self.delete_key)
|
||||
button_layout.addWidget(self._delete_key_button)
|
||||
|
||||
self._rename_key_button = QtGui.QToolButton(self)
|
||||
self._rename_key_button.setToolTip(_('Rename highlighted key'))
|
||||
self._rename_key_button.setIcon(QIcon(I('edit-select-all.png')))
|
||||
self._rename_key_button.clicked.connect(self.rename_key)
|
||||
button_layout.addWidget(self._rename_key_button)
|
||||
|
||||
self.export_key_button = QtGui.QToolButton(self)
|
||||
self.export_key_button.setToolTip(_('Export highlighted key'))
|
||||
@@ -171,10 +178,34 @@ class ConfigWidget(QWidget):
|
||||
self.listy.clear()
|
||||
self.populate_list()
|
||||
|
||||
def rename_key(self):
|
||||
if not self.listy.currentItem():
|
||||
errmsg = '<p>No keyfile selected to export. Highlight a keyfile first.'
|
||||
r = error_dialog(None, PLUGIN_NAME,
|
||||
_(errmsg), show=True, show_copy_button=False)
|
||||
return
|
||||
|
||||
d = RenameKeyDialog(self)
|
||||
d.exec_()
|
||||
|
||||
if d.result() != d.Accepted:
|
||||
# rename cancelled or moot.
|
||||
return
|
||||
keyname = unicode(self.listy.currentItem().text().toUtf8(), 'utf8')
|
||||
if not question_dialog(self, _('Are you sure?'), _('<p>'+
|
||||
'Do you really want to rename the Ignoble key named <strong>%s</strong> to <strong>%s</strong>?') % (keyname, d.key_name),
|
||||
show_copy_button=False, default_yes=False):
|
||||
return
|
||||
self.plugin_keys[d.key_name] = self.plugin_keys[keyname]
|
||||
del self.plugin_keys[keyname]
|
||||
|
||||
self.listy.clear()
|
||||
self.populate_list()
|
||||
|
||||
def delete_key(self):
|
||||
if not self.listy.currentItem():
|
||||
return
|
||||
keyname = unicode(self.listy.currentItem().text())
|
||||
keyname = unicode(self.listy.currentItem().text().toUtf8(), 'utf8')
|
||||
if not question_dialog(self, _('Are you sure?'), _('<p>'+
|
||||
'Do you really want to delete the Ignoble key named <strong>%s</strong>?') % keyname,
|
||||
show_copy_button=False, default_yes=False):
|
||||
@@ -214,21 +245,20 @@ class ConfigWidget(QWidget):
|
||||
new_key_name = os.path.splitext(os.path.basename(filename))[0]
|
||||
match = False
|
||||
for key in self.plugin_keys.keys():
|
||||
if caselessStrCmp(new_key_name, key) == 0:
|
||||
if uStrCmp(new_key_name, key, True):
|
||||
skipped += 1
|
||||
msg = '<p>A key with the name <strong>' + new_key_name + '</strong> already exists! </p>' + \
|
||||
'<p>Skipping key file named <strong>' + filename + '</strong>.</p>' + \
|
||||
'<p>Either delete the existing key and re-migrate, or ' + \
|
||||
'create that key manually with a different name.'
|
||||
inf = info_dialog(None, _(PLUGIN_NAME + 'info_dlg'),
|
||||
_(msg), show=True)
|
||||
match = True
|
||||
break
|
||||
if not match:
|
||||
with open(fpath, 'rb') as f:
|
||||
counter += 1
|
||||
self.plugin_keys[unicode(new_key_name)] = f.read()
|
||||
else:
|
||||
skipped += 1
|
||||
msg = '<p>A key with the name <strong>' + new_key_name + '</strong> already exists! </p>' + \
|
||||
'<p>Skipping key file named <strong>' + filename + '</strong>.</p>' + \
|
||||
'<p>Either delete the existing key and re-migrate, or ' + \
|
||||
'create that key manually with a different name.'
|
||||
inf = info_dialog(None, _(PLUGIN_NAME + 'info_dlg'),
|
||||
_(msg), show=True)
|
||||
|
||||
msg = '<p>Done migrating <strong>' + str(counter) + '</strong> ' + \
|
||||
'key files...</p><p>Skipped <strong>' + str(skipped) + '</strong> key files.'
|
||||
@@ -249,12 +279,12 @@ class ConfigWidget(QWidget):
|
||||
_(errmsg), show=True, show_copy_button=False)
|
||||
return
|
||||
filter = QString('Ignoble Key Files (*.b64)')
|
||||
keyname = unicode(self.listy.currentItem().text())
|
||||
keyname = unicode(self.listy.currentItem().text().toUtf8(), 'utf8')
|
||||
if dynamic.get(PLUGIN_NAME + 'save_dir'):
|
||||
defaultname = os.path.join(dynamic.get(PLUGIN_NAME + 'save_dir'), keyname + '.b64')
|
||||
else:
|
||||
defaultname = os.path.join(os.path.expanduser('~'), keyname + '.b64')
|
||||
filename = str(QtGui.QFileDialog.getSaveFileName(self, "Save Ignoble Key File as...", defaultname,
|
||||
filename = unicode(QtGui.QFileDialog.getSaveFileName(self, "Save Ignoble Key File as...", defaultname,
|
||||
"Ignoble Key Files (*.b64)", filter))
|
||||
if filename:
|
||||
dynamic[PLUGIN_NAME + 'save_dir'] = os.path.split(filename)[0]
|
||||
@@ -266,7 +296,7 @@ class ConfigWidget(QWidget):
|
||||
filter = QString('Text files (*.txt)')
|
||||
default_basefilename = PLUGIN_NAME + ' old customization data.txt'
|
||||
defaultname = os.path.join(os.path.expanduser('~'), default_basefilename)
|
||||
filename = str(QtGui.QFileDialog.getSaveFileName(self, "Save old plugin style customization data as...", defaultname,
|
||||
filename = unicode(QtGui.QFileDialog.getSaveFileName(self, "Save old plugin style customization data as...", defaultname,
|
||||
"Text Files (*.txt)", filter))
|
||||
if filename:
|
||||
fname = open(filename, 'w')
|
||||
|
||||
160
Calibre_Plugins/ignobleepub_plugin/dialogs.py
Normal file
160
Calibre_Plugins/ignobleepub_plugin/dialogs.py
Normal file
@@ -0,0 +1,160 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
|
||||
from __future__ import with_statement
|
||||
__license__ = 'GPL v3'
|
||||
|
||||
from PyQt4.Qt import (Qt, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit,
|
||||
QGroupBox, QDialog, QDialogButtonBox)
|
||||
from calibre.gui2 import error_dialog
|
||||
|
||||
from calibre_plugins.ignoble_epub.__init__ import PLUGIN_NAME, PLUGIN_VERSION
|
||||
from calibre_plugins.ignoble_epub.utilities import uStrCmp
|
||||
|
||||
class AddKeyDialog(QDialog):
|
||||
def __init__(self, parent=None,):
|
||||
QDialog.__init__(self, parent)
|
||||
self.parent = parent
|
||||
self.setWindowTitle('Create New Ignoble Key')
|
||||
layout = QVBoxLayout(self)
|
||||
self.setLayout(layout)
|
||||
|
||||
data_group_box = QGroupBox('', self)
|
||||
layout.addWidget(data_group_box)
|
||||
data_group_box_layout = QVBoxLayout()
|
||||
data_group_box.setLayout(data_group_box_layout)
|
||||
|
||||
key_group = QHBoxLayout()
|
||||
data_group_box_layout.addLayout(key_group)
|
||||
key_group.addWidget(QLabel('Unique Key Name:', self))
|
||||
self.key_ledit = QLineEdit('', self)
|
||||
self.key_ledit.setToolTip(_('<p>Enter an identifying name for this new Ignoble key.</p>' +
|
||||
'<p>It should be something that will help you remember ' +
|
||||
'what personal information was used to create it.'))
|
||||
key_group.addWidget(self.key_ledit)
|
||||
key_label = QLabel(_(''), self)
|
||||
key_label.setAlignment(Qt.AlignHCenter)
|
||||
data_group_box_layout.addWidget(key_label)
|
||||
|
||||
name_group = QHBoxLayout()
|
||||
data_group_box_layout.addLayout(name_group)
|
||||
name_group.addWidget(QLabel('Your Name:', self))
|
||||
self.name_ledit = QLineEdit('', self)
|
||||
self.name_ledit.setToolTip(_('<p>Enter your name as it appears in your B&N ' +
|
||||
'account and/or on your credit card.</p>' +
|
||||
'<p>It will only be used to generate this ' +
|
||||
'one-time key and won\'t be stored anywhere ' +
|
||||
'in calibre or on your computer.</p>' +
|
||||
'<p>(ex: Jonathan Smith)'))
|
||||
name_group.addWidget(self.name_ledit)
|
||||
name_disclaimer_label = QLabel(_('Will not be stored/saved in configuration data:'), self)
|
||||
name_disclaimer_label.setAlignment(Qt.AlignHCenter)
|
||||
data_group_box_layout.addWidget(name_disclaimer_label)
|
||||
|
||||
ccn_group = QHBoxLayout()
|
||||
data_group_box_layout.addLayout(ccn_group)
|
||||
ccn_group.addWidget(QLabel('Credit Card#:', self))
|
||||
self.cc_ledit = QLineEdit('', self)
|
||||
self.cc_ledit.setToolTip(_('<p>Enter the full credit card number on record ' +
|
||||
'in your B&N account.</p>' +
|
||||
'<p>No spaces or dashes... just the numbers. ' +
|
||||
'This CC# will only be used to generate this ' +
|
||||
'one-time key and won\'t be stored anywhere in ' +
|
||||
'calibre or on your computer.'))
|
||||
ccn_group.addWidget(self.cc_ledit)
|
||||
ccn_disclaimer_label = QLabel(_('Will not be stored/saved in configuration data:'), self)
|
||||
ccn_disclaimer_label.setAlignment(Qt.AlignHCenter)
|
||||
data_group_box_layout.addWidget(ccn_disclaimer_label)
|
||||
layout.addSpacing(20)
|
||||
|
||||
self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
||||
self.button_box.accepted.connect(self.accept)
|
||||
self.button_box.rejected.connect(self.reject)
|
||||
layout.addWidget(self.button_box)
|
||||
|
||||
self.resize(self.parent.sizeHint())
|
||||
|
||||
def accept(self):
|
||||
if (self.key_ledit.text().isEmpty() or self.name_ledit.text().isEmpty()
|
||||
or self.cc_ledit.text().isEmpty()):
|
||||
errmsg = '<p>All fields are required!'
|
||||
return error_dialog(None, PLUGIN_NAME,
|
||||
_(errmsg), show=True, show_copy_button=False)
|
||||
if (unicode(self.key_ledit.text()).isspace() or unicode(self.name_ledit.text()).isspace()
|
||||
or unicode(self.cc_ledit.text()).isspace()):
|
||||
errmsg = '<p>All fields are required!'
|
||||
return error_dialog(None, PLUGIN_NAME,
|
||||
_(errmsg), show=True, show_copy_button=False)
|
||||
if not unicode(self.cc_ledit.text()).isdigit():
|
||||
errmsg = '<p>Numbers only in the credit card number field!'
|
||||
return error_dialog(None, PLUGIN_NAME,
|
||||
_(errmsg), show=True, show_copy_button=False)
|
||||
if len(self.key_ledit.text()) < 4:
|
||||
errmsg = '<p>Key name must be at <i>least</i> 4 characters long!'
|
||||
return error_dialog(None, PLUGIN_NAME,
|
||||
_(errmsg), show=True, show_copy_button=False)
|
||||
for k in self.parent.plugin_keys.keys():
|
||||
if uStrCmp(self.key_ledit.text(), k, True):
|
||||
errmsg = '<p>The key name <strong>%s</strong> is already being used.' % self.key_ledit.text()
|
||||
return error_dialog(None, PLUGIN_NAME,
|
||||
_(errmsg), show=True, show_copy_button=False)
|
||||
QDialog.accept(self)
|
||||
|
||||
@property
|
||||
def user_name(self):
|
||||
return unicode(self.name_ledit.text().toUtf8(), 'utf8').strip().lower().replace(' ','')
|
||||
@property
|
||||
def cc_number(self):
|
||||
return unicode(self.cc_ledit.text().toUtf8(), 'utf8').strip().replace(' ', '').replace('-','')
|
||||
@property
|
||||
def key_name(self):
|
||||
return unicode(self.key_ledit.text().toUtf8(), 'utf8')
|
||||
|
||||
class RenameKeyDialog(QDialog):
|
||||
def __init__(self, parent=None,):
|
||||
QDialog.__init__(self, parent)
|
||||
self.parent = parent
|
||||
self.setWindowTitle('Rename Ignoble Key')
|
||||
layout = QVBoxLayout(self)
|
||||
self.setLayout(layout)
|
||||
|
||||
data_group_box = QGroupBox('', self)
|
||||
layout.addWidget(data_group_box)
|
||||
data_group_box_layout = QVBoxLayout()
|
||||
data_group_box.setLayout(data_group_box_layout)
|
||||
|
||||
data_group_box_layout.addWidget(QLabel('Key Name:', self))
|
||||
self.key_ledit = QLineEdit(self.parent.listy.currentItem().text(), self)
|
||||
self.key_ledit.setToolTip(_('<p>Enter a new name for this existing Ignoble key.'))
|
||||
data_group_box_layout.addWidget(self.key_ledit)
|
||||
|
||||
layout.addSpacing(20)
|
||||
|
||||
self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
||||
self.button_box.accepted.connect(self.accept)
|
||||
self.button_box.rejected.connect(self.reject)
|
||||
layout.addWidget(self.button_box)
|
||||
|
||||
def accept(self):
|
||||
if self.key_ledit.text().isEmpty() or unicode(self.key_ledit.text()).isspace():
|
||||
errmsg = '<p>Key name field cannot be empty!'
|
||||
return error_dialog(None, PLUGIN_NAME,
|
||||
_(errmsg), show=True, show_copy_button=False)
|
||||
if len(self.key_ledit.text()) < 4:
|
||||
errmsg = '<p>Key name must be at <i>least</i> 4 characters long!'
|
||||
return error_dialog(None, PLUGIN_NAME,
|
||||
_(errmsg), show=True, show_copy_button=False)
|
||||
if uStrCmp(self.key_ledit.text(), self.parent.listy.currentItem().text()):
|
||||
# Same exact name ... do nothing.
|
||||
return QDialog.reject(self)
|
||||
for k in self.parent.plugin_keys.keys():
|
||||
if (uStrCmp(self.key_ledit.text(), k, True) and
|
||||
not uStrCmp(k, self.parent.listy.currentItem().text(), True)):
|
||||
errmsg = '<p>The key name <strong>%s</strong> is already being used.' % self.key_ledit.text()
|
||||
return error_dialog(None, PLUGIN_NAME,
|
||||
_(errmsg), show=True, show_copy_button=False)
|
||||
QDialog.accept(self)
|
||||
|
||||
@property
|
||||
def key_name(self):
|
||||
return unicode(self.key_ledit.text().toUtf8(), 'utf8')
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
|
||||
from __future__ import with_statement
|
||||
__license__ = 'GPL v3'
|
||||
@@ -6,15 +7,10 @@ __license__ = 'GPL v3'
|
||||
import hashlib
|
||||
|
||||
from ctypes import CDLL, POINTER, c_void_p, c_char_p, c_int, c_long, \
|
||||
Structure, c_ulong, create_string_buffer, cast
|
||||
Structure, c_ulong, create_string_buffer, cast
|
||||
from ctypes.util import find_library
|
||||
|
||||
from PyQt4.Qt import (Qt, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit,
|
||||
QGroupBox, QDialog, QDialogButtonBox)
|
||||
|
||||
from calibre.gui2 import error_dialog
|
||||
from calibre.constants import iswindows
|
||||
|
||||
from calibre_plugins.ignoble_epub.__init__ import PLUGIN_NAME, PLUGIN_VERSION
|
||||
|
||||
DETAILED_MESSAGE = \
|
||||
@@ -37,18 +33,18 @@ def normalize_name(name): # Strip spaces and convert to lowercase.
|
||||
|
||||
# These are the key ENCRYPTING aes crypto functions
|
||||
def generate_keyfile(name, ccn):
|
||||
# Load the necessary crypto libs.
|
||||
AES = _load_crypto()
|
||||
name = normalize_name(name) + '\x00'
|
||||
ccn = ccn + '\x00'
|
||||
name_sha = hashlib.sha1(name).digest()[:16]
|
||||
ccn_sha = hashlib.sha1(ccn).digest()[:16]
|
||||
both_sha = hashlib.sha1(name + ccn).digest()
|
||||
aes = AES(ccn_sha, name_sha)
|
||||
crypt = aes.encrypt(both_sha + ('\x0c' * 0x0c))
|
||||
userkey = hashlib.sha1(crypt).digest()
|
||||
# Load the necessary crypto libs.
|
||||
AES = _load_crypto()
|
||||
name = normalize_name(name) + '\x00'
|
||||
ccn = ccn + '\x00'
|
||||
name_sha = hashlib.sha1(name).digest()[:16]
|
||||
ccn_sha = hashlib.sha1(ccn).digest()[:16]
|
||||
both_sha = hashlib.sha1(name + ccn).digest()
|
||||
aes = AES(ccn_sha, name_sha)
|
||||
crypt = aes.encrypt(both_sha + ('\x0c' * 0x0c))
|
||||
userkey = hashlib.sha1(crypt).digest()
|
||||
|
||||
return userkey.encode('base64')
|
||||
return userkey.encode('base64')
|
||||
|
||||
def _load_crypto_libcrypto():
|
||||
if iswindows:
|
||||
@@ -122,139 +118,23 @@ def _load_crypto():
|
||||
pass
|
||||
return _aes
|
||||
|
||||
def caselessStrCmp(s1, s2):
|
||||
"""
|
||||
A function to case-insensitively compare strings. Python's .lower() function
|
||||
isn't always very accurate when it comes to unicode. Using the standard C lib's
|
||||
strcasecmp instead. Maybe a tad slower, but we're not scouring scads of string lists here.
|
||||
"""
|
||||
str1 = unicode(s1)
|
||||
str2 = unicode(s2)
|
||||
|
||||
c_char_pp = POINTER(c_char_p)
|
||||
c_int_p = POINTER(c_int)
|
||||
|
||||
if iswindows:
|
||||
libc = find_library('msvcrt')
|
||||
def uStrCmp (s1, s2, caseless=False):
|
||||
import unicodedata as ud
|
||||
str1 = s1 if isinstance(s1, unicode) else unicode(s1)
|
||||
str2 = s2 if isinstance(s2, unicode) else unicode(s2)
|
||||
if caseless:
|
||||
return ud.normalize('NFC', str1.lower()) == ud.normalize('NFC', str2.lower())
|
||||
else:
|
||||
libc = find_library('c')
|
||||
if libc is None:
|
||||
raise IgnobleError('libc not found')
|
||||
libc = CDLL(libc)
|
||||
|
||||
def F(restype, name, argtypes):
|
||||
func = getattr(libc, name)
|
||||
func.restype = restype
|
||||
func.argtypes = argtypes
|
||||
return func
|
||||
|
||||
if iswindows:
|
||||
_stricmp = F(c_int, '_stricmp', [c_char_p, c_char_p])
|
||||
return _stricmp(str1, str2)
|
||||
strcasecmp = F(c_int, 'strcasecmp', [c_char_p, c_char_p])
|
||||
return strcasecmp(str1, str2)
|
||||
|
||||
class AddKeyDialog(QDialog):
|
||||
def __init__(self, parent=None,):
|
||||
QDialog.__init__(self, parent)
|
||||
self.parent = parent
|
||||
self.setWindowTitle('Create New Ignoble Key')
|
||||
layout = QVBoxLayout(self)
|
||||
self.setLayout(layout)
|
||||
|
||||
data_group_box = QGroupBox('', self)
|
||||
layout.addWidget(data_group_box)
|
||||
data_group_box_layout = QVBoxLayout()
|
||||
data_group_box.setLayout(data_group_box_layout)
|
||||
|
||||
key_group = QHBoxLayout()
|
||||
data_group_box_layout.addLayout(key_group)
|
||||
key_group.addWidget(QLabel('Unique Key Name:', self))
|
||||
self.key_ledit = QLineEdit('', self)
|
||||
self.key_ledit.setToolTip(_('<p>Enter an identifying name for this new Ignoble key.</p>' +
|
||||
'<p>It should be something that will help you remember ' +
|
||||
'what personal information was used to create it.'))
|
||||
key_group.addWidget(self.key_ledit)
|
||||
key_label = QLabel(_(''), self)
|
||||
key_label.setAlignment(Qt.AlignHCenter)
|
||||
data_group_box_layout.addWidget(key_label)
|
||||
|
||||
name_group = QHBoxLayout()
|
||||
data_group_box_layout.addLayout(name_group)
|
||||
name_group.addWidget(QLabel('Your Name:', self))
|
||||
self.name_ledit = QLineEdit('', self)
|
||||
self.name_ledit.setToolTip(_('<p>Enter your name as it appears in your B&N ' +
|
||||
'account and/or on your credit card.</p>' +
|
||||
'<p>It will only be used to generate this ' +
|
||||
'one-time key and won\'t be stored anywhere ' +
|
||||
'in calibre or on your computer.</p>' +
|
||||
'<p>(ex: Jonathan Smith)'))
|
||||
name_group.addWidget(self.name_ledit)
|
||||
name_disclaimer_label = QLabel(_('Will not be stored/saved in configuration data:'), self)
|
||||
name_disclaimer_label.setAlignment(Qt.AlignHCenter)
|
||||
data_group_box_layout.addWidget(name_disclaimer_label)
|
||||
|
||||
ccn_group = QHBoxLayout()
|
||||
data_group_box_layout.addLayout(ccn_group)
|
||||
ccn_group.addWidget(QLabel('Credit Card#:', self))
|
||||
self.cc_ledit = QLineEdit('', self)
|
||||
self.cc_ledit.setToolTip(_('<p>Enter the full credit card number on record ' +
|
||||
'in your B&N account.</p>' +
|
||||
'<p>No spaces or dashes... just the numbers. ' +
|
||||
'This CC# will only be used to generate this ' +
|
||||
'one-time key and won\'t be stored anywhere in ' +
|
||||
'calibre or on your computer.'))
|
||||
ccn_group.addWidget(self.cc_ledit)
|
||||
ccn_disclaimer_label = QLabel(_('Will not be stored/saved in configuration data:'), self)
|
||||
ccn_disclaimer_label.setAlignment(Qt.AlignHCenter)
|
||||
data_group_box_layout.addWidget(ccn_disclaimer_label)
|
||||
layout.addSpacing(20)
|
||||
|
||||
self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
||||
self.button_box.accepted.connect(self.accept)
|
||||
self.button_box.rejected.connect(self.reject)
|
||||
layout.addWidget(self.button_box)
|
||||
|
||||
self.resize(self.parent.sizeHint())
|
||||
|
||||
def accept(self):
|
||||
match = False
|
||||
if (self.key_ledit.text().isEmpty() or self.name_ledit.text().isEmpty()
|
||||
or self.cc_ledit.text().isEmpty()):
|
||||
errmsg = '<p>All fields are required!'
|
||||
return error_dialog(None, PLUGIN_NAME + 'error_dialog',
|
||||
_(errmsg), show=True, show_copy_button=False)
|
||||
for k in self.parent.plugin_keys.keys():
|
||||
if caselessStrCmp(self.key_ledit.text(), k) == 0:
|
||||
match = True
|
||||
break
|
||||
if match:
|
||||
errmsg = '<p>The key name <strong>%s</strong> is already being used.' % self.key_ledit.text()
|
||||
return error_dialog(None, PLUGIN_NAME + 'error_dialog',
|
||||
_(errmsg), show=True, show_copy_button=False)
|
||||
else:
|
||||
QDialog.accept(self)
|
||||
|
||||
@property
|
||||
def user_name(self):
|
||||
return unicode(self.name_ledit.text()).strip().lower().replace(' ', '')
|
||||
|
||||
@property
|
||||
def cc_number(self):
|
||||
return unicode(self.cc_ledit.text()).strip().replace(' ', '').replace('-','')
|
||||
|
||||
@property
|
||||
def key_name(self):
|
||||
return unicode(self.key_ledit.text())
|
||||
return ud.normalize('NFC', str1) == ud.normalize('NFC', str2)
|
||||
|
||||
def parseCustString(keystuff):
|
||||
userkeys = []
|
||||
ar = keystuff.split(':')
|
||||
for i in ar:
|
||||
try:
|
||||
name, ccn = i.split(',')
|
||||
except:
|
||||
return False
|
||||
# Generate Barnes & Noble EPUB user key from name and credit card number.
|
||||
userkeys.append(generate_keyfile(name, ccn))
|
||||
return userkeys
|
||||
userkeys = []
|
||||
ar = keystuff.split(':')
|
||||
for i in ar:
|
||||
try:
|
||||
name, ccn = i.split(',')
|
||||
except:
|
||||
return False
|
||||
# Generate Barnes & Noble EPUB user key from name and credit card number.
|
||||
userkeys.append(generate_keyfile(name, ccn))
|
||||
return userkeys
|
||||
Reference in New Issue
Block a user