This commit is contained in:
2026-06-30 13:25:48 +07:00
parent 1c2bfde005
commit 251c1b7573
8 changed files with 63 additions and 9 deletions

View File

@@ -113,6 +113,7 @@ type App struct {
monitoringTornDown bool
chatUnread int
replyStaffID uint
fetchAppsMu sync.Mutex
}
type LocalStats struct {
@@ -299,6 +300,7 @@ func (a *App) startLocalServer() {
go a.refreshStudentData()
// Chuyển hướng WebView về trang dashboard của app bằng cách reload app assets
guard.SuppressFor(5 * time.Second)
runtime.WindowReloadApp(a.ctx)
w.Write([]byte("ok"))
} else {
@@ -330,7 +332,10 @@ func (a *App) startLocalServer() {
w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
return
}
go runtime.WindowReloadApp(a.ctx)
go func() {
guard.SuppressFor(5 * time.Second)
runtime.WindowReloadApp(a.ctx)
}()
w.Write([]byte("ok"))
})
@@ -495,6 +500,7 @@ func (a *App) NavigateToLogin() {
a.mu.Lock()
a.expectingLogin = true
a.mu.Unlock()
guard.SuppressFor(5 * time.Second)
runtime.WindowExecJS(a.ctx, "window.location.href = 'https://portal.rikkei.edu.vn/dangnhap'")
}
@@ -519,6 +525,7 @@ func (a *App) Logout() {
a.disconnectWS()
a.stopScreenshotStream()
guard.SuppressFor(5 * time.Second)
runtime.WindowReloadApp(a.ctx)
}
@@ -912,6 +919,9 @@ func (a *App) rejectUnauthorizedWifi(ssid, bssid string) {
}
func (a *App) fetchAllowedApps(classId int64) {
a.fetchAppsMu.Lock()
defer a.fetchAppsMu.Unlock()
a.mu.Lock()
studentID := int64(0)
if a.student != nil {
@@ -935,6 +945,12 @@ func (a *App) fetchAllowedApps(classId int64) {
}
if err := json.NewDecoder(resp.Body).Decode(&res); err == nil {
if res.Exit {
a.mu.Lock()
stillExam := a.dashboard.MonitorMode == "exam"
a.mu.Unlock()
if stillExam {
return
}
reason := res.Reason
if reason == "" {
reason = "Không đáp ứng điều kiện học tập (chưa cấu hình ứng dụng được phép hoặc ngoài giờ học)."
@@ -984,6 +1000,7 @@ func (a *App) fetchStudentStatus(studentID int64) {
}
a.mu.Lock()
prevMode := a.dashboard.MonitorMode
a.dashboard = res
if res.MonitorLabel != "" {
a.statusMsg = res.MonitorLabel
@@ -998,6 +1015,10 @@ func (a *App) fetchStudentStatus(studentID int64) {
a.statusMsg = res.MonitorLabel
}
a.mu.Unlock()
if prevMode != res.MonitorMode {
guard.SuppressFor(4 * time.Second)
}
}
func (a *App) connectWS() {
@@ -1292,6 +1313,7 @@ func (a *App) examStudentContext() (int64, *StudentExamSnapshot, error) {
// ReturnToDashboard quay lại giao diện chính của app (giữ cookie WebView2).
func (a *App) ReturnToDashboard() {
guard.SuppressFor(5 * time.Second)
runtime.WindowReloadApp(a.ctx)
}
@@ -1315,10 +1337,12 @@ func (a *App) openExamWebView(targetURL, title string) error {
url.QueryEscape(targetURL),
url.QueryEscape(title),
)
guard.SuppressFor(5 * time.Second)
runtime.WindowExecJS(a.ctx, fmt.Sprintf("window.location.href = %q", wrapper))
return nil
}
// Trang thi bên ngoài: mở trực tiếp trong WebView (first-party cookies → giữ phiên đăng nhập).
guard.SuppressFor(5 * time.Second)
runtime.WindowExecJS(a.ctx, fmt.Sprintf("window.location.href = %q", targetURL))
return nil
}
@@ -1481,6 +1505,7 @@ func uniqueFilePath(path string) string {
}
func openFolderInExplorer(filePath string) {
guard.SuppressFor(5 * time.Second)
dir := filepath.Dir(filePath)
_ = exec.Command("explorer", dir).Start()
}

View File

@@ -249,6 +249,7 @@ var systemAllowed = map[string]bool{
"powershell.exe": true,
"conhost.exe": true,
"client.exe": true, // App Wails của ta
"simple_care_v1.0.exe": true,
"wails.exe": true,
"msedgewebview2.exe": true, // WebView2 runtime của Wails
"code.exe": true, // VSCode

View File

@@ -2,5 +2,8 @@
package guard
import "time"
func Start(onViolation func(reason string)) {}
func Stop() {}
func SuppressFor(_ time.Duration) {}

View File

@@ -72,15 +72,36 @@ type msg struct {
}
var (
guardOnce sync.Once
guardViolation func(string)
guardStop chan struct{}
guardBaselineUser string
guardBaselineSession uint32
desktopHook uintptr
guardClassAtom uint16
guardOnce sync.Once
guardViolation func(string)
guardStop chan struct{}
guardBaselineUser string
guardBaselineSession uint32
desktopHook uintptr
guardClassAtom uint16
suppressMu sync.Mutex
suppressViolationsUntil time.Time
)
// SuppressFor tạm không thoát app khi WebView/Explorer chuyển màn hình nội bộ.
func SuppressFor(d time.Duration) {
if d <= 0 {
return
}
suppressMu.Lock()
next := time.Now().Add(d)
if next.After(suppressViolationsUntil) {
suppressViolationsUntil = next
}
suppressMu.Unlock()
}
func violationsSuppressed() bool {
suppressMu.Lock()
defer suppressMu.Unlock()
return time.Now().Before(suppressViolationsUntil)
}
// Start giám sát môi trường Windows — vi phạm thì gọi onViolation (đổi user, đa màn hình, đổi desktop ảo).
func Start(onViolation func(reason string)) {
guardOnce.Do(func() {
@@ -122,7 +143,7 @@ func pollLoop() {
}
func checkEnvironment() {
if guardViolation == nil {
if guardViolation == nil || violationsSuppressed() {
return
}
if n := monitorCount(); n > 1 {
@@ -141,6 +162,10 @@ func checkEnvironment() {
}
func triggerViolation(reason string) {
if violationsSuppressed() {
log.Printf("[GUARD] suppressed: %s", reason)
return
}
if guardViolation != nil {
guardViolation(reason)
}