From c54d9c15bc9f0a4fa01a7e10c8858a57ac0279b2 Mon Sep 17 00:00:00 2001 From: Alireza Ahmadi Date: Mon, 26 Feb 2024 19:01:01 +0100 Subject: [PATCH] add base url --- backend/api/api.go | 9 ++++++-- backend/service/setting.go | 26 +++++++++++++++++++++++ backend/web/web.go | 28 ++++++++++++++++--------- frontend/index.html | 3 +++ frontend/src/components/Main.vue | 2 +- frontend/src/layouts/default/Drawer.vue | 2 +- frontend/src/layouts/modals/Stats.vue | 2 +- frontend/src/locales/en.ts | 1 + frontend/src/locales/fa.ts | 1 + frontend/src/plugins/api.ts | 2 ++ frontend/src/router/index.ts | 2 +- frontend/src/store/modules/data.ts | 8 +++---- frontend/src/views/Inbounds.vue | 2 +- frontend/src/views/Login.vue | 2 +- frontend/src/views/Settings.vue | 17 ++++++++------- frontend/vite.config.ts | 3 ++- 16 files changed, 80 insertions(+), 30 deletions(-) diff --git a/backend/api/api.go b/backend/api/api.go index f0299a1..ec1032b 100644 --- a/backend/api/api.go +++ b/backend/api/api.go @@ -27,7 +27,8 @@ func NewAPIHandler(g *gin.RouterGroup) { func (a *APIHandler) initRouter(g *gin.RouterGroup) { g.Use(func(c *gin.Context) { - if c.Request.URL.Path != "/api/login" && c.Request.URL.Path != "/api/logout" { + path := c.Request.URL.Path + if !strings.HasSuffix(path, "login") && !strings.HasSuffix(path, "logout") { checkLogin(c) } }) @@ -62,7 +63,11 @@ func (a *APIHandler) postHandler(c *gin.Context) { } err = SetLoginUser(c, loginUser) - logger.Info("user ", loginUser, " login success") + if err == nil { + logger.Info("user ", loginUser, " login success") + } else { + logger.Warning("login failed: ", err) + } jsonMsg(c, "", nil) case "save": diff --git a/backend/service/setting.go b/backend/service/setting.go index 108984a..4edc3f4 100644 --- a/backend/service/setting.go +++ b/backend/service/setting.go @@ -21,6 +21,7 @@ var defaultValueMap = map[string]string{ "webSecret": common.Random(32), "webCertFile": "", "webKeyFile": "", + "webPath": "/app/", "sessionMaxAge": "0", "timeLocation": "Asia/Tehran", "subListen": "", @@ -158,6 +159,20 @@ func (s *SettingService) GetKeyFile() (string, error) { return s.getString("webKeyFile") } +func (s *SettingService) GetWebPath() (string, error) { + webPath, err := s.getString("webPath") + if err != nil { + return "", err + } + if !strings.HasPrefix(webPath, "/") { + webPath = "/" + webPath + } + if !strings.HasSuffix(webPath, "/") { + webPath += "/" + } + return webPath, nil +} + func (s *SettingService) GetSecret() ([]byte, error) { secret, err := s.getString("webSecret") if secret == defaultValueMap["webSecret"] { @@ -278,6 +293,17 @@ func (s *SettingService) Save(tx *gorm.DB, changes []model.Changes) error { } } + // Correct Pathes start and ends with `/` + if key == "webPath" || + key == "subPath" { + if !strings.HasPrefix(obj, "/") { + obj = "/" + obj + } + if !strings.HasSuffix(obj, "/") { + obj += "/" + } + } + err = tx.Model(model.Setting{}).Where("key = ?", key).Update("value", obj).Error if err != nil { return err diff --git a/backend/web/web.go b/backend/web/web.go index 24a046d..dc6ba03 100644 --- a/backend/web/web.go +++ b/backend/web/web.go @@ -53,6 +53,11 @@ func (s *Server) initRouter() (*gin.Engine, error) { engine := gin.Default() + base_url, err := s.settingService.GetWebPath() + if err != nil { + return nil, err + } + webDomain, err := s.settingService.GetWebDomain() if err != nil { return nil, err @@ -68,10 +73,11 @@ func (s *Server) initRouter() (*gin.Engine, error) { } engine.Use(gzip.Gzip(gzip.DefaultCompression)) - assetsBasePath := "/assets/" + assetsBasePath := base_url + "assets/" store := cookie.NewStore(secret) engine.Use(sessions.Sessions("session", store)) + engine.Use(func(c *gin.Context) { uri := c.Request.RequestURI if strings.HasPrefix(uri, assetsBasePath) { @@ -87,26 +93,28 @@ func (s *Server) initRouter() (*gin.Engine, error) { engine.StaticFS(assetsBasePath, http.FS(assetsFS)) - group_api := engine.Group("/api") + group_api := engine.Group(base_url + "api") api.NewAPIHandler(group_api) + // Load the HTML template + engine.LoadHTMLFiles("backend/web/html/index.html") + // Serve index.html as the entry point // Handle all other routes by serving index.html engine.NoRoute(func(c *gin.Context) { - if c.Request.URL.Path != "/login" && !api.IsLogin(c) { - c.Redirect(http.StatusTemporaryRedirect, "/login") + if !strings.HasPrefix(c.Request.URL.Path, base_url) { + c.String(404, "") return } - if c.Request.URL.Path == "/login" && api.IsLogin(c) { - c.Redirect(http.StatusTemporaryRedirect, "/") + if c.Request.URL.Path != base_url+"login" && !api.IsLogin(c) { + c.Redirect(http.StatusTemporaryRedirect, base_url+"login") return } - data, err := content.ReadFile("html/index.html") - if err != nil { - c.String(http.StatusInternalServerError, "Internal Server Error") + if c.Request.URL.Path == base_url+"login" && api.IsLogin(c) { + c.Redirect(http.StatusTemporaryRedirect, base_url) return } - c.Data(http.StatusOK, "text/html", data) + c.HTML(http.StatusOK, "index.html", gin.H{"BASE_URL": base_url}) }) return engine, nil diff --git a/frontend/index.html b/frontend/index.html index 971aff7..308cd5b 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -5,6 +5,9 @@ + S-UI diff --git a/frontend/src/components/Main.vue b/frontend/src/components/Main.vue index ab2c733..67be341 100644 --- a/frontend/src/components/Main.vue +++ b/frontend/src/components/Main.vue @@ -184,7 +184,7 @@ const reloadItems = computed({ const reloadData = async () => { const request = [...new Set(reloadItems.value.map(r => r.split('-')[1]))] - const data = await HttpUtils.get('/api/status',{ r: request.join(',')}) + const data = await HttpUtils.get('api/status',{ r: request.join(',')}) if (data.success) { tilesData.value = data.obj } diff --git a/frontend/src/layouts/default/Drawer.vue b/frontend/src/layouts/default/Drawer.vue index 35e9b2f..6c0c07d 100644 --- a/frontend/src/layouts/default/Drawer.vue +++ b/frontend/src/layouts/default/Drawer.vue @@ -59,7 +59,7 @@ const menu = [ ] const logout = async () => { - const response = await HttpUtil.get('/api/logout') + const response = await HttpUtil.get('api/logout') if(response.success){ router.push('/login') } diff --git a/frontend/src/layouts/modals/Stats.vue b/frontend/src/layouts/modals/Stats.vue index be2787e..de171cd 100644 --- a/frontend/src/layouts/modals/Stats.vue +++ b/frontend/src/layouts/modals/Stats.vue @@ -101,7 +101,7 @@ export default { methods: { async loadData(limit: number) { this.loading = true - const data = await HttpUtils.get('/api/stats', { resource: this.resource, tag: this.tag, limit: limit }) + const data = await HttpUtils.get('api/stats', { resource: this.resource, tag: this.tag, limit: limit }) if (data.success && data.obj) { const obj = data.obj const l = String(i18n.global.locale) == 'fa' ? "fa-IR" : "en-US" diff --git a/frontend/src/locales/en.ts b/frontend/src/locales/en.ts index 23dc07f..9231783 100644 --- a/frontend/src/locales/en.ts +++ b/frontend/src/locales/en.ts @@ -86,6 +86,7 @@ export default { sub: "Subscription", addr: "Address", port: "Port", + webPath: "Base URI", domain: "Domain", sslKey: "SSL Key Path", sslCert: "SSL Certificate Path", diff --git a/frontend/src/locales/fa.ts b/frontend/src/locales/fa.ts index ce7111d..4e5012c 100644 --- a/frontend/src/locales/fa.ts +++ b/frontend/src/locales/fa.ts @@ -86,6 +86,7 @@ export default { sub: "سابسکریپشن", addr: "آدرس", port: "پورت", + webPath: "مسیر پایه", domain: "دامنه", sslKey: "مسیر فایل کلید", sslCert: "مسیر فایل گواهی", diff --git a/frontend/src/plugins/api.ts b/frontend/src/plugins/api.ts index 138b275..f6c7a73 100644 --- a/frontend/src/plugins/api.ts +++ b/frontend/src/plugins/api.ts @@ -3,6 +3,8 @@ import axios from 'axios' axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8' axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest' +axios.defaults.baseURL = "./" + axios.interceptors.request.use( (config) => { if (config.data instanceof FormData) { diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index 2ca4327..4cc6da7 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -54,7 +54,7 @@ const routes = [ ] const router = createRouter({ - history: createWebHistory(process.env.BASE_URL), + history: createWebHistory((window as any).BASE_URL), routes, }) diff --git a/frontend/src/store/modules/data.ts b/frontend/src/store/modules/data.ts index 3deaaa4..ab99ffa 100644 --- a/frontend/src/store/modules/data.ts +++ b/frontend/src/store/modules/data.ts @@ -15,7 +15,7 @@ const Data = defineStore('Data', { }), actions: { async loadData() { - const msg = await HttpUtils.get('/api/load', this.lastLoad >0 ? {lu: this.lastLoad} : {} ) + const msg = await HttpUtils.get('api/load', this.lastLoad >0 ? {lu: this.lastLoad} : {} ) if(msg.success) { this.lastLoad = Math.floor((new Date()).getTime()/1000) @@ -36,7 +36,7 @@ const Data = defineStore('Data', { config: JSON.stringify(FindDiff.Config(this.config,this.oldData.config)), clients: JSON.stringify(FindDiff.Clients(this.clients,this.oldData.clients)), } - const msg = await HttpUtils.post('/api/save',diff) + const msg = await HttpUtils.post('api/save',diff) if(msg.success) { this.loadData() } @@ -46,7 +46,7 @@ const Data = defineStore('Data', { config: JSON.stringify([{key: "inbounds", action: "del", index: index, obj: null}]), clients: JSON.stringify(FindDiff.Clients(this.clients,this.oldData.clients)), } - const msg = await HttpUtils.post('/api/save',diff) + const msg = await HttpUtils.post('api/save',diff) if(msg.success) { this.loadData() } @@ -56,7 +56,7 @@ const Data = defineStore('Data', { config: JSON.stringify(FindDiff.Config(this.config,this.oldData.config)), clients:JSON.stringify([{key: "clients", action: "del", index: id, obj: null}]), } - const msg = await HttpUtils.post('/api/save',diff) + const msg = await HttpUtils.post('api/save',diff) if(msg.success) { this.loadData() } diff --git a/frontend/src/views/Inbounds.vue b/frontend/src/views/Inbounds.vue index 3bfbd4e..1b89c7d 100644 --- a/frontend/src/views/Inbounds.vue +++ b/frontend/src/views/Inbounds.vue @@ -53,7 +53,7 @@ {{ u }}
- {{ Object.hasOwn(item,'users') ? item.users.length : '-' }} + {{ Array.isArray(item.users) ? item.users.length : '-' }} diff --git a/frontend/src/views/Login.vue b/frontend/src/views/Login.vue index 4af7b78..9d497b8 100644 --- a/frontend/src/views/Login.vue +++ b/frontend/src/views/Login.vue @@ -63,7 +63,7 @@ const router = useRouter() const login = async () => { if (username.value == '' || password.value == '') return loading.value=true - const response = await HttpUtil.post('/api/login',{user: username.value, pass: password.value}) + const response = await HttpUtil.post('api/login',{user: username.value, pass: password.value}) if(response.success){ setTimeout(() => { loading.value=false diff --git a/frontend/src/views/Settings.vue b/frontend/src/views/Settings.vue index 2a9a05c..3d9ca5b 100644 --- a/frontend/src/views/Settings.vue +++ b/frontend/src/views/Settings.vue @@ -32,6 +32,9 @@ + + + @@ -143,6 +146,7 @@ const settings = ref({ webPort: "2095", webCertFile: "", webKeyFile: "", + webPath: "/app/", sessionMaxAge: "0", timeLocation: "Asia/Tehran", subListen: "", @@ -166,7 +170,7 @@ const changeLocale = (l: any) => { const loadData = async () => { loading.value = true - const msg = await HttpUtils.get('/api/setting') + const msg = await HttpUtils.get('api/setting') loading.value = false if (msg.success) { settings.value = msg.obj @@ -179,7 +183,7 @@ const saveChanges = async () => { const diff = { settings: JSON.stringify(FindDiff.Settings(settings.value,oldSettings.value)), } - const msg = await HttpUtils.post('/api/save', diff) + const msg = await HttpUtils.post('api/save', diff) if (msg.success) { loadData() } @@ -190,17 +194,17 @@ const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)) const restartApp = async () => { loading.value = true - const msg = await HttpUtils.post('/api/restartApp',{}) + const msg = await HttpUtils.post('api/restartApp',{}) if (msg.success) { const isTLS = settings.value.webCertFile !== "" || settings.value.webKeyFile !== "" - const url = buildURL(settings.value.webDomain,settings.value.webPort.toString(),isTLS) + const url = buildURL(settings.value.webDomain,settings.value.webPort.toString(),isTLS, settings.value.webPath) await sleep(3000) window.location.replace(url) } loading.value = false } -const buildURL = (host: string, port: string, isTLS: boolean ) => { +const buildURL = (host: string, port: string, isTLS: boolean, path: string) => { if (!host || host.length == 0) host = window.location.hostname if (!port || port.length == 0) port = window.location.port @@ -212,7 +216,7 @@ const buildURL = (host: string, port: string, isTLS: boolean ) => { port = `:${port}` } - return `${protocol}//${host}${port}/settings` + return `${protocol}//${host}${port}${path}settings` } const subEncode = computed({ @@ -245,7 +249,6 @@ const subUpdates = computed({ set: (v:number) => { settings.value.subUpdates = v.toString() } }) - const stateChange = computed(() => { return !FindDiff.deepCompare(settings.value,oldSettings.value) }) diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index c42e359..7019bdf 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -7,6 +7,7 @@ import { defineConfig } from 'vite' import { fileURLToPath, URL } from 'node:url' export default defineConfig({ + base: '', plugins: [ vue({ template: { transformAssetUrls }, @@ -40,7 +41,7 @@ export default defineConfig({ server: { port: 3000, proxy: { - '/api': { + '/app/api': { target: 'http://localhost:2095', changeOrigin: true, },