def verifySignature(self): try: sig, msg = readSigBlock(str(self.signedMessageBlockTextEdit.toPlainText())) addrB58 = verifySignature(sig, msg, 'v1', ord(ADDRBYTE) ) self.displayVerifiedBox(addrB58, msg) self.messageTextEdit.setPlainText(msg) except: self.displayInvalidSignatureMessage() raise
def parseNotificationText(self, fileText): self.notifications = {} if fileText is None: return None try: if SIGNED_BLOCK_HEAD in fileText: fileText = readSigBlock(fileText)[1] notifyLines = [line.strip() for line in fileText.split('\n')][::-1] currID = '' readLongDescr = False longDescrAccum = '' while len(notifyLines) > 0: line = notifyLines.pop() if not readLongDescr and (line.startswith('#') or len(line)==0): continue if line.upper().startswith('UNIQUEID'): currID = line.split(':')[-1].strip() self.notifications[currID] = {} elif line.upper().startswith('LONGDESCR'): readLongDescr = True elif line.startswith("*****"): readLongDescr = False self.notifications[currID]['LONGDESCR'] = longDescrAccum longDescrAccum = '' elif readLongDescr: if len(line.strip())==0: longDescrAccum += '<br><br>' else: longDescrAccum += line.strip() + ' ' else: key = line.split(':')[ 0].strip().upper() val = line.split(':')[-1].strip() self.notifications[currID][key] = val return self.getNotificationMap() except: LOGEXCEPT('Failed to parse notifications') return None
def parseDownloadList(self, fileText): self.downloadMap = {} if fileText is None: return {} def insertLink(mapObj, urlAndHash, keyList): if len(keyList)>1: if not keyList[0] in mapObj: mapObj[keyList[0]] = {} insertLink(mapObj[keyList[0]], urlAndHash, keyList[1:]) else: mapObj[keyList[0]] = urlAndHash try: if SIGNED_BLOCK_HEAD in fileText: fileText = readSigBlock(fileText)[1] dlLines = [line.strip() for line in fileText.split('\n')][::-1] while len(dlLines) > 0: line = dlLines.pop() if line.startswith('#') or len(line)==0: continue lineLists = [pc.split(',') for pc in line.split()[:-2]] urlAndHash = line.split()[-2:] APPLIST, VERLIST, OSLIST, SUBOSLIST, BITLIST = range(5) for app in lineLists[APPLIST]: for ver in lineLists[VERLIST]: for opsys in lineLists[OSLIST]: for subOS in lineLists[SUBOSLIST]: for nbit in lineLists[BITLIST]: insertLink(self.downloadMap, urlAndHash, [app, ver, opsys, subOS, nbit]) return self.getNestedDownloadMap() except: LOGEXCEPT('Failed to parse downloads') return None
def parseNotificationText(self, fileText): self.notifications = {} if fileText is None: return None try: if SIGNED_BLOCK_HEAD in fileText: fileText = readSigBlock(fileText)[1] notifyLines = [line.strip() for line in fileText.split('\n')][::-1] currID = '' readLongDescr = False longDescrAccum = '' while len(notifyLines) > 0: line = notifyLines.pop() if not readLongDescr and (line.startswith('#') or len(line) == 0): continue if line.upper().startswith('UNIQUEID'): currID = line.split(':')[-1].strip() self.notifications[currID] = {} elif line.upper().startswith('LONGDESCR'): readLongDescr = True elif line.startswith("*****"): readLongDescr = False self.notifications[currID]['LONGDESCR'] = longDescrAccum longDescrAccum = '' elif readLongDescr: if len(line.strip()) == 0: longDescrAccum += '<br><br>' else: longDescrAccum += line.strip() + ' ' else: key = line.split(':')[0].strip().upper() val = line.split(':')[-1].strip() self.notifications[currID][key] = val return self.getNotificationMap() except: LOGEXCEPT('Failed to parse notifications') return None
def parseDownloadList(self, fileText): self.downloadMap = {} if fileText is None: return {} def insertLink(mapObj, urlAndHash, keyList): if len(keyList) > 1: if not keyList[0] in mapObj: mapObj[keyList[0]] = {} insertLink(mapObj[keyList[0]], urlAndHash, keyList[1:]) else: mapObj[keyList[0]] = urlAndHash try: if SIGNED_BLOCK_HEAD in fileText: fileText = readSigBlock(fileText)[1] dlLines = [line.strip() for line in fileText.split('\n')][::-1] while len(dlLines) > 0: line = dlLines.pop() if line.startswith('#') or len(line) == 0: continue lineLists = [pc.split(',') for pc in line.split()[:-2]] urlAndHash = line.split()[-2:] APPLIST, VERLIST, OSLIST, SUBOSLIST, BITLIST = range(5) for app in lineLists[APPLIST]: for ver in lineLists[VERLIST]: for opsys in lineLists[OSLIST]: for subOS in lineLists[SUBOSLIST]: for nbit in lineLists[BITLIST]: insertLink(self.downloadMap, urlAndHash, [app, ver, opsys, subOS, nbit]) return self.getNestedDownloadMap() except: LOGEXCEPT('Failed to parse downloads') return None
def parseChangelogText(self, fileText): self.changelog = [] if fileText is None: return None try: if SIGNED_BLOCK_HEAD in fileText: fileText = readSigBlock(fileText)[1] versionLines = [line.strip() for line in fileText.split('\n')][::-1] if len(versionLines)==0: return None # All lines have been stripped already while len(versionLines) > 0: line = versionLines.pop() if line.startswith('#') or len(line)==0: continue if line.startswith('VERSION') and len(line.split())==2: self.changelog.append([line.split(' ')[-1], '', []]) elif line.upper().startswith('RELEASED'): self.changelog[-1][1] = line[8:].strip() elif line.startswith('-'): featureTitle = line[2:] self.changelog[-1][2].append([featureTitle, '']) else: curr = self.changelog[-1][2][-1][-1] self.changelog[-1][2][-1][-1] += ('' if len(curr)==0 else ' ') + line return self.getChangelog() except: LOGEXCEPT('Failed to parse changelog') return None
def parseChangelogText(self, fileText): self.changelog = [] if fileText is None: return None try: if SIGNED_BLOCK_HEAD in fileText: fileText = readSigBlock(fileText)[1] versionLines = [line.strip() for line in fileText.split('\n')][::-1] if len(versionLines) == 0: return None # All lines have been stripped already while len(versionLines) > 0: line = versionLines.pop() if line.startswith('#') or len(line) == 0: continue if line.startswith('VERSION') and len(line.split()) == 2: self.changelog.append([line.split(' ')[-1], '', []]) elif line.upper().startswith('RELEASED'): self.changelog[-1][1] = line[8:].strip() elif line.startswith('-'): featureTitle = line[2:] self.changelog[-1][2].append([featureTitle, '']) else: curr = self.changelog[-1][2][-1][-1] self.changelog[-1][2][-1][-1] += ('' if len(curr) == 0 else ' ') + line return self.getChangelog() except: LOGEXCEPT('Failed to parse changelog') return None
def __runFetchSequence(self): ##### Always decorate the URL with OS, Armory version on the first run digestData = self.__fetchAnnounceDigests(not self.firstSuccess.isSet()) if len(digestData) == 0: LOGWARN('Error fetching announce digest') return self.firstSuccess.set() ##### Digests come in signature blocks. Verify sig using jasvet. try: sig, msg = readSigBlock(digestData) signAddress = verifySignature(sig, msg, 'v1', ord(ADDRBYTE)) if not signAddress == self.validAddrStr: LOGERROR('Announce info carried invalid signature!') LOGERROR('Signature addr: %s' % signAddress) LOGERROR('Expected address: %s', self.validAddrStr) return except: LOGEXCEPT('Could not verify data in signed message block') return # Always rewrite file; it's small and will use mtime for info with open(os.path.join(self.fetchDir, 'announce.file'), 'w') as f: f.write(digestData) ##### We have a valid digest, now parse it justDownloadedMap = {} for row in [line.split() for line in msg.strip().split('\n')]: if len(row) == 3: justDownloadedMap[row[0]] = [row[1], row[2]] else: LOGERROR('Malformed announce matrix: %s' % str(row)) return ##### Check whether any of the hashes have changed for key, val in justDownloadedMap.iteritems(): jdURL, jdHash = val[0], val[1] if not (key in self.fileHashMap and self.fileHashMap[key] == jdHash): LOGINFO('Changed [ "%s" ] == [%s, %s]', key, jdURL, jdHash) newData = self.__fetchFile(jdURL) if len(newData) == 0: LOGERROR('Failed downloading announce file : %s', key) return newHash = binary_to_hex(sha256(newData)) if not newHash == jdHash: LOGERROR('Downloaded file hash does not match!') LOGERROR('Hash of downloaded data: %s', newHash) return filename = os.path.join(self.fetchDir, key + '.file') with open(filename, 'wb') as f: f.write(newData) self.lastChange = RightNow() self.fileHashMap[key] = jdHash ##### Clean up as needed if self.forceCheckFlag.isSet(): self.forceIsFinished.set() self.forceCheckFlag.clear() self.numConsecutiveExceptions = 0
print 'Please verify the above data to your satisfaction:' raw_input('Hit <enter> when ready: ') doSignFile(announcePath, os.path.join(dstAnnounce, announceName)) print '*' * 80 print open(announcePath, 'r').read() print '*' * 80 print '' print 'Verifying files' for fname, vals in fileMappings.iteritems(): if 'bootstrap' in fname: continue with open(os.path.join(dstAnnounce, fname), 'rb') as f: sig, msg = readSigBlock(f.read()) addrB58 = verifySignature(sig, msg, 'v1', ord(ADDRBYTE)) print 'Sign addr for:', vals[0].ljust(longestID + 3), addrB58 print 'Done!' ################################################################################ # GIT SIGN gittag = 'v%s%s' % (topVerStr, topVerType) logprint('*' * 80) logprint('About to tag and sign git repo with:') logprint(' Tag: ' + gittag) logprint(' User: '******' Email: ' + gitemail) gitmsg = raw_input('Put your commit message here: ')
def __runFetchSequence(self): ##### Always decorate the URL with OS, Armory version on the first run digestData = self.__fetchAnnounceDigests(not self.firstSuccess.isSet()) if len(digestData)==0: LOGWARN('Error fetching announce digest') return self.firstSuccess.set() ##### Digests come in signature blocks. Verify sig using jasvet. try: sig, msg = readSigBlock(digestData) signAddress = verifySignature(sig, msg, 'v1', ord(ADDRBYTE)) if not signAddress == self.validAddrStr: LOGERROR('Announce info carried invalid signature!') LOGERROR('Signature addr: %s' % signAddress) LOGERROR('Expected address: %s', self.validAddrStr) return except: LOGEXCEPT('Could not verify data in signed message block') return # Always rewrite file; it's small and will use mtime for info with open(os.path.join(self.fetchDir, 'announce.file'), 'w') as f: f.write(digestData) ##### We have a valid digest, now parse it justDownloadedMap = {} for row in [line.split() for line in msg.strip().split('\n')]: if len(row)==3: justDownloadedMap[row[0]] = [row[1], row[2]] else: LOGERROR('Malformed announce matrix: %s' % str(row)) return ##### Check whether any of the hashes have changed for key,val in justDownloadedMap.iteritems(): jdURL,jdHash = val[0],val[1] if not (key in self.fileHashMap and self.fileHashMap[key]==jdHash): LOGINFO('Changed [ "%s" ] == [%s, %s]', key, jdURL, jdHash) newData = self.__fetchFile(jdURL) if len(newData) == 0: LOGERROR('Failed downloading announce file : %s', key) return newHash = binary_to_hex(sha256(newData)) if not newHash == jdHash: LOGERROR('Downloaded file hash does not match!') LOGERROR('Hash of downloaded data: %s', newHash) return filename = os.path.join(self.fetchDir, key+'.file') with open(filename, 'wb') as f: f.write(newData) self.lastChange = RightNow() self.fileHashMap[key] = jdHash ##### Clean up as needed if self.forceCheckFlag.isSet(): self.forceIsFinished.set() self.forceCheckFlag.clear() self.numConsecutiveExceptions = 0
def signAnnounceFiles(wltPath): if len(CLI_ARGS) < 1: print 'Must specify a wallet file containing the signing key' exit(1) wltPath = CLI_ARGS[0] if not os.path.exists(wltPath): print 'Wallet file was not found (%s)' % wltPath exit(1) inDir = 'unsignedAnnounce' outDir = 'signedAnnounce' origDLFile = os.path.join(inDir, 'dllinks.txt') newDLFile = os.path.join(inDir, 'dllinks_temp.txt') ################################################################################ ################################################################################ # We may need to compute some installer hashes doComputeDLLinks = (len(CLI_ARGS) > 1) if doComputeDLLinks: instDir = CLI_ARGS[1] if not os.path.exists(instDir): print 'Installers dir does not exist!' exit(1) instFileInfo = {} with open('dlmap.txt', 'r') as f: dlmapLines = [line.strip() for line in f.readlines()] verName, verStr, urlPrefix = dlmapLines[0].split() for line in dlmapLines[2:]: fn, opsys, osver, osarch = line.replace('%ver', verStr).split() instFileInfo[fn] = [opsys, osver, osarch] OS, OSVER, OSARCH = range(3) with open(newDLFile, 'w') as f: # Write the existing data from rawfiles/dllinks into temp file f.write(open(origDLFile, 'r').read()) f.write('\n') # Now compute hashes of each installer and write info to temp file for fn in os.listdir(instDir): fullpath = os.path.join(instDir, fn) if not fn in instFileInfo: print 'File in installer directory does not match any in info map' print ' File:', fullpath print ' InfoMap:' for filename in instFileInfo: print ' ', filename exit(1) fdata = open(fullpath, 'rb').read() fhash = binary_to_hex(sha256(fdata)) outputStr = [ verName, verStr, instFileInfo[fn][OS], instFileInfo[fn][OSVER], instFileInfo[fn][OSARCH], os.path.join(urlPrefix, fn), fhash ] f.write(' '.join(outputStr) + '\n') ################################################################################ ### if CLI_OPTIONS.testAnnounceCode: signAddress = '1PpAJyNoocJt38Vcf4AfPffaxo76D4AAEe' announceName = 'testannounce.txt' pathPrefix = 'https://s3.amazonaws.com/bitcoinarmory-testing/' else: signAddress = '1NWvhByxfTXPYNT4zMBmEY3VL8QJQtQoei' announceName = 'announce.txt' pathPrefix = 'https://s3.amazonaws.com/bitcoinarmory-media/' announcePath = os.path.join(outDir, announceName) ### wlt = PyBtcWallet().readWalletFile(wltPath) if not wlt.hasAddr(signAddress): print 'Supplied wallet does not have the correct signing key' exit(1) print 'Must unlock wallet to sign the announce file...' while True: passwd = SecureBinaryData(getpass.getpass('Wallet passphrase: ')) if not wlt.verifyPassphrase(passwd): print 'Invalid passphrase!' continue break wlt.unlock(securePassphrase=passwd) passwd.destroy() addrObj = wlt.getAddrByHash160(addrStr_to_hash160(signAddress)[1]) def doSignFile(inFile, outFile): with open(inFile, 'rb') as f: sigBlock = ASv1CS(addrObj.binPrivKey32_Plain.toBinStr(), f.read()) with open(outFile, 'wb') as f: f.write(sigBlock) fileMappings = {} longestID = 0 longestURL = 0 print 'Reading file mapping...' with open('announcemap.txt', 'r') as f: for line in f.readlines(): fname, fid = line.strip().split() inputPath = os.path.join(inDir, fname) if not os.path.exists(inputPath): print 'ERROR: Could not find %s-file (%s)' % (fid, inputPath) exit(1) print ' Map: %s --> %s' % (fname, fid) if os.path.exists(outDir): print 'Wiping old, announced files...' shutil.rmtree(outDir) os.mkdir(outDir) print 'Signing and copying files to %s directory...' % outDir with open('announcemap.txt', 'r') as f: for line in f.readlines(): fname, fid = line.strip().split() inputPath = os.path.join(inDir, fname) outputPath = os.path.join(outDir, fname) # If we're using a modified DL file if fname == 'dllinks.txt' and doComputeDLLinks: inputPath = newDLFile if fname.endswith('.txt'): doSignFile(inputPath, outputPath) else: shutil.copy(inputPath, outputPath) fdata = open(outputPath, 'rb').read() fhash = binary_to_hex(sha256(fdata)) fileMappings[fname] = [fid, fhash] longestID = max(longestID, len(fid)) longestURL = max(longestURL, len(pathPrefix + fname)) print 'Creating digest file...' digestFile = open(announcePath, 'w') ### for fname, vals in fileMappings.iteritems(): fid = vals[0].ljust(longestID + 3) url = (pathPrefix + fname).ljust(longestURL + 3) fhash = vals[1] digestFile.write('%s %s %s\n' % (fid, url, fhash)) digestFile.close() print '' print '------' with open(announcePath, 'r') as f: dfile = f.read() print dfile print '------' print 'Please verify the above data to your satisfaction:' raw_input('Hit <enter> when ready: ') doSignFile(announcePath, os.path.join(outDir, announceName)) print '*' * 80 print open(announcePath, 'r').read() print '*' * 80 print '' print 'Verifying files' for fname, vals in fileMappings.iteritems(): if 'bootstrap' in fname: continue with open(os.path.join(outDir, fname), 'rb') as f: sig, msg = readSigBlock(f.read()) addrB58 = verifySignature(sig, msg, 'v1', ord(ADDRBYTE)) print 'Sign addr for:', vals[0].ljust(longestID + 3), addrB58 print 'Done!'
doSignFile(announcePath, os.path.join(dstAnnounce, announceName)) print '*'*80 print open(announcePath, 'r').read() print '*'*80 print '' print 'Verifying files' for fname,vals in fileMappings.iteritems(): if 'bootstrap' in fname: continue with open(os.path.join(dstAnnounce, fname), 'rb') as f: sig,msg = readSigBlock(f.read()) addrB58 = verifySignature(sig, msg, 'v1', ord(ADDRBYTE)) print 'Sign addr for:', vals[0].ljust(longestID+3), addrB58 print 'Done!' ################################################################################ # GIT SIGN gittag = 'v%s%s' % (topVerStr, topVerType) logprint('*'*80) logprint('About to tag and sign git repo with:') logprint(' Tag: ' + gittag)
def signAnnounceFiles(wltPath): if len(CLI_ARGS)<1: print 'Must specify a wallet file containing the signing key' exit(1) wltPath = CLI_ARGS[0] if not os.path.exists(wltPath): print 'Wallet file was not found (%s)' % wltPath exit(1) inDir = 'unsignedAnnounce' outDir = 'signedAnnounce' origDLFile = os.path.join(inDir, 'dllinks.txt') newDLFile = os.path.join(inDir, 'dllinks_temp.txt') ################################################################################ ################################################################################ # We may need to compute some installer hashes doComputeDLLinks = (len(CLI_ARGS)>1) if doComputeDLLinks: instDir = CLI_ARGS[1] if not os.path.exists(instDir): print 'Installers dir does not exist!' exit(1) instFileInfo = {} with open('dlmap.txt','r') as f: dlmapLines = [line.strip() for line in f.readlines()] verName, verStr, urlPrefix = dlmapLines[0].split() for line in dlmapLines[2:]: fn,opsys,osver,osarch = line.replace('%ver',verStr).split() instFileInfo[fn] = [opsys, osver, osarch] OS,OSVER,OSARCH = range(3) with open(newDLFile, 'w') as f: # Write the existing data from rawfiles/dllinks into temp file f.write(open(origDLFile, 'r').read()) f.write('\n') # Now compute hashes of each installer and write info to temp file for fn in os.listdir(instDir): fullpath = os.path.join(instDir, fn) if not fn in instFileInfo: print 'File in installer directory does not match any in info map' print ' File:', fullpath print ' InfoMap:' for filename in instFileInfo: print ' ', filename exit(1) fdata = open(fullpath, 'rb').read() fhash = binary_to_hex(sha256(fdata)) outputStr = [verName, verStr, instFileInfo[fn][OS], instFileInfo[fn][OSVER], instFileInfo[fn][OSARCH], os.path.join(urlPrefix, fn), fhash] f.write(' '.join(outputStr) + '\n') ################################################################################ ### if CLI_OPTIONS.testAnnounceCode: signAddress = '1PpAJyNoocJt38Vcf4AfPffaxo76D4AAEe' announceName = 'testannounce.txt' pathPrefix = 'https://s3.amazonaws.com/bitcoinarmory-testing/' else: signAddress = '1NWvhByxfTXPYNT4zMBmEY3VL8QJQtQoei' announceName = 'announce.txt' pathPrefix = 'https://s3.amazonaws.com/bitcoinarmory-media/' announcePath = os.path.join(outDir, announceName) ### wlt = PyBtcWallet().readWalletFile(wltPath) if not wlt.hasAddr(signAddress): print 'Supplied wallet does not have the correct signing key' exit(1) print 'Must unlock wallet to sign the announce file...' while True: passwd = SecureBinaryData(getpass.getpass('Wallet passphrase: ')) if not wlt.verifyPassphrase(passwd): print 'Invalid passphrase!' continue break wlt.unlock(securePassphrase=passwd) passwd.destroy() addrObj = wlt.getAddrByHash160(addrStr_to_hash160(signAddress)[1]) def doSignFile(inFile, outFile): with open(inFile, 'rb') as f: sigBlock = ASv1CS(addrObj.binPrivKey32_Plain.toBinStr(), f.read()) with open(outFile, 'wb') as f: f.write(sigBlock) fileMappings = {} longestID = 0 longestURL = 0 print 'Reading file mapping...' with open('announcemap.txt','r') as f: for line in f.readlines(): fname, fid = line.strip().split() inputPath = os.path.join(inDir, fname) if not os.path.exists(inputPath): print 'ERROR: Could not find %s-file (%s)' % (fid, inputPath) exit(1) print ' Map: %s --> %s' % (fname, fid) if os.path.exists(outDir): print 'Wiping old, announced files...' shutil.rmtree(outDir) os.mkdir(outDir) print 'Signing and copying files to %s directory...' % outDir with open('announcemap.txt','r') as f: for line in f.readlines(): fname, fid = line.strip().split() inputPath = os.path.join(inDir, fname) outputPath = os.path.join(outDir, fname) # If we're using a modified DL file if fname=='dllinks.txt' and doComputeDLLinks: inputPath = newDLFile if fname.endswith('.txt'): doSignFile(inputPath, outputPath) else: shutil.copy(inputPath, outputPath) fdata = open(outputPath, 'rb').read() fhash = binary_to_hex(sha256(fdata)) fileMappings[fname] = [fid, fhash] longestID = max(longestID, len(fid)) longestURL = max(longestURL, len(pathPrefix+fname)) print 'Creating digest file...' digestFile = open(announcePath, 'w') ### for fname,vals in fileMappings.iteritems(): fid = vals[0].ljust(longestID + 3) url = (pathPrefix + fname).ljust(longestURL + 3) fhash = vals[1] digestFile.write('%s %s %s\n' % (fid, url, fhash)) digestFile.close() print '' print '------' with open(announcePath, 'r') as f: dfile = f.read() print dfile print '------' print 'Please verify the above data to your satisfaction:' raw_input('Hit <enter> when ready: ') doSignFile(announcePath, os.path.join(outDir, announceName)) print '*'*80 print open(announcePath, 'r').read() print '*'*80 print '' print 'Verifying files' for fname,vals in fileMappings.iteritems(): if 'bootstrap' in fname: continue with open(os.path.join(outDir, fname), 'rb') as f: sig,msg = readSigBlock(f.read()) addrB58 = verifySignature(sig, msg, 'v1', ord(ADDRBYTE)) print 'Sign addr for:', vals[0].ljust(longestID+3), addrB58 print 'Done!'