URI: 
       tvalidate version update announcements using "bitcoin address" message signing - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 0bfda7c8c74757d261bbc7e24eee44fa09965e85
   DIR parent 34c99c3b366ade7adaa919bf1f75d39fe9fcf250
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Mon, 21 Jan 2019 17:39:49 +0100
       
       validate version update announcements using "bitcoin address" message signing
       
       Diffstat:
         M electrum/gui/qt/util.py             |      28 +++++++++++++++++++++++++++-
       
       1 file changed, 27 insertions(+), 1 deletion(-)
       ---
   DIR diff --git a/electrum/gui/qt/util.py b/electrum/gui/qt/util.py
       t@@ -8,12 +8,14 @@ import traceback
        from distutils.version import StrictVersion
        from functools import partial
        from typing import NamedTuple, Callable, Optional, TYPE_CHECKING
       +import base64
        
        from PyQt5.QtGui import *
        from PyQt5.QtCore import *
        from PyQt5.QtWidgets import *
        
        from electrum import version
       +from electrum import ecc
        from electrum.i18n import _, languages
        from electrum.util import FileImportFailed, FileExportFailed, make_aiohttp_session, PrintError
        from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_EXPIRED
       t@@ -828,6 +830,10 @@ class UpdateCheck(QWidget, PrintError):
            url = "https://electrum.org/version"
            download_url = "https://electrum.org/#download"
        
       +    VERSION_ANNOUNCEMENT_SIGNING_KEYS = (
       +        "13xjmVAB1EATPP8RshTE8S8sNwwSUM9p1P",
       +    )
       +
            def __init__(self, main_window, latest_version=None):
                self.main_window = main_window
                QWidget.__init__(self)
       t@@ -904,7 +910,27 @@ class UpdateCheckThread(QThread, PrintError):
            async def get_update_info(self):
                async with make_aiohttp_session(proxy=self.main_window.network.proxy) as session:
                    async with session.get(UpdateCheck.url) as result:
       -                return StrictVersion((await result.text()).strip())
       +                signed_version_dict = await result.json(content_type=None)
       +                # example signed_version_dict:
       +                # {
       +                #     "version": "3.9.9",
       +                #     "signatures": {
       +                #         "1Lqm1HphuhxKZQEawzPse8gJtgjm9kUKT4": "IA+2QG3xPRn4HAIFdpu9eeaCYC7S5wS/sDxn54LJx6BdUTBpse3ibtfq8C43M7M1VfpGkD5tsdwl5C6IfpZD/gQ="
       +                #     }
       +                # }
       +                version_num = signed_version_dict['version']
       +                sigs = signed_version_dict['signatures']
       +                for address, sig in sigs.items():
       +                    if address not in UpdateCheck.VERSION_ANNOUNCEMENT_SIGNING_KEYS:
       +                        continue
       +                    sig = base64.b64decode(sig)
       +                    msg = version_num.encode('utf-8')
       +                    if ecc.verify_message_with_address(address=address, sig65=sig, message=msg):
       +                        self.print_error(f"valid sig for version announcement '{version_num}' from address '{address}'")
       +                        break
       +                else:
       +                    raise Exception('no valid signature for version announcement')
       +                return StrictVersion(version_num.strip())
        
            def run(self):
                try: