1
0

qml: change wizard passphrase flow

This commit is contained in:
f321x
2025-07-08 14:12:56 +02:00
parent bb5b1b3932
commit 290da21187
7 changed files with 204 additions and 69 deletions

View File

@@ -0,0 +1,72 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import QtQuick.Controls.Material
import org.electrum 1.0
import "../controls"
WizardComponent {
id: root
securePage: true
valid: false
property int cosigner: 0
function checkValid() {
valid = false
var input = customwordstext.text
if (input == '') {
return
}
if (cosigner) {
// multisig cosigner
if (input != wizard_data['multisig_cosigner_data'][cosigner.toString()]['seed_extra_words']) {
return
}
} else {
if (input != wizard_data['seed_extra_words']) {
return
}
}
valid = true
}
Flickable {
anchors.fill: parent
contentHeight: mainLayout.height
clip: true
interactive: height < contentHeight
ColumnLayout {
id: mainLayout
width: parent.width
spacing: constants.paddingLarge
Label {
Layout.fillWidth: true
wrapMode: Text.Wrap
text: qsTr('Please enter your custom word(s) a second time:')
}
TextField {
id: customwordstext
Layout.fillWidth: true
Layout.columnSpan: 2
placeholderText: qsTr('Enter your custom word(s) here')
inputMethodHints: Qt.ImhSensitiveData | Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase
onTextChanged: checkValid()
}
}
}
Component.onCompleted: {
if (wizard_data['wallet_type'] == 'multisig') {
if ('multisig_current_cosigner' in wizard_data)
cosigner = wizard_data['multisig_current_cosigner']
}
}
}

View File

@@ -14,8 +14,7 @@ WizardComponent {
function checkValid() {
var seedvalid = wizard.wiz.isMatchingSeed(wizard_data['seed'], confirm.text)
var customwordsvalid = customwordstext.text == wizard_data['seed_extra_words']
valid = seedvalid && (wizard_data['seed_extend'] ? customwordsvalid : true)
valid = seedvalid
}
Flickable {
@@ -46,19 +45,6 @@ WizardComponent {
placeholderText: qsTr('Enter your seed')
onTextChanged: checkValid()
}
TextField {
id: customwordstext
Layout.fillWidth: true
placeholderText: qsTr('Enter your custom word(s)')
inputMethodHints: Qt.ImhNoPredictiveText
onTextChanged: checkValid()
}
}
}
Component.onCompleted: {
customwordstext.visible = wizard_data['seed_extend']
}
}

View File

@@ -9,13 +9,12 @@ import "../controls"
WizardComponent {
securePage: true
valid: seedtext.text != '' && extendcb.checked ? customwordstext.text != '' : true
valid: seedtext.text != ''
function apply() {
wizard_data['seed'] = seedtext.text
wizard_data['seed_variant'] = 'electrum' // generated seed always electrum variant
wizard_data['seed_extend'] = extendcb.checked
wizard_data['seed_extra_words'] = extendcb.checked ? customwordstext.text : ''
wizard_data['seed_extend'] = true // true so we get forwarded to the passphrase page
}
function setWarningText(numwords) {
@@ -70,20 +69,6 @@ WizardComponent {
}
}
ElCheckBox {
id: extendcb
Layout.fillWidth: true
text: qsTr('Extend seed with custom words')
}
TextField {
id: customwordstext
visible: extendcb.checked
Layout.fillWidth: true
placeholderText: qsTr('Enter your custom word(s)')
inputMethodHints: Qt.ImhNoPredictiveText
}
Component.onCompleted : {
setWarningText(12)
}

View File

@@ -0,0 +1,119 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import QtQuick.Controls.Material
import org.electrum 1.0
import "../controls"
WizardComponent {
id: root
securePage: true
valid: true
property int cosigner: 0
function apply() {
var seed_extend = extendcb.checked
if (cosigner) {
wizard_data['multisig_cosigner_data'][cosigner.toString()]['seed_extend'] = seed_extend
wizard_data['multisig_cosigner_data'][cosigner.toString()]['seed_extra_words'] = seed_extend ? customwordstext.text : ''
} else {
wizard_data['seed_extend'] = seed_extend
wizard_data['seed_extra_words'] = seed_extend ? customwordstext.text : ''
}
}
function checkValid() {
valid = false
validationtext.text = ''
if (extendcb.checked && customwordstext.text == '') {
return
} else {
// passphrase is either disabled or filled with text
apply()
if (cosigner && wizard_data['multisig_cosigner_data'][cosigner.toString()]['seed_variant'] == 'electrum') {
// check if master keys are not duplicated after entering passphrase
if (wiz.hasDuplicateMasterKeys(wizard_data)) {
validationtext.text = qsTr('Error: duplicate master public key')
return
}
}
}
valid = true
}
Flickable {
anchors.fill: parent
contentHeight: mainLayout.height
clip: true
interactive: height < contentHeight
ColumnLayout {
id: mainLayout
width: parent.width
spacing: constants.paddingLarge
InfoTextArea {
id: validationtext
Layout.fillWidth: true
Layout.columnSpan: 2
visible: text
iconStyle: InfoTextArea.IconStyle.Error
}
Label {
Layout.fillWidth: true
wrapMode: Text.Wrap
text: [
qsTr('You may extend your seed with custom words.'),
qsTr('Your seed extension must be saved together with your seed.'),
qsTr('Note that this is NOT your encryption password.'),
'<br/>',
qsTr('Do not enable it unless you know what it does!'),
].join(' ')
}
ElCheckBox {
id: extendcb
Layout.columnSpan: 2
Layout.fillWidth: true
text: qsTr('Extend seed with custom words')
onCheckedChanged: checkValid()
}
TextField {
id: customwordstext
enabled: extendcb.checked
Layout.fillWidth: true
Layout.columnSpan: 2
placeholderText: qsTr('Enter your custom word(s)')
inputMethodHints: Qt.ImhSensitiveData | Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase
onTextChanged: startValidationTimer()
}
}
}
function startValidationTimer() {
valid = false
validationTimer.restart()
}
Timer {
id: validationTimer
interval: 250
repeat: false
onTriggered: checkValid()
}
Component.onCompleted: {
if (wizard_data['wallet_type'] == 'multisig') {
if ('multisig_current_cosigner' in wizard_data)
cosigner = wizard_data['multisig_current_cosigner']
}
checkValid()
}
}

View File

@@ -24,19 +24,16 @@ WizardComponent {
property bool _seedValid
function apply() {
var seed_extend = extendcb.checked && _canPassphrase
if (cosigner) {
wizard_data['multisig_cosigner_data'][cosigner.toString()]['seed'] = seedtext.text
wizard_data['multisig_cosigner_data'][cosigner.toString()]['seed_variant'] = seed_variant_cb.currentValue
wizard_data['multisig_cosigner_data'][cosigner.toString()]['seed_type'] = _seedType
wizard_data['multisig_cosigner_data'][cosigner.toString()]['seed_extend'] = seed_extend
wizard_data['multisig_cosigner_data'][cosigner.toString()]['seed_extra_words'] = seed_extend ? customwordstext.text : ''
wizard_data['multisig_cosigner_data'][cosigner.toString()]['seed_extend'] = _canPassphrase
} else {
wizard_data['seed'] = seedtext.text
wizard_data['seed_variant'] = seed_variant_cb.currentValue
wizard_data['seed_type'] = _seedType
wizard_data['seed_extend'] = seed_extend
wizard_data['seed_extra_words'] = seed_extend ? customwordstext.text : ''
wizard_data['seed_extend'] = _canPassphrase
// determine script type from electrum seed type
// (used to limit script type options for bip39 cosigners)
@@ -52,22 +49,20 @@ WizardComponent {
function setSeedTypeHelpText() {
var t = {
'electrum': [
// not shown as electrum is the default seed type anyways and the name is self-explanatory
qsTr('Electrum seeds are the default seed type.'),
qsTr('If you are restoring from a seed previously created by Electrum, choose this option')
].join(' '),
'bip39': [
qsTr('BIP39 seeds can be imported in Electrum, so that users can access funds locked in other wallets.'),
'<br/><br/>',
qsTr('However, we do not generate BIP39 seeds, because they do not meet our safety standard.'),
qsTr('BIP39 seeds do not include a version number, which compromises compatibility with future software.')
qsTr('BIP39 seeds do not include a version number, which compromises compatibility with future software.'),
].join(' '),
'slip39': [
qsTr('SLIP39 seeds can be imported in Electrum, so that users can access funds locked in other wallets.'),
'<br/><br/>',
qsTr('However, we do not generate SLIP39 seeds.')
].join(' ')
}
infotext.text = t[seed_variant_cb.currentValue]
infotext.visible = !cosigner && !is2fa && seed_variant_cb.currentValue != 'electrum'
}
function checkValid() {
@@ -100,11 +95,6 @@ WizardComponent {
}
}
if (_canPassphrase && extendcb.checked && customwordstext.text == '') {
valid = false
return
}
valid = _seedValid
}
@@ -196,7 +186,6 @@ WizardComponent {
InfoTextArea {
id: infotext
visible: !cosigner && !is2fa
Layout.fillWidth: true
Layout.columnSpan: 2
Layout.bottomMargin: constants.paddingLarge
@@ -221,26 +210,6 @@ WizardComponent {
startValidationTimer()
}
}
ElCheckBox {
id: extendcb
Layout.columnSpan: 2
Layout.fillWidth: true
visible: _canPassphrase
text: qsTr('Extend seed with custom words')
onCheckedChanged: startValidationTimer()
}
TextField {
id: customwordstext
visible: extendcb.checked && extendcb.visible
Layout.fillWidth: true
Layout.columnSpan: 2
placeholderText: qsTr('Enter your custom word(s)')
inputMethodHints: Qt.ImhNoPredictiveText
onTextChanged: startValidationTimer()
}
}
}

View File

@@ -68,14 +68,18 @@ class QENewWalletWizard(NewWalletWizard, QEAbstractWizard):
'wallet_type': {'gui': 'WCWalletType'},
'keystore_type': {'gui': 'WCKeystoreType'},
'create_seed': {'gui': 'WCCreateSeed'},
'create_ext': {'gui': 'WCEnterExt'},
'confirm_seed': {'gui': 'WCConfirmSeed'},
'confirm_ext': {'gui': 'WCConfirmExt'},
'have_seed': {'gui': 'WCHaveSeed'},
'have_ext': {'gui': 'WCEnterExt'},
'script_and_derivation': {'gui': 'WCScriptAndDerivation'},
'have_master_key': {'gui': 'WCHaveMasterKey'},
'multisig': {'gui': 'WCMultisig'},
'multisig_cosigner_keystore': {'gui': 'WCCosignerKeystore'},
'multisig_cosigner_key': {'gui': 'WCHaveMasterKey'},
'multisig_cosigner_seed': {'gui': 'WCHaveSeed'},
'multisig_cosigner_have_ext': {'gui': 'WCEnterExt'},
'multisig_cosigner_script_and_derivation': {'gui': 'WCScriptAndDerivation'},
'imported': {'gui': 'WCImport'},
'wallet_password': {'gui': 'WCWalletPassword'}

View File

@@ -333,7 +333,7 @@ class KeystoreWizard(AbstractWizard):
def keystore_from_data(self, wallet_type: str, data: dict):
if data['keystore_type'] in ['createseed', 'haveseed'] and 'seed' in data:
seed_extension = data['seed_extra_words'] if data['seed_extend'] else ''
seed_extension = data.get('seed_extra_words', '')
if data['seed_variant'] == 'electrum':
for_multisig = wallet_type in ['multisig']
return keystore.from_seed(data['seed'], passphrase=seed_extension, for_multisig=for_multisig)