diff --git a/frontend/package.json b/frontend/package.json index b3940af2e..3f7d6ff7f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -25,6 +25,7 @@ "markdown-it-anchor": "^9.0.1", "parse-md": "^3.0.3", "pinia": "^2.2.2", + "terser": "^5.33.0", "timeago.js": "^4.0.2", "tippy.js": "^6.3.7", "tributejs": "^5.1.3", diff --git a/frontend/src/views/layouts/base.html b/frontend/src/views/layouts/base.html index c332e163b..4bbf733c6 100644 --- a/frontend/src/views/layouts/base.html +++ b/frontend/src/views/layouts/base.html @@ -7,6 +7,7 @@ + diff --git a/frontend/vite.config.js b/frontend/vite.config.js index 105a444f1..40605abca 100644 --- a/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -9,10 +9,27 @@ export default defineConfig((configEnv) => { plugins: [vue()], build: { rollupOptions: { - input: getHtmlEntryFiles('src') + input: getHtmlEntryFiles('src'), + output: { + manualChunks(id) { + if (id.includes('node_modules')) { + return 'vendor' + } + if (id.includes('src/components')) { + return 'components' + } + } + } }, emptyOutDir: true, - sourcemap: configEnv.mode === 'development' + sourcemap: configEnv.mode === 'development', + minify: 'terser', + terserOptions: { + compress: { + drop_console: true, // Remove console logs + drop_debugger: true // Remove debugger statements + } + } }, resolve: { alias: { @@ -24,27 +41,27 @@ export default defineConfig((configEnv) => { }) function getHtmlEntryFiles(srcDir) { - const entry = {}; + const entry = {} - function traverseDir(currentDir) { - const files = fs.readdirSync(currentDir); + function traverseDir(currentDir) { + const files = fs.readdirSync(currentDir) - files.forEach((file) => { - const filePath = path.join(currentDir, file); - const isDirectory = fs.statSync(filePath).isDirectory(); + files.forEach((file) => { + const filePath = path.join(currentDir, file) + const isDirectory = fs.statSync(filePath).isDirectory() - if (isDirectory) { - // If it's a directory, recursively traverse it - traverseDir(filePath); - } else if (path.extname(file) === '.html') { - // If it's an HTML file, add it to the entry object - const name = path.relative(srcDir, filePath).replace(/\..*$/, ''); - entry[name] = filePath; - } - }); - } + if (isDirectory) { + // If it's a directory, recursively traverse it + traverseDir(filePath) + } else if (path.extname(file) === '.html') { + // If it's an HTML file, add it to the entry object + const name = path.relative(srcDir, filePath).replace(/\..*$/, '') + entry[name] = filePath + } + }) + } - traverseDir(srcDir); + traverseDir(srcDir) - return entry; + return entry } diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 97686693b..0754634eb 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -280,7 +280,7 @@ wrap-ansi "^8.1.0" wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" -"@jridgewell/gen-mapping@^0.3.2": +"@jridgewell/gen-mapping@^0.3.2", "@jridgewell/gen-mapping@^0.3.5": version "0.3.5" resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== @@ -299,12 +299,20 @@ resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== +"@jridgewell/source-map@^0.3.3": + version "0.3.6" + resolved "https://mirrors.huaweicloud.com/repository/npm/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a" + integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": version "1.5.0" resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== -"@jridgewell/trace-mapping@^0.3.24": +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== @@ -698,6 +706,11 @@ abbrev@1: resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== +acorn@^8.8.2: + version "8.12.1" + resolved "https://mirrors.huaweicloud.com/repository/npm/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== + ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" @@ -794,6 +807,11 @@ browserslist@^4.23.3: node-releases "^2.0.18" update-browserslist-db "^1.1.0" +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://mirrors.huaweicloud.com/repository/npm/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + camelcase-css@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" @@ -844,6 +862,11 @@ color-name@~1.1.4: resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +commander@^2.20.0: + version "2.20.3" + resolved "https://mirrors.huaweicloud.com/repository/npm/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + commander@^4.0.0: version "4.1.1" resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" @@ -1633,7 +1656,15 @@ source-map-js@^1.0.2, source-map-js@^1.2.0: resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== -source-map@~0.6.0: +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://mirrors.huaweicloud.com/repository/npm/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@~0.6.0: version "0.6.1" resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -1723,6 +1754,16 @@ tailwindcss@^3.4.10: resolve "^1.22.2" sucrase "^3.32.0" +terser@^5.33.0: + version "5.33.0" + resolved "https://mirrors.huaweicloud.com/repository/npm/terser/-/terser-5.33.0.tgz#8f9149538c7468ffcb1246cfec603c16720d2db1" + integrity sha512-JuPVaB7s1gdFKPKTelwUyRq5Sid2A3Gko2S0PncwdBq7kN9Ti9HPWDQ06MPsEDGsZeVESjKEnyGy68quBk1w6g== + dependencies: + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" + commander "^2.20.0" + source-map-support "~0.5.20" + thenify-all@^1.0.0: version "1.6.0" resolved "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" diff --git a/internal/handlers/render/session.go b/internal/handlers/render/session.go index 802af5c39..fd17c3047 100644 --- a/internal/handlers/render/session.go +++ b/internal/handlers/render/session.go @@ -6,6 +6,7 @@ import ( "fmt" "log/slog" "net/http" + "runtime/debug" "github.com/gin-gonic/gin" "opencsg.com/portal/config" @@ -55,21 +56,25 @@ func (i *SessionHandlerImpl) Create(ctx *gin.Context) { var user *models.User jwtToken := ctx.Query("jwt") if jwtToken == "" { + slog.Error("Login Error", "error", "jwt is blank") ctx.Redirect(http.StatusFound, "/error/login-failed?error_msg='invalid jwt token'") return } userResp, _, err := i.Server.VerifyJWTToken(jwtToken) if err != nil { - ctx.Redirect(http.StatusFound, "/error/login-failed") + stackTrace := string(debug.Stack()) + slog.Error("Login Error", "error", "verify jwt token failed", "jwt", jwtToken, slog.Any("error", err), "stack", stackTrace) + ctx.Redirect(http.StatusFound, "/errors/login-failed") return } if userResp == nil { + slog.Error("Login Error", "error", "verify jwt token failed", "jwt", jwtToken) ctx.Redirect(http.StatusFound, "/error/login-failed?error_msg='invalid jwt token'") return } - ctx.SetCookie("user_token", ctx.Param("jwt"), cookieMaxAge, "/", "", false, false) + ctx.SetCookie("user_token", jwtToken, cookieMaxAge, "/", "", false, false) ctx.SetCookie("can_change_username", fmt.Sprintf("%v", userResp.CanChangeUserName), cookieMaxAge, "/", "", false, false) dbUser, err := i.userModel.FindByLoginIdentity(ctx, userResp.UUID) @@ -88,8 +93,9 @@ func (i *SessionHandlerImpl) Create(ctx *gin.Context) { err = i.userModel.Create(ctx, user) if err != nil { - slog.Error("failed to create user", slog.Any("error", err)) - ctx.Redirect(http.StatusInternalServerError, "/error/login-failed") + stackTrace := string(debug.Stack()) + slog.Error("Login Error", "error", "create user failed", slog.Any("error", err), "uuid", userResp.UUID, "stack", stackTrace) + ctx.Redirect(http.StatusFound, "/errors/login-failed") return } } else { @@ -105,8 +111,8 @@ func (i *SessionHandlerImpl) Create(ctx *gin.Context) { user.SessionIP = ctx.ClientIP() err = i.userModel.Update(ctx, user) if err != nil { - slog.Error("failed to set user session ip", slog.Any("error", err)) - ctx.Redirect(http.StatusInternalServerError, "/error/login-failed") + slog.Error("Login Error", "error", "failed to set user session ip", slog.Any("error", err), "session_ip", user.SessionIP) + ctx.Redirect(http.StatusFound, "/errors/login-failed") return } diff --git a/internal/middleware/log.go b/internal/middleware/log.go index e4177e74f..6e9562532 100644 --- a/internal/middleware/log.go +++ b/internal/middleware/log.go @@ -10,6 +10,11 @@ import ( func Log() gin.HandlerFunc { return func(ctx *gin.Context) { + if ctx.Request.Method == "OPTIONS" || ctx.Request.Method == "HEAD" { + ctx.Next() + return + } + startTime := time.Now() ctx.Next() diff --git a/pkg/server/backend/csghubserver/csghubserver.go b/pkg/server/backend/csghubserver/csghubserver.go index b85db702c..96d9bff1d 100644 --- a/pkg/server/backend/csghubserver/csghubserver.go +++ b/pkg/server/backend/csghubserver/csghubserver.go @@ -2,9 +2,11 @@ package csghubserver import ( "context" + "crypto/tls" "encoding/json" "fmt" "io" + "log/slog" "net/http" "sync" "time" @@ -34,10 +36,16 @@ func NewCsgHubServer(ctx context.Context, baseURL, apiKey string) (*CsgHubServer if apiKey == "" { return nil, fmt.Errorf("api key not set in environment") } + + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + return &CsgHubServer{ baseURL: baseURL, httpClient: &http.Client{ - Timeout: time.Second * 5, + Timeout: time.Second * 5, + Transport: tr, }, apiKey: apiKey, ctx: ctx, @@ -53,6 +61,12 @@ func (c *CsgHubServer) getParsedResponse(method, path string, header http.Header } func (c *CsgHubServer) getResponse(method, path string, header http.Header, body io.Reader) ([]byte, *http.Response, error) { + bodyString := "" + if body != nil { + bodyData, _ := io.ReadAll(body) + bodyString = string(bodyData) + } + slog.Info("CsghubServer API Key Request", method, path, headersToString(header), bodyString) resp, err := c.doRequest(method, path, header, body) if err != nil { return nil, resp, err @@ -74,6 +88,16 @@ func (c *CsgHubServer) getResponse(method, path string, header http.Header, body return data, resp, nil } +func headersToString(headers http.Header) string { + var result string + for key, values := range headers { + for _, value := range values { + result += fmt.Sprintf("%s: %s\n", key, value) + } + } + return result +} + // Converts a response for a HTTP status code indicating an error condition // (non-2XX) to a well-known error value and response body. For non-problematic // (2XX) status codes nil will be returned. Note that on a non-2XX response, the