diff --git a/build.sh b/build.sh index 5633fcc..014e8a0 100644 --- a/build.sh +++ b/build.sh @@ -5,7 +5,7 @@ if [ $? -ne 0 ]; then fi cp -r static build/ cp -r GeoLite2-Country.mmdb build/ -cp -r Logo.png build/static/ +cp -r Logo.png build/ mkdir build/images cp client/src/assets/images/icons/cosmos_gray.png build/cosmos_gray.png cp client/src/assets/images/icons/cosmos_gray.png cosmos_gray.png diff --git a/client/src/api/config.ts b/client/src/api/config.ts index 5010406..7207c35 100644 --- a/client/src/api/config.ts +++ b/client/src/api/config.ts @@ -33,6 +33,15 @@ function restart() { }) } +function canSendEmail() { + return wrap(fetch('/cosmos/api/can-send-email', { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + }, + })) +} + async function rawUpdateRoute(routeName: string, operation: Operation, newRoute?: Route): Promise { const payload = { routeName, @@ -82,4 +91,5 @@ export { moveRouteDown, deleteRoute, addRoute, + canSendEmail, }; \ No newline at end of file diff --git a/client/src/pages/authentication/auth-forms/AuthLogin.jsx b/client/src/pages/authentication/auth-forms/AuthLogin.jsx index 15be3e9..7e84775 100644 --- a/client/src/pages/authentication/auth-forms/AuthLogin.jsx +++ b/client/src/pages/authentication/auth-forms/AuthLogin.jsx @@ -36,6 +36,7 @@ import { LoadingButton } from '@mui/lab'; const AuthLogin = () => { const [checked, setChecked] = React.useState(false); + const [showResetPassword, setShowResetPassword] = React.useState(false); const [showPassword, setShowPassword] = React.useState(false); const handleClickShowPassword = () => { @@ -61,7 +62,14 @@ const AuthLogin = () => { window.location.href = '/ui/newInstall'; } }); - }); + + + API.config.canSendEmail().then((resp) => { + if(resp.status == 'OK' && resp.data.canSendEmail) { + setShowResetPassword(true); + } + }); + }, []); return ( <> @@ -184,9 +192,12 @@ const AuthLogin = () => { } label={Keep me sign in} />*/} - + {showResetPassword && Forgot Your Password? - + } + {!showResetPassword && + This server does not allow password reset. + } {errors.submit && ( diff --git a/client/src/pages/config/routes/routeSecurity.jsx b/client/src/pages/config/routes/routeSecurity.jsx index fc56ee1..6af2f8a 100644 --- a/client/src/pages/config/routes/routeSecurity.jsx +++ b/client/src/pages/config/routes/routeSecurity.jsx @@ -173,7 +173,7 @@ const RouteSecurity = ({ routeConfig }) => { { import('../pages/dashboard'))); @@ -22,6 +24,7 @@ const Color = Loadable(lazy(() => import('../pages/components-overview/Color'))) const Shadow = Loadable(lazy(() => import('../pages/components-overview/Shadow'))); const AntIcons = Loadable(lazy(() => import('../pages/components-overview/AntIcons'))); + // ==============================|| MAIN ROUTING ||============================== // const MainRoutes = { @@ -33,6 +36,11 @@ const MainRoutes = { // redirect to /ui element: }, + { + path: '/ui/logo', + // redirect to /ui + element: + }, { path: '/ui', element: diff --git a/dockerfile b/dockerfile index e76c257..c0f5025 100644 --- a/dockerfile +++ b/dockerfile @@ -12,6 +12,7 @@ WORKDIR /app COPY build/cosmos . COPY build/cosmos_gray.png . +COPY build/Logo.png . COPY build/GeoLite2-Country.mmdb . COPY build/meta.json . COPY static ./static diff --git a/dockerfile.arm64 b/dockerfile.arm64 index 8753810..7b8a5f5 100644 --- a/dockerfile.arm64 +++ b/dockerfile.arm64 @@ -12,6 +12,7 @@ WORKDIR /app COPY build/cosmos . COPY build/cosmos_gray.png . +COPY build/Logo.png . COPY build/GeoLite2-Country.mmdb . COPY build/meta.json . COPY static ./static diff --git a/package.json b/package.json index a627069..f6247f2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cosmos-server", - "version": "0.3.0-unstable10", + "version": "0.3.0-unstable11", "description": "", "main": "test-server.js", "bugs": { diff --git a/src/httpServer.go b/src/httpServer.go index 5cb2090..0cbe7f5 100644 --- a/src/httpServer.go +++ b/src/httpServer.go @@ -185,6 +185,7 @@ func StartServer() { } router := mux.NewRouter().StrictSlash(true) + router.HandleFunc("/logo", SendLogo) // need rewrite bc it catches too many things and prevent // client to be notified of the error @@ -199,6 +200,7 @@ func StartServer() { srapi := router.PathPrefix("/cosmos").Subrouter() srapi.HandleFunc("/api/status", StatusRoute) + srapi.HandleFunc("/api/can-send-email", CanSendEmail) srapi.HandleFunc("/api/favicon", GetFavicon) srapi.HandleFunc("/api/ping", PingURL) srapi.HandleFunc("/api/newInstall", NewInstallRoute) diff --git a/src/icons.go b/src/icons.go index 831389e..dab14c1 100644 --- a/src/icons.go +++ b/src/icons.go @@ -197,4 +197,19 @@ func PingURL(w http.ResponseWriter, req *http.Request) { utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001") return } +} + +func SendLogo(w http.ResponseWriter, req *http.Request) { + pwd,_ := os.Getwd() + imgsrc := "Logo.png" + Logo, err := ioutil.ReadFile(pwd + "/" + imgsrc) + if err != nil { + utils.Error("Logo", err) + utils.HTTPError(w, "Favicon", http.StatusInternalServerError, "FA003") + return + } + w.Header().Set("Content-Type", "image/png") + w.Header().Set("Cache-Control", "max-age=5") + w.WriteHeader(http.StatusOK) + w.Write(Logo) } \ No newline at end of file diff --git a/src/proxy/shield.go b/src/proxy/shield.go index cb80ee7..0d1a70c 100644 --- a/src/proxy/shield.go +++ b/src/proxy/shield.go @@ -266,7 +266,8 @@ func SmartShieldMiddleware(policy utils.SmartShieldPolicy) func(http.Handler) ht userConsumed := shield.GetUserUsedBudgets(clientID) if !isPrivileged(r, policy) && !shield.isAllowedToReqest(policy, userConsumed) { - utils.Log("SmartShield: User is blocked due to abuse") + utils.Log("SmartShield: User is blocked due to abuse: " + fmt.Sprintf("%+v", userConsumed)) + http.Error(w, "Too many requests", http.StatusTooManyRequests) return } else { diff --git a/src/status.go b/src/status.go index f729ad1..81bec10 100644 --- a/src/status.go +++ b/src/status.go @@ -51,4 +51,19 @@ func StatusRoute(w http.ResponseWriter, req *http.Request) { utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001") return } -} \ No newline at end of file +} + +func CanSendEmail(w http.ResponseWriter, req *http.Request) { + if(req.Method == "GET") { + json.NewEncoder(w).Encode(map[string]interface{}{ + "status": "OK", + "data": map[string]interface{}{ + "canSendEmail": utils.GetMainConfig().EmailConfig.Enabled, + }, + }) + } else { + utils.Error("UserList: Method not allowed" + req.Method, nil) + utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001") + return + } +} diff --git a/src/utils/emails.go b/src/utils/emails.go index e602c0a..c20f81b 100644 --- a/src/utils/emails.go +++ b/src/utils/emails.go @@ -93,7 +93,7 @@ func SendEmail(recipients []string, subject string, body string) error { } ServerURL := GetServerURL() - LogoURL := ServerURL + "/ui/assets/Logo.png" + LogoURL := ServerURL + "logo" send := func(addr string, a smtp.Auth, from string, to []string, msg []byte) error { c, err := smtp.Dial(addr) diff --git a/src/utils/middleware.go b/src/utils/middleware.go index 486b272..dfa0801 100644 --- a/src/utils/middleware.go +++ b/src/utils/middleware.go @@ -165,4 +165,4 @@ func BlockPostWithoutReferer(next http.Handler) http.Handler { // If it's not a POST request or the POST request has a Referer header, pass the request to the next handler next.ServeHTTP(w, r) }) -} \ No newline at end of file +} diff --git a/src/utils/utils.go b/src/utils/utils.go index 69ff515..2ffb1c3 100644 --- a/src/utils/utils.go +++ b/src/utils/utils.go @@ -5,9 +5,13 @@ import ( "math/rand" "regexp" "net/http" + "encoding/base64" "os" "strconv" "strings" + "io/ioutil" + "fmt" + "path/filepath" "github.com/shirou/gopsutil/v3/mem" ) @@ -359,4 +363,37 @@ func GetServerURL() string { } return ServerURL + "/" -} \ No newline at end of file +} + +func ImageToBase64(path string) (string, error) { + imageFile, err := os.Open(path) + if err != nil { + return "", err + } + defer imageFile.Close() + + imageData, err := ioutil.ReadAll(imageFile) + if err != nil { + return "", err + } + + encodedData := base64.StdEncoding.EncodeToString(imageData) + + fileExt := strings.ToLower(filepath.Ext(path)) + var mimeType string + switch fileExt { + case ".jpg", ".jpeg": + mimeType = "image/jpeg" + case ".png": + mimeType = "image/png" + case ".gif": + mimeType = "image/gif" + case ".bmp": + mimeType = "image/bmp" + default: + return "", fmt.Errorf("unsupported file format: %s", fileExt) + } + + dataURI := fmt.Sprintf("data:%s;base64,%s", mimeType, encodedData) + return dataURI, nil +}