Merge branch 'design-revamp' of github.com:otkstdio/specter-desktop into design-revamp

This commit is contained in:
moneymanolis 2023-01-10 21:15:54 +01:00
commit afde53e406
9 changed files with 105 additions and 109 deletions

View file

@ -4,7 +4,7 @@
- [Specter Desktop](#specter-desktop)
- [DISCLAIMER](#disclaimer)
- [Video Walkthrough](#video-walkthrough)
- [Documentation and Video Walkthrough](#documentation-and-video-walkthrough)
- [Why?](#why)
- [Help wanted: Do you like Specter?](#help-wanted-do-you-like-specter)
- [How to run](#how-to-run)
@ -27,7 +27,6 @@
The Crypto Anarchist Manifesto - Timothy C. May - Sun, 22 Nov 92 12:11:24 PST
[![Build Status](https://api.cirrus-ci.com/github/cryptoadvance/specter-desktop.svg)](https://cirrus-ci.com/github/cryptoadvance/specter-desktop)
[![Support the project](https://img.shields.io/badge/btcpay-support%20project-orange.svg)](https://donate.specter.solutions/apps/3k77BAT6zshCGNd3i7gw9WKwXQy1/pos)
## DISCLAIMER
@ -35,8 +34,10 @@ This software might be ready to be used but at your own risk.
If something doesn't work open an issue here or ask a question in our [Telegram group](https://t.me/spectersupport).
## Video Walkthrough
![video](https://www.youtube.com/embed/v3SEp0SkOWs) [Watch here](https://www.youtube.com/watch?v=v3SEp0SkOWs)
## Documentation and Video Walkthrough
* ![video](https://www.youtube.com/embed/v3SEp0SkOWs) [Watch here](https://www.youtube.com/watch?v=v3SEp0SkOWs)
* [documentation](https://docs.specter.solutions/desktop/)
## Why?

View file

@ -65,7 +65,7 @@ sudo yum -y install libusb libudev-devel libffi libffi-devel openssl-devel && su
```
#### Windows
* Install python 3.8.x by downloading from [python.org](https://www.python.org/downloads/windows/)
* Install python 3.10.x by downloading from [python.org](https://www.python.org/downloads/windows/)
_Do NOT install python from the Microsoft Store! It runs in a different execution environment that creates enormous headaches!_
@ -85,8 +85,7 @@ sudo yum -y install libusb libudev-devel libffi libffi-devel openssl-devel && su
### Set up virtualenv
Specter is using `hwi-2.1.0` which by now supports higher Python versions than Specter itself. Specter currently supports Python 3.7-3.9.
If you have Python 3.10 as your global version then be sure to also install an old Python version and pass it to `virtualenv` (e.g. `virtualenv --python=python3.8 .env`) or use pyenv.
Specter is using `hwi-2.1.0` which by now supports higher Python versions than Specter itself. Specter currently supports Python 3.9 and 3.10.
```sh
git clone https://github.com/cryptoadvance/specter-desktop.git
@ -113,6 +112,7 @@ Run the server:
cd specter-desktop
python3 -m cryptoadvance.specter server --config DevelopmentConfig --debug
```
After that, Specter will be available at http://127.0.0.1:25441/.
#### If `pip install` fails on `cryptography==3.4.x`

View file

@ -380,13 +380,13 @@ To check (before and/or afterwards) your installed version, you can use: `pip3 s
### Raspiblitz
You might want to wait until raspiblitz is providing an update. It takes longer but if you're not technically literate, that might be a better option. However, up from Version 1.6.1, Raspiblitz offers an update-possibility in the menu. Prior to that or as a part of troubleshooting-procedure, you can also do something like this:
```
sudo su - bitcoin
cd .specter/
sudo su - specter
. ./.env/bin/activate
pip3 list | grep specter
pip3 install cryptoadvance.specter --upgrade
pip3 list | grep specter
service cryptoadvance-specter restart
exit
sudo systemctl restart specter
```
### umbrel

12
package-lock.json generated
View file

@ -3589,9 +3589,9 @@
}
},
"node_modules/minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dependencies": {
"brace-expansion": "^1.1.7"
},
@ -8856,9 +8856,9 @@
"dev": true
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"requires": {
"brace-expansion": "^1.1.7"
}

View file

@ -1410,9 +1410,9 @@
}
},
"node_modules/filelist/node_modules/minimatch": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
"integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz",
"integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==",
"dev": true,
"dependencies": {
"brace-expansion": "^2.0.1"
@ -1885,13 +1885,10 @@
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
},
"node_modules/json5": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz",
"integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true,
"dependencies": {
"minimist": "^1.2.5"
},
"bin": {
"json5": "lib/cli.js"
},
@ -2079,9 +2076,9 @@
}
},
"node_modules/minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
@ -4488,9 +4485,9 @@
}
},
"minimatch": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
"integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz",
"integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==",
"dev": true,
"requires": {
"brace-expansion": "^2.0.1"
@ -4859,13 +4856,10 @@
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
},
"json5": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz",
"integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==",
"dev": true,
"requires": {
"minimist": "^1.2.5"
}
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true
},
"jsonfile": {
"version": "4.0.0",
@ -5012,9 +5006,9 @@
"dev": true
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"

View file

@ -14,6 +14,7 @@ from pathlib import Path
import cryptography
import pgpy
import requests
from cryptoadvance.specter.util.wallet_importer import WalletImporter
from flask import Blueprint, Flask
from flask import current_app as app
from flask import jsonify, redirect, render_template, request, send_file, url_for
@ -29,7 +30,7 @@ from ..helpers import (
from ..persistence import write_devices, write_wallet
from ..server_endpoints import flash
from ..services.service import callbacks
from ..specter_error import handle_exception
from ..specter_error import SpecterError, handle_exception
from ..user import UserSecretException
from ..util.sha256sum import sha256sum
from ..util.shell import get_last_lines_from_file
@ -149,74 +150,58 @@ def general():
app.specter.device_manager.update()
rescanning = False
logger.info(f"Importing {len(restore_wallets)} wallets ...")
counter = {
"success": 0,
"specific_error": 0,
"unspecific_error": 0,
"rescan_error": 0,
}
for wallet in restore_wallets:
try:
app.specter.wallet_manager.rpc.createwallet(
os.path.join(
app.specter.wallet_manager.rpc_path, wallet["alias"]
),
True,
)
except Exception as e:
# if wallet already exists in Bitcoin Core
# continue with the existing one
if "already exists" not in str(e):
flash(
_("Failed to import wallet {}, error: {}").format(
wallet["name"], e
),
"error",
)
handle_exception(e)
continue
logger.debug(
f"Wallet {wallet['alias']} already exists, skipping creation"
)
write_wallet(wallet)
app.specter.wallet_manager.update(use_threading=False)
try:
wallet_obj = app.specter.wallet_manager.get_by_alias(
wallet["alias"]
logger.info(f"Importing wallet {wallet['name']}")
wallet_importer = WalletImporter(json.dumps(wallet), app.specter)
wallet_importer.create_wallet(app.specter.wallet_manager)
wallet_importer.rescan_as_needed(app.specter)
counter["success"] += 1
except SpecterError as se:
error_type = (
"rescan_error" if "rescan" in str(se) else "specific_error"
)
wallet_obj.keypoolrefill(0, wallet_obj.IMPORT_KEYPOOL, change=False)
wallet_obj.keypoolrefill(0, wallet_obj.IMPORT_KEYPOOL, change=True)
wallet_obj.import_labels(wallet.get("labels", {}))
try:
wallet_obj.rpc.rescanblockchain(
wallet["blockheight"]
if "blockheight" in wallet
else get_startblock_by_chain(app.specter),
no_wait=True,
)
app.logger.info("Rescanning Blockchain ...")
rescanning = True
except Exception as e:
app.logger.exception(
"Exception while rescanning blockchain for wallet {}: {}".format(
wallet["alias"], e
),
e,
)
flash(
_("Failed to perform rescan for wallet: {}").format(e),
"error",
)
wallet_obj.getdata()
flash(f"Wallet '{wallet.get('name')}': {se} (skipped)", "error")
counter[error_type] += 1
except Exception as e:
flash(
_("Failed to import wallet {}").format(wallet["name"]), "error"
f"Error while importing wallet {wallet['name']}, check logs for details! (skipped)",
"error",
)
handle_exception(e)
flash(_("Specter data was successfully loaded from backup"), "info")
logger.exception(
f"Error while importing wallet {wallet['name']}: {e}"
)
counter["unspecific_error"] += 1
counter["errors_sum"] = (
counter["rescan_error"]
+ counter["specific_error"]
+ counter["unspecific_error"]
)
if counter["success"] > 0:
message = f"{counter['success']} wallets successfully restored. "
else:
message = f"Sorry, this doesn't went that well. "
if counter["errors_sum"] > 0:
message += "however, we had " if counter["success"] > 0 else "We had "
message += f"""<br>
Successful imports: {counter["success"]}<br>
Specific errors: {counter["specific_error"]}<br>
Unspecific errors: {counter["unspecific_error"]} (create an issue about it on github)<br>
Rescan issues: {counter["rescan_error"]}<br>
"""
if rescanning:
flash(
_(
"Wallets are rescanning for transactions history.\n\
This may take a few hours to complete."
),
"info",
)
message += "Wallets are rescanning for transactions history. This may take a few hours to complete."
flash(message, "info")
return render_template(
"settings/general_settings.jinja",

View file

@ -197,13 +197,21 @@
reader.onload = function(e) {
if (files[i].webkitRelativePath.indexOf('devices/') != -1) {
console.log(files[i].name);
devices.push(JSON.parse(reader.result));
try {
devices.push(JSON.parse(reader.result));
} catch {
showError(`Could not load Device ${files[i].name}: not valid json! This Device will be skipped for import which might affect corresponding Wallets.`)
}
document.getElementById('restoredevices').value = JSON.stringify(devices);
document.getElementById('filesloaded').innerHTML = `<br>Found ${devices.length} devices and ${wallets.length} wallets:`;
document.getElementById('restore').style.display = 'block';
} else if (files[i].webkitRelativePath.indexOf('wallets/') != -1) {
console.log(files[i].name);
wallets.push(JSON.parse(reader.result));
try {
wallets.push(JSON.parse(reader.result));
} catch {
showError(`Could not load Wallet ${files[i].name}: not valid json! This wallet will be skipped for import.`)
}
document.getElementById('restorewallets').value = JSON.stringify(wallets);
document.getElementById('filesloaded').innerHTML = `<br>Found ${devices.length} devices and ${wallets.length} wallets:`;
document.getElementById('restore').style.display = 'block';

View file

@ -50,8 +50,8 @@ class WalletImporter:
try:
self.descriptor = DescriptorCls.from_string(recv_descriptor)
self.check_descriptor()
except Exception as e:
raise SpecterError(f"Invalid wallet descriptor: {e}")
except ValueError as e:
raise SpecterError(f"{e}: {recv_descriptor}")
if self.wallet_name in specter.wallet_manager.wallets_names:
raise SpecterError(f"Wallet with the same name already exists")
(
@ -242,7 +242,7 @@ class WalletImporter:
)
except Exception as e:
logger.exception(e)
raise SpecterError(f"Failed to create wallet: {e}")
raise SpecterError(f"Failed to create wallet: {e} (check logs for details)")
logger.info(f"Created Wallet {self.wallet}")
self.wallet.keypoolrefill(0, self.wallet.IMPORT_KEYPOOL, change=False)
self.wallet.keypoolrefill(0, self.wallet.IMPORT_KEYPOOL, change=True)
@ -333,7 +333,7 @@ class WalletImporter:
wallet_data["x1/"]["xpub"]
)
else:
raise Exception('"xpub" not found in "x1/" in Electrum backup json')
raise SpecterError('"xpub" not found in "x1/" in Electrum backup json')
required_sigs = int(wallet_data.get("wallet_type").split("of")[0])
recv_descriptor = "{}(sortedmulti({},{}))".format(
@ -482,7 +482,7 @@ class WalletImporter:
wallet_data["keystore"]["xpub"], is_multisig=False
)
else:
raise Exception(
raise SpecterError(
'"xpub" not found in "keystore" in Electrum backup json'
)
recv_descriptor = "{}({})".format(
@ -517,6 +517,13 @@ class WalletImporter:
wallet_name = wallet_data.get("label", "Imported Wallet")
recv_descriptor = wallet_data.get("descriptor", None)
if wallet_name is None:
raise SpecterError(
f"Couldn't find 'name' in wallet json (alias: {wallet_data.get('alias','also not existing')})."
)
if recv_descriptor is None:
raise SpecterError("Couldn't find 'recv_descriptor' in wallet json.")
return (wallet_name, recv_descriptor, cosigners_types)
@classmethod

View file

@ -1454,6 +1454,7 @@ class Wallet:
else self.rpc.getbalances()["watchonly"]
)
except Exception as e:
handle_exception(e)
raise SpecterError(f"was not able to get wallet_balance because {e}")
self.balance = balance
return self.balance