From 4e5645f9bb577ba7a0148f61ac1002699694fd26 Mon Sep 17 00:00:00 2001 From: Yann Stepienik Date: Tue, 13 Feb 2024 19:07:44 +0000 Subject: [PATCH] [release] v0.15.8 --- changelog.md | 6 + client/src/api/storage.jsx | 4 +- client/src/components/logsInModal.jsx | 42 +++-- client/src/components/passwordModal.jsx | 82 ++++++++ client/src/pages/newInstall/newInstall.jsx | 2 +- client/src/pages/servapps/actionBar.jsx | 2 +- client/src/pages/servapps/createNetwork.jsx | 13 ++ client/src/pages/storage/FormatModal.jsx | 103 ++++++++++ client/src/pages/storage/disks.jsx | 197 +++++++++++--------- client/src/pages/storage/mounts.jsx | 2 +- go.mod | 1 + package.json | 2 +- src/docker/api_blueprint.go | 22 ++- src/docker/api_networks.go | 19 +- src/docker/network.go | 71 ++++++- src/metrics/aggl.go | 4 +- src/storage/API_parts.go | 39 ++-- src/storage/disks.go | 6 +- src/user/login.go | 4 +- src/utils/utils.go | 41 ++++ 20 files changed, 508 insertions(+), 154 deletions(-) create mode 100644 client/src/components/passwordModal.jsx create mode 100644 client/src/pages/storage/FormatModal.jsx diff --git a/changelog.md b/changelog.md index 72acfdd..dc09329 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,9 @@ +## Version 0.15.0 + - Added Disk management (Format, mount, SMART, etc...) + - Added Storage management (MergeFS, SnapRAID, RClone, etc...) + - Overwrite all docker networks size to prevent Cosmos from running out of IP addresses + - Added optional subnet input to the network creation + ## Version 0.14.6 - Fix custom back-up folder logic diff --git a/client/src/api/storage.jsx b/client/src/api/storage.jsx index 8372b4d..70ff1ea 100644 --- a/client/src/api/storage.jsx +++ b/client/src/api/storage.jsx @@ -43,13 +43,13 @@ const disks = { })) }, - format({disk, format}, onProgress) { + format({disk, format, password}, onProgress) { const requestOptions = { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({disk, format}) + body: JSON.stringify({disk, format, password}) }; return fetch('/cosmos/api/disks/format', requestOptions) diff --git a/client/src/components/logsInModal.jsx b/client/src/components/logsInModal.jsx index 83ba87a..8b28130 100644 --- a/client/src/components/logsInModal.jsx +++ b/client/src/components/logsInModal.jsx @@ -53,24 +53,32 @@ const LogsInModal = ({title, request, OnSuccess, OnError, closeAnytime, OnClose, if(request === null) return; - request((newlog) => { - setLogs((old) => smartDockerLogConcat(old, newlog)); + try { + request((newlog) => { + setLogs((old) => smartDockerLogConcat(old, newlog)); - if(preRef.current) - preRef.current.scrollTop = preRef.current.scrollHeight; - - if (newlog.includes('[OPERATION SUCCEEDED]')) { - setDone(true); - if(!alwaysShow) - close(); - OnSuccess && OnSuccess(); - } else if (newlog.includes('[OPERATION FAILED]')) { - setDone(true); - OnError && OnError(newlog); - } else { - setOpenModal(true); - } - }); + if(preRef.current) + preRef.current.scrollTop = preRef.current.scrollHeight; + + if (newlog.includes('[OPERATION SUCCEEDED]')) { + setDone(true); + if(!alwaysShow) + close(); + OnSuccess && OnSuccess(); + } else if (newlog.includes('[OPERATION FAILED]')) { + setDone(true); + OnError && OnError(newlog); + } else { + setOpenModal(true); + } + }).catch((err) => { + setLogs((old) => smartDockerLogConcat(old, err.message)); + OnError && OnError(err); + }); + } catch(err) { + setLogs((old) => smartDockerLogConcat(old, err.message)); + OnError && OnError(err); + }; }, [request]); return <> diff --git a/client/src/components/passwordModal.jsx b/client/src/components/passwordModal.jsx new file mode 100644 index 0000000..80f74c6 --- /dev/null +++ b/client/src/components/passwordModal.jsx @@ -0,0 +1,82 @@ +// material-ui +import * as React from 'react'; +import { Alert, Button, Checkbox, FormControl, FormHelperText, Grid, InputLabel, MenuItem, Select, Stack, TextField } from '@mui/material'; +import Dialog from '@mui/material/Dialog'; +import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import DialogContentText from '@mui/material/DialogContentText'; +import DialogTitle from '@mui/material/DialogTitle'; +import { LoadingButton } from '@mui/lab'; +import { useFormik, FormikProvider } from 'formik'; +import * as Yup from 'yup'; + +const PasswordModal = ({ textInfos, cb, OnClose }) => { + + const formik = useFormik({ + initialValues: { + password: '' + }, + validationSchema: Yup.object({ + password: Yup.string().required('Required'), + }), + onSubmit: async (values, { setErrors, setStatus, setSubmitting }) => { + setSubmitting(true); + cb(values.password).then((res) => { + setStatus({ success: true }); + setSubmitting(false); + OnClose(); + }).catch((err) => { + setStatus({ success: false }); + setErrors({ submit: err.message }); + setSubmitting(false); + }); + }, + }); + + return ( + <> + OnClose()}> + + Confirm Password + + +
+ + + +
+ {formik.errors.submit && ( + + {formik.errors.submit} + + )} +
+
+ + + + Confirm + + +
+
+ + ); +}; + +export default PasswordModal; diff --git a/client/src/pages/newInstall/newInstall.jsx b/client/src/pages/newInstall/newInstall.jsx index 432d487..9ad3544 100644 --- a/client/src/pages/newInstall/newInstall.jsx +++ b/client/src/pages/newInstall/newInstall.jsx @@ -204,7 +204,7 @@ const NewInstall = () => { setDatabaseEnable(false); } pullRequestOnSuccess(); - API.getStatus().then((res) => { + return API.getStatus().then((res) => { formik.setSubmitting(false); formik.setStatus({ success: true }); }); diff --git a/client/src/pages/servapps/actionBar.jsx b/client/src/pages/servapps/actionBar.jsx index f767482..1a3114f 100644 --- a/client/src/pages/servapps/actionBar.jsx +++ b/client/src/pages/servapps/actionBar.jsx @@ -28,7 +28,7 @@ const GetActions = ({ if(action === 'update') { setPullRequest(() => ((cb) => { - API.docker.updateContainerImage(Id, cb, true) + return API.docker.updateContainerImage(Id, cb, true) })); return; } diff --git a/client/src/pages/servapps/createNetwork.jsx b/client/src/pages/servapps/createNetwork.jsx index 3a79eb9..ede2246 100644 --- a/client/src/pages/servapps/createNetwork.jsx +++ b/client/src/pages/servapps/createNetwork.jsx @@ -24,6 +24,7 @@ const NewNetworkButton = ({ fullWidth, refresh }) => { driver: 'bridge', attachCosmos: false, parentInterface: '', + subnet: '', }, validationSchema: Yup.object({ name: Yup.string().required('Required'), @@ -93,6 +94,18 @@ const NewNetworkButton = ({ fullWidth, refresh }) => { MCVLAN + + {formik.values.driver === 'mcvlan' && ( { + const formik = useFormik({ + initialValues: { + password: '', + format: 'ext4' + }, + validationSchema: Yup.object({ + password: Yup.string().required('Required'), + }), + onSubmit: async (values, { setErrors, setStatus, setSubmitting }) => { + setSubmitting(true); + cb(values).then((res) => { + setStatus({ success: true }); + setSubmitting(false); + OnClose(); + }).catch((err) => { + setStatus({ success: false }); + setErrors({ submit: err.message }); + setSubmitting(false); + }); + }, + }); + + return ( + <> + OnClose()}> + + Format Disk + + +
+ + + + Disk Format + + + + + +
+ {formik.errors.submit && ( + + {formik.errors.submit} + + )} +
+
+ + + + Confirm + + +
+
+ + ); +}; + +export default FormatModal; diff --git a/client/src/pages/storage/disks.jsx b/client/src/pages/storage/disks.jsx index e046831..585fa08 100644 --- a/client/src/pages/storage/disks.jsx +++ b/client/src/pages/storage/disks.jsx @@ -22,6 +22,8 @@ import raidIcon from '../../assets/images/icons/database.svg'; import { simplifyNumber } from "../dashboard/components/utils"; import LogsInModal from "../../components/logsInModal"; import MountDialog from "./mountDialog"; +import PasswordModal from "../../components/passwordModal"; +import FormatModal from "./FormatModal"; const diskStyle = { width: "100%", @@ -44,21 +46,37 @@ const icons = { const FormatButton = ({disk, refresh}) => { const [formatting, setFormatting] = useState(false); const [loading, setLoading] = useState(false); + const [passwordConfirm, setPasswordConfirm] = useState(false); + const [values, setValues] = useState(""); return <> {setFormatting(true); setLoading(true)}} - variant="contained" + onClick={() => {setPasswordConfirm(true); setLoading(true)}} + variant="outlined" color="error" size="small" >Format + + {passwordConfirm && { + setPasswordConfirm(false); + setLoading(false); + }} + textInfos={`Enter your password to confirm you want to format ${disk.name}`} + cb={async (values) => { + setPasswordConfirm(false); + setFormatting(values); + }} + />} + {formatting && { - API.storage.disks.format({ - disk: disk.name, - format: "ext4", - }, cb) + return API.storage.disks.format({ + disk: disk.name, + format: formatting.format, + password: formatting.password, + }, cb) }} initialLogs={[ "Starting format disk " + disk.name + "..." @@ -85,92 +103,94 @@ const Disk = ({disk, refresh}) => { percent = Math.round((disk.usage / disk.size) * 100); } - return - 55 ? (disk.smart.Temperature > 70 ? "red" : "orange") : "green") : "gray")), - }}> - -
- {disk.smart.Temperature ?
- - {disk.smart.Temperature > 55 && } {disk.smart.Temperature}°C -
: ""} - - - {icons[disk.type] ? : } - -
-
- -
- {disk.name.replace("/dev/", "")} - - {disk.rota ? " (HDD)" : " (SSD)"} - {disk.fstype ? ` - ${disk.fstype}` : ""} - {disk.model ? ` - ${disk.model}` : ""} {disk.mountpoint ? ` (${disk.mountpoint})` : ""} - -
- {disk.usage ? <> -
95 ? 'error' : (percent > 75 ? 'warning' : 'info')} - value={percent} />
-
{simplifyNumber(disk.usage, 'b')} / {simplifyNumber(disk.size, 'b')} ({percent}%)
- : simplifyNumber(disk.size, 'b')} + return <> + + 55 ? (disk.smart.Temperature > 70 ? "red" : "orange") : "green") : "gray")), + }}> + +
+ {disk.smart.Temperature ?
+ + {disk.smart.Temperature > 55 && } {disk.smart.Temperature}°C +
: ""} + + + {icons[disk.type] ? : } + +
+
+ +
+ {disk.name.replace("/dev/", "")} + + {disk.rota ? " (HDD)" : " (SSD)"} + {disk.fstype ? ` - ${disk.fstype}` : ""} + {disk.model ? ` - ${disk.model}` : ""} {disk.mountpoint ? ` (${disk.mountpoint})` : ""} + +
+ {disk.usage ? <> +
95 ? 'error' : (percent > 75 ? 'warning' : 'info')} + value={percent} />
+
{simplifyNumber(disk.usage, 'b')} / {simplifyNumber(disk.size, 'b')} ({percent}%)
+ : simplifyNumber(disk.size, 'b')} +
+
+
+ + + {Object.keys(disk).filter(key => key !== "name" && key !== "children" && key !== "smart"&& key !== "fstype"&& key !== "mountpoint"&& key !== "model" && key !== "usage" &&key !== "rota" && key !== "type" && key !== "size").map((key, index) => { + return
{key}: { + (typeof disk[key] == "object" ? JSON.stringify(disk[key]) : disk[key]) + }
+ })} +
+ + {(disk.type == "disk" || disk.type == "part") ? : ""} + + {disk.mountpoint ? : ""} + + {( + (disk.type == "part" || (disk.type == "disk" && (!disk.children || !disk.children.length))) && + disk.fstype && + disk.fstype !== "swap" && + !disk.mountpoint + ) ? : ""} -
-
- - - {Object.keys(disk).filter(key => key !== "name" && key !== "children" && key !== "smart"&& key !== "fstype"&& key !== "mountpoint"&& key !== "model" && key !== "usage" &&key !== "rota" && key !== "type" && key !== "size").map((key, index) => { - return
{key}: { - (typeof disk[key] == "object" ? JSON.stringify(disk[key]) : disk[key]) - }
- })} -
- - {(disk.type == "disk" || disk.type == "part") ? : ""} - - {disk.mountpoint ? : ""} - - {( - (disk.type == "part" || (disk.type == "disk" && (!disk.children || !disk.children.length))) && - disk.fstype && - disk.fstype !== "swap" && - !disk.mountpoint - ) ? : ""}
-
- - }> - {disk.children && disk.children.map((child, index) => { - return - })} -
+ + }> + {disk.children && disk.children.map((child, index) => { + return + })} + + ; } export const StorageDisks = () => { @@ -206,7 +226,6 @@ export const StorageDisks = () => { > {disks && disks.map((disk, index) => { return { - // wait 1s await new Promise(r => setTimeout(r, 1000)); await refresh() }} /> diff --git a/client/src/pages/storage/mounts.jsx b/client/src/pages/storage/mounts.jsx index 1738a06..283deca 100644 --- a/client/src/pages/storage/mounts.jsx +++ b/client/src/pages/storage/mounts.jsx @@ -37,7 +37,7 @@ export const StorageMounts = () => {
{mounts && mounts.map((mount, index) => { return
- {mount.Device} - {mount.Path} ({mount.Type}) + {mount.device} - {mount.path} ({mount.type})
})}
diff --git a/go.mod b/go.mod index 1466c1b..5cd89e0 100644 --- a/go.mod +++ b/go.mod @@ -249,4 +249,5 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.4.0 // indirect k8s.io/klog/v2 v2.80.1 // indirect + k8s.io/utils v0.0.0-20240102154912-e7106e64919e // indirect ) diff --git a/package.json b/package.json index 6cee749..893ba64 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cosmos-server", - "version": "0.15.0-unstable7", + "version": "0.15.0-unstable8", "description": "", "main": "test-server.js", "bugs": { diff --git a/src/docker/api_blueprint.go b/src/docker/api_blueprint.go index 6945690..bc027ec 100644 --- a/src/docker/api_blueprint.go +++ b/src/docker/api_blueprint.go @@ -320,16 +320,18 @@ func CreateService(serviceRequest DockerServiceCreateRequest, OnLog func(string) } } - _, err = DockerClient.NetworkCreate(DockerContext, networkToCreateName, doctype.NetworkCreate{ - Driver: networkToCreate.Driver, - Attachable: networkToCreate.Attachable, - Internal: networkToCreate.Internal, - EnableIPv6: networkToCreate.EnableIPv6, - IPAM: &network.IPAM{ - Driver: networkToCreate.IPAM.Driver, - Config: ipamConfig, - }, - }) + networkPayload := doctype.NetworkCreate{ + Driver: networkToCreate.Driver, + Attachable: networkToCreate.Attachable, + Internal: networkToCreate.Internal, + EnableIPv6: networkToCreate.EnableIPv6, + IPAM: &network.IPAM{ + Driver: networkToCreate.IPAM.Driver, + Config: ipamConfig, + }, + } + + _, err = CreateReasonableNetwork(networkToCreateName, networkPayload) if err != nil { utils.Error("CreateService: Rolling back changes because of -- Network", err) diff --git a/src/docker/api_networks.go b/src/docker/api_networks.go index 6dea319..f25912f 100644 --- a/src/docker/api_networks.go +++ b/src/docker/api_networks.go @@ -9,6 +9,7 @@ import ( "github.com/gorilla/mux" "github.com/azukaar/cosmos-server/src/utils" "github.com/docker/docker/api/types" + network "github.com/docker/docker/api/types/network" ) func ListNetworksRoute(w http.ResponseWriter, req *http.Request) { @@ -251,7 +252,8 @@ type createNetworkPayload struct { Name string `json:"name"` Driver string `json:"driver"` AttachCosmos bool `json:"attachCosmos"` - parentInterface string `json:"parentInterface"` + ParentInterface string `json:"parentInterface"` + Subnet string `json:"subnet"` } func CreateNetworkRoute(w http.ResponseWriter, req *http.Request) { @@ -279,11 +281,22 @@ func CreateNetworkRoute(w http.ResponseWriter, req *http.Request) { CheckDuplicate: true, Driver: payload.Driver, Options: map[string]string{ - "parent": payload.parentInterface, + "parent": payload.ParentInterface, }, } - resp, err := DockerClient.NetworkCreate(context.Background(), payload.Name, networkCreate) + if payload.Subnet != "" { + networkCreate.IPAM = &network.IPAM{ + Driver: "default", + Config: []network.IPAMConfig{ + { + Subnet: payload.Subnet, + }, + }, + } + } + + resp, err := CreateReasonableNetwork(payload.Name, networkCreate) if err != nil { utils.Error("CreateNetworkRoute: Error while creating network", err) utils.HTTPError(w, "Network Create Error: " + err.Error(), http.StatusInternalServerError, "CN004") diff --git a/src/docker/network.go b/src/docker/network.go index 1a4d606..8c2e031 100644 --- a/src/docker/network.go +++ b/src/docker/network.go @@ -55,19 +55,63 @@ func doesSubnetOverlap(networks []types.NetworkResource, subnet string) bool { return false } -func findAvailableSubnet() string { +func findAvailableSubnets(nb int) ([]string, error) { + result := []string{} baseSubnet := "100.0.0.0/29" networks, err := DockerClient.NetworkList(DockerContext, types.NetworkListOptions{}) if err != nil { - panic(err) + utils.Error("Docker Network List", err) + return []string{}, err } - for doesSubnetOverlap(networks, baseSubnet) { - baseSubnet = getNextSubnet(baseSubnet) + for i := 0; i < nb; i++ { + for doesSubnetOverlap(networks, baseSubnet) { + baseSubnet = getNextSubnet(baseSubnet) + } + result = append(result, baseSubnet) } - return baseSubnet + if len(result) != nb { + return []string{}, errors.New("Not enough subnets available. Try cleaning up networks.") + } + + return result, nil +} + +func CreateReasonableNetwork(name string, networkDef types.NetworkCreate) (types.NetworkCreateResponse, error) { + // if no subnet + if networkDef.IPAM == nil { + networkDef.IPAM = &network.IPAM{ + Driver: "default", + } + } + + if len(networkDef.IPAM.Config) == 0 { + subnets, err := findAvailableSubnets(1) + if err != nil { + return types.NetworkCreateResponse{}, err + } + + networkDef.IPAM.Config = []network.IPAMConfig{ + network.IPAMConfig{ + Subnet: subnets[0], + }, + } + } else { + subnets, err := findAvailableSubnets(len(networkDef.IPAM.Config)) + if err != nil { + return types.NetworkCreateResponse{}, err + } + + for i, config := range networkDef.IPAM.Config { + if config.Subnet == "" { + config.Subnet = subnets[i] + } + } + } + + return DockerClient.NetworkCreate(DockerContext, name, networkDef) } func CreateCosmosNetwork(name string) (string, error) { @@ -93,7 +137,11 @@ func CreateCosmosNetwork(name string) (string, error) { utils.Log("Creating new secure network: " + newNeworkName) - subnet := findAvailableSubnet() + subnet, err := findAvailableSubnets(1) + if err != nil { + utils.Error("Docker Network Create", err) + return "", err + } // create network newNetHan, err := DockerClient.NetworkCreate(DockerContext, newNeworkName, types.NetworkCreate{ @@ -102,7 +150,7 @@ func CreateCosmosNetwork(name string) (string, error) { Driver: "default", Config: []network.IPAMConfig{ network.IPAMConfig{ - Subnet: subnet, + Subnet: subnet[0], }, }, }, @@ -345,11 +393,14 @@ func _debounceNetworkCleanUp() func(string) { } func CreateLinkNetwork(containerName string, container2Name string) error { - subnet := findAvailableSubnet() + subnet, err := findAvailableSubnets(1) + if err != nil { + return err + } // create network networkName := "cosmos-link-" + containerName + "-" + container2Name + "-" + utils.GenerateRandomString(2) - _, err := DockerClient.NetworkCreate(DockerContext, networkName, types.NetworkCreate{ + _, err = DockerClient.NetworkCreate(DockerContext, networkName, types.NetworkCreate{ CheckDuplicate: true, Labels: map[string]string{ "cosmos-link": "true", @@ -360,7 +411,7 @@ func CreateLinkNetwork(containerName string, container2Name string) error { IPAM: &network.IPAM{ Config: []network.IPAMConfig{ network.IPAMConfig{ - Subnet: subnet, + Subnet: subnet[0], }, }, }, diff --git a/src/metrics/aggl.go b/src/metrics/aggl.go index 2969f3d..7d5b163 100644 --- a/src/metrics/aggl.go +++ b/src/metrics/aggl.go @@ -161,7 +161,7 @@ func AggloMetrics(metricsList []string) []DataDefDB { metric.ValuesAggl["hour_" + valueHourlyPool] = currentPool } else { - utils.Warn("Metrics: Agglomeration - Pool not found : " + "hour_" + valueHourlyPool) + utils.Debug("Metrics: Agglomeration - Pool not found : " + "hour_" + valueHourlyPool) } if _, ok := metric.ValuesAggl["day_" + valueDailyPool]; ok { @@ -174,7 +174,7 @@ func AggloMetrics(metricsList []string) []DataDefDB { metric.ValuesAggl["day_" + valueDailyPool] = currentPool } else { - utils.Warn("Metrics: Agglomeration - Pool not found: " + "day_" + valueDailyPool) + utils.Debug("Metrics: Agglomeration - Pool not found: " + "day_" + valueDailyPool) } values[valInd].Processed = true diff --git a/src/storage/API_parts.go b/src/storage/API_parts.go index a1564e9..ba6ab24 100644 --- a/src/storage/API_parts.go +++ b/src/storage/API_parts.go @@ -13,6 +13,7 @@ import ( type FormatDiskJSON struct { Disk string `json:"disk"` Format string `json:"format"` + Password string `json:"password"` } func isDiskOrPartition(path string) (string, error) { @@ -43,15 +44,8 @@ func FormatDiskRoute(w http.ResponseWriter, req *http.Request) { return } - if req.Method == "POST" { - var request FormatDiskJSON - err := json.NewDecoder(req.Body).Decode(&request) - if err != nil { - utils.Error("FormatDiskRoute: Invalid User Request", err) - utils.HTTPError(w, "FormatDiskRoute Error", http.StatusInternalServerError, "FD001") - return - } + if req.Method == "POST" { // Enable streaming of response by setting appropriate headers w.Header().Set("X-Content-Type-Options", "nosniff") w.Header().Set("Transfer-Encoding", "chunked") @@ -63,10 +57,31 @@ func FormatDiskRoute(w http.ResponseWriter, req *http.Request) { return } + var request FormatDiskJSON + err := json.NewDecoder(req.Body).Decode(&request) + if err != nil { + utils.Error("FormatDiskRoute: Invalid User Request", err) + fmt.Fprintf(w, "[OPERATION FAILED] FormatDiskRoute Syntax Error") + http.Error(w, "FormatDiskRoute Syntax Error", http.StatusBadRequest) + + return + } + + nickname := req.Header.Get("x-cosmos-user") + + errp := utils.CheckPassword(nickname, request.Password) + if errp != nil { + utils.Error("FormatDiskRoute: Invalid User Request", errp) + fmt.Fprintf(w, "[OPERATION FAILED] Wrong password supplied. Try again") + http.Error(w, "Wrong password supplied. Try again", http.StatusUnauthorized) + return + } + out, err := FormatDisk(request.Disk, request.Format) if err != nil { utils.Error("FormatDiskRoute: Error formatting disk", err) - utils.HTTPError(w, "FormatDiskRoute Error", http.StatusInternalServerError, "FD002") + fmt.Fprintf(w, "[OPERATION FAILED] Error formatting disk: " + err.Error()) + http.Error(w, "Error formatting disk", http.StatusInternalServerError) return } @@ -85,7 +100,8 @@ func FormatDiskRoute(w http.ResponseWriter, req *http.Request) { out, err = CreateSinglePartition(request.Disk) if err != nil { utils.Error("FormatDiskRoute: Error creating partition", err) - utils.HTTPError(w, "FormatDiskRoute Error", http.StatusInternalServerError, "FD003") + fmt.Fprintf(w, "[OPERATION FAILED] Error creating partition: " + err.Error()) + http.Error(w, "Error creating partition", http.StatusInternalServerError) return } @@ -99,7 +115,8 @@ func FormatDiskRoute(w http.ResponseWriter, req *http.Request) { out, err = FormatDisk(request.Disk + "1", request.Format) if err != nil { utils.Error("FormatDiskRoute: Error formatting partition", err) - utils.HTTPError(w, "FormatDiskRoute Error", http.StatusInternalServerError, "FD002") + fmt.Fprintf(w, "[OPERATION FAILED] Error formatting partition: " + err.Error()) + http.Error(w, "Error formatting partition", http.StatusInternalServerError) return } diff --git a/src/storage/disks.go b/src/storage/disks.go index 01fc233..b1c6262 100644 --- a/src/storage/disks.go +++ b/src/storage/disks.go @@ -60,10 +60,10 @@ func GetRecursiveDiskUsageAndSMARTInfo(devices []lsblk.BlockDevice) ([]BlockDevi if err == nil { devicesF[i].SMART = *smartInfo } else { - utils.Error("GetRecursiveDiskUsageAndSMARTInfo - Error fetching SMART info for " + device.Name + " : ", err) + utils.Warn("GetRecursiveDiskUsageAndSMARTInfo - Error fetching SMART info for " + device.Name + " : " + err.Error()) } } else { - utils.Error("GetRecursiveDiskUsageAndSMARTInfo - Error fetching SMART info for " + device.Name + " : ", err) + utils.Warn("GetRecursiveDiskUsageAndSMARTInfo - Error fetching SMART info for " + device.Name + " : " + err.Error()) } } @@ -78,8 +78,6 @@ func GetRecursiveDiskUsageAndSMARTInfo(devices []lsblk.BlockDevice) ([]BlockDevi } func GetDiskUsage(path string) (perc uint64, err error) { - fmt.Println("[STORAGE] Getting usage of disk " + path) - // Get the disk usage using the df command cmd := exec.Command("df", "-k", path) diff --git a/src/user/login.go b/src/user/login.go index 982dcff..03a6e01 100644 --- a/src/user/login.go +++ b/src/user/login.go @@ -25,7 +25,7 @@ func UserLogin(w http.ResponseWriter, req *http.Request) { utils.Error("UserLogin: User already logged ing", nil) utils.HTTPError(w, "User is already logged in", http.StatusUnauthorized, "UL002") return - } + } var request LoginRequestJSON err1 := json.NewDecoder(req.Body).Decode(&request) @@ -36,7 +36,7 @@ func UserLogin(w http.ResponseWriter, req *http.Request) { } c, closeDb, errCo := utils.GetEmbeddedCollection(utils.GetRootAppId(), "users") - defer closeDb() + defer closeDb() if errCo != nil { utils.Error("Database Connect", errCo) utils.HTTPError(w, "Database Error", http.StatusInternalServerError, "DB001") diff --git a/src/utils/utils.go b/src/utils/utils.go index dd09457..f2306d6 100644 --- a/src/utils/utils.go +++ b/src/utils/utils.go @@ -13,13 +13,18 @@ import ( "fmt" "sync" "time" + "errors" "path/filepath" + + "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/mem" "github.com/shirou/gopsutil/v3/disk" "github.com/shirou/gopsutil/v3/net" "golang.org/x/net/publicsuffix" "github.com/Masterminds/semver" + "golang.org/x/crypto/bcrypt" + "go.mongodb.org/mongo-driver/mongo" ) var ConfigLock sync.Mutex @@ -711,3 +716,39 @@ func CompareSemver(v1, v2 string) (int, error) { return ver1.Compare(ver2), nil } + + +func CheckPassword(nickname, password string) error { + time.Sleep(time.Duration(rand.Float64()*1)*time.Second) + + c, closeDb, errCo := GetEmbeddedCollection(GetRootAppId(), "users") + defer closeDb() + if errCo != nil { + return errCo + } + + user := User{} + + err3 := c.FindOne(nil, map[string]interface{}{ + "Nickname": nickname, + }).Decode(&user) + + + if err3 == mongo.ErrNoDocuments { + bcrypt.CompareHashAndPassword([]byte("$2a$14$4nzsVwEnR3.jEbMTME7kqeCo4gMgR/Tuk7ivNExvXjr73nKvLgHka"), []byte("dummyPassword")) + return err3 + } else if err3 != nil { + bcrypt.CompareHashAndPassword([]byte("$2a$14$4nzsVwEnR3.jEbMTME7kqeCo4gMgR/Tuk7ivNExvXjr73nKvLgHka"), []byte("dummyPassword")) + return err3 + } else if user.Password == "" { + return errors.New("User not registered") + } else { + err2 := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)) + + if err2 != nil { + return err2 + } + + return nil + } +} \ No newline at end of file