~ubuntu-branches/debian/jessie/armory/jessie

« back to all changes in this revision

Viewing changes to ui/toolsDialogs.py

  • Committer: Package Import Robot
  • Author(s): Joseph Bisch
  • Date: 2014-10-07 10:22:45 UTC
  • Revision ID: package-import@ubuntu.com-20141007102245-2s3x3rhjxg689hek
Tags: upstream-0.92.3
ImportĀ upstreamĀ versionĀ 0.92.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
################################################################################
 
2
#                                                                              #
 
3
# Copyright (C) 2011-2014, Armory Technologies, Inc.                           #
 
4
# Distributed under the GNU Affero General Public License (AGPL v3)            #
 
5
# See LICENSE or http://www.gnu.org/licenses/agpl.html                         #
 
6
#                                                                              #
 
7
################################################################################
 
8
from PyQt4 import Qt, QtCore
 
9
from PyQt4.QtCore import *
 
10
from PyQt4.QtGui import *
 
11
 
 
12
from armorycolors import htmlColor
 
13
from jasvet import ASv0, ASv1B64, ASv1CS, verifySignature, readSigBlock
 
14
from qtdefines import *
 
15
from qtdialogs import MIN_PASSWD_WIDTH, DlgPasswd3, createAddrBookButton,\
 
16
   DlgUnlockWallet
 
17
from armoryengine.ArmoryUtils import isASCII
 
18
from announcefetch import ANNOUNCE_SIGN_PUBKEY
 
19
 
 
20
class MessageSigningVerificationDialog(ArmoryDialog):
 
21
 
 
22
   def __init__(self, parent=None, main=None):
 
23
      super(MessageSigningVerificationDialog, self).__init__(parent, main)
 
24
      layout = QVBoxLayout()
 
25
      self.setWindowTitle("Message Signing/Verification")
 
26
      self.setWindowIcon(QIcon( self.main.iconfile))
 
27
      self.setMinimumWidth(600)
 
28
      
 
29
      tabbedPanel = QTabWidget()
 
30
      messageSigningTab = MessageSigningWidget(parent, main)
 
31
      bareSignatureVerificationTab = BareSignatureVerificationWidget(parent, main)
 
32
      signedMsgBlockVerificationTab = SignedMessageBlockVerificationWidget(parent, main)
 
33
      tabbedPanel.addTab(messageSigningTab, "Sign Message")
 
34
      tabbedPanel.addTab(bareSignatureVerificationTab, "Verify Bare Signature")
 
35
      tabbedPanel.addTab(signedMsgBlockVerificationTab, "Verify Signed Message Block")
 
36
      layout.addWidget(tabbedPanel)
 
37
      
 
38
      self.goBackButton = QPushButton("Done")
 
39
      actionButtonBox = QDialogButtonBox()
 
40
      actionButtonBox.addButton(self.goBackButton, QDialogButtonBox.RejectRole)
 
41
      layout.addWidget(actionButtonBox)
 
42
 
 
43
      self.setLayout(layout)
 
44
      self.connect(self.goBackButton, SIGNAL('clicked()'), \
 
45
                   self,           SLOT('reject()'))
 
46
      
 
47
   def clearFields(self):
 
48
      self.addressLineEdit.setText('')
 
49
      self.messageTextEdit.setPlainText('')
 
50
      self.signatureDisplay.setPlainText('')
 
51
      
 
52
      
 
53
 
 
54
 
 
55
class MessageSigningWidget(QWidget):
 
56
 
 
57
   def __init__(self, parent=None, main=None):
 
58
      super(MessageSigningWidget, self).__init__(parent)
 
59
      self.main = main
 
60
      signMessageLayout = QGridLayout()
 
61
      self.setMinimumWidth(800)
 
62
      
 
63
      # Pick an Address in Row 0 of the grid layout
 
64
      addressLabel = QLabel('Sign with Address:')
 
65
      self.addressLineEdit = QLineEdit()
 
66
      self.addressBookButton = createAddrBookButton(self, self.addressLineEdit, None,
 
67
                                                    selectMineOnly=True, showLockboxes=False)
 
68
      signMessageLayout.addWidget(addressLabel,      0, 0)
 
69
      signMessageLayout.addWidget(self.addressLineEdit,  0, 1)
 
70
      signMessageLayout.addWidget(self.addressBookButton,  0, 2)
 
71
 
 
72
      # Create a message in Row 1
 
73
      messageLabel = QLabel("Message to sign:")
 
74
      self.messageTextEdit = QTextEdit()
 
75
      self.messageTextEdit.setAcceptRichText(False)
 
76
      self.messageTextEdit.setStyleSheet("font: 9pt \"Courier\";")
 
77
      signMessageLayout.addWidget(messageLabel,          1, 0)
 
78
      signMessageLayout.addWidget(self.messageTextEdit,  1, 1, 1, 2)
 
79
      
 
80
      
 
81
      # Create a row with just a sign message button
 
82
      
 
83
      self.bareSigButton = QPushButton('Bare Signature (Bitcoin-Qt Compatible)')
 
84
      self.base64SigButton = QPushButton('Base64 Signature')
 
85
      self.clearSigButton = QPushButton('Clearsign Signature')
 
86
      sigButtonFrame = makeHorizFrame([self.bareSigButton,\
 
87
                                        self.base64SigButton,\
 
88
                                        self.clearSigButton,\
 
89
                                        'Stretch'])
 
90
      signMessageLayout.addWidget(sigButtonFrame,  2, 1, 1, 3)
 
91
      
 
92
      # Create a Signature display
 
93
      signatureLabel = QLabel('Message Signature:')
 
94
      self.signatureDisplay = QTextEdit()
 
95
      self.signatureDisplay.setReadOnly(True)
 
96
      self.signatureDisplay.setStyleSheet("font: 9pt \"Courier\"; background-color: #bbbbbb;")
 
97
      signMessageLayout.addWidget(signatureLabel,         3, 0)
 
98
      signMessageLayout.addWidget(self.signatureDisplay,  3, 1, 1, 2)
 
99
 
 
100
      self.copySignatureButton = QPushButton("Copy Signature")
 
101
      self.clearFieldsButton = QPushButton("Clear All")
 
102
      
 
103
      buttonFrame = makeHorizFrame([self.copySignatureButton, self.clearFieldsButton,'Stretch'])
 
104
      signMessageLayout.addWidget(buttonFrame, 4, 1, 1, 3)
 
105
 
 
106
      self.setLayout(signMessageLayout)
 
107
      self.connect(self.bareSigButton, SIGNAL('clicked()'), \
 
108
                   self.bareSignMessage)
 
109
      self.connect(self.base64SigButton, SIGNAL('clicked()'), \
 
110
                    self.base64SignMessage)
 
111
      self.connect(self.clearSigButton, SIGNAL('clicked()'), \
 
112
                    self.clearSignMessage)
 
113
      self.connect(self.copySignatureButton, SIGNAL('clicked()'), \
 
114
                   self.copySignature)
 
115
      self.connect(self.clearFieldsButton, SIGNAL('clicked()'), \
 
116
                   self.clearFields)
 
117
      
 
118
   def getPrivateKeyFromAddrInput(self):
 
119
      atype, addr160 = addrStr_to_hash160(str(self.addressLineEdit.text()))
 
120
      if atype==P2SHBYTE:
 
121
         LOGWARN('P2SH address requested')
 
122
      walletId = self.main.getWalletForAddr160(addr160)
 
123
      wallet = self.main.walletMap[walletId]
 
124
      if wallet.useEncryption and wallet.isLocked:
 
125
         # Target wallet is encrypted...
 
126
         unlockdlg = DlgUnlockWallet(wallet, self, self.main, 'Unlock Wallet to Import')
 
127
         if not unlockdlg.exec_():
 
128
            QMessageBox.critical(self, 'Wallet is Locked', \
 
129
               'Cannot import private keys without unlocking wallet!', \
 
130
               QMessageBox.Ok)
 
131
            return
 
132
      return wallet.addrMap[addr160].binPrivKey32_Plain.toBinStr()
 
133
 
 
134
   def bareSignMessage(self):
 
135
      messageText = str(self.messageTextEdit.toPlainText())
 
136
      if not isASCII(messageText):
 
137
         QMessageBox.warning(self, 'Non ASCII Text', 'Message to sign must be ASCII', QMessageBox.Ok)
 
138
      else:
 
139
         try:
 
140
            privateKey = self.getPrivateKeyFromAddrInput()
 
141
            if privateKey:
 
142
               signature = ASv0(privateKey, messageText)
 
143
               self.signatureDisplay.setPlainText(signature['b64-signature'])
 
144
            else:
 
145
               QMessageBox.warning(self, 'Private Key Not Known', 'The private key is not known for this address.', QMessageBox.Ok)         
 
146
         except:
 
147
            QMessageBox.warning(self, 'Invalid Address', 'The signing address is invalid.', QMessageBox.Ok)
 
148
            raise
 
149
   
 
150
   def base64SignMessage(self):
 
151
      messageText = str(self.messageTextEdit.toPlainText())
 
152
      if not isASCII(messageText):
 
153
         QMessageBox.warning(self, 'Non ASCII Text', 'Message to sign must be ASCII', QMessageBox.Ok)
 
154
      else:
 
155
         try:
 
156
            privateKey = self.getPrivateKeyFromAddrInput()
 
157
            if privateKey:
 
158
               signature = ASv1B64(self.getPrivateKeyFromAddrInput(), messageText)
 
159
               self.signatureDisplay.setPlainText(signature)    
 
160
            else:
 
161
               QMessageBox.warning(self, 'Private Key Not Known', 'The private key is not known for this address.', QMessageBox.Ok)
 
162
         except:
 
163
            QMessageBox.warning(self, 'Invalid Address', 'The signing address is invalid.', QMessageBox.Ok)
 
164
            raise
 
165
   
 
166
   def clearSignMessage(self):
 
167
      messageText = str(self.messageTextEdit.toPlainText())
 
168
      if not isASCII(messageText):
 
169
         QMessageBox.warning(self, 'Non ASCII Text', 'Message to sign must be ASCII', QMessageBox.Ok)
 
170
      else:
 
171
         try:
 
172
            privateKey = self.getPrivateKeyFromAddrInput()
 
173
         except:
 
174
            QMessageBox.warning(self, 'Invalid Address', 'The signing address is invalid.', QMessageBox.Ok)
 
175
            raise
 
176
         if privateKey:
 
177
            signature = ASv1CS(privateKey, messageText)
 
178
            self.signatureDisplay.setPlainText(signature)
 
179
         else:
 
180
            QMessageBox.warning(self, 'Private Key Not Known', 'The private key is not known for this address.', QMessageBox.Ok)
 
181
 
 
182
   def copySignature(self):
 
183
      clipb = QApplication.clipboard()
 
184
      clipb.clear()
 
185
      clipb.setText(str(self.signatureDisplay.toPlainText()))
 
186
 
 
187
   def clearFields(self):
 
188
      self.addressLineEdit.setText('')
 
189
      self.messageTextEdit.setPlainText('')
 
190
      self.signatureDisplay.setPlainText('')
 
191
 
 
192
# Intended to be a base class
 
193
class SignatureVerificationWidget(QWidget):
 
194
 
 
195
   def __init__(self, parent=None, main=None):
 
196
      super(SignatureVerificationWidget, self).__init__(parent)
 
197
      self.main = main
 
198
      self.signMessageLayout = QGridLayout()
 
199
      self.setMinimumWidth(800)
 
200
 
 
201
      self.verifySignatureButton = QPushButton("Verify Signature")
 
202
      self.clearFieldsButton = QPushButton("Clear All")
 
203
      
 
204
      self.lblSigResult = QRichLabel('', doWrap=False)
 
205
      buttonFrame = makeHorizFrame([self.verifySignatureButton, self.clearFieldsButton,\
 
206
                                    'Stretch', self.lblSigResult])
 
207
      self.signMessageLayout.addWidget(buttonFrame, 3, 1, 1, 2)
 
208
 
 
209
      self.setLayout(self.signMessageLayout)
 
210
      self.connect(self.verifySignatureButton, SIGNAL('clicked()'), \
 
211
                   self.verifySignature)
 
212
      self.connect(self.clearFieldsButton, SIGNAL('clicked()'), \
 
213
                   self.clearFields)
 
214
 
 
215
   # To be implemented by child classes
 
216
   def verifySignature(self):
 
217
      pass
 
218
         
 
219
   def clearFields(self):
 
220
      self.lblSigResult.setText('')
 
221
      
 
222
   def displayVerifiedBox(self, addrB58, messageString):
 
223
      atihash160 = hash160(hex_to_binary(ANNOUNCE_SIGN_PUBKEY))
 
224
      addrDisp = addrB58
 
225
      if addrB58==hash160_to_addrStr(atihash160):
 
226
         addrDisp = '<b>Armory Technologies, Inc.</b>'
 
227
         if CLI_OPTIONS.testAnnounceCode:
 
228
            ownerStr = tr("""
 
229
               <font color="%s"><b>Armory Technologies, Inc.
 
230
               (testing key)</b></font> has signed the following
 
231
               block of text:<br>""") % htmlColor('TextGreen')
 
232
         else:
 
233
            ownerStr = tr("""
 
234
               <font color="%s"><b>Armory Technologies, Inc.</b></font> 
 
235
               has signed the following block of text:<br>""") % \
 
236
               htmlColor('TextGreen')
 
237
      else:
 
238
         ownerStr = tr("""
 
239
         The owner of the following Bitcoin address...
 
240
         <br>
 
241
         <blockquote>
 
242
         <font face="Courier" size=4 color="#000060"><b>%s</b></font>
 
243
         </blockquote>
 
244
         <br>
 
245
         ... has produced a <b><u>valid</u></b> signature for 
 
246
         the following message:<br>
 
247
         """) % addrB58
 
248
         
 
249
      if addrB58:
 
250
         msg = messageString.replace('\r\n','\n')
 
251
         msg = '   ' + '<br>   '.join(msg.split('\n'))
 
252
         # The user will be able to see the entire message 
 
253
         # in the Message Signing/Verification dialog
 
254
         msg =  '<br>'.join([line[:60]+ '...'*(len(line)>60) for line in msg.split('<br>')][:12])
 
255
         MsgBoxCustom(MSGBOX.Good, tr('Verified!'), tr(""" 
 
256
            %s
 
257
            <hr>
 
258
            <blockquote>
 
259
            <font face="Courier" color="#000060"><b>%s</b></font>
 
260
            </blockquote>
 
261
            <hr><br>
 
262
            <b>Please</b> make sure that the address above (%s...) matches the 
 
263
            exact address you were expecting.  A valid signature is meaningless 
 
264
            unless it is made
 
265
            from a recognized address!""") % (ownerStr, msg, addrB58[:10]))
 
266
         self.lblSigResult.setText(\
 
267
            '<font color="green">Valid Signature by %s</font>' % addrDisp)
 
268
      else:
 
269
         self.displayInvalidSignatureMessage()
 
270
 
 
271
   def displayInvalidSignatureMessage(self):
 
272
      MsgBoxCustom(MSGBOX.Error, 'Invalid Signature!', \
 
273
                                 'The supplied signature <b>is not valid</b>!')
 
274
      self.lblSigResult.setText('<font color="red">Invalid Signature!</font>')
 
275
      
 
276
class BareSignatureVerificationWidget(SignatureVerificationWidget):
 
277
 
 
278
   def __init__(self, parent=None, main=None):
 
279
      super(BareSignatureVerificationWidget, self).__init__(parent, main)
 
280
      # Pick an Address in Row 0 of the grid layout
 
281
      addressLabel = QLabel('Signing Address:')
 
282
      self.addressLineEdit = QLineEdit()
 
283
      self.addressBookButton = createAddrBookButton(self, self.addressLineEdit, None,
 
284
                                                    selectMineOnly=True, showLockboxes=False)
 
285
      self.signMessageLayout.addWidget(addressLabel,      0, 0)
 
286
      self.signMessageLayout.addWidget(self.addressLineEdit,  0, 1)
 
287
      self.signMessageLayout.addWidget(self.addressBookButton,  0, 2)
 
288
      
 
289
      # Create a message text box
 
290
      messageLabel = QLabel("Signed Message:")
 
291
      self.messageTextEdit = QTextEdit()
 
292
      self.messageTextEdit.setAcceptRichText(False)
 
293
      self.messageTextEdit.setStyleSheet("font: 9pt \"Courier\";")
 
294
      self.signMessageLayout.addWidget(messageLabel,          1, 0)
 
295
      self.signMessageLayout.addWidget(self.messageTextEdit,  1, 1)
 
296
      # Create a Signature display
 
297
      signatureLabel = QLabel('Signature:')
 
298
      self.signatureTextEdit = QTextEdit()
 
299
      self.signatureTextEdit.setStyleSheet("font: 9pt \"Courier\";")
 
300
      self.signMessageLayout.addWidget(signatureLabel,         2, 0)
 
301
      self.signMessageLayout.addWidget(self.signatureTextEdit,  2, 1)
 
302
      
 
303
   def verifySignature(self):
 
304
      messageString = str(self.messageTextEdit.toPlainText())
 
305
      try:
 
306
         addrB58 = verifySignature(str(self.signatureTextEdit.toPlainText()), \
 
307
                         messageString, 'v0', ord(ADDRBYTE))
 
308
         if addrB58 == str(self.addressLineEdit.text()):
 
309
            self.displayVerifiedBox(addrB58, messageString)
 
310
         else:
 
311
            self.displayInvalidSignatureMessage()
 
312
      except:   
 
313
         self.displayInvalidSignatureMessage()
 
314
         raise
 
315
 
 
316
         
 
317
   def clearFields(self):
 
318
      super(BareSignatureVerificationWidget, self).clearFields()
 
319
      self.addressLineEdit.setText('')
 
320
      self.messageTextEdit.setPlainText('')
 
321
      self.signatureTextEdit.setPlainText('')
 
322
 
 
323
class SignedMessageBlockVerificationWidget(SignatureVerificationWidget):
 
324
 
 
325
   def __init__(self, parent=None, main=None):
 
326
      super(SignedMessageBlockVerificationWidget, self).__init__(parent, main)
 
327
      # Create a Signature display
 
328
      signatureLabel = QLabel('Signed Message Block:')
 
329
      self.signedMessageBlockTextEdit = QTextEdit()
 
330
      self.signedMessageBlockTextEdit.setStyleSheet("font: 9pt \"Courier\";")
 
331
      self.signedMessageBlockTextEdit.setAcceptRichText(False)
 
332
      self.signMessageLayout.addWidget(signatureLabel,         0, 0)
 
333
      self.signMessageLayout.addWidget(self.signedMessageBlockTextEdit,  0, 1)
 
334
 
 
335
      # Create a message in Row 1
 
336
      messageLabel = QLabel("Message:")
 
337
      self.messageTextEdit = QTextEdit()
 
338
      self.messageTextEdit.setAcceptRichText(False)
 
339
      self.messageTextEdit.setReadOnly(True)
 
340
      self.messageTextEdit.setStyleSheet("font: 9pt \"Courier\"; background-color: #bbbbbb;")
 
341
      self.signMessageLayout.addWidget(messageLabel,          1, 0)
 
342
      self.signMessageLayout.addWidget(self.messageTextEdit,  1, 1, 1, 2)
 
343
      
 
344
      
 
345
   def verifySignature(self):
 
346
      try:
 
347
         sig, msg = readSigBlock(str(self.signedMessageBlockTextEdit.toPlainText()))
 
348
         addrB58 = verifySignature(sig, msg, 'v1', ord(ADDRBYTE) )
 
349
         self.displayVerifiedBox(addrB58, msg)
 
350
         self.messageTextEdit.setPlainText(msg)
 
351
      except:   
 
352
         self.displayInvalidSignatureMessage()
 
353
         raise
 
354
         
 
355
   def clearFields(self):
 
356
      super(SignedMessageBlockVerificationWidget, self).clearFields()
 
357
      self.signedMessageBlockTextEdit.setPlainText('')
 
358
      self.messageTextEdit.setPlainText('')
 
359
 
 
360
 
 
361