mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-08-07 14:08:29 -04:00
@@ -126,3 +126,6 @@ __pycache__
|
|||||||
distro/void/temp/
|
distro/void/temp/
|
||||||
distro/void/hostdir/
|
distro/void/hostdir/
|
||||||
distro/void/masterdir*/
|
distro/void/masterdir*/
|
||||||
|
|
||||||
|
# Often gets built
|
||||||
|
core/dms
|
||||||
|
|||||||
@@ -22,13 +22,14 @@ type ConnectionStateChecker interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type IWDAgent struct {
|
type IWDAgent struct {
|
||||||
conn *dbus.Conn
|
conn *dbus.Conn
|
||||||
objPath dbus.ObjectPath
|
objPath dbus.ObjectPath
|
||||||
prompts PromptBroker
|
prompts PromptBroker
|
||||||
onUserCanceled func()
|
onUserCanceled func()
|
||||||
onPromptRetry func(ssid string)
|
onPromptRetry func(ssid string)
|
||||||
lastRequestSSID string
|
takePendingSecret func(ssid string) (string, bool)
|
||||||
stateChecker ConnectionStateChecker
|
lastRequestSSID string
|
||||||
|
stateChecker ConnectionStateChecker
|
||||||
}
|
}
|
||||||
|
|
||||||
const iwdAgentIntrospectXML = `
|
const iwdAgentIntrospectXML = `
|
||||||
@@ -119,6 +120,13 @@ func (a *IWDAgent) RequestPassphrase(network dbus.ObjectPath) (string, *dbus.Err
|
|||||||
return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
|
return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if a.takePendingSecret != nil {
|
||||||
|
if psk, ok := a.takePendingSecret(ssid); ok {
|
||||||
|
a.lastRequestSSID = ssid
|
||||||
|
return psk, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if a.prompts == nil {
|
if a.prompts == nil {
|
||||||
if a.onUserCanceled != nil {
|
if a.onUserCanceled != nil {
|
||||||
a.onUserCanceled()
|
a.onUserCanceled()
|
||||||
@@ -126,19 +134,24 @@ func (a *IWDAgent) RequestPassphrase(network dbus.ObjectPath) (string, *dbus.Err
|
|||||||
return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
|
return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.lastRequestSSID == ssid {
|
retry := a.lastRequestSSID == ssid
|
||||||
if a.onPromptRetry != nil {
|
if retry && a.onPromptRetry != nil {
|
||||||
a.onPromptRetry(ssid)
|
a.onPromptRetry(ssid)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
a.lastRequestSSID = ssid
|
a.lastRequestSSID = ssid
|
||||||
|
|
||||||
|
reason := ""
|
||||||
|
if retry {
|
||||||
|
reason = "wrong-password"
|
||||||
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
token, err := a.prompts.Ask(ctx, PromptRequest{
|
token, err := a.prompts.Ask(ctx, PromptRequest{
|
||||||
SSID: ssid,
|
SSID: ssid,
|
||||||
Fields: []string{"psk"},
|
Fields: []string{"psk"},
|
||||||
|
Reason: reason,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if a.onUserCanceled != nil {
|
if a.onUserCanceled != nil {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ const (
|
|||||||
type connectAttempt struct {
|
type connectAttempt struct {
|
||||||
ssid string
|
ssid string
|
||||||
netPath dbus.ObjectPath
|
netPath dbus.ObjectPath
|
||||||
|
saved bool
|
||||||
start time.Time
|
start time.Time
|
||||||
deadline time.Time
|
deadline time.Time
|
||||||
sawAuthish bool
|
sawAuthish bool
|
||||||
@@ -53,6 +54,37 @@ type IWDBackend struct {
|
|||||||
attemptMutex sync.RWMutex
|
attemptMutex sync.RWMutex
|
||||||
recentScans map[string]time.Time
|
recentScans map[string]time.Time
|
||||||
recentScansMu sync.Mutex
|
recentScansMu sync.Mutex
|
||||||
|
pendingPSK *pendingReplacementPSK
|
||||||
|
pendingPSKMu sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
type pendingReplacementPSK struct {
|
||||||
|
ssid string
|
||||||
|
psk string
|
||||||
|
expires time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *IWDBackend) storePendingPSK(ssid, psk string) {
|
||||||
|
b.pendingPSKMu.Lock()
|
||||||
|
b.pendingPSK = &pendingReplacementPSK{
|
||||||
|
ssid: ssid,
|
||||||
|
psk: psk,
|
||||||
|
expires: time.Now().Add(30 * time.Second),
|
||||||
|
}
|
||||||
|
b.pendingPSKMu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *IWDBackend) takePendingPSK(ssid string) (string, bool) {
|
||||||
|
b.pendingPSKMu.Lock()
|
||||||
|
defer b.pendingPSKMu.Unlock()
|
||||||
|
|
||||||
|
pending := b.pendingPSK
|
||||||
|
if pending == nil || pending.ssid != ssid || time.Now().After(pending.expires) {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
b.pendingPSK = nil
|
||||||
|
return pending.psk, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIWDBackend() (*IWDBackend, error) {
|
func NewIWDBackend() (*IWDBackend, error) {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ func (b *IWDBackend) StartMonitoring(onStateChange func()) error {
|
|||||||
}
|
}
|
||||||
agent.onUserCanceled = b.OnUserCanceledPrompt
|
agent.onUserCanceled = b.OnUserCanceledPrompt
|
||||||
agent.onPromptRetry = b.OnPromptRetry
|
agent.onPromptRetry = b.OnPromptRetry
|
||||||
|
agent.takePendingSecret = b.takePendingPSK
|
||||||
b.iwdAgent = agent
|
b.iwdAgent = agent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network
|
package network
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -314,6 +315,133 @@ func TestConnectAttempt_Finalization(t *testing.T) {
|
|||||||
backend.stateMutex.RUnlock()
|
backend.stateMutex.RUnlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIWDBackend_PendingPSK(t *testing.T) {
|
||||||
|
backend, _ := NewIWDBackend()
|
||||||
|
|
||||||
|
_, ok := backend.takePendingPSK("Home")
|
||||||
|
assert.False(t, ok)
|
||||||
|
|
||||||
|
backend.storePendingPSK("Home", "newpass")
|
||||||
|
|
||||||
|
_, ok = backend.takePendingPSK("Other")
|
||||||
|
assert.False(t, ok, "pending PSK should not match a different SSID")
|
||||||
|
|
||||||
|
psk, ok := backend.takePendingPSK("Home")
|
||||||
|
assert.True(t, ok)
|
||||||
|
assert.Equal(t, "newpass", psk)
|
||||||
|
|
||||||
|
_, ok = backend.takePendingPSK("Home")
|
||||||
|
assert.False(t, ok, "pending PSK should be consumed on take")
|
||||||
|
|
||||||
|
backend.storePendingPSK("Home", "newpass")
|
||||||
|
backend.pendingPSKMu.Lock()
|
||||||
|
backend.pendingPSK.expires = time.Now().Add(-time.Second)
|
||||||
|
backend.pendingPSKMu.Unlock()
|
||||||
|
|
||||||
|
_, ok = backend.takePendingPSK("Home")
|
||||||
|
assert.False(t, ok, "expired pending PSK should not be returned")
|
||||||
|
}
|
||||||
|
|
||||||
|
type fakePromptBroker struct {
|
||||||
|
asked chan PromptRequest
|
||||||
|
reply PromptReply
|
||||||
|
replyErr error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakePromptBroker) Ask(ctx context.Context, req PromptRequest) (string, error) {
|
||||||
|
f.asked <- req
|
||||||
|
return "token", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakePromptBroker) Wait(ctx context.Context, token string) (PromptReply, error) {
|
||||||
|
return f.reply, f.replyErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakePromptBroker) Resolve(token string, reply PromptReply) error { return nil }
|
||||||
|
|
||||||
|
func (f *fakePromptBroker) Cancel(path string, setting string) error { return nil }
|
||||||
|
|
||||||
|
func TestIWDBackend_BadCredentialsSavedNetwork_PromptsReplacement(t *testing.T) {
|
||||||
|
backend, _ := NewIWDBackend()
|
||||||
|
backend.state = &BackendState{}
|
||||||
|
broker := &fakePromptBroker{
|
||||||
|
asked: make(chan PromptRequest, 1),
|
||||||
|
reply: PromptReply{Cancel: true},
|
||||||
|
}
|
||||||
|
backend.promptBroker = broker
|
||||||
|
|
||||||
|
att := &connectAttempt{
|
||||||
|
ssid: "Home",
|
||||||
|
netPath: "/test",
|
||||||
|
saved: true,
|
||||||
|
start: time.Now(),
|
||||||
|
deadline: time.Now().Add(15 * time.Second),
|
||||||
|
}
|
||||||
|
|
||||||
|
backend.finalizeAttempt(att, "bad-credentials")
|
||||||
|
|
||||||
|
select {
|
||||||
|
case req := <-broker.asked:
|
||||||
|
assert.Equal(t, "Home", req.SSID)
|
||||||
|
assert.Equal(t, "wrong-password", req.Reason)
|
||||||
|
assert.Equal(t, []string{"psk"}, req.Fields)
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Fatal("expected replacement credentials prompt for saved network")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIWDBackend_BadCredentialsUnsavedNetwork_NoReplacementPrompt(t *testing.T) {
|
||||||
|
backend, _ := NewIWDBackend()
|
||||||
|
backend.state = &BackendState{}
|
||||||
|
broker := &fakePromptBroker{
|
||||||
|
asked: make(chan PromptRequest, 1),
|
||||||
|
reply: PromptReply{Cancel: true},
|
||||||
|
}
|
||||||
|
backend.promptBroker = broker
|
||||||
|
|
||||||
|
att := &connectAttempt{
|
||||||
|
ssid: "Home",
|
||||||
|
netPath: "/test",
|
||||||
|
start: time.Now(),
|
||||||
|
deadline: time.Now().Add(15 * time.Second),
|
||||||
|
}
|
||||||
|
|
||||||
|
backend.finalizeAttempt(att, "bad-credentials")
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-broker.asked:
|
||||||
|
t.Fatal("unsaved network should not trigger a replacement prompt")
|
||||||
|
case <-time.After(100 * time.Millisecond):
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIWDBackend_BadCredentialsAfterPromptRetry_NoReplacementPrompt(t *testing.T) {
|
||||||
|
backend, _ := NewIWDBackend()
|
||||||
|
backend.state = &BackendState{}
|
||||||
|
broker := &fakePromptBroker{
|
||||||
|
asked: make(chan PromptRequest, 1),
|
||||||
|
reply: PromptReply{Cancel: true},
|
||||||
|
}
|
||||||
|
backend.promptBroker = broker
|
||||||
|
|
||||||
|
att := &connectAttempt{
|
||||||
|
ssid: "Home",
|
||||||
|
netPath: "/test",
|
||||||
|
saved: true,
|
||||||
|
sawPromptRetry: true,
|
||||||
|
start: time.Now(),
|
||||||
|
deadline: time.Now().Add(15 * time.Second),
|
||||||
|
}
|
||||||
|
|
||||||
|
backend.finalizeAttempt(att, "bad-credentials")
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-broker.asked:
|
||||||
|
t.Fatal("attempt that already prompted should not trigger a replacement prompt")
|
||||||
|
case <-time.After(100 * time.Millisecond):
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestConnectAttempt_DoubleFinalization(t *testing.T) {
|
func TestConnectAttempt_DoubleFinalization(t *testing.T) {
|
||||||
backend, _ := NewIWDBackend()
|
backend, _ := NewIWDBackend()
|
||||||
backend.state = &BackendState{}
|
backend.state = &BackendState{}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
package network
|
package network
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/errdefs"
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/errdefs"
|
||||||
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
|
||||||
"github.com/godbus/dbus/v5"
|
"github.com/godbus/dbus/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -476,6 +478,73 @@ func (b *IWDBackend) finalizeAttempt(att *connectAttempt, code string) {
|
|||||||
if b.onStateChange != nil {
|
if b.onStateChange != nil {
|
||||||
b.onStateChange()
|
b.onStateChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if code == errdefs.ErrBadCredentials {
|
||||||
|
b.maybeReplaceSavedPSK(att)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *IWDBackend) maybeReplaceSavedPSK(att *connectAttempt) {
|
||||||
|
if b.promptBroker == nil || !att.saved {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
att.mu.Lock()
|
||||||
|
prompted := att.sawPromptRetry
|
||||||
|
att.mu.Unlock()
|
||||||
|
if prompted {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
b.sigWG.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer b.sigWG.Done()
|
||||||
|
b.requestReplacementPSK(att.ssid)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *IWDBackend) requestReplacementPSK(ssid string) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case <-b.stopChan:
|
||||||
|
cancel()
|
||||||
|
case <-ctx.Done():
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
token, err := b.promptBroker.Ask(ctx, PromptRequest{
|
||||||
|
SSID: ssid,
|
||||||
|
SettingName: "802-11-wireless-security",
|
||||||
|
Fields: []string{"psk"},
|
||||||
|
Reason: "wrong-password",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("failed to request replacement credentials for %s: %v", ssid, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
reply, err := b.promptBroker.Wait(ctx, token)
|
||||||
|
if err != nil || reply.Cancel {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
psk, ok := reply.Secrets["psk"]
|
||||||
|
if !ok || psk == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := b.ForgetWiFiNetwork(ssid); err != nil {
|
||||||
|
log.Warnf("failed to forget %s before credential replacement: %v", ssid, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.storePendingPSK(ssid, psk)
|
||||||
|
|
||||||
|
if err := b.ConnectWiFi(ConnectionRequest{SSID: ssid}); err != nil {
|
||||||
|
log.Warnf("failed to reconnect %s with replacement credentials: %v", ssid, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *IWDBackend) startAttemptWatchdog(att *connectAttempt) {
|
func (b *IWDBackend) startAttemptWatchdog(att *connectAttempt) {
|
||||||
@@ -560,7 +629,7 @@ func (b *IWDBackend) ConnectWiFi(req ConnectionRequest) error {
|
|||||||
return fmt.Errorf("no WiFi device available")
|
return fmt.Errorf("no WiFi device available")
|
||||||
}
|
}
|
||||||
|
|
||||||
networkPath, err := b.findNetworkPath(req.SSID)
|
networkPath, saved, err := b.findNetworkPath(req.SSID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.setConnectError(errdefs.ErrNoSuchSSID)
|
b.setConnectError(errdefs.ErrNoSuchSSID)
|
||||||
if b.onStateChange != nil {
|
if b.onStateChange != nil {
|
||||||
@@ -572,6 +641,7 @@ func (b *IWDBackend) ConnectWiFi(req ConnectionRequest) error {
|
|||||||
att := &connectAttempt{
|
att := &connectAttempt{
|
||||||
ssid: req.SSID,
|
ssid: req.SSID,
|
||||||
netPath: networkPath,
|
netPath: networkPath,
|
||||||
|
saved: saved,
|
||||||
start: time.Now(),
|
start: time.Now(),
|
||||||
deadline: time.Now().Add(15 * time.Second),
|
deadline: time.Now().Add(15 * time.Second),
|
||||||
}
|
}
|
||||||
@@ -619,26 +689,39 @@ func (b *IWDBackend) ConnectWiFi(req ConnectionRequest) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *IWDBackend) findNetworkPath(ssid string) (dbus.ObjectPath, error) {
|
func (b *IWDBackend) findNetworkPath(ssid string) (dbus.ObjectPath, bool, error) {
|
||||||
obj := b.conn.Object(iwdBusName, iwdObjectPath)
|
obj := b.conn.Object(iwdBusName, iwdObjectPath)
|
||||||
|
|
||||||
var objects map[dbus.ObjectPath]map[string]map[string]dbus.Variant
|
var objects map[dbus.ObjectPath]map[string]map[string]dbus.Variant
|
||||||
err := obj.Call(dbusObjectManager+".GetManagedObjects", 0).Store(&objects)
|
err := obj.Call(dbusObjectManager+".GetManagedObjects", 0).Store(&objects)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var netPath dbus.ObjectPath
|
||||||
|
saved := false
|
||||||
for path, interfaces := range objects {
|
for path, interfaces := range objects {
|
||||||
if netProps, ok := interfaces[iwdNetworkInterface]; ok {
|
if netProps, ok := interfaces[iwdNetworkInterface]; ok {
|
||||||
if nameVar, ok := netProps["Name"]; ok {
|
if nameVar, ok := netProps["Name"]; ok {
|
||||||
if name, ok := nameVar.Value().(string); ok && name == ssid {
|
if name, ok := nameVar.Value().(string); ok && name == ssid {
|
||||||
return path, nil
|
netPath = path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if knownProps, ok := interfaces[iwdKnownNetworkInterface]; ok {
|
||||||
|
if nameVar, ok := knownProps["Name"]; ok {
|
||||||
|
if name, ok := nameVar.Value().(string); ok && name == ssid {
|
||||||
|
saved = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", fmt.Errorf("network not found")
|
if netPath == "" {
|
||||||
|
return "", false, fmt.Errorf("network not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return netPath, saved, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *IWDBackend) DisconnectWiFi() error {
|
func (b *IWDBackend) DisconnectWiFi() error {
|
||||||
|
|||||||
@@ -577,6 +577,12 @@ Singleton {
|
|||||||
|
|
||||||
credentialsRequested = false;
|
credentialsRequested = false;
|
||||||
|
|
||||||
|
if (credentialsReason === "wrong-password" && credentialsSSID && credentialsSetting === "802-11-wireless-security") {
|
||||||
|
pendingConnectionSSID = credentialsSSID;
|
||||||
|
pendingConnectionStartTime = Date.now();
|
||||||
|
connectionStatus = "connecting";
|
||||||
|
}
|
||||||
|
|
||||||
DMSService.sendRequest("network.credentials.submit", params, response => {
|
DMSService.sendRequest("network.credentials.submit", params, response => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
log.warn("Failed to submit credentials:", response.error);
|
log.warn("Failed to submit credentials:", response.error);
|
||||||
|
|||||||
Reference in New Issue
Block a user