mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-05 21:15:38 -05:00
polkit: support for polkit escalation prompts
This commit is contained in:
@@ -213,6 +213,10 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PolkitAuthModal {
|
||||||
|
id: polkitAuthModal
|
||||||
|
}
|
||||||
|
|
||||||
property string lastCredentialsToken: ""
|
property string lastCredentialsToken: ""
|
||||||
property var lastCredentialsTime: 0
|
property var lastCredentialsTime: 0
|
||||||
|
|
||||||
|
|||||||
283
Modals/PolkitAuthModal.qml
Normal file
283
Modals/PolkitAuthModal.qml
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
import QtQuick
|
||||||
|
import qs.Common
|
||||||
|
import qs.Modals.Common
|
||||||
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
|
DankModal {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string passwordInput: ""
|
||||||
|
|
||||||
|
function show() {
|
||||||
|
passwordInput = ""
|
||||||
|
open()
|
||||||
|
Qt.callLater(() => {
|
||||||
|
if (contentLoader.item && contentLoader.item.passwordField) {
|
||||||
|
contentLoader.item.passwordField.forceActiveFocus()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldBeVisible: false
|
||||||
|
width: 420
|
||||||
|
height: contentLoader.item ? contentLoader.item.implicitHeight + Theme.spacingM * 2 : 240
|
||||||
|
|
||||||
|
onShouldBeVisibleChanged: () => {
|
||||||
|
if (!shouldBeVisible) {
|
||||||
|
passwordInput = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onOpened: {
|
||||||
|
Qt.callLater(() => {
|
||||||
|
if (contentLoader.item && contentLoader.item.passwordField) {
|
||||||
|
contentLoader.item.passwordField.forceActiveFocus()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onBackgroundClicked: () => {
|
||||||
|
PolkitService.cancel()
|
||||||
|
close()
|
||||||
|
passwordInput = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: PolkitService
|
||||||
|
|
||||||
|
function onAuthenticationRequested() {
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
|
||||||
|
function onAuthenticationCompleted() {
|
||||||
|
close()
|
||||||
|
passwordInput = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
function onIsResponseRequiredChanged() {
|
||||||
|
if (PolkitService.isResponseRequired && root.shouldBeVisible) {
|
||||||
|
passwordInput = ""
|
||||||
|
if (contentLoader.item && contentLoader.item.passwordField) {
|
||||||
|
contentLoader.item.passwordField.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
content: Component {
|
||||||
|
FocusScope {
|
||||||
|
id: authContent
|
||||||
|
|
||||||
|
property alias passwordField: passwordField
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
focus: true
|
||||||
|
implicitHeight: mainColumn.implicitHeight
|
||||||
|
|
||||||
|
Keys.onEscapePressed: event => {
|
||||||
|
PolkitService.cancel()
|
||||||
|
close()
|
||||||
|
passwordInput = ""
|
||||||
|
event.accepted = true
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: mainColumn
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.leftMargin: Theme.spacingM
|
||||||
|
anchors.rightMargin: Theme.spacingM
|
||||||
|
anchors.topMargin: Theme.spacingM
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width - 40
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: I18n.tr("Authentication Required")
|
||||||
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
|
color: Theme.surfaceText
|
||||||
|
font.weight: Font.Medium
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: PolkitService.message
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceTextMedium
|
||||||
|
width: parent.width
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
visible: PolkitService.supplementaryMessage !== ""
|
||||||
|
text: PolkitService.supplementaryMessage
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceTextMedium
|
||||||
|
width: parent.width
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
opacity: 0.8
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
visible: PolkitService.failed
|
||||||
|
text: I18n.tr("Authentication failed, please try again")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.error
|
||||||
|
width: parent.width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankActionButton {
|
||||||
|
iconName: "close"
|
||||||
|
iconSize: Theme.iconSize - 4
|
||||||
|
iconColor: Theme.surfaceText
|
||||||
|
onClicked: () => {
|
||||||
|
PolkitService.cancel()
|
||||||
|
close()
|
||||||
|
passwordInput = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: PolkitService.inputPrompt
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
width: parent.width
|
||||||
|
visible: PolkitService.inputPrompt !== ""
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: parent.width
|
||||||
|
height: 50
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Theme.surfaceHover
|
||||||
|
border.color: passwordField.activeFocus ? Theme.primary : Theme.outlineStrong
|
||||||
|
border.width: passwordField.activeFocus ? 2 : 1
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: () => {
|
||||||
|
passwordField.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankTextField {
|
||||||
|
id: passwordField
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
textColor: Theme.surfaceText
|
||||||
|
text: passwordInput
|
||||||
|
echoMode: PolkitService.responseVisible ? TextInput.Normal : TextInput.Password
|
||||||
|
placeholderText: I18n.tr("Password")
|
||||||
|
backgroundColor: "transparent"
|
||||||
|
enabled: root.shouldBeVisible
|
||||||
|
onTextEdited: () => {
|
||||||
|
passwordInput = text
|
||||||
|
}
|
||||||
|
onAccepted: () => {
|
||||||
|
if (passwordInput.length > 0) {
|
||||||
|
PolkitService.submit(passwordInput)
|
||||||
|
passwordInput = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: 40
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: Math.max(70, cancelText.contentWidth + Theme.spacingM * 2)
|
||||||
|
height: 36
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: cancelArea.containsMouse ? Theme.surfaceTextHover : "transparent"
|
||||||
|
border.color: Theme.surfaceVariantAlpha
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: cancelText
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: I18n.tr("Cancel")
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
font.weight: Font.Medium
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: cancelArea
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: () => {
|
||||||
|
PolkitService.cancel()
|
||||||
|
close()
|
||||||
|
passwordInput = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: Math.max(80, authText.contentWidth + Theme.spacingM * 2)
|
||||||
|
height: 36
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: authArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary
|
||||||
|
enabled: passwordInput.length > 0 || !PolkitService.isResponseRequired
|
||||||
|
opacity: enabled ? 1 : 0.5
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: authText
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: I18n.tr("Authenticate")
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.background
|
||||||
|
font.weight: Font.Medium
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: authArea
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
enabled: parent.enabled
|
||||||
|
onClicked: () => {
|
||||||
|
PolkitService.submit(passwordInput)
|
||||||
|
passwordInput = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.standardEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
101
Services/PolkitService.qml
Normal file
101
Services/PolkitService.qml
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
pragma Singleton
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property bool disablePolkitIntegration: Quickshell.env("DMS_DISABLE_POLKIT") === "1"
|
||||||
|
|
||||||
|
property bool polkitAvailable: false
|
||||||
|
|
||||||
|
property var agent: null
|
||||||
|
property var currentFlow: null
|
||||||
|
property bool isActive: false
|
||||||
|
|
||||||
|
property string message: ""
|
||||||
|
property string supplementaryMessage: ""
|
||||||
|
property string inputPrompt: ""
|
||||||
|
property bool failed: false
|
||||||
|
property bool responseVisible: false
|
||||||
|
property bool isResponseRequired: false
|
||||||
|
|
||||||
|
signal authenticationRequested()
|
||||||
|
signal authenticationCompleted()
|
||||||
|
signal authenticationFailed()
|
||||||
|
|
||||||
|
function createPolkitAgent() {
|
||||||
|
try {
|
||||||
|
const qmlString = `
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell.Services.Polkit
|
||||||
|
|
||||||
|
PolkitAgent {
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
agent = Qt.createQmlObject(qmlString, root, "PolkitService.Agent")
|
||||||
|
|
||||||
|
agent.isActiveChanged.connect(function() {
|
||||||
|
root.isActive = agent.isActive
|
||||||
|
if (agent.isActive) {
|
||||||
|
root.authenticationRequested()
|
||||||
|
} else {
|
||||||
|
root.authenticationCompleted()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
agent.flowChanged.connect(function() {
|
||||||
|
currentFlow = agent.flow
|
||||||
|
if (currentFlow) {
|
||||||
|
updateFlowProperties()
|
||||||
|
|
||||||
|
if (currentFlow.messageChanged) currentFlow.messageChanged.connect(() => updateFlowProperties())
|
||||||
|
if (currentFlow.supplementaryMessageChanged) currentFlow.supplementaryMessageChanged.connect(() => updateFlowProperties())
|
||||||
|
if (currentFlow.inputPromptChanged) currentFlow.inputPromptChanged.connect(() => updateFlowProperties())
|
||||||
|
if (currentFlow.failedChanged) currentFlow.failedChanged.connect(() => updateFlowProperties())
|
||||||
|
if (currentFlow.responseVisibleChanged) currentFlow.responseVisibleChanged.connect(() => updateFlowProperties())
|
||||||
|
if (currentFlow.isResponseRequiredChanged) currentFlow.isResponseRequiredChanged.connect(() => updateFlowProperties())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
polkitAvailable = true
|
||||||
|
console.info("PolkitService: Initialized successfully")
|
||||||
|
} catch (e) {
|
||||||
|
polkitAvailable = false
|
||||||
|
console.warn("PolkitService: Polkit not available - authentication prompts disabled. This requires a newer version of Quickshell.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateFlowProperties() {
|
||||||
|
if (!currentFlow) return
|
||||||
|
|
||||||
|
message = currentFlow.message !== undefined ? currentFlow.message : ""
|
||||||
|
supplementaryMessage = currentFlow.supplementaryMessage !== undefined ? currentFlow.supplementaryMessage : ""
|
||||||
|
inputPrompt = currentFlow.inputPrompt !== undefined ? currentFlow.inputPrompt : ""
|
||||||
|
failed = currentFlow.failed !== undefined ? currentFlow.failed : false
|
||||||
|
responseVisible = currentFlow.responseVisible !== undefined ? currentFlow.responseVisible : false
|
||||||
|
isResponseRequired = currentFlow.isResponseRequired !== undefined ? currentFlow.isResponseRequired : false
|
||||||
|
}
|
||||||
|
|
||||||
|
function submit(response) {
|
||||||
|
if (currentFlow && isResponseRequired) {
|
||||||
|
currentFlow.submit(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancel() {
|
||||||
|
if (currentFlow) {
|
||||||
|
currentFlow.cancelAuthenticationRequest()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
if (disablePolkitIntegration) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
createPolkitAgent()
|
||||||
|
}
|
||||||
|
}
|
||||||
40
assets/danklogo.svg
Normal file
40
assets/danklogo.svg
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="500px" height="500px" viewBox="0 0 500 500" enable-background="new 0 0 500 500" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="#808080" d="M151.583,133.43c-1.255,1.946,0.646,1.946,5.704,0C155.385,133.43,153.484,133.43,151.583,133.43z"/>
|
||||||
|
<path fill="#808080" d="M423.762,406.435C351.624,511.72,195.549,530.36,100.813,443.681
|
||||||
|
c-29.726-27.249-61.828-70.379-45.267-112.843c9.16-23.487,37.102-24.426,57.716-32.065
|
||||||
|
c27.527-10.201,54.303-25.636,71.783-49.842c1.823,22.976,23.814,52.576,33.269,73.388c9.772,21.51,19.334,43.117,28.757,64.783
|
||||||
|
c0.991-8.282,16.502-92.821-14.752-76.345c19.458-21.14,35.548-31.5,54.594,0.311c-2.329-1.542-4.659-3.084-6.988-4.625
|
||||||
|
c-13.702,28.822,6.996,68.66,14.663,97.275c-0.159-44.012,1.277-88.943-3.305-132.758c25.284,18.425,52.786,29.832,81.891,41.012
|
||||||
|
C411.181,326.572,412.863,370.402,423.762,406.435C416.231,417.427,422.675,402.841,423.762,406.435z"/>
|
||||||
|
<path fill="#808080" d="M141.639,217.359c-1.449,30.049-3.187,60.252-7.215,90.078c-1.049,7.765-10.07,31.329,4.856,29.922
|
||||||
|
c5.631-0.531,26.431-6.722,28.324-12.94c7.661-25.155,15.321-50.31,22.982-75.465
|
||||||
|
C194.325,236.673,152.531,222.984,141.639,217.359z"/>
|
||||||
|
<path fill="#808080" d="M151.583,133.43c-1.255,1.946,0.646,1.946,5.704,0C155.385,133.43,153.484,133.43,151.583,133.43z"/>
|
||||||
|
<path fill="#808080" d="M380.027,190.172c2.551-3.381,12.116-35.014,7.979-40.841c-21.139-9.962-38.084,1.086-58.839,0.144
|
||||||
|
c-28.481-1.292-52.16-10.216-82.194-5.857c-20.152,2.925-40.476,6.822-59.248,14.892c-5.085,2.171-33.296,22.994-33.035,23.122
|
||||||
|
c-14.027-6.836,43.648-35.195,48.133-36.619c33.084-10.501,67.297-12.315,101.608-15.552c25.236-2.379,54.641-1.008,78.47-11.112
|
||||||
|
c16.618-7.047,20.647-25.35,3.137-33.427c-22.945-10.585-53.247,1.025-64.749-21.947c-9.865-19.703-19.126-50.833-42.862-57.923
|
||||||
|
c-36.643-10.945-98.407,4.036-125.468,30.683c-14.664,14.44-12.628,32.211-13.789,51.294c-0.771,12.674,2.771,18.959-9.236,22.648
|
||||||
|
c-11.996,3.686-35.259,9.105-41.089,21.843c-9.907,21.645,60.404,18.041,70.524,17.445
|
||||||
|
c-48.116,78.556,9.309,154.103,95.828,138.485c21.662-3.91,46.538-11.144,63.301-26.06c14.268-12.696,18.851-26.329,38.884-31.764
|
||||||
|
c22.88-6.207,48.618-2.853,71.213,3.225C425.427,211.414,397.813,197.701,380.027,190.172z M147.943,113.559
|
||||||
|
c32.398-5.478,64.75-11.227,97.122-16.857c18.865-3.281,37.73-6.561,56.594-9.842c2.704-0.47,37.591-8.61,26.975,6.476
|
||||||
|
c-8.441,11.996-61.367,8.371-74.078,9.64C219.023,106.522,183.499,110.243,147.943,113.559
|
||||||
|
C162.475,111.102,162.63,112.189,147.943,113.559z M370.763,155.911c8.064,4.793,6.789,19.245,0,26.465
|
||||||
|
C372.129,173.756,372.669,164.493,370.763,155.911z M300.604,159.526c19.572-0.816,8.747,23.495-2.02,28.95
|
||||||
|
C303.101,186.108,301.518,163.22,300.604,159.526z M284.787,217.004c-13.756-0.207-27.836-4.341-34.89-17.079
|
||||||
|
c-3.743-6.76-3.246-24.814-13.996-23.708c-17.975,1.85-35.949,3.701-53.924,5.551c17.165-8.213,32.693-15.006,51.887-17.165
|
||||||
|
c24.854-2.796,13.115,15.487,25.149,31.147c14.31,18.621,50.25,11.317,61.727-7.041c2.807-4.491,3.5-9.537,5.626-14.35
|
||||||
|
c9.82-22.233,13.955,4.169,18.087,9.218c-10.884-13.363-14.883,7.391-19.096,13.609
|
||||||
|
C316.276,210.59,300.73,217.253,284.787,217.004C252.941,216.524,316.35,217.498,284.787,217.004z M327.761,210.296
|
||||||
|
c11.885-7.741,12.4-23.74,26.261-19.392c19.134,6.002,40.641,14.199,54.49,29.334
|
||||||
|
C382.501,213.437,354.709,208.449,327.761,210.296z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.7 KiB |
Reference in New Issue
Block a user