mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-28 15:32:50 -05:00
vpn: attempt to support pkcs11 prompts
This commit is contained in:
@@ -282,111 +282,33 @@ func (b *NetworkManagerBackend) ConnectVPN(uuidOrName string, singleActive bool)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
needsUsernamePrePrompt := false
|
|
||||||
var vpnServiceType string
|
var vpnServiceType string
|
||||||
|
var vpnData map[string]string
|
||||||
if vpnSettings, ok := targetSettings["vpn"]; ok {
|
if vpnSettings, ok := targetSettings["vpn"]; ok {
|
||||||
if svc, ok := vpnSettings["service-type"].(string); ok {
|
if svc, ok := vpnSettings["service-type"].(string); ok {
|
||||||
vpnServiceType = svc
|
vpnServiceType = svc
|
||||||
}
|
}
|
||||||
if data, ok := vpnSettings["data"].(map[string]string); ok {
|
if data, ok := vpnSettings["data"].(map[string]string); ok {
|
||||||
connType := data["connection-type"]
|
vpnData = data
|
||||||
username := data["username"]
|
|
||||||
// OpenVPN password auth needs username in vpn.data
|
|
||||||
if strings.Contains(vpnServiceType, "openvpn") &&
|
|
||||||
(connType == "password" || connType == "password-tls") &&
|
|
||||||
username == "" {
|
|
||||||
needsUsernamePrePrompt = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If username is needed but missing, prompt for it before activating
|
authAction := detectVPNAuthAction(vpnServiceType, vpnData)
|
||||||
if needsUsernamePrePrompt && b.promptBroker != nil {
|
|
||||||
log.Infof("[ConnectVPN] OpenVPN requires username in vpn.data - prompting before activation")
|
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
switch authAction {
|
||||||
defer cancel()
|
case "pkcs11_pin":
|
||||||
|
if b.promptBroker == nil {
|
||||||
token, err := b.promptBroker.Ask(ctx, PromptRequest{
|
return fmt.Errorf("PKCS11 authentication requires interactive prompt")
|
||||||
Name: connName,
|
|
||||||
ConnType: "vpn",
|
|
||||||
VpnService: vpnServiceType,
|
|
||||||
SettingName: "vpn",
|
|
||||||
Fields: []string{"username", "password"},
|
|
||||||
FieldsInfo: []FieldInfo{{Name: "username", Label: "Username", IsSecret: false}, {Name: "password", Label: "Password", IsSecret: true}},
|
|
||||||
Reason: "required",
|
|
||||||
ConnectionId: connName,
|
|
||||||
ConnectionUuid: targetUUID,
|
|
||||||
ConnectionPath: string(targetConn.GetPath()),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to request credentials: %w", err)
|
|
||||||
}
|
}
|
||||||
|
if err := b.handlePKCS11Auth(targetConn, connName, targetUUID, vpnServiceType); err != nil {
|
||||||
reply, err := b.promptBroker.Wait(ctx, token)
|
return err
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("credentials prompt failed: %w", err)
|
|
||||||
}
|
}
|
||||||
|
case "openvpn_username":
|
||||||
username := reply.Secrets["username"]
|
if b.promptBroker == nil {
|
||||||
password := reply.Secrets["password"]
|
return fmt.Errorf("OpenVPN password authentication requires interactive prompt")
|
||||||
if username != "" {
|
}
|
||||||
connObj := b.dbusConn.Object("org.freedesktop.NetworkManager", targetConn.GetPath())
|
if err := b.handleOpenVPNUsernameAuth(targetConn, connName, targetUUID, vpnServiceType); err != nil {
|
||||||
var existingSettings map[string]map[string]dbus.Variant
|
return err
|
||||||
if err := connObj.Call("org.freedesktop.NetworkManager.Settings.Connection.GetSettings", 0).Store(&existingSettings); err != nil {
|
|
||||||
return fmt.Errorf("failed to get settings for username save: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
settings := make(map[string]map[string]dbus.Variant)
|
|
||||||
if connSection, ok := existingSettings["connection"]; ok {
|
|
||||||
settings["connection"] = connSection
|
|
||||||
}
|
|
||||||
vpn := existingSettings["vpn"]
|
|
||||||
var data map[string]string
|
|
||||||
if dataVariant, ok := vpn["data"]; ok {
|
|
||||||
if dm, ok := dataVariant.Value().(map[string]string); ok {
|
|
||||||
data = make(map[string]string)
|
|
||||||
for k, v := range dm {
|
|
||||||
data[k] = v
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
data = make(map[string]string)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
data = make(map[string]string)
|
|
||||||
}
|
|
||||||
data["username"] = username
|
|
||||||
|
|
||||||
if reply.Save && password != "" {
|
|
||||||
data["password-flags"] = "0"
|
|
||||||
secs := make(map[string]string)
|
|
||||||
secs["password"] = password
|
|
||||||
vpn["secrets"] = dbus.MakeVariant(secs)
|
|
||||||
log.Infof("[ConnectVPN] Saving username and password to vpn.data")
|
|
||||||
} else {
|
|
||||||
log.Infof("[ConnectVPN] Saving username to vpn.data (password will be prompted)")
|
|
||||||
}
|
|
||||||
|
|
||||||
vpn["data"] = dbus.MakeVariant(data)
|
|
||||||
settings["vpn"] = vpn
|
|
||||||
|
|
||||||
var result map[string]dbus.Variant
|
|
||||||
if err := connObj.Call("org.freedesktop.NetworkManager.Settings.Connection.Update2", 0,
|
|
||||||
settings, uint32(0x1), map[string]dbus.Variant{}).Store(&result); err != nil {
|
|
||||||
return fmt.Errorf("failed to save username: %w", err)
|
|
||||||
}
|
|
||||||
log.Infof("[ConnectVPN] Username saved to connection, now activating")
|
|
||||||
|
|
||||||
if password != "" && !reply.Save {
|
|
||||||
b.cachedVPNCredsMu.Lock()
|
|
||||||
b.cachedVPNCreds = &cachedVPNCredentials{
|
|
||||||
ConnectionUUID: targetUUID,
|
|
||||||
Password: password,
|
|
||||||
SavePassword: reply.Save,
|
|
||||||
}
|
|
||||||
b.cachedVPNCredsMu.Unlock()
|
|
||||||
log.Infof("[ConnectVPN] Cached password for GetSecrets")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,6 +339,201 @@ func (b *NetworkManagerBackend) ConnectVPN(uuidOrName string, singleActive bool)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func detectVPNAuthAction(serviceType string, data map[string]string) string {
|
||||||
|
if data == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case strings.Contains(serviceType, "openconnect"):
|
||||||
|
authType := data["authtype"]
|
||||||
|
userCert := data["usercert"]
|
||||||
|
if authType == "cert" && strings.HasPrefix(userCert, "pkcs11:") {
|
||||||
|
return "pkcs11_pin"
|
||||||
|
}
|
||||||
|
case strings.Contains(serviceType, "openvpn"):
|
||||||
|
connType := data["connection-type"]
|
||||||
|
username := data["username"]
|
||||||
|
if (connType == "password" || connType == "password-tls") && username == "" {
|
||||||
|
return "openvpn_username"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *NetworkManagerBackend) handlePKCS11Auth(targetConn gonetworkmanager.Connection, connName, targetUUID, vpnServiceType string) error {
|
||||||
|
log.Infof("[ConnectVPN] PKCS11 authentication detected - prompting for PIN")
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
token, err := b.promptBroker.Ask(ctx, PromptRequest{
|
||||||
|
Name: connName,
|
||||||
|
ConnType: "vpn",
|
||||||
|
VpnService: vpnServiceType,
|
||||||
|
SettingName: "vpn",
|
||||||
|
Fields: []string{"key_pass"},
|
||||||
|
FieldsInfo: []FieldInfo{{Name: "key_pass", Label: "PIN", IsSecret: true}},
|
||||||
|
Reason: "pkcs11",
|
||||||
|
ConnectionId: connName,
|
||||||
|
ConnectionUuid: targetUUID,
|
||||||
|
ConnectionPath: string(targetConn.GetPath()),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to request PIN: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
reply, err := b.promptBroker.Wait(ctx, token)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("PIN prompt failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if reply.Cancel {
|
||||||
|
return fmt.Errorf("user cancelled PIN entry")
|
||||||
|
}
|
||||||
|
|
||||||
|
pin := reply.Secrets["key_pass"]
|
||||||
|
if pin == "" {
|
||||||
|
return fmt.Errorf("PIN required for PKCS11 authentication")
|
||||||
|
}
|
||||||
|
|
||||||
|
connObj := b.dbusConn.Object("org.freedesktop.NetworkManager", targetConn.GetPath())
|
||||||
|
var existingSettings map[string]map[string]dbus.Variant
|
||||||
|
if err := connObj.Call("org.freedesktop.NetworkManager.Settings.Connection.GetSettings", 0).Store(&existingSettings); err != nil {
|
||||||
|
return fmt.Errorf("failed to get settings: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
settings := make(map[string]map[string]dbus.Variant)
|
||||||
|
if connSection, ok := existingSettings["connection"]; ok {
|
||||||
|
settings["connection"] = connSection
|
||||||
|
}
|
||||||
|
|
||||||
|
vpn := existingSettings["vpn"]
|
||||||
|
var data map[string]string
|
||||||
|
if dataVariant, ok := vpn["data"]; ok {
|
||||||
|
if dm, ok := dataVariant.Value().(map[string]string); ok {
|
||||||
|
data = make(map[string]string)
|
||||||
|
for k, v := range dm {
|
||||||
|
data[k] = v
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data = make(map[string]string)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data = make(map[string]string)
|
||||||
|
}
|
||||||
|
data["key_pass"] = pin
|
||||||
|
|
||||||
|
vpn["data"] = dbus.MakeVariant(data)
|
||||||
|
settings["vpn"] = vpn
|
||||||
|
|
||||||
|
var result map[string]dbus.Variant
|
||||||
|
if err := connObj.Call("org.freedesktop.NetworkManager.Settings.Connection.Update2", 0,
|
||||||
|
settings, uint32(0x2), map[string]dbus.Variant{}).Store(&result); err != nil {
|
||||||
|
return fmt.Errorf("failed to set PIN: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("[ConnectVPN] PIN set (in-memory only)")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *NetworkManagerBackend) handleOpenVPNUsernameAuth(targetConn gonetworkmanager.Connection, connName, targetUUID, vpnServiceType string) error {
|
||||||
|
log.Infof("[ConnectVPN] OpenVPN requires username in vpn.data - prompting before activation")
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
token, err := b.promptBroker.Ask(ctx, PromptRequest{
|
||||||
|
Name: connName,
|
||||||
|
ConnType: "vpn",
|
||||||
|
VpnService: vpnServiceType,
|
||||||
|
SettingName: "vpn",
|
||||||
|
Fields: []string{"username", "password"},
|
||||||
|
FieldsInfo: []FieldInfo{{Name: "username", Label: "Username", IsSecret: false}, {Name: "password", Label: "Password", IsSecret: true}},
|
||||||
|
Reason: "required",
|
||||||
|
ConnectionId: connName,
|
||||||
|
ConnectionUuid: targetUUID,
|
||||||
|
ConnectionPath: string(targetConn.GetPath()),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to request credentials: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
reply, err := b.promptBroker.Wait(ctx, token)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("credentials prompt failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if reply.Cancel {
|
||||||
|
return fmt.Errorf("user cancelled authentication")
|
||||||
|
}
|
||||||
|
|
||||||
|
username := reply.Secrets["username"]
|
||||||
|
password := reply.Secrets["password"]
|
||||||
|
if username == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
connObj := b.dbusConn.Object("org.freedesktop.NetworkManager", targetConn.GetPath())
|
||||||
|
var existingSettings map[string]map[string]dbus.Variant
|
||||||
|
if err := connObj.Call("org.freedesktop.NetworkManager.Settings.Connection.GetSettings", 0).Store(&existingSettings); err != nil {
|
||||||
|
return fmt.Errorf("failed to get settings for username save: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
settings := make(map[string]map[string]dbus.Variant)
|
||||||
|
if connSection, ok := existingSettings["connection"]; ok {
|
||||||
|
settings["connection"] = connSection
|
||||||
|
}
|
||||||
|
vpn := existingSettings["vpn"]
|
||||||
|
var data map[string]string
|
||||||
|
if dataVariant, ok := vpn["data"]; ok {
|
||||||
|
if dm, ok := dataVariant.Value().(map[string]string); ok {
|
||||||
|
data = make(map[string]string)
|
||||||
|
for k, v := range dm {
|
||||||
|
data[k] = v
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data = make(map[string]string)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data = make(map[string]string)
|
||||||
|
}
|
||||||
|
data["username"] = username
|
||||||
|
|
||||||
|
if reply.Save && password != "" {
|
||||||
|
data["password-flags"] = "0"
|
||||||
|
secs := make(map[string]string)
|
||||||
|
secs["password"] = password
|
||||||
|
vpn["secrets"] = dbus.MakeVariant(secs)
|
||||||
|
log.Infof("[ConnectVPN] Saving username and password to vpn.data")
|
||||||
|
} else {
|
||||||
|
log.Infof("[ConnectVPN] Saving username to vpn.data (password will be prompted)")
|
||||||
|
}
|
||||||
|
|
||||||
|
vpn["data"] = dbus.MakeVariant(data)
|
||||||
|
settings["vpn"] = vpn
|
||||||
|
|
||||||
|
var result map[string]dbus.Variant
|
||||||
|
if err := connObj.Call("org.freedesktop.NetworkManager.Settings.Connection.Update2", 0,
|
||||||
|
settings, uint32(0x1), map[string]dbus.Variant{}).Store(&result); err != nil {
|
||||||
|
return fmt.Errorf("failed to save username: %w", err)
|
||||||
|
}
|
||||||
|
log.Infof("[ConnectVPN] Username saved to connection")
|
||||||
|
|
||||||
|
if password != "" && !reply.Save {
|
||||||
|
b.cachedVPNCredsMu.Lock()
|
||||||
|
b.cachedVPNCreds = &cachedVPNCredentials{
|
||||||
|
ConnectionUUID: targetUUID,
|
||||||
|
Password: password,
|
||||||
|
SavePassword: reply.Save,
|
||||||
|
}
|
||||||
|
b.cachedVPNCredsMu.Unlock()
|
||||||
|
log.Infof("[ConnectVPN] Cached password for GetSecrets")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (b *NetworkManagerBackend) DisconnectVPN(uuidOrName string) error {
|
func (b *NetworkManagerBackend) DisconnectVPN(uuidOrName string) error {
|
||||||
nm := b.nmConn.(gonetworkmanager.NetworkManager)
|
nm := b.nmConn.(gonetworkmanager.NetworkManager)
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ FloatingWindow {
|
|||||||
property string passwordInput: ""
|
property string passwordInput: ""
|
||||||
property var currentFlow: PolkitService.agent?.flow
|
property var currentFlow: PolkitService.agent?.flow
|
||||||
property bool isLoading: false
|
property bool isLoading: false
|
||||||
|
readonly property int inputFieldHeight: Theme.fontSizeMedium + Theme.spacingL * 2
|
||||||
property int calculatedHeight: Math.max(240, headerRow.implicitHeight + mainColumn.implicitHeight + Theme.spacingM * 3)
|
property int calculatedHeight: Math.max(240, headerRow.implicitHeight + mainColumn.implicitHeight + Theme.spacingM * 3)
|
||||||
|
|
||||||
function focusPasswordField() {
|
function focusPasswordField() {
|
||||||
@@ -202,7 +203,7 @@ FloatingWindow {
|
|||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 50
|
height: inputFieldHeight
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: Theme.surfaceHover
|
color: Theme.surfaceHover
|
||||||
border.color: passwordField.activeFocus ? Theme.primary : Theme.outlineStrong
|
border.color: passwordField.activeFocus ? Theme.primary : Theme.outlineStrong
|
||||||
|
|||||||
@@ -28,14 +28,29 @@ FloatingWindow {
|
|||||||
property var fieldsInfo: []
|
property var fieldsInfo: []
|
||||||
property var secretValues: ({})
|
property var secretValues: ({})
|
||||||
|
|
||||||
|
readonly property bool showUsernameField: requiresEnterprise && !isVpnPrompt && fieldsInfo.length === 0
|
||||||
|
readonly property bool showPasswordField: fieldsInfo.length === 0
|
||||||
|
readonly property bool showAnonField: requiresEnterprise && !isVpnPrompt
|
||||||
|
readonly property bool showDomainField: requiresEnterprise && !isVpnPrompt
|
||||||
|
readonly property bool showShowPasswordCheckbox: fieldsInfo.length === 0
|
||||||
|
readonly property bool showSavePasswordCheckbox: (isVpnPrompt || fieldsInfo.length > 0) && promptReason !== "pkcs11"
|
||||||
|
|
||||||
|
readonly property int inputFieldHeight: Theme.fontSizeMedium + Theme.spacingL * 2
|
||||||
|
readonly property int inputFieldWithSpacing: inputFieldHeight + Theme.spacingM
|
||||||
|
readonly property int checkboxRowHeight: Theme.fontSizeMedium + Theme.spacingS
|
||||||
|
readonly property int headerHeight: Theme.fontSizeLarge + Theme.fontSizeMedium + Theme.spacingM * 2
|
||||||
|
readonly property int buttonRowHeight: 36 + Theme.spacingM
|
||||||
|
|
||||||
property int calculatedHeight: {
|
property int calculatedHeight: {
|
||||||
if (fieldsInfo.length > 0)
|
let h = headerHeight + buttonRowHeight + Theme.spacingL * 2;
|
||||||
return 180 + (fieldsInfo.length * 60);
|
h += fieldsInfo.length * inputFieldWithSpacing;
|
||||||
if (requiresEnterprise)
|
if (showUsernameField) h += inputFieldWithSpacing;
|
||||||
return 430;
|
if (showPasswordField) h += inputFieldWithSpacing;
|
||||||
if (isVpnPrompt)
|
if (showAnonField) h += inputFieldWithSpacing;
|
||||||
return 260;
|
if (showDomainField) h += inputFieldWithSpacing;
|
||||||
return 230;
|
if (showShowPasswordCheckbox) h += checkboxRowHeight;
|
||||||
|
if (showSavePasswordCheckbox) h += checkboxRowHeight;
|
||||||
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
function focusFirstField() {
|
function focusFirstField() {
|
||||||
@@ -127,6 +142,7 @@ FloatingWindow {
|
|||||||
case "private-key-password":
|
case "private-key-password":
|
||||||
return I18n.tr("Private Key Password");
|
return I18n.tr("Private Key Password");
|
||||||
case "pin":
|
case "pin":
|
||||||
|
case "key_pass":
|
||||||
return I18n.tr("PIN");
|
return I18n.tr("PIN");
|
||||||
case "psk":
|
case "psk":
|
||||||
return I18n.tr("Password");
|
return I18n.tr("Password");
|
||||||
@@ -188,7 +204,13 @@ FloatingWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
objectName: "wifiPasswordModal"
|
objectName: "wifiPasswordModal"
|
||||||
title: isVpnPrompt ? I18n.tr("VPN Password") : I18n.tr("Wi-Fi Password")
|
title: {
|
||||||
|
if (promptReason === "pkcs11")
|
||||||
|
return I18n.tr("Smartcard PIN");
|
||||||
|
if (isVpnPrompt)
|
||||||
|
return I18n.tr("VPN Password");
|
||||||
|
return I18n.tr("Wi-Fi Password");
|
||||||
|
}
|
||||||
minimumSize: Qt.size(420, calculatedHeight)
|
minimumSize: Qt.size(420, calculatedHeight)
|
||||||
maximumSize: Qt.size(420, calculatedHeight)
|
maximumSize: Qt.size(420, calculatedHeight)
|
||||||
color: Theme.surfaceContainer
|
color: Theme.surfaceContainer
|
||||||
@@ -242,7 +264,7 @@ FloatingWindow {
|
|||||||
Column {
|
Column {
|
||||||
id: contentCol
|
id: contentCol
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
width: parent.width - Theme.spacingM * 2
|
width: parent.width - Theme.spacingL * 2
|
||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
@@ -260,7 +282,13 @@ FloatingWindow {
|
|||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: isVpnPrompt ? I18n.tr("Connect to VPN") : I18n.tr("Connect to Wi-Fi")
|
text: {
|
||||||
|
if (promptReason === "pkcs11")
|
||||||
|
return I18n.tr("Smartcard Authentication");
|
||||||
|
if (isVpnPrompt)
|
||||||
|
return I18n.tr("Connect to VPN");
|
||||||
|
return I18n.tr("Connect to Wi-Fi");
|
||||||
|
}
|
||||||
font.pixelSize: Theme.fontSizeLarge
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
@@ -272,6 +300,8 @@ FloatingWindow {
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: {
|
text: {
|
||||||
|
if (promptReason === "pkcs11")
|
||||||
|
return I18n.tr("Enter PIN for ") + wifiPasswordSSID;
|
||||||
if (fieldsInfo.length > 0)
|
if (fieldsInfo.length > 0)
|
||||||
return I18n.tr("Enter credentials for ") + wifiPasswordSSID;
|
return I18n.tr("Enter credentials for ") + wifiPasswordSSID;
|
||||||
if (isVpnPrompt)
|
if (isVpnPrompt)
|
||||||
@@ -325,7 +355,7 @@ FloatingWindow {
|
|||||||
required property int index
|
required property int index
|
||||||
|
|
||||||
width: contentCol.width
|
width: contentCol.width
|
||||||
height: 50
|
height: inputFieldHeight
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: Theme.surfaceHover
|
color: Theme.surfaceHover
|
||||||
border.color: fieldInput.activeFocus ? Theme.primary : Theme.outlineStrong
|
border.color: fieldInput.activeFocus ? Theme.primary : Theme.outlineStrong
|
||||||
@@ -388,12 +418,12 @@ FloatingWindow {
|
|||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 50
|
height: inputFieldHeight
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: Theme.surfaceHover
|
color: Theme.surfaceHover
|
||||||
border.color: usernameInput.activeFocus ? Theme.primary : Theme.outlineStrong
|
border.color: usernameInput.activeFocus ? Theme.primary : Theme.outlineStrong
|
||||||
border.width: usernameInput.activeFocus ? 2 : 1
|
border.width: usernameInput.activeFocus ? 2 : 1
|
||||||
visible: requiresEnterprise && !isVpnPrompt && fieldsInfo.length === 0
|
visible: showUsernameField
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -419,12 +449,12 @@ FloatingWindow {
|
|||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 50
|
height: inputFieldHeight
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: Theme.surfaceHover
|
color: Theme.surfaceHover
|
||||||
border.color: passwordInput.activeFocus ? Theme.primary : Theme.outlineStrong
|
border.color: passwordInput.activeFocus ? Theme.primary : Theme.outlineStrong
|
||||||
border.width: passwordInput.activeFocus ? 2 : 1
|
border.width: passwordInput.activeFocus ? 2 : 1
|
||||||
visible: fieldsInfo.length === 0
|
visible: showPasswordField
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -456,9 +486,9 @@ FloatingWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
visible: requiresEnterprise && !isVpnPrompt
|
visible: showAnonField
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 50
|
height: inputFieldHeight
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: Theme.surfaceHover
|
color: Theme.surfaceHover
|
||||||
border.color: anonInput.activeFocus ? Theme.primary : Theme.outlineStrong
|
border.color: anonInput.activeFocus ? Theme.primary : Theme.outlineStrong
|
||||||
@@ -487,9 +517,9 @@ FloatingWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
visible: requiresEnterprise && !isVpnPrompt
|
visible: showDomainField
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 50
|
height: inputFieldHeight
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: Theme.surfaceHover
|
color: Theme.surfaceHover
|
||||||
border.color: domainMatchInput.activeFocus ? Theme.primary : Theme.outlineStrong
|
border.color: domainMatchInput.activeFocus ? Theme.primary : Theme.outlineStrong
|
||||||
@@ -523,7 +553,7 @@ FloatingWindow {
|
|||||||
|
|
||||||
Row {
|
Row {
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
visible: fieldsInfo.length === 0
|
visible: showShowPasswordCheckbox
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: showPasswordCheckbox
|
id: showPasswordCheckbox
|
||||||
@@ -563,7 +593,7 @@ FloatingWindow {
|
|||||||
|
|
||||||
Row {
|
Row {
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
visible: isVpnPrompt || fieldsInfo.length > 0
|
visible: showSavePasswordCheckbox
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: savePasswordCheckbox
|
id: savePasswordCheckbox
|
||||||
|
|||||||
@@ -6677,6 +6677,18 @@
|
|||||||
"reference": "Modules/Settings/DockTab.qml:144",
|
"reference": "Modules/Settings/DockTab.qml:144",
|
||||||
"comment": ""
|
"comment": ""
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"term": "Smartcard Authentication",
|
||||||
|
"context": "Smartcard Authentication",
|
||||||
|
"reference": "Modals/WifiPasswordModal.qml:272",
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"term": "Smartcard PIN",
|
||||||
|
"context": "Smartcard PIN",
|
||||||
|
"reference": "Modals/WifiPasswordModal.qml:194",
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"term": "Some plugins require a newer version of DMS:",
|
"term": "Some plugins require a newer version of DMS:",
|
||||||
"context": "Some plugins require a newer version of DMS:",
|
"context": "Some plugins require a newer version of DMS:",
|
||||||
|
|||||||
Reference in New Issue
Block a user