Skip to content

Commit

Permalink
QR Encode on Seedpicker (#5)
Browse files Browse the repository at this point in the history
* stashing changes

* stashing funky changes that sort of resize. needs cleanup

* stashing working changes

* stashing changes on working version

* stashing more changes. Needs testing.

* bump version

* bump version

* add qr image

* get rid of signed psbt qr for now (need to add bech32 encoding)

Co-authored-by: Michael Flaxman <[email protected]>
  • Loading branch information
mflaxman and Michael Flaxman authored Nov 18, 2020
1 parent 3b795c8 commit 16576ca
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 13 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,22 @@ GUI version of CLI [multiwallet](https://twitter.com/mflaxman/status/13215030367

## Install

### Pillow (for QR Codes)

Mac:
```
$ brew install libtiff libjpeg webp little-cms2
```

Ubuntu:
```
$ sudo apt-get install python3-dev python3-setuptools apt-get install libtiff5-dev libjpeg8-dev libopenjp2-7-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev python3-tk libharfbuzz-dev libfribidi-dev libxcb1-dev
```

For more see instructions [here](https://pillow.readthedocs.io/en/latest/installation.html)

### Multiwallet

#### Easy
Downloadable binary link here (MacOS only):
<https://github.com/mflaxman/multiwallet/releases>
Expand Down
72 changes: 71 additions & 1 deletion multiwallet_gui/helper.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,35 @@
from PyQt5.QtWidgets import QMessageBox
import qrcode
import re

from io import BytesIO
from PyQt5.QtWidgets import QMessageBox, QDialog, QVBoxLayout, QLabel
from PyQt5.QtGui import QPixmap, QIcon


def strip_html(data):
# https://stackoverflow.com/questions/3398852/using-python-remove-html-tags-formatting-from-a-string
p = re.compile(r"<.*?>")
return p.sub("", data)


def create_qr_icon():
return QIcon("multiwallet_gui/images/qr.png")


def create_qt_pixmap_qr(text):
"""
How to use this:
label.setText("")
label.setPixmap(create_qt_pixmap_qr(text="foo"))
https://stackoverflow.com/a/58251630/1754586
"""
buf = BytesIO()
img = qrcode.make(text)
img.save(buf, "PNG")
qt_pixmap = QPixmap()
qt_pixmap.loadFromData(buf.getvalue(), "PNG")
return qt_pixmap


def _clean_submisission(string):
Expand All @@ -20,6 +51,45 @@ def _msgbox_err(main_text=None, informative_text=None, detailed_text=None):
msg.exec_()


class QRPopup(QDialog):
def __init__(self, window_title, qr_text):
super().__init__()

self.setWindowTitle(window_title)

self.setMaximumHeight(16777215)
self.setMaximumWidth(16777215)

self.qr_text = qr_text

self.vbox = QVBoxLayout()

self.labelImage = QLabel()
self.labelImage.setMaximumHeight(16777215)
self.labelImage.setMaximumWidth(16777215)

self._set_pixmap()

self.vbox.addWidget(self.labelImage)
self.setLayout(self.vbox)

self.show()

def _set_pixmap(self):
self.pixmap = create_qt_pixmap_qr(text=self.qr_text).scaledToHeight(
self.height() * 0.9
)
self.labelImage.setPixmap(self.pixmap)

def resizeEvent(self, event):
self.pixmap = self._set_pixmap()


def qr_dialog(qr_text, window_title):
dialog = QRPopup(qr_text=qr_text, window_title=strip_html(window_title))
return dialog.exec_()


def _is_libsec_enabled():
# TODO: move to buidl
try:
Expand Down
Binary file added multiwallet_gui/images/qr.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 30 additions & 10 deletions multiwallet_gui/seedpicker.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
BITCOIN_NETWORK_TOOLTIP,
BITCOIN_TESTNET_TOOLTIP,
BITCOIN_MAINNET_TOOLTIP,
create_qr_icon,
_clean_submisission,
_msgbox_err,
qr_dialog,
)

from PyQt5.QtWidgets import (
Expand Down Expand Up @@ -73,7 +75,6 @@ def __init__(self):
self.testnet_button.setChecked(True)

self.firstWordsSubmitButton = QPushButton("Calculate Full Seed")
self.firstWordsSubmitButton.setText("Calculate Full Seed")
self.firstWordsSubmitButton.clicked.connect(self.process_submit)

self.privResultsLabel = QLabel("")
Expand All @@ -88,9 +89,14 @@ def __init__(self):
self.pubResultsLabel.setToolTip(
"For export to your online computer and eventaully other hardware wallets. This represents your bitcoin <i>public</i> keys, which are neccesary-but-not-sufficient to spend your bitcoin."
)
self.pubResultsEdit = QPlainTextEdit("")
self.pubResultsEdit.setReadOnly(True)
self.pubResultsEdit.setHidden(True)
self.pubResultsROEdit = QPlainTextEdit("")
self.pubResultsROEdit.setReadOnly(True)
self.pubResultsROEdit.setHidden(True)

self.qrButton = QPushButton()
self.qrButton.setText("QR")
self.qrButton.setHidden(True)
self.qrButton.clicked.connect(self.make_qr_popup)

for widget in (
self.firstWordsLabel,
Expand All @@ -102,7 +108,8 @@ def __init__(self):
self.privResultsLabel,
self.privResultsEdit,
self.pubResultsLabel,
self.pubResultsEdit,
self.pubResultsROEdit,
self.qrButton,
):
self.layout.addWidget(widget)

Expand All @@ -116,9 +123,11 @@ def process_submit(self):
self.privResultsEdit.clear()
self.privResultsEdit.setHidden(True)
self.privResultsLabel.setText("")
self.pubResultsEdit.clear()
self.pubResultsEdit.setHidden(True)
self.pubResultsROEdit.clear()
self.pubResultsROEdit.setHidden(True)
self.pubResultsLabel.setText("")
self.qrButton.setHidden(True)
self.qrButton.setText("")
# TODO: why setText and not hide?

first_words = _clean_submisission(self.firstWordsEdit.toPlainText())
Expand Down Expand Up @@ -182,8 +191,19 @@ def process_submit(self):
self.privResultsEdit.setHidden(False)
self.privResultsEdit.appendPlainText("\n".join(priv_to_display))

self.pubResultsLabel.setText(
pubkey_results_text = (
f"<b>PUBLIC KEY INFO</b> - {'Testnet' if self.IS_TESTNET else 'Mainnet'}"
)
self.pubResultsEdit.setHidden(False)
self.pubResultsEdit.appendPlainText("\n".join(pub_to_display))
self.pubResultsLabel.setText(pubkey_results_text)
self.pubResultsROEdit.setHidden(False)
self.pubResultsROEdit.appendPlainText("\n".join(pub_to_display))

self.qrButton.setHidden(False)
self.qrButton.setText("QR")
self.qrButton.setIcon(create_qr_icon())

def make_qr_popup(self):
qr_dialog(
qr_text=self.pubResultsROEdit.toPlainText(),
window_title=self.pubResultsLabel.text(),
)
4 changes: 3 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
buidl==0.2.1
buidl==0.2.2
PyQt5==5.15.1
qrcode==6.1
Pillow==8.0.1
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

setup(
name="multiwallet",
version="0.3.6",
version="0.3.7",
author="Michael Flaxman",
author_email="[email protected]",
description="Stateless multisig bitcoin wallet",
Expand Down

0 comments on commit 16576ca

Please sign in to comment.