Skip to content

Commit

Permalink
Merge branch 'master' into upgrade_hwi
Browse files Browse the repository at this point in the history
  • Loading branch information
k9ert authored Jul 1, 2022
2 parents 428054c + a0633c7 commit 766e8e4
Show file tree
Hide file tree
Showing 33 changed files with 781 additions and 283 deletions.
5 changes: 3 additions & 2 deletions cypress/integration/spec_devices.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ describe('Test adding different devices', () => {
before(() => {
cy.viewport(1200,660)
cy.visit('/')
Cypress.config('includeShadowDom', true)
})

// Keeps the session cookie alive, Cypress by default clears all cookies before each test
Expand All @@ -15,8 +16,8 @@ describe('Test adding different devices', () => {
cy.get('#electrum_device_card').click()
cy.get('#device_name').type("Electron's Electrum Device")
// Open and close the explainer
cy.get('#toggle-explainer').click()
cy.get('#toggle-explainer').click()
cy.get('#toggle-explainer').find('#drop-icon').click()
cy.get('#toggle-explainer').find('#drop-icon').click()
cy.get('#master_pub_key').type("vpub5VGXXixD2pHLFtcKtCF57e8mx2JW6fie8VydXijC8sRKAL4RshgjEmzbmV915NeVB9pd23DVYem6zWM7HXFLNwaffNVHowdD9SJWwESyQhp")
cy.get('.small-card > .btn').click()
cy.contains('New device was added successfully!')
Expand Down
5 changes: 5 additions & 0 deletions docs/endless-pacman.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ Sometimes some devices attached via USB are blocking the startup. We had that in
Maybe there is another instance (still) running. Check that via opening your brower here: [http://localhost:25441](http://localhost:25441)
If that's the case, the most easy solution is to reboot your computer.

# Check security software
Sometimes, security software is distorting the startup.

E.g. Acronis is a protective system which is known to prevent starting up of Specter on windows. Other security-software might be behaving similary. For troubleshooting purposes, switch off your protective software and try again. If that helps, you need to allow specter to be running on port 25441. Check the manual on how to achieve that manually.

# Check Whether the Binary is Existing
The first thing Specter is doing if you start up the app is downloading the correct specterd from the GitHub-release page and storing that executable in the `Homefolder/.specter/specterd-binaries` subfolder. You should find a file called `specterd`.
If the file is there but you still get the endless Pacman, try one of the following things:
Expand Down
22 changes: 18 additions & 4 deletions docs/release-notes.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
## v1.10.2 Juni 03, 2022
## v1.10.3 June 22, 2022
- Bugfix: Display address on device #1774 (Manolis Mandrapilias)
- Bugfix: Longer Timeout for run_the_numbers #1769 (k9ert)
- Bugfix: Rescan won't work for fullnodes without explorer #1771 (k9ert)
- Bugfix: Send max with multiple recipients #1744 (Harshit)
- Bugfix: Start_specter ran twice in sub_open #1768 (k9ert)
- Bugfix: Visual artifact in the electron settings dialog #1754 (djpnewton)
- Chore: Making text-explainer a webcomponent #1752 (Shlok Pandey)
- Chore: Refactor_wallet_manager #1667 (k9ert)
- Docs: Corrected links in development.md #1742 (Ankur)
- Feature: combined test script for cypress and pytest #1749 (relativisticelectron)
- Feature: Drag and drop for PSBT import #1758 (Shlok Pandey)
- UIUX: Fixed html character codes for multisig guide & polishment of about page #1743 (Manolis Mandrapilias)

## v1.10.2 June 03, 2022
- Feature: Basic auth in electron #1730 (djpnewton)
- Feature: Multisig beginner guide #1731 (relativisticelectron)
- Bugfix: Corrected build instructions and made virtuelenv name dynamic #1735 (relativisticelectron)
- Bugfix: issues while using specter as library #1740 (k9ert)
- Bugfix: PDF backup does not open for multisig #1741 (k9ert)
- UIUX: fix typo in error_logs #1739 (Bufo)

## v1.10.0 Mai 27, 2022
## v1.10.0 May 27, 2022
- Feature: adding has_service() method to user #1732 (Kim Neunert)
- Feature: Choose file button for labels import #1682 (Manolis)
- Feature: Customised front end for adding Electrum devices #1622 (relativisticelectron)
Expand Down Expand Up @@ -55,7 +69,7 @@
- Chore: Bump minimist from 1.2.5 to 1.2.6 #1639 (dependabot[bot])
- Chore: Update elements to 0.21.0.2 #1641 (Kim Neunert)

## v1.9.0 März 30, 2022
## v1.9.0 March 30, 2022
- Feature: added better scrollbar for all table-style-lists #1598 (relativisticelectron)
- Feature: CLI and a publishing model for extensions #1566 (Kim Neunert)
- Feature: Import of raw transaction #1591 (relativisticelectron)
Expand Down Expand Up @@ -97,7 +111,7 @@
- Docs: Update daemon.md #1586 (GoofyAF)


## v1.8.0 Januar 29, 2022
## v1.8.0 January 29, 2022
- Feature: Add Jade multisig support #1520 (Stepan Snigirev)
- Feature: add liquid-testnet support #1527 (Stepan Snigirev)
- Feature: Allow descriptors with xpubs but without derivations (just wpkh(xpub) ) for wallet imports #1519 (Stepan Snigirev)
Expand Down
39 changes: 39 additions & 0 deletions docs/services/services.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,45 @@ If the extension has a UI (currently all of them have one), `has_blueprint` is T
`isolated_client` Should not be used yet. It is determining where in the url-path-tree the blueprint will be mounted. This might have an impact on whether the extension's frontend-client has access to the cookie used in specter. Check `config.py` for details.
`devstatus` is one of `devstatus_alpha`, `devstatus_beta` or `devstatus_prod` defined in `cryptoadvance.specter.services.service`. Each specter-instance will have a config-variable called `SERVICES_DEVSTATUS_THRESHOLD` (prod in Production and alpha in Development) and depending on that, the plugin will be available to the user.

## Frontend aspects

As stated, you can have your own frontend with a blueprint. If you only have one, it needs to have a `/` route in order to be linkable from the `choose your plugin` page.
If you create your extension with a blueprint, it'll create also a controller for you which, simplified, look like this:
```
rubberduck_endpoint = ScratchpadService.blueprint
def ext() -> ScratchpadService:
''' convenience for getting the extension-object'''
return app.specter.ext["rubberduck"]
def specter() -> Specter:
''' convenience for getting the specter-object'''
return app.specter
@rubberduck.route("/")
@login_required
@user_secret_decrypted_required
def index():
return render_template(
"rubberduck/index.jinja",
)
[...]
```
But you can also have more than one blueprint. Define them like this in your service-class:
```
blueprint_modules = {
"default" : "mynym.specterext.rubberduck.controller",
"ui" : "mynym.specterext.rubberduck.controller_ui"
}
```
You have to have a default-blueprint which has the above mentioned index-page.
In your controller, the endpoint needs to be specified like this:
```
ui = RubberduckService.blueprints["ui"]
```


## Data-Storage
Effort has been taken to provide `Service` data storage that is separate from existing data stores in order to keep those areas clean and simple. Where touchpoints are unavoidable, they are kept to the absolute bare minimum (e.g. `User.services` list, `Address.service_id` field).

Expand Down
20 changes: 6 additions & 14 deletions src/cryptoadvance/specter/hwi_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,14 +271,15 @@ def extract_xpub(
@locked(hwilock)
def display_address(
self,
descriptor={},
descriptor="",
xpubs_descriptor="",
device_type=None,
path=None,
fingerprint=None,
passphrase="",
chain="",
):
if descriptor == "":
if descriptor == "" and xpubs_descriptor == "":
raise Exception("Descriptor must not be empty")

with self._get_client(
Expand All @@ -288,19 +289,10 @@ def display_address(
passphrase=passphrase,
chain=chain,
) as client:
if descriptor.get("xpubs_descriptor", None):
try:
status = hwi_commands.displayaddress(
client, desc=descriptor["xpubs_descriptor"]
)
except Exception:
status = hwi_commands.displayaddress(
client, desc=descriptor.get("descriptor", "")
)
if xpubs_descriptor:
status = hwi_commands.displayaddress(client, desc=xpubs_descriptor)
else:
status = hwi_commands.displayaddress(
client, desc=descriptor.get("descriptor", "")
)
status = hwi_commands.displayaddress(client, desc=descriptor)
if "error" in status:
raise Exception(status["error"])
elif "address" in status:
Expand Down
2 changes: 1 addition & 1 deletion src/cryptoadvance/specter/managers/config_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ def update_explorer(self, explorer_id, explorer_data, user, chain):
chain_name = (
""
if (chain == "main" or chain == "regtest")
else ("signet/" if self.chain == "signet" else "testnet/")
else ("signet/" if chain == "signet" else "testnet/")
)
explorer_data["url"] += chain_name
# update the urls in the app config
Expand Down
131 changes: 83 additions & 48 deletions src/cryptoadvance/specter/managers/service_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,69 +102,104 @@ def __init__(self, specter, devstatus_threshold):
def register_blueprint_for_ext(cls, clazz, ext):
if not clazz.has_blueprint:
return
if hasattr(clazz, "blueprint_module"):
import_name = clazz.blueprint_module
controller_module = clazz.blueprint_module
if hasattr(clazz, "blueprint_modules"):
controller_modules = clazz.blueprint_modules
setattr(clazz, "blueprints", {})
elif hasattr(clazz, "blueprint_module"):
controller_modules = {"default": clazz.blueprint_module}
else:
# The import_name helps to locate the root_path for the blueprint
import_name = f"cryptoadvance.specter.services.{clazz.id}.service"
controller_module = f"cryptoadvance.specter.services.{clazz.id}.controller"
controller_modules = controller_modules = {
"default": f"cryptoadvance.specter.services.{clazz.id}.controller"
}

clazz.blueprint = Blueprint(
f"{clazz.id}_endpoint",
import_name,
template_folder=get_template_static_folder("templates"),
static_folder=get_template_static_folder("static"),
)
only_one_blueprint = len(controller_modules.items()) == 1

def inject_stuff():
"""Can be used in all jinja2 templates"""
return dict(specter=app.specter, service=ext)

clazz.blueprint.context_processor(inject_stuff)
if "default" not in controller_modules.keys():
raise SpecterError(
"You need at least one Blueprint, with the key 'default'. It will be used to link to your UI"
)

# Import the controller for this service
logger.info(f" Loading Controller {controller_module}")
controller_module = import_module(controller_module)
for bp_key, bp_value in controller_modules.items():
if bp_key == "":
raise SpecterError("Empty keys are not allowed in the blueprints map")
middple_part = "" if bp_key == "default" else f"{bp_key}_"
bp_name = f"{clazz.id}_{middple_part}endpoint"
logger.debug(
f" Creating blueprint with name {bp_name} (middle_part:{middple_part}:"
)
bp = Blueprint(
f"{clazz.id}_{middple_part}endpoint",
bp_value,
template_folder=get_template_static_folder("templates"),
static_folder=get_template_static_folder("static"),
)
if only_one_blueprint:
setattr(clazz, "blueprint", bp)
else:
clazz.blueprints[bp_key] = bp
bp.context_processor(inject_stuff)

# finally register the blueprint
if clazz.isolated_client:
ext_prefix = app.config["ISOLATED_CLIENT_EXT_URL_PREFIX"]
else:
ext_prefix = app.config["EXT_URL_PREFIX"]
# Import the controller for this service
logger.info(f" Loading Controller {bp_value}")

try:
if (
app.testing
and len([vf for vf in app.view_functions if vf.startswith(clazz.id)])
<= 1
): # the swan-static one
# Yet again that nasty workaround which has been described in the archblog.
# The easy variant can be found in server.py
# The good news is, that we'll only do that for testing
import importlib

logger.info("Reloading Extension controller")
importlib.reload(controller_module)
app.register_blueprint(
clazz.blueprint, url_prefix=f"{ext_prefix}/{clazz.id}"
)
else:
app.register_blueprint(
clazz.blueprint, url_prefix=f"{ext_prefix}/{clazz.id}"
)
logger.info(f" Mounted {clazz.id} to {ext_prefix}/{clazz.id}")
except AssertionError as e:
if str(e).startswith("A name collision"):
raise SpecterError(
try:
controller_module = import_module(bp_value)
except ModuleNotFoundError as e:
raise Exception(
f"""
There is a name collision for the {clazz.blueprint.name}. \n
This is probably because you're running in DevelopementConfig and configured
the extension at the same time in the EXTENSION_LIST which currently loks like this:
{app.config['EXTENSION_LIST']})
There was an issue finding a controller module:
{e}
That module was specified in the Service class of service {clazz.id}
check that specification in {clazz.__module__}
"""
)

# finally register the blueprint
if clazz.isolated_client:
ext_prefix = app.config["ISOLATED_CLIENT_EXT_URL_PREFIX"]
else:
ext_prefix = app.config["EXT_URL_PREFIX"]

try:
bp_postfix = "" if only_one_blueprint else f"/{bp_key}"
if (
app.testing
and len(
[vf for vf in app.view_functions if vf.startswith(clazz.id)]
)
<= 1
): # the swan-static one
# Yet again that nasty workaround which has been described in the archblog.
# The easy variant can be found in server.py
# The good news is, that we'll only do that for testing
import importlib

logger.info("Reloading Extension controller")
importlib.reload(controller_module)
app.register_blueprint(
bp, url_prefix=f"{ext_prefix}/{clazz.id}{bp_postfix}"
)
else:
app.register_blueprint(
bp, url_prefix=f"{ext_prefix}/{clazz.id}{bp_postfix}"
)
logger.info(f" Mounted {bp} to {ext_prefix}/{clazz.id}{bp_postfix}")
except AssertionError as e:
if str(e).startswith("A name collision"):
raise SpecterError(
f"""
There is a name collision for the {clazz.blueprint.name}. \n
This is probably because you're running in DevelopementConfig and configured
the extension at the same time in the EXTENSION_LIST which currently loks like this:
{app.config['EXTENSION_LIST']})
"""
)

@classmethod
def configure_service_for_module(cls, clazz):
"""searches for ConfigClasses in the module-Directory and merges its config in the global config"""
Expand Down
2 changes: 1 addition & 1 deletion src/cryptoadvance/specter/server_endpoints/wallets.py
Original file line number Diff line number Diff line change
Expand Up @@ -782,7 +782,7 @@ def settings(wallet_alias):

wallet.rescanutxo(
explorer,
app.specter.requests_session(explorer.endswith(".onion")),
app.specter.requests_session(explorer and explorer.endswith(".onion")),
app.specter.only_tor,
)
app.specter.info["utxorescan"] = 1
Expand Down
10 changes: 5 additions & 5 deletions src/cryptoadvance/specter/server_endpoints/wallets_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def generatemnemonic():
@login_required
@app.csrf.exempt
def txout_set_info():
res = app.specter.rpc.gettxoutsetinfo()
res = app.specter.rpc.gettxoutsetinfo(timeout=3600)
return res


Expand Down Expand Up @@ -491,11 +491,11 @@ def addressinfo(wallet_alias):
wallet = app.specter.wallet_manager.get_by_alias(wallet_alias)
address = request.form.get("address", "")
if address:
descriptor = add_checksum(
wallet.get_descriptor(address=address, keep_xpubs=False).to_string()
descriptor = wallet.get_descriptor(
address=address, keep_xpubs=False, to_string=True, with_checksum=True
)
xpubs_descriptor = add_checksum(
wallet.get_descriptor(address=address, keep_xpubs=True).to_string()
xpubs_descriptor = wallet.get_descriptor(
address=address, keep_xpubs=True, to_string=True, with_checksum=True
)
# The last two regex groups are optional since Electrum's derivation path is shorter
derivation_path_pattern = (
Expand Down
5 changes: 3 additions & 2 deletions src/cryptoadvance/specter/static/hwi.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,15 +175,16 @@ class HWIBridge {
}


async displayAddress(device, descriptor, passphrase=""){
async displayAddress(device, descriptor, xpubs_descriptor, passphrase=""){
if(!('passphrase' in device)){
device.passphrase = passphrase;
}
return await this.fetch('display_address', {
device_type: device.type,
path: device.path,
passphrase: device.passphrase,
descriptor: JSON.parse(descriptor),
descriptor: descriptor,
xpubs_descriptor: xpubs_descriptor,
});
}
}
Loading

0 comments on commit 766e8e4

Please sign in to comment.