mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-08-12 16:38:28 -04:00
@@ -545,12 +545,18 @@ func (a *SecretAgent) GetSecrets(
|
|||||||
out[settingName] = sec
|
out[settingName] = sec
|
||||||
}
|
}
|
||||||
if settingName == "vpn" && a.backend != nil && !isPKCS11 && (vpnUsername != "" || reply.Save) {
|
if settingName == "vpn" && a.backend != nil && !isPKCS11 && (vpnUsername != "" || reply.Save) {
|
||||||
pw := reply.Secrets["password"]
|
secrets := make(map[string]string)
|
||||||
|
for k, v := range reply.Secrets {
|
||||||
|
if k != "username" {
|
||||||
|
secrets[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
a.backend.pendingVPNSaveMu.Lock()
|
a.backend.pendingVPNSaveMu.Lock()
|
||||||
a.backend.pendingVPNSave = &pendingVPNCredentials{
|
a.backend.pendingVPNSave = &pendingVPNCredentials{
|
||||||
ConnectionPath: string(path),
|
ConnectionPath: string(path),
|
||||||
Username: vpnUsername,
|
Username: vpnUsername,
|
||||||
Password: pw,
|
Password: reply.Secrets["password"],
|
||||||
|
Secrets: secrets,
|
||||||
SavePassword: reply.Save,
|
SavePassword: reply.Save,
|
||||||
}
|
}
|
||||||
a.backend.pendingVPNSaveMu.Unlock()
|
a.backend.pendingVPNSaveMu.Unlock()
|
||||||
@@ -790,7 +796,23 @@ func inferVPNFields(conn map[string]nmVariantMap, vpnService string) []string {
|
|||||||
fields = []string{"username", "password"}
|
fields = []string{"username", "password"}
|
||||||
}
|
}
|
||||||
case strings.Contains(vpnService, "openvpn"):
|
case strings.Contains(vpnService, "openvpn"):
|
||||||
if connType == "password" || connType == "password-tls" {
|
switch connType {
|
||||||
|
case "tls":
|
||||||
|
// Cert auth wants the private-key passphrase, not a password.
|
||||||
|
if secretFlagsNotRequired(dataMap["cert-pass-flags"]) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return []string{"cert-pass"}
|
||||||
|
case "password-tls":
|
||||||
|
fields = []string{}
|
||||||
|
if dataMap["username"] == "" {
|
||||||
|
fields = append(fields, "username")
|
||||||
|
}
|
||||||
|
fields = append(fields, "password")
|
||||||
|
if !secretFlagsNotRequired(dataMap["cert-pass-flags"]) {
|
||||||
|
fields = append(fields, "cert-pass")
|
||||||
|
}
|
||||||
|
case "password":
|
||||||
if dataMap["username"] == "" {
|
if dataMap["username"] == "" {
|
||||||
fields = []string{"username", "password"}
|
fields = []string{"username", "password"}
|
||||||
}
|
}
|
||||||
@@ -805,6 +827,19 @@ func inferVPNFields(conn map[string]nmVariantMap, vpnService string) []string {
|
|||||||
return fields
|
return fields
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NetworkManager secret flags: bit 1 (value 2) marks a secret as not-saved,
|
||||||
|
// bit 2 (value 4) as not-required. A not-required secret must not be prompted.
|
||||||
|
func secretFlagsNotRequired(flags string) bool {
|
||||||
|
if flags == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
n, err := strconv.Atoi(flags)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return n&0x4 != 0
|
||||||
|
}
|
||||||
|
|
||||||
func needsExternalBrowserAuth(protocol, authType, username string, data map[string]string) bool {
|
func needsExternalBrowserAuth(protocol, authType, username string, data map[string]string) bool {
|
||||||
if method, ok := data["saml-auth-method"]; ok {
|
if method, ok := data["saml-auth-method"]; ok {
|
||||||
if method == "REDIRECT" || method == "POST" {
|
if method == "REDIRECT" || method == "POST" {
|
||||||
|
|||||||
@@ -315,6 +315,44 @@ func TestInferVPNFields_GPSaml(t *testing.T) {
|
|||||||
expectedLen: 1,
|
expectedLen: 1,
|
||||||
shouldHave: []string{"password"},
|
shouldHave: []string{"password"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "OpenVPN cert auth (tls) - private-key passphrase",
|
||||||
|
vpnService: "org.freedesktop.NetworkManager.openvpn",
|
||||||
|
dataMap: map[string]string{
|
||||||
|
"connection-type": "tls",
|
||||||
|
},
|
||||||
|
expectedLen: 1,
|
||||||
|
shouldHave: []string{"cert-pass"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OpenVPN cert auth (tls) with passphrase-less key",
|
||||||
|
vpnService: "org.freedesktop.NetworkManager.openvpn",
|
||||||
|
dataMap: map[string]string{
|
||||||
|
"connection-type": "tls",
|
||||||
|
"cert-pass-flags": "4",
|
||||||
|
},
|
||||||
|
expectedLen: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OpenVPN password-tls no username",
|
||||||
|
vpnService: "org.freedesktop.NetworkManager.openvpn",
|
||||||
|
dataMap: map[string]string{
|
||||||
|
"connection-type": "password-tls",
|
||||||
|
},
|
||||||
|
expectedLen: 3,
|
||||||
|
shouldHave: []string{"username", "password", "cert-pass"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OpenVPN password-tls with username, passphrase-less key",
|
||||||
|
vpnService: "org.freedesktop.NetworkManager.openvpn",
|
||||||
|
dataMap: map[string]string{
|
||||||
|
"connection-type": "password-tls",
|
||||||
|
"username": "john",
|
||||||
|
"cert-pass-flags": "4",
|
||||||
|
},
|
||||||
|
expectedLen: 1,
|
||||||
|
shouldHave: []string{"password"},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
|||||||
@@ -90,6 +90,9 @@ type pendingVPNCredentials struct {
|
|||||||
ConnectionPath string
|
ConnectionPath string
|
||||||
Username string
|
Username string
|
||||||
Password string
|
Password string
|
||||||
|
// Secrets holds all VPN secret fields keyed by name (e.g. "cert-pass");
|
||||||
|
// falls back to Password under the "password" key when empty.
|
||||||
|
Secrets map[string]string
|
||||||
SavePassword bool
|
SavePassword bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -863,13 +863,17 @@ func (b *NetworkManagerBackend) saveVPNCredentials(creds *pendingVPNCredentials)
|
|||||||
log.Infof("[saveVPNCredentials] Saving username")
|
log.Infof("[saveVPNCredentials] Saving username")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save password if requested
|
// Save secrets if requested
|
||||||
if creds.SavePassword {
|
if creds.SavePassword {
|
||||||
data["password-flags"] = "0"
|
secs := creds.Secrets
|
||||||
secs := make(map[string]string)
|
if len(secs) == 0 {
|
||||||
secs["password"] = creds.Password
|
secs = map[string]string{"password": creds.Password}
|
||||||
|
}
|
||||||
|
for field := range secs {
|
||||||
|
data[field+"-flags"] = "0"
|
||||||
|
}
|
||||||
vpn["secrets"] = dbus.MakeVariant(secs)
|
vpn["secrets"] = dbus.MakeVariant(secs)
|
||||||
log.Infof("[saveVPNCredentials] Saving password with password-flags=0")
|
log.Infof("[saveVPNCredentials] Saving %d secret field(s) with flags=0", len(secs))
|
||||||
}
|
}
|
||||||
|
|
||||||
vpn["data"] = dbus.MakeVariant(data)
|
vpn["data"] = dbus.MakeVariant(data)
|
||||||
|
|||||||
@@ -1027,17 +1027,6 @@ Singleton {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
// Standalone bar xray is unsafe when windows can render beneath its surface
|
|
||||||
function _standaloneBarXrayAvailable(configs) {
|
|
||||||
const list = configs || [];
|
|
||||||
const activeBars = list.filter(c => c && c.enabled && (c.visible ?? true));
|
|
||||||
const gapsOverride = (typeof CompositorService !== "undefined" && CompositorService.isHyprland) ? hyprlandLayoutGapsOverride : niriLayoutGapsOverride;
|
|
||||||
const layoutGaps = gapsOverride >= 0 ? gapsOverride : Math.max(4, (list[0]?.spacing ?? 4));
|
|
||||||
return activeBars.every(c => !c.autoHide && !(c.useOverlayLayer ?? false) && (c.spacing ?? 4) + (c.bottomGap ?? 0) + layoutGaps >= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly property bool standaloneBarXrayAvailable: _standaloneBarXrayAvailable(barConfigs)
|
|
||||||
|
|
||||||
property bool desktopClockEnabled: false
|
property bool desktopClockEnabled: false
|
||||||
property string desktopClockStyle: "analog"
|
property string desktopClockStyle: "analog"
|
||||||
property real desktopClockTransparency: 0.8
|
property real desktopClockTransparency: 0.8
|
||||||
@@ -2479,17 +2468,13 @@ Singleton {
|
|||||||
if (index === -1)
|
if (index === -1)
|
||||||
return;
|
return;
|
||||||
const positionChanged = updates.position !== undefined && configs[index].position !== updates.position;
|
const positionChanged = updates.position !== undefined && configs[index].position !== updates.position;
|
||||||
const barXrayTargetWasAvailable = _standaloneBarXrayAvailable(configs);
|
|
||||||
if (updates.autoHide === false || updates.visible === false)
|
if (updates.autoHide === false || updates.visible === false)
|
||||||
setBarIpcReveal(barId, false);
|
setBarIpcReveal(barId, false);
|
||||||
|
|
||||||
Object.assign(configs[index], updates);
|
Object.assign(configs[index], updates);
|
||||||
const sanitizedConfigs = _sanitizeBarConfigsForConnectedFrame(configs).configs;
|
barConfigs = _sanitizeBarConfigsForConnectedFrame(configs).configs;
|
||||||
barConfigs = sanitizedConfigs;
|
|
||||||
updateBarConfigs();
|
updateBarConfigs();
|
||||||
|
|
||||||
if (!frameEnabled && _standaloneBarXrayAvailable(sanitizedConfigs) !== barXrayTargetWasAvailable)
|
|
||||||
updateCompositorLayout();
|
|
||||||
if (positionChanged) {
|
if (positionChanged) {
|
||||||
NotificationService.dismissAllPopups();
|
NotificationService.dismissAllPopups();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -341,10 +341,11 @@ Singleton {
|
|||||||
const borderSize = (typeof SettingsData !== "undefined" && SettingsData.hyprlandLayoutBorderSize >= 0) ? SettingsData.hyprlandLayoutBorderSize : defaultBorderSize;
|
const borderSize = (typeof SettingsData !== "undefined" && SettingsData.hyprlandLayoutBorderSize >= 0) ? SettingsData.hyprlandLayoutBorderSize : defaultBorderSize;
|
||||||
const resizeOnBorder = (typeof SettingsData !== "undefined" && SettingsData.hyprlandResizeOnBorder) ? true : false;
|
const resizeOnBorder = (typeof SettingsData !== "undefined" && SettingsData.hyprlandResizeOnBorder) ? true : false;
|
||||||
const frameEnabled = typeof SettingsData !== "undefined" && SettingsData.frameEnabled;
|
const frameEnabled = typeof SettingsData !== "undefined" && SettingsData.frameEnabled;
|
||||||
const frameConnectedMode = frameEnabled && SettingsData.frameMode === "connected";
|
|
||||||
// Hyprland `xray = false` is still early-development; unset already samples real content, so only force xray=true
|
// Hyprland `xray = false` is still early-development; unset already samples real content, so only force xray=true
|
||||||
// Connected frame mode has no separate bar/frame surface to target
|
// dms:frame only in separate mode — connected-mode frame blur overlaps windows via popouts/arcs
|
||||||
const barFrameTargetNamespace = !frameEnabled ? (SettingsData.standaloneBarXrayAvailable ? "dms:bar" : null) : (frameConnectedMode ? null : "dms:frame");
|
const xrayNamespaces = ["dms:bar"];
|
||||||
|
if (frameEnabled && SettingsData.frameMode !== "connected")
|
||||||
|
xrayNamespaces.push("dms:frame");
|
||||||
|
|
||||||
const generalLines = [];
|
const generalLines = [];
|
||||||
if (manageGaps)
|
if (manageGaps)
|
||||||
@@ -371,14 +372,16 @@ hl.layer_rule({
|
|||||||
})
|
})
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
if (layoutBarXrayEnabled && barFrameTargetNamespace) {
|
if (layoutBarXrayEnabled) {
|
||||||
|
for (const ns of xrayNamespaces) {
|
||||||
content += `
|
content += `
|
||||||
hl.layer_rule({
|
hl.layer_rule({
|
||||||
match = { namespace = "^${barFrameTargetNamespace}$" },
|
match = { namespace = "^${ns}$" },
|
||||||
xray = true,
|
xray = true,
|
||||||
})
|
})
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Marker persists the preference even while the rule has no target
|
// Marker persists the preference even while the rule has no target
|
||||||
if (!layoutBarXrayEnabled) {
|
if (!layoutBarXrayEnabled) {
|
||||||
content += `
|
content += `
|
||||||
|
|||||||
@@ -1189,19 +1189,18 @@ Singleton {
|
|||||||
const gaps = gapsOverride >= 0 ? gapsOverride : defaultGaps;
|
const gaps = gapsOverride >= 0 ? gapsOverride : defaultGaps;
|
||||||
const borderSize = (typeof SettingsData !== "undefined" && SettingsData.niriLayoutBorderSize >= 0) ? SettingsData.niriLayoutBorderSize : defaultBorderSize;
|
const borderSize = (typeof SettingsData !== "undefined" && SettingsData.niriLayoutBorderSize >= 0) ? SettingsData.niriLayoutBorderSize : defaultBorderSize;
|
||||||
const frameEnabled = typeof SettingsData !== "undefined" && SettingsData.frameEnabled;
|
const frameEnabled = typeof SettingsData !== "undefined" && SettingsData.frameEnabled;
|
||||||
const frameConnectedMode = frameEnabled && SettingsData.frameMode === "connected";
|
// dms:frame only in separate mode — connected-mode frame blur overlaps windows via popouts/arcs
|
||||||
// Connected frame mode has no separate bar/frame surface to target
|
const excludeNamespaces = ["dms:bar"];
|
||||||
const barFrameTargetNamespace = !frameEnabled ? (SettingsData.standaloneBarXrayAvailable ? "dms:bar" : null) : (frameConnectedMode ? null : "dms:frame");
|
if (frameEnabled && SettingsData.frameMode !== "connected")
|
||||||
|
excludeNamespaces.push("dms:frame");
|
||||||
|
|
||||||
// Xray is niri's default blur, so only the off state needs a rule.
|
// Xray is niri's default blur, so only the off state needs a rule.
|
||||||
// A single rule excluding the bar/frame keeps its blur on the wallpaper
|
|
||||||
// without a second namespace-matched override rule.
|
|
||||||
let xrayRules = "";
|
let xrayRules = "";
|
||||||
if (!layoutXrayEnabled) {
|
if (!layoutXrayEnabled) {
|
||||||
const excludeLine = (layoutBarXrayEnabled && barFrameTargetNamespace) ? `\n exclude namespace="^${barFrameTargetNamespace}$"` : "";
|
const excludeLines = layoutBarXrayEnabled ? excludeNamespaces.map(ns => `\n exclude namespace="^${ns}$"`).join("") : "";
|
||||||
xrayRules += `
|
xrayRules += `
|
||||||
|
|
||||||
layer-rule {${excludeLine}
|
layer-rule {${excludeLines}
|
||||||
background-effect {
|
background-effect {
|
||||||
xray false
|
xray false
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user