From c54d517f6e7ecb3bc00d7db2adcbba780e3ada30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=8B=E7=94=B0=E5=BC=98?= <1240092443@qq.com> Date: Fri, 17 Jan 2025 16:18:00 +0800 Subject: [PATCH 1/5] =?UTF-8?q?add=EF=BC=9A=E9=94=81=E5=B1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/desktop/LockDesktop.vue | 66 ++- .../src/components/setting/SetAccount.vue | 500 +++++++++++------- frontend/src/system/index.ts | 29 + godo/cmd/main.go | 8 +- godo/cmd/serve.go | 2 +- godo/user/user.go | 27 +- 6 files changed, 443 insertions(+), 189 deletions(-) diff --git a/frontend/src/components/desktop/LockDesktop.vue b/frontend/src/components/desktop/LockDesktop.vue index a1c1182..d22c48d 100644 --- a/frontend/src/components/desktop/LockDesktop.vue +++ b/frontend/src/components/desktop/LockDesktop.vue @@ -1,9 +1,11 @@ @@ -322,6 +324,34 @@ + + + + + + + + + + + + + + + 锁屏 + @@ -330,8 +360,9 @@ import { useSystem } from "@/system"; import { getSystemConfig, setSystemConfig } from "@/system/config"; import router from "@/system/router"; + import { SystemStateEnum } from "@/system/type/enum"; import { RestartApp } from "@/util/goutil"; - import { notifyError } from "@/util/msg"; + import { notifyError, notifySuccess } from "@/util/msg"; import { computed, onMounted, ref, watchEffect } from "vue"; import { useRoute } from "vue-router"; const route = useRoute(); @@ -346,6 +377,12 @@ localStorage.removeItem("ThirdPartyPlatform"); }; + // /screen/unlock + const unlockForm = ref({ + username: "123", + password: "123", + }); + const phoneForm = ref({ phone: "", code: "", @@ -356,6 +393,20 @@ code: "", }); + const lockScreen = async () => { + const res = await fetch(config.apiUrl + "/user/screen/unlock", { + method: "POST", + body: JSON.stringify(unlockForm.value), + }); + const data = await res.json(); + if (data.code == 0) { + sys._rootState.state = SystemStateEnum.open; + notifySuccess("解锁成功"); + } else { + notifyError("解锁失败"); + } + }; + const thirdpartyCode = ref(""); const validateAndLoginByThirdparty = () => { @@ -1210,4 +1261,17 @@ } } } + + .lock-card { + border-radius: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 300px; + height: 300px; + background-color: #ffffff; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + padding: 20px; + } diff --git a/frontend/src/components/setting/SetAccount.vue b/frontend/src/components/setting/SetAccount.vue index 39b6838..5395993 100644 --- a/frontend/src/components/setting/SetAccount.vue +++ b/frontend/src/components/setting/SetAccount.vue @@ -1,199 +1,341 @@ - - - - - {{ item }} - - - - - - - {{ t("background") }} - - - - - - - - - - - - - - - - - - - - - - - - - - - - 锁屏 - - - {{ t('account') }} - - - - {{ t('password') }} - - + + + + + {{ item }} + + + + + + + {{ t("background") }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + 锁屏 + + + {{ t("account") }} + + + + {{ t("password") }} + + - - - - {{ t('confirm') }} - - - - - - 广告与更新提示 + + + + 锁屏 + 立即注册 + + - - - - - - - - - {{ t("language") }} - - - - - - - + + + 还没有账号?立即注册 + + 注册完成, + 点我返回 + + + + + + 广告与更新提示 + + + + + + + + + {{ t("language") }} + + + + + + + - - - - {{ t("confirm") }} - - - - - + + + + {{ t("confirm") }} + + + + + diff --git a/frontend/src/system/index.ts b/frontend/src/system/index.ts index 55b225e..713c6dc 100644 --- a/frontend/src/system/index.ts +++ b/frontend/src/system/index.ts @@ -103,6 +103,28 @@ export class System { initBuiltinApp(this); initBuiltinFileOpener(this); // 注册内建文件打开器 await this.initSavedConfig(); // 初始化保存的配置 + const config = getSystemConfig(); + const syslock = localStorage.getItem("syslock"); + const lockData = JSON.parse(syslock || "{}"); + + // 判断是解锁 + if (lockData.lock) { + const sysuser = lockData.sysuser; + const res = await fetch(config.apiUrl + "/user/screen/status", { + headers: { + "sysuser": sysuser, + }, + }); + const data = await res.json(); + // data.data 为 true 表示锁屏 + // 如果没锁屏,则删除 sysuser + if (!data.data) { + lockData.lock = false; + lockData.sysuser = ""; + localStorage.setItem("syslock", JSON.stringify(lockData)); + } + } + // 判断是否为钉钉工作台登录 const login_type = new URLSearchParams(window.location.search).get("login_type"); @@ -177,6 +199,13 @@ export class System { } this._rootState.state = SystemStateEnum.lock; + + const syslock = localStorage.getItem("syslock"); + const lockData = JSON.parse(syslock || "{}"); + if (!lockData.lock) { + this._rootState.state = SystemStateEnum.open; + } + const tempCallBack = this._options.loginCallback; if (!tempCallBack) { throw new Error('没有设置登录回调函数'); diff --git a/godo/cmd/main.go b/godo/cmd/main.go index b727854..daa4d4a 100644 --- a/godo/cmd/main.go +++ b/godo/cmd/main.go @@ -186,10 +186,10 @@ func OsStart() { proxyRouter.HandleFunc("/frpc/status", proxy.StatusFrpcHandler).Methods(http.MethodGet) userRouter := router.PathPrefix("/user").Subrouter() - userRouter.HandleFunc("/register", user.RegisterSysUserHandler).Methods(http.MethodPost) - userRouter.HandleFunc("/screen/lock", user.LockedScreenHandler).Methods(http.MethodPost) - userRouter.HandleFunc("/screen/unlock", user.UnLockScreenHandler).Methods(http.MethodPost) - userRouter.HandleFunc("/screen/status", user.CheckLockedScreenHandler).Methods(http.MethodGet) + userRouter.HandleFunc("/register", user.RegisterSysUserHandler).Methods(http.MethodPost) // 注册系统用户 + userRouter.HandleFunc("/screen/lock", user.LockedScreenHandler).Methods(http.MethodPost) // 锁屏 + userRouter.HandleFunc("/screen/unlock", user.UnLockScreenHandler).Methods(http.MethodPost) // 解锁 + userRouter.HandleFunc("/screen/status", user.CheckLockedScreenHandler).Methods(http.MethodGet) // 检查锁屏状态 // 注册根路径的处理函数 distFS, _ := fs.Sub(deps.Frontendassets, "dist") diff --git a/godo/cmd/serve.go b/godo/cmd/serve.go index c07a650..113c56c 100644 --- a/godo/cmd/serve.go +++ b/godo/cmd/serve.go @@ -115,7 +115,7 @@ func recoverMiddleware(next http.Handler) http.Handler { // CORS 中间件 func corsMiddleware() mux.MiddlewareFunc { - allowHeaders := "Content-Type, Accept, Authorization, Origin, Pwd" + allowHeaders := "Content-Type, Accept, Authorization, Origin, Pwd, sysuser" allowMethods := "GET, POST, PUT, DELETE, OPTIONS" return func(next http.Handler) http.Handler { diff --git a/godo/user/user.go b/godo/user/user.go index 4d421c0..debe8a6 100644 --- a/godo/user/user.go +++ b/godo/user/user.go @@ -4,6 +4,8 @@ import ( "encoding/json" "godo/libs" "godo/model" + "io" + "log" "net/http" "strconv" "sync" @@ -21,20 +23,35 @@ func RegisterSysUserHandler(w http.ResponseWriter, r *http.Request) { } var user model.SysUser - if err := json.NewDecoder(r.Body).Decode(&user); err != nil { + + // 获取请求体 + body, err := io.ReadAll(r.Body) + if err != nil { + log.Println("读取请求体错误:", err) libs.ErrorMsg(w, "invalid input") return } + + // 解析请求体 + if err := json.Unmarshal(body, &user); err != nil { + log.Println("解析请求体错误:", err) + libs.ErrorMsg(w, "invalid input") + return + } + + // 检查用户名和密码是否为空 if user.Username == "" || user.Password == "" { libs.ErrorMsg(w, "username or password is empty") return } + // 创建用户 if err := model.Db.Create(&user).Error; err != nil { libs.ErrorMsg(w, "failed to create user") return } + // 返回成功消息 libs.SuccessMsg(w, user.ID, "") } @@ -63,7 +80,7 @@ func LockedScreenHandler(w http.ResponseWriter, r *http.Request) { return } - w.Header().Set("sysuser", userEncodeStr) + // w.Header().Set("sysuser", userEncodeStr) // 登录成功,锁屏状态设置为 true mu.Lock() @@ -73,7 +90,7 @@ func LockedScreenHandler(w http.ResponseWriter, r *http.Request) { userLockedScreen[user.ID] = true mu.Unlock() - libs.SuccessMsg(w, nil, "system locked") + libs.SuccessMsg(w, userEncodeStr, "system locked") } // 系统用户登录(解锁) @@ -115,9 +132,11 @@ func CheckLockedScreenHandler(w http.ResponseWriter, r *http.Request) { decoderUid := r.Header.Get("sysuser") if decoderUid == "" { - libs.ErrorMsg(w, "invalid uid") + //获取锁屏状态 + libs.SuccessMsg(w, false, "") return } + uidStr, err := libs.DecodeFile("godoos", decoderUid) if err != nil { libs.ErrorMsg(w, "invalid uid") From 688447213058dffa2e2957f349bf9c823bbb93e0 Mon Sep 17 00:00:00 2001 From: pcong Date: Fri, 17 Jan 2025 17:08:38 +0800 Subject: [PATCH 2/5] fix: user locked screen and local proxy --- godo/model/local_proxy.go | 11 +++---- godo/proxy/local.go | 66 +++++++++++++++++++-------------------- godo/user/user.go | 20 +++--------- 3 files changed, 42 insertions(+), 55 deletions(-) diff --git a/godo/model/local_proxy.go b/godo/model/local_proxy.go index 7599500..bcc0ec9 100644 --- a/godo/model/local_proxy.go +++ b/godo/model/local_proxy.go @@ -2,12 +2,11 @@ package model type LocalProxy struct { BaseModel - Port uint `json:"port"` // 本地端口 - ProxyType string `json:"proxyType"` // 代理类型 - Domain string `json:"domain"` // 代理域名 - Path string `json:"path"` // 代理路径 - Status bool `json:"status"` // 状态 - ListenPort uint `json:"listenPort"` // 代理端口 + Port uint `json:"port"` // 本地端口 + ProxyType string `json:"proxyType"` // 代理类型 + Domain string `json:"domain"` // 代理域名 + Path string `json:"path"` // 代理路径 + Status bool `json:"status"` // 状态 } func (*LocalProxy) TableName() string { diff --git a/godo/proxy/local.go b/godo/proxy/local.go index df16b65..d9c62e4 100644 --- a/godo/proxy/local.go +++ b/godo/proxy/local.go @@ -3,13 +3,16 @@ package proxy import ( "context" "encoding/json" + "errors" "fmt" "godo/libs" "godo/model" + "log" "net" "net/http" "net/http/httputil" "net/url" + "os" "strconv" "sync" "time" @@ -116,11 +119,10 @@ func UpdateLocalProxyHandler(w http.ResponseWriter, r *http.Request) { return } updata := map[string]interface{}{ - "port": lp.Port, - "proxy_type": lp.ProxyType, - "domain": lp.Domain, - "status": lp.Status, - "listen_port": lp.ListenPort, + "port": lp.Port, + "proxy_type": lp.ProxyType, + "domain": lp.Domain, + "status": lp.Status, // path } @@ -267,58 +269,56 @@ func stopProxy(id uint) { default: fmt.Printf("Unknown proxy type: %s\n", proxyServer.Type) } + proxyServers.Delete(id) } } // HTTP 代理处理函数 func httpProxyHandler(proxy model.LocalProxy) { - // 如果 ListenPort 没有传递,默认为 80 - if proxy.ListenPort == 0 { - proxy.ListenPort = 80 - } - - fmt.Printf("Initializing HTTP proxy for ID %d on domain %s and listen port %d\n", proxy.ID, proxy.Domain, proxy.ListenPort) - - // 使用 proxy.Port 作为本地目标端口 - remote, err := url.Parse(fmt.Sprintf("http://localhost:%d", proxy.Port)) + remote, err := url.Parse(proxy.Domain) if err != nil { fmt.Printf("Failed to parse remote URL for port %d: %v\n", proxy.Port, err) return } - fmt.Printf("Parsed remote URL: %s\n", remote.String()) + if remote.Scheme == "" { + fmt.Printf("Remote URL for port %d does not contain a scheme (http/https): %s\n", proxy.Port, proxy.Domain) + return + } + + // 创建反向代理 reverseProxy := httputil.NewSingleHostReverseProxy(remote) + + // 设置请求头(如需要可以启用) reverseProxy.Director = func(req *http.Request) { + req.Header.Set("X-Forwarded-Host", req.Host) + req.Header.Set("X-Origin-Host", remote.Host) + req.Header.Set("User-Agent", "Mozilla/5.0 (compatible; curl/7.68.0)") // 设置常见的 User-Agent + req.Host = remote.Host req.URL.Scheme = remote.Scheme req.URL.Host = remote.Host - req.Host = remote.Host - req.URL.Path = proxy.Path + req.URL.Path // 使用代理路径 - fmt.Printf("Proxying request to: %s\n", req.URL.String()) - } - - reverseProxy.ModifyResponse = func(resp *http.Response) error { - fmt.Printf("Received response with status: %s\n", resp.Status) - return nil } - reverseProxy.ErrorHandler = func(rw http.ResponseWriter, req *http.Request, err error) { - fmt.Printf("Error during proxying: %v\n", err) - http.Error(rw, "Proxy error", http.StatusBadGateway) - } + reverseProxy.ErrorLog = log.New(os.Stderr, "proxy-debug: ", log.LstdFlags) - // 监听配置中指定的域名和端口 + // 启动 HTTP 服务器并监听指定端口 + bindAddress := "127.0.0.1" + serverAddr := fmt.Sprintf("%s:%d", bindAddress, proxy.Port) server := &http.Server{ - Addr: fmt.Sprintf(":%d", proxy.ListenPort), + Addr: serverAddr, Handler: reverseProxy, } proxyServers.Store(proxy.ID, ProxyServer{Type: "http", Server: server}) - if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { - fmt.Printf("Failed to start HTTP proxy on domain %s and listen port %d: %v\n", proxy.Domain, proxy.ListenPort, err) - } else { - fmt.Printf("HTTP proxy on domain %s and listen port %d started successfully\n", proxy.Domain, proxy.ListenPort) + fmt.Printf("Starting HTTP proxy on LocalHost port %d and forwarding to %s \n", proxy.Port, proxy.Domain) + if err := server.ListenAndServe(); err != nil { + if errors.Is(err, http.ErrServerClosed) { + fmt.Printf("HTTP proxy on port %d stopped gracefully.\n", proxy.Port) + } else { + fmt.Printf("Error starting HTTP proxy on port %d: %v\n", proxy.Port, err) + } } } diff --git a/godo/user/user.go b/godo/user/user.go index debe8a6..75480b8 100644 --- a/godo/user/user.go +++ b/godo/user/user.go @@ -2,6 +2,7 @@ package user import ( "encoding/json" + "fmt" "godo/libs" "godo/model" "io" @@ -74,14 +75,6 @@ func LockedScreenHandler(w http.ResponseWriter, r *http.Request) { return } - userEncodeStr, err := libs.EncodeFile("godoos", strconv.Itoa(int(user.ID))) - if err != nil { - libs.ErrorMsg(w, "failed to encode user") - return - } - - // w.Header().Set("sysuser", userEncodeStr) - // 登录成功,锁屏状态设置为 true mu.Lock() if userLockedScreen == nil { @@ -90,7 +83,7 @@ func LockedScreenHandler(w http.ResponseWriter, r *http.Request) { userLockedScreen[user.ID] = true mu.Unlock() - libs.SuccessMsg(w, userEncodeStr, "system locked") + libs.SuccessMsg(w, fmt.Sprint(user.ID), "system locked") } // 系统用户登录(解锁) @@ -130,18 +123,13 @@ func CheckLockedScreenHandler(w http.ResponseWriter, r *http.Request) { return } - decoderUid := r.Header.Get("sysuser") - if decoderUid == "" { + uidStr := r.Header.Get("sysuser") + if uidStr == "" { //获取锁屏状态 libs.SuccessMsg(w, false, "") return } - uidStr, err := libs.DecodeFile("godoos", decoderUid) - if err != nil { - libs.ErrorMsg(w, "invalid uid") - return - } uid, err := strconv.Atoi(uidStr) if err != nil { libs.ErrorMsg(w, "parse uid fail") From db6136ebf401a1354e7e29d0ed0240c228ce6cd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=8B=E7=94=B0=E5=BC=98?= <1240092443@qq.com> Date: Fri, 17 Jan 2025 17:10:39 +0800 Subject: [PATCH 3/5] =?UTF-8?q?fix=EF=BC=9A=E7=A7=BB=E9=99=A4=E6=9C=AC?= =?UTF-8?q?=E5=9C=B0=E4=BB=A3=E7=90=86=E7=9B=91=E5=90=AC=E7=AB=AF=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/setting/LocalProxy.vue | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/setting/LocalProxy.vue b/frontend/src/components/setting/LocalProxy.vue index 5c44c82..2f61664 100644 --- a/frontend/src/components/setting/LocalProxy.vue +++ b/frontend/src/components/setting/LocalProxy.vue @@ -11,7 +11,7 @@ domain: string; path?: string; status: boolean; - listenPort: number; + // listenPort: number; } const proxyInit = { id: Date.now(), @@ -20,7 +20,7 @@ domain: "", // 代理域名 path: "", // 文件路径 status: true, - listenPort: 80, + // listenPort: 80, }; const config = getSystemConfig(); const proxies = ref([]); @@ -143,7 +143,7 @@ pwdRef.value.validate((valid: boolean) => { if (valid) { proxyData.value.port = Number(proxyData.value.port); - proxyData.value.listenPort = Number(proxyData.value.listenPort); + // proxyData.value.listenPort = Number(proxyData.value.listenPort); if (isEditing.value) { updateProxies(proxyData.value); } else { @@ -169,8 +169,8 @@ { required: true, message: "代理域名不能为空", trigger: "blur" }, { pattern: - /^(https?:\/\/)?((?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{1,5})?(\/[^\s]*)?$/, - message: "请输入有效的域名格式", + /^(https?:\/\/)?((?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}|localhost|(\d{1,3}\.){3}\d{1,3})(:\d{1,5})?(\/[^\s]*)?$/, + message: "请输入有效的域名、IP或端口格式", trigger: "blur", }, ], @@ -289,12 +289,12 @@ > - - + --> Date: Fri, 17 Jan 2025 17:49:56 +0800 Subject: [PATCH 4/5] fix: unable to close local proxy --- godo/proxy/local.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/godo/proxy/local.go b/godo/proxy/local.go index d9c62e4..856d44a 100644 --- a/godo/proxy/local.go +++ b/godo/proxy/local.go @@ -135,8 +135,10 @@ func UpdateLocalProxyHandler(w http.ResponseWriter, r *http.Request) { // 停止旧的代理服务 stopProxy(lp.ID) - // 启动新的代理服务 - go startProxy(lp) + if !lp.Status { + // 启动新的代理服务 + go startProxy(lp) + } libs.SuccessMsg(w, lp, "") } @@ -237,11 +239,13 @@ func stopProxy(id uint) { switch proxyServer.Type { case "http": + fmt.Println("closing http proxy...") httpServer, ok := proxyServer.Server.(*http.Server) if ok { // 创建一个上下文,用于传递给 server.Shutdown(ctx) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() + defer httpServer.Close() if err := httpServer.Shutdown(ctx); err != nil { fmt.Printf("Failed to shutdown HTTP server on port %s: %v\n", httpServer.Addr, err) } else { From 486caf444ef186d6457101440841f6079da11bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=8B=E7=94=B0=E5=BC=98?= <1240092443@qq.com> Date: Fri, 17 Jan 2025 18:16:49 +0800 Subject: [PATCH 5/5] =?UTF-8?q?style=EF=BC=9A=E4=BC=98=E5=8C=96=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E9=A1=B5=E9=9D=A2ui?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/setting/NetProxy.vue | 6 +- frontend/src/components/setting/Setting.vue | 632 +++++++++---------- 2 files changed, 301 insertions(+), 337 deletions(-) diff --git a/frontend/src/components/setting/NetProxy.vue b/frontend/src/components/setting/NetProxy.vue index 68cd18b..3db399b 100644 --- a/frontend/src/components/setting/NetProxy.vue +++ b/frontend/src/components/setting/NetProxy.vue @@ -75,12 +75,12 @@ - + - - - - ← - - {{ t("setting") }} - - - - - - - - - - - - - - {{ t("windows.setting") }} - - - - - - - - - - - - - {{ item.title }} - {{ item.desc }} - - - - - - - + + + + + ← + + + {{ t("setting") }} + + + + + + + + + + + + + + + + -