From b702287cfbe57f7337c4d7204b6e39a3f845a87c Mon Sep 17 00:00:00 2001 From: Phuoc NTB Date: Wed, 1 Jul 2026 10:06:31 +0700 Subject: [PATCH] add macos --- .DS_Store | Bin 8196 -> 8196 bytes client/.DS_Store | Bin 8196 -> 8196 bytes client/app.go | 57 ++++++++++++++--- client/build/.DS_Store | Bin 10244 -> 12292 bytes client/build/darwin/Info.dev.plist | 2 + client/build/darwin/Info.plist | 2 + client/internal/winapi/wifi_darwin.go | 83 ++++++++++++++----------- client/internal/winapi/wifi_darwin.m | 45 ++++++++++++++ client/internal/winapi/wifi_other.go | 3 + client/internal/winapi/wifi_windows.go | 3 + 10 files changed, 148 insertions(+), 47 deletions(-) create mode 100644 client/internal/winapi/wifi_darwin.m diff --git a/.DS_Store b/.DS_Store index b352f1213d7e45415eaa74040897a54cfe2dc971..c94ca090ad902a7979c306d567a9380f0a1e7f1e 100644 GIT binary patch delta 21 ccmZp1XmQwZLV&}_(p*Qu$i!sx1pyO&08PpUcK`qY delta 21 ccmZp1XmQwZLV&~Az)(lQ$i!pyO&08JeRX8-^I diff --git a/client/.DS_Store b/client/.DS_Store index b7e1b5a04a367100a814356d569a2f8a0a4cca00..fb9bb093833f52fb032117ba78ad59be2518f2de 100644 GIT binary patch delta 21 ccmZp1XmQvuOMt`3(p*Qu$i!sxB7r1+07{MqNdN!< delta 21 ccmZp1XmQvuOMt`Jz)(lQ$i!&#B7r1+07>BnIRF3v diff --git a/client/app.go b/client/app.go index 35e05ca..29aa498 100644 --- a/client/app.go +++ b/client/app.go @@ -124,9 +124,10 @@ type App struct { lastSyncTime time.Time isStreamingSc bool streamScStop chan struct{} - statusMsg string - expectingLogin bool - backendOnline bool + statusMsg string + expectingLogin bool + needsClearPortalStorage bool + backendOnline bool dashboard StudentDashboardSnapshot wifiEnforce bool acceptedWifi map[string]bool @@ -209,6 +210,9 @@ func (a *App) startup(ctx context.Context) { a.loadSession() a.loadStats() + // Request Location Access (macOS) + winapi.RequestLocationAccess() + // Register blocker callbacks blocker.Instance.OnBlocked = func(procName string, title string) { go a.reportBlockedApp(procName, title) @@ -534,7 +538,8 @@ func (a *App) NavigateToLogin() { func (a *App) Logout() { a.mu.Lock() a.student = nil - a.expectingLogin = false + a.expectingLogin = true + a.needsClearPortalStorage = true a.mu.Unlock() _ = os.Remove(a.sessionPath) @@ -552,7 +557,7 @@ func (a *App) Logout() { a.stopScreenshotStream() guard.SuppressFor(5 * time.Second) - runtime.WindowReloadApp(a.ctx) + runtime.WindowExecJS(a.ctx, "window.location.href = 'https://portal.rikkei.edu.vn/dangnhap'") } // GetStats trả về Wifi, thời gian online/offline và trạng thái giám sát @@ -622,9 +627,23 @@ func (a *App) authStorageScanner() { a.mu.Lock() expecting := a.expectingLogin + needsClear := a.needsClearPortalStorage loggedIn := a.student != nil a.mu.Unlock() + if needsClear && expecting { + runtime.WindowExecJS(a.ctx, ` + try { + localStorage.removeItem("student"); + localStorage.removeItem("token"); + } catch(e) {} + `) + a.mu.Lock() + a.needsClearPortalStorage = false + a.mu.Unlock() + continue + } + if loggedIn || !expecting { continue } @@ -661,8 +680,16 @@ func (a *App) runMonitorTick() { wifi := winapi.GetWifiConnection() a.mu.Lock() - a.wifiSSID = wifi.SSID - a.wifiBSSID = wifi.BSSID + if strings.Contains(strings.ToLower(wifi.SSID), "redacted") { + a.wifiSSID = "Chưa cấp quyền Vị Trí (macOS)" + } else { + a.wifiSSID = wifi.SSID + } + if strings.Contains(strings.ToLower(wifi.BSSID), "redacted") { + a.wifiBSSID = "Chưa cấp quyền Vị Trí (macOS)" + } else { + a.wifiBSSID = wifi.BSSID + } a.mu.Unlock() backendOnline := a.pingBackend() @@ -732,8 +759,16 @@ func (a *App) refreshNetworkStatus() { wifi := winapi.GetWifiConnection() backendOnline := a.pingBackend() a.mu.Lock() - a.wifiSSID = wifi.SSID - a.wifiBSSID = wifi.BSSID + if strings.Contains(strings.ToLower(wifi.SSID), "redacted") { + a.wifiSSID = "Chưa cấp quyền Vị Trí (macOS)" + } else { + a.wifiSSID = wifi.SSID + } + if strings.Contains(strings.ToLower(wifi.BSSID), "redacted") { + a.wifiBSSID = "Chưa cấp quyền Vị Trí (macOS)" + } else { + a.wifiBSSID = wifi.BSSID + } a.backendOnline = backendOnline a.mu.Unlock() if backendOnline { @@ -923,6 +958,10 @@ func (a *App) isWifiAllowed(ssid, bssid string) bool { if !enforce || len(allowed) == 0 { return true } + // Bypass Wi-Fi check if it's redacted by macOS privacy controls + if strings.Contains(strings.ToLower(ssid), "redacted") || strings.Contains(strings.ToLower(bssid), "redacted") { + return true + } bKey := winapi.BSSIDKey(bssid) if bKey == "" || len(bKey) != 12 { return false diff --git a/client/build/.DS_Store b/client/build/.DS_Store index d6807164eb5a7b1ce05d12f5605afc1564164153..7b16691f67d4865f1e138df5569e9fa7b4462892 100644 GIT binary patch delta 261 zcmZn(Xh~3DU|?W$DortDV9)?EIe-{M3-B;7uy8RjC~!|yP?u!}DFR}kAOnysz`#(% zP|lFake5?j=De|RG4o^t6&6;I3YN{s1oN3E7l^ci)Ph8SfP;Hup*YKCb)F~8jBJ}t zMK5t}Y|v$8WSz_-(8Xb7X|AJSWMVRTo`C!2Yl2D4%*+f)n;k_DGEKfG@Ip5~FF3O* zHC{lVv^X^=H7BtIXdWxrR0a)hAnl6m){TYlnJ4qBc!GQZvYcabhRV#zjY8_1#l>DT Kg3J@dFb@Ds={N2G delta 175 zcmZokXbF&DU|?W$DortDU{C-uIe-{M3-C-V6q~3gIoUvmMH0wo-~wVspg2QuK~heB z5|FnusbI6A)GgMH4JR2nfl?sA!3`7=XW6XI^Msj^Ych{Q*W`8Tu9I&oa7`9cf4EtI zC7*dSkH94^L1u`01#Tei3bJmqAjfy+$^1H=ll^%(IG7+V(U_c|GjpNSAllowsLocalNetworking + NSLocationWhenInUseUsageDescription + Ứng dụng cần quyền vị trí để xác thực mạng Wi-Fi phòng thi. diff --git a/client/build/darwin/Info.plist b/client/build/darwin/Info.plist index d17a747..a4698d6 100644 --- a/client/build/darwin/Info.plist +++ b/client/build/darwin/Info.plist @@ -59,5 +59,7 @@ {{end}} {{end}} + NSLocationWhenInUseUsageDescription + Ứng dụng cần quyền vị trí để xác thực mạng Wi-Fi phòng thi. diff --git a/client/internal/winapi/wifi_darwin.go b/client/internal/winapi/wifi_darwin.go index 1f5a3af..21cea90 100644 --- a/client/internal/winapi/wifi_darwin.go +++ b/client/internal/winapi/wifi_darwin.go @@ -2,45 +2,52 @@ package winapi +/* +#cgo LDFLAGS: -framework CoreWLAN -framework CoreLocation -framework Foundation +#include + +typedef struct { + char* ssid; + char* bssid; +} CWifiInfo; + +void RequestLocationPermission(); +CWifiInfo GetCurrentWifiInfo(); +*/ +import "C" import ( - "bytes" - "os/exec" - "strings" + "unsafe" ) -// GetWifiConnection đọc SSID và BSSID từ ipconfig (macOS) -func GetWifiConnection() WifiConnection { - // Find Wi-Fi interface dynamically - wifiInterface := "en0" - cmdPort := exec.Command("networksetup", "-listallhardwareports") - if outPort, err := cmdPort.Output(); err == nil { - lines := strings.Split(string(outPort), "\n") - for i := 0; i < len(lines)-1; i++ { - if strings.Contains(lines[i], "Hardware Port: Wi-Fi") { - next := strings.TrimSpace(lines[i+1]) - if strings.HasPrefix(next, "Device:") { - wifiInterface = strings.TrimSpace(strings.TrimPrefix(next, "Device:")) - break - } - } - } - } - - cmd := exec.Command("ipconfig", "getsummary", wifiInterface) - var out bytes.Buffer - cmd.Stdout = &out - if err := cmd.Run(); err != nil { - return WifiConnection{} - } - - var conn WifiConnection - for _, line := range strings.Split(out.String(), "\n") { - trimmed := strings.TrimSpace(line) - if strings.HasPrefix(trimmed, "SSID :") { - conn.SSID = strings.TrimSpace(strings.TrimPrefix(trimmed, "SSID :")) - } else if strings.HasPrefix(trimmed, "BSSID :") { - conn.BSSID = normalizeMAC(strings.TrimSpace(strings.TrimPrefix(trimmed, "BSSID :"))) - } - } - return conn +// RequestLocationAccess requests Location permission on macOS +func RequestLocationAccess() { + C.RequestLocationPermission() +} + +// GetWifiConnection đọc SSID và BSSID từ CoreWLAN (macOS) +func GetWifiConnection() WifiConnection { + info := C.GetCurrentWifiInfo() + defer func() { + if info.ssid != nil { + C.free(unsafe.Pointer(info.ssid)) + } + if info.bssid != nil { + C.free(unsafe.Pointer(info.bssid)) + } + }() + + ssid := "" + if info.ssid != nil { + ssid = C.GoString(info.ssid) + } + + bssid := "" + if info.bssid != nil { + bssid = C.GoString(info.bssid) + } + + return WifiConnection{ + SSID: ssid, + BSSID: normalizeMAC(bssid), + } } diff --git a/client/internal/winapi/wifi_darwin.m b/client/internal/winapi/wifi_darwin.m new file mode 100644 index 0000000..35e8e03 --- /dev/null +++ b/client/internal/winapi/wifi_darwin.m @@ -0,0 +1,45 @@ +#import +#import +#import + +static CLLocationManager *locationManager = nil; + +void RequestLocationPermission() { + dispatch_async(dispatch_get_main_queue(), ^{ + if (locationManager == nil) { + locationManager = [[CLLocationManager alloc] init]; + } + if (@available(macOS 10.15, *)) { + [locationManager requestWhenInUseAuthorization]; + } + }); +} + +typedef struct { + char* ssid; + char* bssid; +} CWifiInfo; + +CWifiInfo GetCurrentWifiInfo() { + CWifiInfo info; + info.ssid = NULL; + info.bssid = NULL; + + @autoreleasepool { + CWWiFiClient *client = [CWWiFiClient sharedWiFiClient]; + if (client != nil) { + CWInterface *interface = [client interface]; + if (interface != nil) { + NSString *ssidStr = [interface ssid]; + NSString *bssidStr = [interface bssid]; + if (ssidStr != nil) { + info.ssid = strdup([ssidStr UTF8String]); + } + if (bssidStr != nil) { + info.bssid = strdup([bssidStr UTF8String]); + } + } + } + } + return info; +} diff --git a/client/internal/winapi/wifi_other.go b/client/internal/winapi/wifi_other.go index 550643c..f823f62 100644 --- a/client/internal/winapi/wifi_other.go +++ b/client/internal/winapi/wifi_other.go @@ -6,3 +6,6 @@ package winapi func GetWifiConnection() WifiConnection { return WifiConnection{} } + +// RequestLocationAccess requests Location permission (stub for other systems) +func RequestLocationAccess() {} diff --git a/client/internal/winapi/wifi_windows.go b/client/internal/winapi/wifi_windows.go index a7e6bf0..4400976 100644 --- a/client/internal/winapi/wifi_windows.go +++ b/client/internal/winapi/wifi_windows.go @@ -38,3 +38,6 @@ func GetWifiConnection() WifiConnection { } return conn } + +// RequestLocationAccess requests Location permission (stub for Windows) +func RequestLocationAccess() {}