1pragma ComponentBehavior: Bound
8import QGroundControl.Controls
11 id: _signingKeyManager
13 Layout.fillWidth: true
14 heading: qsTr("MAVLink 2 Signing")
15 headingDescription: qsTr("Signing keys should only be sent to the vehicle over secure links (e.g. USB).")
17 property Vehicle _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
19 // Wipe clipboard 30s after Export so a casually-copied key doesn't linger across paste targets.
21 id: clipboardWipeTimer
24 onTriggered: QGroundControl.copyToClipboard("")
27 QGCPopupDialogFactory {
28 id: addKeyDialogFactory
29 dialogComponent: addKeyDialogComponent
33 id: addKeyDialogComponent
37 title: qsTr("Add Signing Key")
38 buttons: Dialog.Ok | Dialog.Cancel
39 acceptButtonEnabled: keyNameField.text !== "" &&
40 (addKeyDialog.useRawKey
41 ? rawKeyField.text.length === 64
42 : passphraseField.text.length >= addKeyDialog._minPassphraseLength)
44 property bool useRawKey: false
45 readonly property int _minPassphraseLength: 8
49 if (addKeyDialog.useRawKey) {
50 ok = QGroundControl.mavlinkSigningKeys.addRawKey(keyNameField.text, rawKeyField.text)
52 ok = QGroundControl.mavlinkSigningKeys.addKey(keyNameField.text, passphraseField.text)
55 addKeyDialog.preventClose = true
56 errorLabel.text = qsTr("Could not add key. Name may already exist or input is invalid.")
61 spacing: ScreenTools.defaultFontPixelHeight / 2
63 QGCLabel { text: qsTr("Key Name") }
66 Layout.fillWidth: true
67 Layout.preferredWidth: ScreenTools.defaultFontPixelWidth * 30
68 placeholderText: qsTr("Enter a friendly name")
72 spacing: ScreenTools.defaultFontPixelWidth
75 text: qsTr("Passphrase")
76 checked: !addKeyDialog.useRawKey
77 onClicked: addKeyDialog.useRawKey = false
80 text: qsTr("Raw Key (hex)")
81 checked: addKeyDialog.useRawKey
82 onClicked: addKeyDialog.useRawKey = true
88 visible: !addKeyDialog.useRawKey
89 Layout.fillWidth: true
90 Layout.preferredWidth: ScreenTools.defaultFontPixelWidth * 30
91 placeholderText: qsTr("Enter passphrase (min %1 chars)").arg(addKeyDialog._minPassphraseLength)
92 echoMode: TextInput.Password
93 inputMethodHints: Qt.ImhNoPredictiveText
97 visible: !addKeyDialog.useRawKey && passphraseField.text.length > 0 && passphraseField.text.length < addKeyDialog._minPassphraseLength
98 text: qsTr("Passphrase too short (%1/%2)").arg(passphraseField.text.length).arg(addKeyDialog._minPassphraseLength)
99 color: QGroundControl.globalPalette.warningText
100 font.pointSize: ScreenTools.smallFontPointSize
104 visible: addKeyDialog.useRawKey
105 spacing: ScreenTools.defaultFontPixelWidth / 2
109 Layout.fillWidth: true
110 Layout.preferredWidth: ScreenTools.defaultFontPixelWidth * 30
111 placeholderText: qsTr("64 hex characters")
113 inputMethodHints: Qt.ImhNoPredictiveText
114 validator: RegularExpressionValidator { regularExpression: /[0-9a-fA-F]*/ }
118 text: qsTr("Generate")
119 onClicked: rawKeyField.text = QGroundControl.mavlinkSigningKeys.generateRandomHexKey()
124 visible: addKeyDialog.useRawKey && rawKeyField.text.length > 0 && rawKeyField.text.length !== 64
125 text: qsTr("%1/64 hex characters").arg(rawKeyField.text.length)
126 color: QGroundControl.globalPalette.warningText
127 font.pointSize: ScreenTools.smallFontPointSize
133 color: QGroundControl.globalPalette.warningText
134 font.pointSize: ScreenTools.smallFontPointSize
135 Layout.fillWidth: true
136 wrapMode: Text.WordWrap
143 Layout.fillWidth: true
144 label: qsTr("Active Key")
145 labelText: _signingKeyManager._activeVehicle && _signingKeyManager._activeVehicle.signingController.signingStatus.keyName !== ""
146 ? _signingKeyManager._activeVehicle.signingController.signingStatus.keyName
148 visible: _signingKeyManager._activeVehicle
152 model: QGroundControl.mavlinkSigningKeys.keys
156 Layout.fillWidth: true
157 spacing: ScreenTools.defaultFontPixelWidth
159 required property var object
160 required property int index
162 property string _keyName: keyDelegate.object.name
163 property bool _keyIsActive: { void(QGroundControl.mavlinkSigningKeys.keyUsageRevision); return QGroundControl.mavlinkSigningKeys.isKeyInUse(keyDelegate._keyName) }
164 property bool _keyIsActiveVehicle: _signingKeyManager._activeVehicle && _signingKeyManager._activeVehicle.signingController.signingStatus.keyName === keyDelegate._keyName
165 property bool _anyKeyActive: _signingKeyManager._activeVehicle && _signingKeyManager._activeVehicle.signingController.signingStatus.keyName !== ""
166 property bool _otherKeyActive: keyDelegate._anyKeyActive && !keyDelegate._keyIsActiveVehicle
167 property bool _signingPending: _signingKeyManager._activeVehicle && _signingKeyManager._activeVehicle.signingController.signingStatus.pending
170 text: keyDelegate._keyName
171 Layout.fillWidth: true
174 // Quiet hint when a different key on this vehicle is the active one — explains why
175 // Enable/Disable are both hidden on this row.
177 text: qsTr("(another key active)")
178 visible: keyDelegate._otherKeyActive
179 font.pointSize: ScreenTools.smallFontPointSize
184 text: keyDelegate._signingPending ? qsTr("Configuring…") : qsTr("Enable")
185 visible: !keyDelegate._anyKeyActive
186 enabled: _signingKeyManager._activeVehicle && !keyDelegate._signingPending
188 if (!_signingKeyManager._activeVehicle) {
191 const linkName = _signingKeyManager._activeVehicle.vehicleLinkManager
192 ? _signingKeyManager._activeVehicle.vehicleLinkManager.primaryLinkName
193 : qsTr("active link")
194 QGroundControl.showMessageDialog(
196 qsTr("Send Signing Key"),
197 qsTr("This will transmit key '%1' to the vehicle over '%2'. Only proceed if this link is secure (USB or trusted local network).").arg(keyDelegate._keyName).arg(linkName),
198 Dialog.Ok | Dialog.Cancel,
200 if (_signingKeyManager._activeVehicle) {
201 _signingKeyManager._activeVehicle.signingController.enable(keyDelegate._keyName)
208 text: keyDelegate._signingPending ? qsTr("Disabling…") : qsTr("Disable")
209 visible: keyDelegate._keyIsActiveVehicle
210 enabled: _signingKeyManager._activeVehicle && !keyDelegate._signingPending
212 if (!_signingKeyManager._activeVehicle) {
215 // ArduPilot refuses SETUP_SIGNING while armed; disabling a flying vehicle leaves GCS unsigned vs. signed-required.
216 if (_signingKeyManager._activeVehicle.armed) {
217 QGroundControl.showMessageDialog(
219 qsTr("Disable Signing While Armed?"),
220 qsTr("Vehicle is armed. ArduPilot will refuse to disable signing while armed and PX4 will not accept the disable packet without a valid signature. The disable attempt will likely time out and leave the link in an inconsistent state.\n\nDisarm the vehicle first."),
224 _signingKeyManager._activeVehicle.signingController.disable()
230 visible: !keyDelegate._keyIsActive
232 let hex = QGroundControl.mavlinkSigningKeys.keyHexByName(keyDelegate._keyName)
234 QGroundControl.copyToClipboard(hex)
235 clipboardWipeTimer.restart()
236 QGroundControl.showMessageDialog(
238 qsTr("Export Key: %1").arg(keyDelegate._keyName),
239 qsTr("Key copied to clipboard. Store it securely — it will be cleared from the clipboard in 30 seconds."),
247 visible: !keyDelegate._keyIsActive
248 onClicked: QGroundControl.showMessageDialog(
250 qsTr("Delete Signing Key"),
251 qsTr("Are you sure you want to delete '%1'?\n\nIf a vehicle still has this key configured, you will no longer be able to communicate with it over a signed connection. Raw or generated keys cannot be recovered — Export the hex first if you may need it later.").arg(keyDelegate._keyName),
252 Dialog.Ok | Dialog.Cancel,
253 function () { QGroundControl.mavlinkSigningKeys.removeKey(keyDelegate._keyName) })
259 text: qsTr("No keys configured")
260 visible: QGroundControl.mavlinkSigningKeys.keys.count === 0
264 text: qsTr("Add Key")
265 onClicked: addKeyDialogFactory.open()