[release] version 0.5.0-unstable11
This commit is contained in:
parent
e3503f4345
commit
467f84187f
|
@ -3,6 +3,7 @@
|
||||||
- Add Create Container
|
- Add Create Container
|
||||||
- Add support for importing Docker Compose
|
- Add support for importing Docker Compose
|
||||||
- Fixed 2 bugs with the smart shield, that made it too strict
|
- Fixed 2 bugs with the smart shield, that made it too strict
|
||||||
|
- Fixed issues that prevented from login in with different hostnames
|
||||||
- Added more infoon the shield when blocking someone
|
- Added more infoon the shield when blocking someone
|
||||||
- Fixed home background image
|
- Fixed home background image
|
||||||
|
|
||||||
|
|
|
@ -268,6 +268,15 @@ function pullImage(imageName, onProgress, ifMissing) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function autoUpdate(id, toggle) {
|
||||||
|
return wrap(fetch('/cosmos/api/servapps/' + id + '/auto-update/'+toggle, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
list,
|
list,
|
||||||
get,
|
get,
|
||||||
|
@ -289,4 +298,5 @@ export {
|
||||||
createTerminal,
|
createTerminal,
|
||||||
createService,
|
createService,
|
||||||
pullImage,
|
pullImage,
|
||||||
|
autoUpdate,
|
||||||
};
|
};
|
|
@ -1,24 +1,39 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { IconButton, Tooltip, useMediaQuery } from '@mui/material';
|
import { Box, IconButton, LinearProgress, Stack, Tooltip, useMediaQuery } from '@mui/material';
|
||||||
import { CheckCircleOutlined, CloseSquareOutlined, DeleteOutlined, PauseCircleOutlined, PlaySquareOutlined, ReloadOutlined, RollbackOutlined, StopOutlined, UpCircleOutlined } from '@ant-design/icons';
|
import { CheckCircleOutlined, CloseSquareOutlined, DeleteOutlined, PauseCircleOutlined, PlaySquareOutlined, ReloadOutlined, RollbackOutlined, StopOutlined, UpCircleOutlined } from '@ant-design/icons';
|
||||||
import * as API from '../../api';
|
import * as API from '../../api';
|
||||||
|
import LogsInModal from '../../components/logsInModal';
|
||||||
|
|
||||||
const GetActions = ({
|
const GetActions = ({
|
||||||
Id,
|
Id,
|
||||||
state,
|
state,
|
||||||
|
image,
|
||||||
refreshServeApps,
|
refreshServeApps,
|
||||||
setIsUpdatingId,
|
setIsUpdatingId,
|
||||||
updateAvailable
|
updateAvailable
|
||||||
}) => {
|
}) => {
|
||||||
const [confirmDelete, setConfirmDelete] = React.useState(false);
|
const [confirmDelete, setConfirmDelete] = React.useState(false);
|
||||||
const isMiniMobile = useMediaQuery((theme) => theme.breakpoints.down('xsm'));
|
const isMiniMobile = useMediaQuery((theme) => theme.breakpoints.down('xsm'));
|
||||||
|
const [pullRequest, setPullRequest] = React.useState(null);
|
||||||
|
const [isUpdating, setIsUpdating] = React.useState(false);
|
||||||
console.log(isMiniMobile)
|
console.log(isMiniMobile)
|
||||||
|
|
||||||
const doTo = (action) => {
|
const doTo = (action) => {
|
||||||
|
setIsUpdating(true);
|
||||||
|
|
||||||
|
if(action === 'pull') {
|
||||||
|
setPullRequest(() => ((cb) => {
|
||||||
|
API.docker.pullImage(image, cb, true)
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setIsUpdatingId(Id, true);
|
setIsUpdatingId(Id, true);
|
||||||
API.docker.manageContainer(Id, action).then((res) => {
|
return API.docker.manageContainer(Id, action).then((res) => {
|
||||||
|
setIsUpdating(false);
|
||||||
refreshServeApps();
|
refreshServeApps();
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
|
setIsUpdating(false);
|
||||||
refreshServeApps();
|
refreshServeApps();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -27,7 +42,7 @@ const GetActions = ({
|
||||||
{
|
{
|
||||||
t: 'Update Available',
|
t: 'Update Available',
|
||||||
if: ['update_available'],
|
if: ['update_available'],
|
||||||
e: <IconButton className="shinyButton" color='primary' onClick={() => {doTo('update')}} size={isMiniMobile ? 'medium' : 'large'}>
|
e: <IconButton className="shinyButton" color='primary' onClick={() => {doTo('pull')}} size={isMiniMobile ? 'medium' : 'large'}>
|
||||||
<UpCircleOutlined />
|
<UpCircleOutlined />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
},
|
},
|
||||||
|
@ -93,11 +108,28 @@ const GetActions = ({
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
return actions.filter((action) => {
|
return <>
|
||||||
return action.if.includes(state) || (updateAvailable && action.if.includes('update_available'));
|
<LogsInModal
|
||||||
}).map((action) => {
|
request={pullRequest}
|
||||||
return <Tooltip title={action.t}>{action.e}</Tooltip>
|
title="Updating ServeApp..."
|
||||||
});
|
OnSuccess={() => {
|
||||||
|
doTo('update')
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{!isUpdating && actions.filter((action) => {
|
||||||
|
updateAvailable = true;
|
||||||
|
return action.if.includes(state) || (updateAvailable && action.if.includes('update_available'));
|
||||||
|
}).map((action) => {
|
||||||
|
return <Tooltip title={action.t}>{action.e}</Tooltip>
|
||||||
|
})}
|
||||||
|
|
||||||
|
{isUpdating && <Stack sx={{
|
||||||
|
width: '100%', height: '44px',
|
||||||
|
}}
|
||||||
|
justifyContent={'center'}
|
||||||
|
><LinearProgress /></Stack>}
|
||||||
|
</>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default GetActions;
|
export default GetActions;
|
|
@ -91,6 +91,7 @@ const ContainerOverview = ({ containerInfo, config, refresh }) => {
|
||||||
<Stack spacing={2} direction={'row'} >
|
<Stack spacing={2} direction={'row'} >
|
||||||
<GetActions
|
<GetActions
|
||||||
Id={containerInfo.Name}
|
Id={containerInfo.Name}
|
||||||
|
image={Image}
|
||||||
state={State.Status}
|
state={State.Status}
|
||||||
refreshServeApps={() => {
|
refreshServeApps={() => {
|
||||||
refreshAll()
|
refreshAll()
|
||||||
|
@ -130,6 +131,20 @@ const ContainerOverview = ({ containerInfo, config, refresh }) => {
|
||||||
}}
|
}}
|
||||||
/> Force Secure Network
|
/> Force Secure Network
|
||||||
</Stack>
|
</Stack>
|
||||||
|
<Stack style={{ fontSize: '80%' }} direction={"row"} alignItems="center">
|
||||||
|
<Checkbox
|
||||||
|
checked={Config.Labels['cosmos-auto-update'] === 'true'}
|
||||||
|
disabled={isUpdating}
|
||||||
|
onChange={(e) => {
|
||||||
|
setIsUpdating(true);
|
||||||
|
API.docker.autoUpdate(Name, e.target.checked).then(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
refreshAll();
|
||||||
|
}, 3000);
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
/> Auto Update Container
|
||||||
|
</Stack>
|
||||||
<strong><NodeExpandOutlined /> URLs</strong>
|
<strong><NodeExpandOutlined /> URLs</strong>
|
||||||
<div>
|
<div>
|
||||||
{routes.map((route) => {
|
{routes.map((route) => {
|
||||||
|
|
|
@ -188,16 +188,14 @@ const ServeApps = () => {
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
<Stack direction="row" spacing={2}>
|
<Stack direction="row" spacing={2} width='100%'>
|
||||||
{/* <Button variant="contained" size="small" onClick={() => {}}>
|
|
||||||
Update
|
|
||||||
</Button> */}
|
|
||||||
<GetActions
|
<GetActions
|
||||||
Id={app.Names[0].replace('/', '')}
|
Id={app.Names[0].replace('/', '')}
|
||||||
|
image={app.Image}
|
||||||
state={app.State}
|
state={app.State}
|
||||||
setIsUpdatingId={setIsUpdatingId}
|
setIsUpdatingId={setIsUpdatingId}
|
||||||
refreshServeApps={refreshServeApps}
|
refreshServeApps={refreshServeApps}
|
||||||
updateAvailable={updatesAvailable[app.Names[0]]}
|
updateAvailable={updatesAvailable && updatesAvailable[app.Names[0]]}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
@ -242,10 +240,31 @@ const ServeApps = () => {
|
||||||
setIsUpdatingId(app.Id, false);
|
setIsUpdatingId(app.Id, false);
|
||||||
refreshServeApps();
|
refreshServeApps();
|
||||||
}, 3000);
|
}, 3000);
|
||||||
|
}).catch(() => {
|
||||||
|
setIsUpdatingId(app.Id, false);
|
||||||
|
refreshServeApps();
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
/> Force Secure Network
|
/> Force Secure Network
|
||||||
</Stack>
|
</Stack>
|
||||||
|
<Stack style={{ fontSize: '80%' }} direction={"row"} alignItems="center">
|
||||||
|
<Checkbox
|
||||||
|
checked={app.Labels['cosmos-auto-update'] === 'true'}
|
||||||
|
disabled={app.State !== 'running'}
|
||||||
|
onChange={(e) => {
|
||||||
|
setIsUpdatingId(app.Id, true);
|
||||||
|
API.docker.autoUpdate(app.Id, e.target.checked).then(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
setIsUpdatingId(app.Id, false);
|
||||||
|
refreshServeApps();
|
||||||
|
}, 3000);
|
||||||
|
}).catch(() => {
|
||||||
|
setIsUpdatingId(app.Id, false);
|
||||||
|
refreshServeApps();
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
/> Auto Update Container
|
||||||
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
}
|
}
|
||||||
<Stack margin={1} direction="column" spacing={1} alignItems="flex-start">
|
<Stack margin={1} direction="column" spacing={1} alignItems="flex-start">
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "cosmos-server",
|
"name": "cosmos-server",
|
||||||
"version": "0.5.0-unstable10",
|
"version": "0.5.0-unstable11",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "test-server.js",
|
"main": "test-server.js",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
|
|
57
src/docker/api_autoupdate.go
Normal file
57
src/docker/api_autoupdate.go
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package docker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/azukaar/cosmos-server/src/utils"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AutoUpdateContainerRoute(w http.ResponseWriter, req *http.Request) {
|
||||||
|
if utils.AdminOnly(w, req) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(req)
|
||||||
|
containerName := utils.SanitizeSafe(vars["containerId"])
|
||||||
|
status := utils.Sanitize(vars["status"])
|
||||||
|
|
||||||
|
if os.Getenv("HOSTNAME") != "" && containerName == os.Getenv("HOSTNAME") {
|
||||||
|
utils.Error("AutoUpdateContainerRoute - Container cannot update itself", nil)
|
||||||
|
utils.HTTPError(w, "Container cannot update itself", http.StatusBadRequest, "DS003")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if(req.Method == "GET") {
|
||||||
|
container, err := DockerClient.ContainerInspect(DockerContext, containerName)
|
||||||
|
if err != nil {
|
||||||
|
utils.Error("AutoUpdateContainer Inscpect", err)
|
||||||
|
utils.HTTPError(w, "Internal server error: " + err.Error(), http.StatusInternalServerError, "DS002")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
AddLabels(container, map[string]string{
|
||||||
|
"cosmos-auto-update": status,
|
||||||
|
});
|
||||||
|
|
||||||
|
utils.Log("API: Set Auto Update "+status+" : " + containerName)
|
||||||
|
|
||||||
|
_, errEdit := EditContainer(container.ID, container)
|
||||||
|
if errEdit != nil {
|
||||||
|
utils.Error("AutoUpdateContainer Edit", errEdit)
|
||||||
|
utils.HTTPError(w, "Internal server error: " + errEdit.Error(), http.StatusInternalServerError, "DS003")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||||
|
"status": "OK",
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
utils.Error("AutoUpdateContainer: Method not allowed" + req.Method, nil)
|
||||||
|
utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
|
@ -161,7 +161,7 @@ func CreateServiceRoute(w http.ResponseWriter, req *http.Request) {
|
||||||
|
|
||||||
errD := Connect()
|
errD := Connect()
|
||||||
if errD != nil {
|
if errD != nil {
|
||||||
utils.Error("CreateService", errD)
|
utils.Error("CreateService - connect - ", errD)
|
||||||
utils.HTTPError(w, "Internal server error: " + errD.Error(), http.StatusInternalServerError, "DS002")
|
utils.HTTPError(w, "Internal server error: " + errD.Error(), http.StatusInternalServerError, "DS002")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ func CreateServiceRoute(w http.ResponseWriter, req *http.Request) {
|
||||||
var serviceRequest DockerServiceCreateRequest
|
var serviceRequest DockerServiceCreateRequest
|
||||||
err := decoder.Decode(&serviceRequest)
|
err := decoder.Decode(&serviceRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error("CreateService", err)
|
utils.Error("CreateService - decode - ", err)
|
||||||
utils.HTTPError(w, "Bad request: "+err.Error(), http.StatusBadRequest, "DS003")
|
utils.HTTPError(w, "Bad request: "+err.Error(), http.StatusBadRequest, "DS003")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -230,6 +230,7 @@ func StartServer() {
|
||||||
|
|
||||||
srapi.HandleFunc("/api/servapps/{containerId}/manage/{action}", docker.ManageContainerRoute)
|
srapi.HandleFunc("/api/servapps/{containerId}/manage/{action}", docker.ManageContainerRoute)
|
||||||
srapi.HandleFunc("/api/servapps/{containerId}/secure/{status}", docker.SecureContainerRoute)
|
srapi.HandleFunc("/api/servapps/{containerId}/secure/{status}", docker.SecureContainerRoute)
|
||||||
|
srapi.HandleFunc("/api/servapps/{containerId}/auto-update/{status}", docker.AutoUpdateContainerRoute)
|
||||||
srapi.HandleFunc("/api/servapps/{containerId}/logs", docker.GetContainerLogsRoute)
|
srapi.HandleFunc("/api/servapps/{containerId}/logs", docker.GetContainerLogsRoute)
|
||||||
srapi.HandleFunc("/api/servapps/{containerId}/terminal/{action}", docker.TerminalRoute)
|
srapi.HandleFunc("/api/servapps/{containerId}/terminal/{action}", docker.TerminalRoute)
|
||||||
srapi.HandleFunc("/api/servapps/{containerId}/update", docker.UpdateContainerRoute)
|
srapi.HandleFunc("/api/servapps/{containerId}/update", docker.UpdateContainerRoute)
|
||||||
|
|
|
@ -24,6 +24,10 @@ func main() {
|
||||||
|
|
||||||
docker.BootstrapAllContainersFromTags()
|
docker.BootstrapAllContainersFromTags()
|
||||||
|
|
||||||
|
// TODO DELET THIS BEFORE RELEASE
|
||||||
|
|
||||||
|
docker.CheckUpdatesAvailable()
|
||||||
|
|
||||||
version, err := docker.DockerClient.ServerVersion(context.Background())
|
version, err := docker.DockerClient.ServerVersion(context.Background())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
utils.Log("Docker API version: " + version.APIVersion)
|
utils.Log("Docker API version: " + version.APIVersion)
|
||||||
|
|
|
@ -75,7 +75,7 @@ func Check2FA(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SendUserToken(w, userInBase, true)
|
SendUserToken(w, req, userInBase, true)
|
||||||
|
|
||||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||||
"status": "OK",
|
"status": "OK",
|
||||||
|
|
|
@ -70,7 +70,7 @@ func UserLogin(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
SendUserToken(w, user, false)
|
SendUserToken(w, req, user, false)
|
||||||
|
|
||||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||||
"status": "OK",
|
"status": "OK",
|
||||||
|
|
|
@ -10,7 +10,7 @@ func UserLogout(w http.ResponseWriter, req *http.Request) {
|
||||||
if(req.Method == "GET") {
|
if(req.Method == "GET") {
|
||||||
utils.Debug("UserLogout: Logging out user")
|
utils.Debug("UserLogout: Logging out user")
|
||||||
|
|
||||||
logOutUser(w);
|
logOutUser(w, req);
|
||||||
|
|
||||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||||
"status": "OK",
|
"status": "OK",
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
|
|
||||||
func quickLoggout(w http.ResponseWriter, req *http.Request, err error) (utils.User, error) {
|
func quickLoggout(w http.ResponseWriter, req *http.Request, err error) (utils.User, error) {
|
||||||
utils.Error("UserToken: Token likely falsified", err)
|
utils.Error("UserToken: Token likely falsified", err)
|
||||||
logOutUser(w)
|
logOutUser(w, req)
|
||||||
redirectToReLogin(w, req)
|
redirectToReLogin(w, req)
|
||||||
return utils.User{}, errors.New("Token likely falsified")
|
return utils.User{}, errors.New("Token likely falsified")
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ func RefreshUserToken(w http.ResponseWriter, req *http.Request) (utils.User, err
|
||||||
|
|
||||||
if errP != nil {
|
if errP != nil {
|
||||||
utils.Error("UserToken: token is not valid", nil)
|
utils.Error("UserToken: token is not valid", nil)
|
||||||
logOutUser(w)
|
logOutUser(w, req)
|
||||||
redirectToReLogin(w, req)
|
redirectToReLogin(w, req)
|
||||||
return utils.User{}, errors.New("Token not valid")
|
return utils.User{}, errors.New("Token not valid")
|
||||||
}
|
}
|
||||||
|
@ -85,6 +85,7 @@ func RefreshUserToken(w http.ResponseWriter, req *http.Request) (utils.User, err
|
||||||
passwordCycle int
|
passwordCycle int
|
||||||
mfaDone bool
|
mfaDone bool
|
||||||
ok bool
|
ok bool
|
||||||
|
forDomain string
|
||||||
)
|
)
|
||||||
|
|
||||||
if nickname, ok = claims["nickname"].(string); !ok {
|
if nickname, ok = claims["nickname"].(string); !ok {
|
||||||
|
@ -107,6 +108,22 @@ func RefreshUserToken(w http.ResponseWriter, req *http.Request) (utils.User, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if forDomain, ok = claims["forDomain"].(string); !ok {
|
||||||
|
if _, e := quickLoggout(w, req, nil); e != nil {
|
||||||
|
return utils.User{}, e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reqHostname := req.Host
|
||||||
|
reqHostNoPort := strings.Split(reqHostname, ":")[0]
|
||||||
|
|
||||||
|
if !strings.HasSuffix(reqHostNoPort, forDomain) {
|
||||||
|
utils.Error("UserToken: token is not valid for this domain", nil)
|
||||||
|
logOutUser(w, req)
|
||||||
|
redirectToReLogin(w, req)
|
||||||
|
return utils.User{}, errors.New("JWT Token not valid for this domain")
|
||||||
|
}
|
||||||
|
|
||||||
userInBase := utils.User{}
|
userInBase := utils.User{}
|
||||||
|
|
||||||
c, errCo := utils.GetCollection(utils.GetRootAppId(), "users")
|
c, errCo := utils.GetCollection(utils.GetRootAppId(), "users")
|
||||||
|
@ -122,14 +139,14 @@ func RefreshUserToken(w http.ResponseWriter, req *http.Request) (utils.User, err
|
||||||
|
|
||||||
if errDB != nil {
|
if errDB != nil {
|
||||||
utils.Error("UserToken: User not found", errDB)
|
utils.Error("UserToken: User not found", errDB)
|
||||||
logOutUser(w)
|
logOutUser(w, req)
|
||||||
redirectToReLogin(w, req)
|
redirectToReLogin(w, req)
|
||||||
return utils.User{}, errors.New("User not found")
|
return utils.User{}, errors.New("User not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
if userInBase.PasswordCycle != passwordCycle {
|
if userInBase.PasswordCycle != passwordCycle {
|
||||||
utils.Error("UserToken: Password cycle changed, token is too old", nil)
|
utils.Error("UserToken: Password cycle changed, token is too old", nil)
|
||||||
logOutUser(w)
|
logOutUser(w, req)
|
||||||
redirectToReLogin(w, req)
|
redirectToReLogin(w, req)
|
||||||
return utils.User{}, errors.New("Password cycle changed, token is too old")
|
return utils.User{}, errors.New("Password cycle changed, token is too old")
|
||||||
}
|
}
|
||||||
|
@ -148,7 +165,7 @@ func RefreshUserToken(w http.ResponseWriter, req *http.Request) (utils.User, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if time.Now().Unix() - int64(claims["iat"].(float64)) > 3600 {
|
if time.Now().Unix() - int64(claims["iat"].(float64)) > 3600 {
|
||||||
SendUserToken(w, userInBase, mfaDone)
|
SendUserToken(w, req, userInBase, mfaDone)
|
||||||
}
|
}
|
||||||
|
|
||||||
return userInBase, nil
|
return userInBase, nil
|
||||||
|
@ -159,7 +176,10 @@ func GetUserR(req *http.Request) (string, string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func logOutUser(w http.ResponseWriter) {
|
func logOutUser(w http.ResponseWriter, req *http.Request) {
|
||||||
|
reqHostname := req.Host
|
||||||
|
reqHostNoPort := strings.Split(reqHostname, ":")[0]
|
||||||
|
|
||||||
cookie := http.Cookie{
|
cookie := http.Cookie{
|
||||||
Name: "jwttoken",
|
Name: "jwttoken",
|
||||||
Value: "",
|
Value: "",
|
||||||
|
@ -167,11 +187,12 @@ func logOutUser(w http.ResponseWriter) {
|
||||||
Path: "/",
|
Path: "/",
|
||||||
Secure: utils.IsHTTPS,
|
Secure: utils.IsHTTPS,
|
||||||
HttpOnly: true,
|
HttpOnly: true,
|
||||||
Domain: utils.GetMainConfig().HTTPConfig.Hostname,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(utils.GetMainConfig().HTTPConfig.Hostname == "localhost" || utils.GetMainConfig().HTTPConfig.Hostname == "0.0.0.0") {
|
if reqHostNoPort == "localhost" || reqHostNoPort == "0.0.0.0" {
|
||||||
cookie.Domain = ""
|
cookie.Domain = ""
|
||||||
|
} else {
|
||||||
|
cookie.Domain = "." + reqHostNoPort
|
||||||
}
|
}
|
||||||
|
|
||||||
http.SetCookie(w, &cookie)
|
http.SetCookie(w, &cookie)
|
||||||
|
@ -191,7 +212,10 @@ func redirectToNewMFA(w http.ResponseWriter, req *http.Request) {
|
||||||
http.Redirect(w, req, "/ui/newmfa?invalid=1&redirect=" + req.URL.Path + "&" + req.URL.RawQuery, http.StatusTemporaryRedirect)
|
http.Redirect(w, req, "/ui/newmfa?invalid=1&redirect=" + req.URL.Path + "&" + req.URL.RawQuery, http.StatusTemporaryRedirect)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SendUserToken(w http.ResponseWriter, user utils.User, mfaDone bool) {
|
func SendUserToken(w http.ResponseWriter, req *http.Request, user utils.User, mfaDone bool) {
|
||||||
|
reqHostname := req.Host
|
||||||
|
reqHostNoPort := strings.Split(reqHostname, ":")[0]
|
||||||
|
|
||||||
expiration := time.Now().Add(3 * 24 * time.Hour)
|
expiration := time.Now().Add(3 * 24 * time.Hour)
|
||||||
|
|
||||||
token := jwt.New(jwt.SigningMethodEdDSA)
|
token := jwt.New(jwt.SigningMethodEdDSA)
|
||||||
|
@ -203,6 +227,7 @@ func SendUserToken(w http.ResponseWriter, user utils.User, mfaDone bool) {
|
||||||
claims["iat"] = time.Now().Unix()
|
claims["iat"] = time.Now().Unix()
|
||||||
claims["nbf"] = time.Now().Unix()
|
claims["nbf"] = time.Now().Unix()
|
||||||
claims["mfaDone"] = mfaDone
|
claims["mfaDone"] = mfaDone
|
||||||
|
claims["forDomain"] = reqHostNoPort
|
||||||
|
|
||||||
key, err5 := jwt.ParseEdPrivateKeyFromPEM([]byte(utils.GetPrivateAuthKey()))
|
key, err5 := jwt.ParseEdPrivateKeyFromPEM([]byte(utils.GetPrivateAuthKey()))
|
||||||
|
|
||||||
|
@ -227,11 +252,20 @@ func SendUserToken(w http.ResponseWriter, user utils.User, mfaDone bool) {
|
||||||
Path: "/",
|
Path: "/",
|
||||||
Secure: utils.IsHTTPS,
|
Secure: utils.IsHTTPS,
|
||||||
HttpOnly: true,
|
HttpOnly: true,
|
||||||
Domain: utils.GetMainConfig().HTTPConfig.Hostname,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(utils.GetMainConfig().HTTPConfig.Hostname == "localhost" || utils.GetMainConfig().HTTPConfig.Hostname == "0.0.0.0") {
|
utils.Log("UserLogin: Setting cookie for " + reqHostNoPort)
|
||||||
|
|
||||||
|
if reqHostNoPort == "localhost" || reqHostNoPort == "0.0.0.0" {
|
||||||
cookie.Domain = ""
|
cookie.Domain = ""
|
||||||
|
} else {
|
||||||
|
if utils.IsValidHostname(reqHostNoPort) {
|
||||||
|
cookie.Domain = "." + reqHostNoPort
|
||||||
|
} else {
|
||||||
|
utils.Error("UserLogin: Invalid hostname", nil)
|
||||||
|
utils.HTTPError(w, "User Logging Error", http.StatusInternalServerError, "UL001")
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
http.SetCookie(w, &cookie)
|
http.SetCookie(w, &cookie)
|
||||||
|
|
|
@ -202,4 +202,42 @@ func EnsureHostname(next http.Handler) http.Handler {
|
||||||
|
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsValidHostname(hostname string) bool {
|
||||||
|
og := GetMainConfig().HTTPConfig.Hostname
|
||||||
|
ni := GetMainConfig().NewInstall
|
||||||
|
|
||||||
|
if ni || og == "0.0.0.0" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
hostnames := GetAllHostnames()
|
||||||
|
|
||||||
|
reqHostNoPort := strings.Split(hostname, ":")[0]
|
||||||
|
|
||||||
|
reqHostNoPortNoSubdomain := ""
|
||||||
|
|
||||||
|
if parts := strings.Split(reqHostNoPort, "."); len(parts) < 2 {
|
||||||
|
reqHostNoPortNoSubdomain = reqHostNoPort
|
||||||
|
} else {
|
||||||
|
reqHostNoPortNoSubdomain = parts[len(parts)-2] + "." + parts[len(parts)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, hostname := range hostnames {
|
||||||
|
hostnameNoPort := strings.Split(hostname, ":")[0]
|
||||||
|
hostnameNoPortNoSubdomain := ""
|
||||||
|
|
||||||
|
if parts := strings.Split(hostnameNoPort, "."); len(parts) < 2 {
|
||||||
|
hostnameNoPortNoSubdomain = hostnameNoPort
|
||||||
|
} else {
|
||||||
|
hostnameNoPortNoSubdomain = parts[len(parts)-2] + "." + parts[len(parts)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if reqHostNoPortNoSubdomain == hostnameNoPortNoSubdomain {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
Loading…
Reference in a new issue