diff --git a/client/Logo.png b/client/Logo.png new file mode 100644 index 0000000..381512f Binary files /dev/null and b/client/Logo.png differ diff --git a/client/index.html b/client/index.html index 44adf8a..1ee4a67 100644 --- a/client/index.html +++ b/client/index.html @@ -2,9 +2,16 @@ - Cosmos + +
diff --git a/client/src/api/index.jsx b/client/src/api/index.jsx index 97dd64a..f5f85c4 100644 --- a/client/src/api/index.jsx +++ b/client/src/api/index.jsx @@ -1,4 +1,6 @@ import * as auth from './authentication.jsx'; +import * as users from './users.jsx'; export { - auth + auth, + users }; \ No newline at end of file diff --git a/client/src/api/users.jsx b/client/src/api/users.jsx new file mode 100644 index 0000000..ef775dc --- /dev/null +++ b/client/src/api/users.jsx @@ -0,0 +1,14 @@ + +function list() { + return fetch('/cosmos/api/users', { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + }, + }) + .then((res) => res.json()) +} + +export { + list, +}; \ No newline at end of file diff --git a/client/src/assets/images/auth/AuthBackground.jsx b/client/src/assets/images/auth/AuthBackground.jsx index f287662..79fbcaf 100644 --- a/client/src/assets/images/auth/AuthBackground.jsx +++ b/client/src/assets/images/auth/AuthBackground.jsx @@ -9,7 +9,7 @@ import logo from '../../../../../Logo.png'; const AuthBackground = () => { const theme = useTheme(); return ( - + Cosmos ); diff --git a/client/src/assets/images/icons/discord_white.svg b/client/src/assets/images/icons/discord_white.svg new file mode 100644 index 0000000..22ee27b --- /dev/null +++ b/client/src/assets/images/icons/discord_white.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/components/MainCard.jsx b/client/src/components/MainCard.jsx index b47b179..b68d636 100644 --- a/client/src/components/MainCard.jsx +++ b/client/src/components/MainCard.jsx @@ -28,7 +28,7 @@ const MainCard = forwardRef( divider = true, elevation, secondary, - shadow, + // shadow, sx = {}, title, codeHighlight, @@ -37,7 +37,7 @@ const MainCard = forwardRef( ref ) => { const theme = useTheme(); - boxShadow = theme.palette.mode === 'dark' ? boxShadow || true : boxShadow; + boxShadow = false; // theme.palette.mode === 'dark' ? boxShadow || true : boxShadow; return ( { setOpen(false); }; - const iconBackColorOpen = 'grey.300'; - const iconBackColor = 'grey.100'; + const iconBackColor = theme.palette.mode === 'dark' ? 'grey.700' : 'grey.100'; + const iconBackColorOpen = theme.palette.mode === 'dark' ? 'grey.800' : 'grey.200'; return ( diff --git a/client/src/layout/MainLayout/Header/index.jsx b/client/src/layout/MainLayout/Header/index.jsx index f18513d..b188247 100644 --- a/client/src/layout/MainLayout/Header/index.jsx +++ b/client/src/layout/MainLayout/Header/index.jsx @@ -17,8 +17,8 @@ const Header = ({ open, handleDrawerToggle }) => { const theme = useTheme(); const matchDownMD = useMediaQuery(theme.breakpoints.down('lg')); - const iconBackColor = 'grey.100'; - const iconBackColorOpen = 'grey.200'; + const iconBackColor = theme.palette.mode === 'dark' ? 'grey.700' : 'grey.100'; + const iconBackColorOpen = theme.palette.mode === 'dark' ? 'grey.800' : 'grey.200'; // common header const mainHeader = ( @@ -28,7 +28,7 @@ const Header = ({ open, handleDrawerToggle }) => { aria-label="open drawer" onClick={handleDrawerToggle} edge="start" - color="secondary" + color="red" sx={{ color: 'text.primary', bgcolor: open ? iconBackColorOpen : iconBackColor, ml: { xs: 0, lg: -2 } }} > {!open ? : } diff --git a/client/src/layout/MainLayout/index.jsx b/client/src/layout/MainLayout/index.jsx index a6640ef..37a00b7 100644 --- a/client/src/layout/MainLayout/index.jsx +++ b/client/src/layout/MainLayout/index.jsx @@ -50,7 +50,7 @@ const MainLayout = () => { - + diff --git a/client/src/menu-items/support.jsx b/client/src/menu-items/support.jsx index a1a31f1..b48cb4c 100644 --- a/client/src/menu-items/support.jsx +++ b/client/src/menu-items/support.jsx @@ -1,12 +1,16 @@ // assets import { GithubOutlined, QuestionOutlined } from '@ant-design/icons'; import DiscordOutlined from '../assets/images/icons/discord.svg' +import DiscordOutlinedWhite from '../assets/images/icons/discord_white.svg' +import { useTheme } from '@mui/material/styles'; // ==============================|| MENU ITEMS - SAMPLE PAGE & DOCUMENTATION ||============================== // const DiscordOutlinedIcon = (props) => { + const theme = useTheme(); return ( - Discord + Discord ); }; diff --git a/client/src/pages/authentication/AuthCard.jsx b/client/src/pages/authentication/AuthCard.jsx index 0607bad..fa1e4a7 100644 --- a/client/src/pages/authentication/AuthCard.jsx +++ b/client/src/pages/authentication/AuthCard.jsx @@ -8,16 +8,16 @@ import MainCard from '../../components/MainCard'; // ==============================|| AUTHENTICATION - CARD WRAPPER ||============================== // -const AuthCard = ({ children, ...other }) => ( - ( *': { flexGrow: 1, flexBasis: '50%' - } + }, }} + style={{ zIndex: 1, position: 'relative' }} content={false} {...other} border={false} diff --git a/client/src/pages/config/users/usermanagement.jsx b/client/src/pages/config/users/usermanagement.jsx new file mode 100644 index 0000000..6159640 --- /dev/null +++ b/client/src/pages/config/users/usermanagement.jsx @@ -0,0 +1,69 @@ +// material-ui +import { Button, Typography } from '@mui/material'; + +import Table from '@mui/material/Table'; +import TableBody from '@mui/material/TableBody'; +import TableCell from '@mui/material/TableCell'; +import TableContainer from '@mui/material/TableContainer'; +import TableHead from '@mui/material/TableHead'; +import TableRow from '@mui/material/TableRow'; +import Paper from '@mui/material/Paper'; + +import * as API from '../../../api'; + +// project import +import MainCard from '../../../components/MainCard'; +import isLoggedIn from '../../../isLoggedIn'; +import { useEffect, useState } from 'react'; + +// ==============================|| SAMPLE PAGE ||============================== // + +const UserManagement = () => { + + const [rows, setRows] = useState([ + { id: 0, nickname: '12313', reset:'123132' }, + { id: 1, nickname: '354345', reset:'345345' }, + ]); + + isLoggedIn(); + + useEffect(() => { + API.users.list() + .then(data => { + console.log(data); + setRows(data.data); + }) + }, []) + + return + + + + + Nickname + Role + Password + Actions + + + + {rows.map((row) => ( + + + {row.nickname} + + User + + + + ))} + +
+
+
+}; + +export default UserManagement; diff --git a/client/src/routes/MainRoutes.jsx b/client/src/routes/MainRoutes.jsx index bc228cf..6b567bd 100644 --- a/client/src/routes/MainRoutes.jsx +++ b/client/src/routes/MainRoutes.jsx @@ -3,6 +3,7 @@ import { lazy } from 'react'; // project import import Loadable from '../components/Loadable'; import MainLayout from '../layout/MainLayout'; +import UserManagement from '../pages/config/users/usermanagement'; // render - dashboard const DashboardDefault = Loadable(lazy(() => import('../pages/dashboard'))); @@ -40,8 +41,8 @@ const MainRoutes = { ] }, { - path: 'sample-page', - element: + path: 'config/users', + element: }, { path: 'shadow', diff --git a/client/src/themes/index.jsx b/client/src/themes/index.jsx index 4ef49ce..5266601 100644 --- a/client/src/themes/index.jsx +++ b/client/src/themes/index.jsx @@ -14,7 +14,9 @@ import componentsOverride from './overrides'; // ==============================|| DEFAULT THEME - MAIN ||============================== // export default function ThemeCustomization({ children }) { - const theme = Palette('light', 'default'); + const theme = Palette( + window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? + 'dark' : 'light'); // eslint-disable-next-line react-hooks/exhaustive-deps const themeTypography = Typography(`'Public Sans', sans-serif`); diff --git a/client/src/themes/palette.jsx b/client/src/themes/palette.jsx index 7a1b2f3..7eafb5e 100644 --- a/client/src/themes/palette.jsx +++ b/client/src/themes/palette.jsx @@ -32,28 +32,48 @@ const Palette = (mode) => { const paletteColor = ThemeOption(colors); - return createTheme({ + return createTheme(mode === 'dark' ? { palette: { mode, common: { - black: '#000', - white: '#fff' + black: '#fff', + white: '#000' }, ...paletteColor, text: { - primary: paletteColor.grey[700], - secondary: paletteColor.grey[500], - disabled: paletteColor.grey[400] + primary: paletteColor.grey[0], + secondary: paletteColor.grey[200], + disabled: paletteColor.grey[300] }, action: { disabled: paletteColor.grey[300] }, - divider: paletteColor.grey[200], + divider: paletteColor.grey[600], background: { - paper: paletteColor.grey[0], - default: paletteColor.grey.A50 + paper: paletteColor.grey[700], + default: paletteColor.grey[800] } } + } : { + mode, + common: { + black: '#000', + white: '#fff' + }, + ...paletteColor, + text: { + primary: paletteColor.grey[700], + secondary: paletteColor.grey[500], + disabled: paletteColor.grey[400] + }, + action: { + disabled: paletteColor.grey[300] + }, + divider: paletteColor.grey[200], + background: { + paper: paletteColor.grey[0], + default: paletteColor.grey.A50 + } }); }; diff --git a/gupm.json b/gupm.json index f2efa72..fa7fe07 100644 --- a/gupm.json +++ b/gupm.json @@ -33,6 +33,7 @@ "npm://@esbuild/linux-x64": "0.16.17", "npm://@mui/lab": "^5.0.0-alpha.100", "npm://@mui/material": "^5.10.6", + "npm://@mui/x-data-grid": "6.0.1", "npm://@reduxjs/toolkit": "^1.8.5", "npm://@testing-library/jest-dom": "^5.16.5", "npm://@testing-library/react": "^13.4.0", @@ -85,6 +86,6 @@ }, "description": "Cosmos Server", "name": "cosmos-server", - "version": "0.0.2", + "version": "0.0.3", "wrapInstallFolder": "src" } \ No newline at end of file diff --git a/readme.md b/readme.md index a8c3652..55bbe10 100644 --- a/readme.md +++ b/readme.md @@ -5,14 +5,16 @@ # Cosmos Server ``` -Disclaimer: Cosmos is still in early Alpha stage, please be careful when you use it. It is not (yet, at least ;p) a replacement for proper control and mindfulness of your own security. +**Disclaimer**: Cosmos is still in early Alpha stage, please be careful when you use it. It is not (yet, at least ;p) a replacement for proper control and mindfulness of your own security. ``` -Looking for a **secure** and **robust** way to run your **self-hosted applications**? With **Cosmos**, you can take control of your data and privacy without sacrificing security and stability. +Looking for the right way to run your **self-hosted applications**? With **Cosmos**, you can take control of your data and privacy without sacrificing security and stability. **Safe** and **secure** platform by design, and most importantly, **easy to setup** without ambiguity. It is a combination of a **reverse proxy**, an **authentication provider** and an **application manager**. + +![screenshot1](./screenshot1.png) Whether you have a **server**, a **NAS**, or a **Raspberry Pi** with applications such as **Plex**, **HomeAssistant** or even a blog, Cosmos is the perfect solution to secure it all. Simply install Cosmos on your server and connect to your applications through it to enjoy built-in security and robustness for all your services, right out of the box. - * **Authentication** Connect to all your application with the same account, including strong security and multi-factor authentication + * **Authentication** Connect to all your application with the same account, including strong security and **multi-factor authentication** * **Automatic HTTPS** certificates provision * **Anti-bot** protections such as Captcha and IP rate limiting * **Anti-DDOS** protections such as variable timeouts/throttling, IP rate limiting and IP blacklisting diff --git a/screenshot1.png b/screenshot1.png new file mode 100644 index 0000000..f1c9dcf Binary files /dev/null and b/screenshot1.png differ diff --git a/src/httpServer.go b/src/httpServer.go index 734d774..8e11a82 100644 --- a/src/httpServer.go +++ b/src/httpServer.go @@ -172,8 +172,8 @@ func StartServer() { // srapi.Use(utils.AcceptHeader("*/*")) srapi.Use(utils.CORSHeader(utils.GetMainConfig().HTTPConfig.Hostname)) - srapi.Use(utils.MiddlewareTimeout(5 * time.Second)) - srapi.Use(httprate.Limit(20, 1*time.Minute, + srapi.Use(utils.MiddlewareTimeout(20 * time.Second)) + srapi.Use(httprate.Limit(60, 1*time.Minute, httprate.WithKeyFuncs(httprate.KeyByIP), httprate.WithLimitHandler(func(w http.ResponseWriter, r *http.Request) { utils.Error("Too many requests. Throttling", nil)