[release] v0.10.0-unstable
This commit is contained in:
parent
525146a210
commit
bc7aaa21d0
30 changed files with 1099 additions and 30 deletions
|
@ -53,6 +53,24 @@ jobs:
|
|||
command: |
|
||||
curl -s -L "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=$MAX_TOKEN&suffix=tar.gz" -o GeoLite2-Country.tar.gz
|
||||
tar -xzf GeoLite2-Country.tar.gz --strip-components 1 --wildcards "*.mmdb"
|
||||
|
||||
- run:
|
||||
name: Download and Extract ARM Nebula Binary
|
||||
command: |
|
||||
curl -LO https://github.com/slackhq/nebula/releases/download/v1.7.2/nebula-linux-arm64.tar.gz
|
||||
tar -xzvf nebula-linux-arm64.tar.gz
|
||||
|
||||
- run:
|
||||
name: Rename ARM Nebula Binary
|
||||
command: |
|
||||
mv nebula nebula-arm
|
||||
mv nebula-cert nebula-cert-arm
|
||||
|
||||
- run:
|
||||
name: Download and Extract Nebula Binary
|
||||
command: |
|
||||
curl -LO https://github.com/slackhq/nebula/releases/download/v1.7.2/nebula-linux-amd64.tar.gz
|
||||
tar -xzvf nebula-linux-amd64.tar.gz
|
||||
|
||||
- run:
|
||||
name: Build UI
|
||||
|
|
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -12,4 +12,9 @@ todo.txt
|
|||
LICENCE
|
||||
tokens.json
|
||||
.vscode
|
||||
GeoLite2-Country.mmdb
|
||||
GeoLite2-Country.mmdb
|
||||
zz_test_config
|
||||
nebula-arm
|
||||
nebula-arm-cert
|
||||
nebula
|
||||
nebula-cert
|
1
build.sh
1
build.sh
|
@ -18,6 +18,7 @@ echo " ---- Build complete, copy assets ----"
|
|||
|
||||
cp -r static build/
|
||||
cp -r GeoLite2-Country.mmdb build/
|
||||
cp nebula-arm-cert nebula-cert nebula-arm nebula build/
|
||||
cp -r Logo.png build/
|
||||
mkdir build/images
|
||||
cp client/src/assets/images/icons/cosmos_gray.png build/cosmos_gray.png
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
<<<<<<< HEAD
|
||||
## Version 0.9.20 - 0.9.21
|
||||
- Add option to disable CORS hardening (with empty value)
|
||||
|
||||
=======
|
||||
## Version 0.10.0
|
||||
- Added Constellation
|
||||
- DNS Challenge is now used for all certificates when enabled
|
||||
>>>>>>> b8a9e71 ([release] v0.10.0-unstable)
|
||||
## Version 0.9.19
|
||||
- Add country whitelist option to geoblocker
|
||||
- No countries blocked by default anymore
|
||||
|
|
25
client/src/api/constellation.tsx
Normal file
25
client/src/api/constellation.tsx
Normal file
|
@ -0,0 +1,25 @@
|
|||
import wrap from './wrap';
|
||||
|
||||
function list() {
|
||||
return wrap(fetch('/cosmos/api/constellation/devices', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
function addDevice(device) {
|
||||
return wrap(fetch('/cosmos/api/constellation/devices', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(device),
|
||||
}))
|
||||
}
|
||||
|
||||
export {
|
||||
list,
|
||||
addDevice,
|
||||
};
|
28
client/src/api/downloadButton.jsx
Normal file
28
client/src/api/downloadButton.jsx
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { Button } from "@mui/material";
|
||||
|
||||
export const DownloadFile = ({ filename, content, label }) => {
|
||||
const downloadFile = () => {
|
||||
// Create a blob with the content
|
||||
const blob = new Blob([content], { type: "text/plain;charset=utf-8" });
|
||||
|
||||
// Create a link element
|
||||
const link = document.createElement("a");
|
||||
link.href = URL.createObjectURL(blob);
|
||||
link.download = filename;
|
||||
|
||||
// Append the link to the document (needed for Firefox)
|
||||
document.body.appendChild(link);
|
||||
|
||||
// Simulate a click to start the download
|
||||
link.click();
|
||||
|
||||
// Cleanup the DOM by removing the link element
|
||||
document.body.removeChild(link);
|
||||
}
|
||||
|
||||
return (
|
||||
<Button onClick={downloadFile}>
|
||||
{label}
|
||||
</Button>
|
||||
);
|
||||
}
|
|
@ -3,6 +3,7 @@ import * as _users from './users';
|
|||
import * as _config from './config';
|
||||
import * as _docker from './docker';
|
||||
import * as _market from './market';
|
||||
import * as _constellation from './constellation';
|
||||
|
||||
import * as authDemo from './authentication.demo';
|
||||
import * as usersDemo from './users.demo';
|
||||
|
@ -211,6 +212,7 @@ let users = _users;
|
|||
let config = _config;
|
||||
let docker = _docker;
|
||||
let market = _market;
|
||||
let constellation = _constellation;
|
||||
|
||||
if(isDemo) {
|
||||
auth = authDemo;
|
||||
|
@ -232,6 +234,7 @@ export {
|
|||
config,
|
||||
docker,
|
||||
market,
|
||||
constellation,
|
||||
getStatus,
|
||||
newInstall,
|
||||
isOnline,
|
||||
|
|
BIN
client/src/assets/images/icons/constellation.png
Normal file
BIN
client/src/assets/images/icons/constellation.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.5 KiB |
|
@ -1,5 +1,6 @@
|
|||
// assets
|
||||
import { ProfileOutlined, PicLeftOutlined, SettingOutlined, NodeExpandOutlined, AppstoreOutlined} from '@ant-design/icons';
|
||||
import ConstellationIcon from '../assets/images/icons/constellation.png'
|
||||
|
||||
// icons
|
||||
const icons = {
|
||||
|
@ -7,7 +8,6 @@ const icons = {
|
|||
ProfileOutlined,
|
||||
SettingOutlined
|
||||
};
|
||||
|
||||
// ==============================|| MENU ITEMS - EXTRA PAGES ||============================== //
|
||||
|
||||
const pages = {
|
||||
|
@ -29,6 +29,14 @@ const pages = {
|
|||
url: '/cosmos-ui/config-url',
|
||||
icon: icons.NodeExpandOutlined,
|
||||
},
|
||||
{
|
||||
id: 'constellation',
|
||||
title: 'Constellation',
|
||||
type: 'item',
|
||||
url: '/cosmos-ui/constellation',
|
||||
icon: () => <img height="28px" width="28px" style={{marginLeft: "-6px"}} src={ConstellationIcon} />,
|
||||
|
||||
},
|
||||
{
|
||||
id: 'users',
|
||||
title: 'Users',
|
||||
|
|
147
client/src/pages/constellation/addDevice.jsx
Normal file
147
client/src/pages/constellation/addDevice.jsx
Normal file
|
@ -0,0 +1,147 @@
|
|||
// material-ui
|
||||
import { Alert, Button, 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 * as React from 'react';
|
||||
import { useState } from 'react';
|
||||
import ResponsiveButton from '../../components/responseiveButton';
|
||||
import { PlusCircleFilled } from '@ant-design/icons';
|
||||
import { Formik } from 'formik';
|
||||
import * as yup from 'yup';
|
||||
import * as API from '../../api';
|
||||
import { CosmosInputText, CosmosSelect } from '../config/users/formShortcuts';
|
||||
import { DownloadFile } from '../../api/downloadButton';
|
||||
|
||||
const AddDeviceModal = ({ config, isAdmin, refreshConfig, devices }) => {
|
||||
const [openModal, setOpenModal] = useState(false);
|
||||
const [isDone, setIsDone] = useState(null);
|
||||
|
||||
return <>
|
||||
<Dialog open={openModal} onClose={() => setOpenModal(false)}>
|
||||
<Formik
|
||||
initialValues={{
|
||||
nickname: '',
|
||||
deviceName: '',
|
||||
ip: '192.168.201.1/24',
|
||||
publicKey: '',
|
||||
}}
|
||||
|
||||
validationSchema={yup.object({
|
||||
})}
|
||||
|
||||
onSubmit={(values, { setSubmitting, setStatus, setErrors }) => {
|
||||
return API.constellation.addDevice(values).then(({data}) => {
|
||||
setIsDone(data);
|
||||
refreshConfig();
|
||||
}).catch((err) => {
|
||||
setErrors(err.response.data);
|
||||
});
|
||||
}}
|
||||
>
|
||||
{(formik) => (
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<DialogTitle>Manually Add Device</DialogTitle>
|
||||
|
||||
{isDone ? <DialogContent>
|
||||
<DialogContentText>
|
||||
<p>
|
||||
Device added successfully!
|
||||
Download the private and public keys to your device along side the config and network certificate to connect:
|
||||
</p>
|
||||
|
||||
<Stack spacing={2} direction={"column"}>
|
||||
<DownloadFile
|
||||
filename={`config.yml`}
|
||||
content={isDone.Config}
|
||||
label={"Download config.yml"}
|
||||
/>
|
||||
<DownloadFile
|
||||
filename={isDone.DeviceName + `.key`}
|
||||
content={isDone.PrivateKey}
|
||||
label={"Download " + isDone.DeviceName + `.key`}
|
||||
/>
|
||||
<DownloadFile
|
||||
filename={isDone.DeviceName + `.crt`}
|
||||
content={isDone.PublicKey}
|
||||
label={"Download " + isDone.DeviceName + `.crt`}
|
||||
/>
|
||||
<DownloadFile
|
||||
filename={`ca.crt`}
|
||||
content={isDone.CA}
|
||||
label={"Download ca.crt"}
|
||||
/>
|
||||
</Stack>
|
||||
</DialogContentText>
|
||||
</DialogContent> : <DialogContent>
|
||||
<DialogContentText>
|
||||
<p>Manually add a device to the constellation. It is recommended that you use the Cosmos app instead. Use this form to add another Nebula device manually</p>
|
||||
<div>
|
||||
<Stack spacing={2} style={{}}>
|
||||
<CosmosSelect
|
||||
name="nickname"
|
||||
label="Owner"
|
||||
formik={formik}
|
||||
// disabled={!isAdmin}
|
||||
options={[
|
||||
["admin", "admin"]
|
||||
]}
|
||||
/>
|
||||
|
||||
<CosmosInputText
|
||||
name="deviceName"
|
||||
label="Device Name"
|
||||
formik={formik}
|
||||
/>
|
||||
|
||||
<CosmosInputText
|
||||
name="ip"
|
||||
label="Constellation IP Address"
|
||||
formik={formik}
|
||||
/>
|
||||
|
||||
<CosmosInputText
|
||||
multiline
|
||||
name="publicKey"
|
||||
label="Public Key (Optional)"
|
||||
formik={formik}
|
||||
/>
|
||||
<div>
|
||||
{formik.errors && formik.errors.length > 0 && <Stack spacing={2} direction={"column"}>
|
||||
<Alert severity="error">{formik.errors.map((err) => {
|
||||
return <div>{err}</div>
|
||||
})}</Alert>
|
||||
</Stack>}
|
||||
</div>
|
||||
</Stack>
|
||||
</div>
|
||||
</DialogContentText>
|
||||
</DialogContent>}
|
||||
|
||||
<DialogActions>
|
||||
<Button onClick={() => setOpenModal(false)}>Close</Button>
|
||||
<Button color="primary" variant="contained" type="submit">Add</Button>
|
||||
</DialogActions>
|
||||
</form>
|
||||
|
||||
)}
|
||||
</Formik>
|
||||
</Dialog>
|
||||
|
||||
<ResponsiveButton
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
setIsDone(null);
|
||||
setOpenModal(true);
|
||||
}}
|
||||
variant="contained"
|
||||
startIcon={<PlusCircleFilled />}
|
||||
>
|
||||
Manually Add Device
|
||||
</ResponsiveButton>
|
||||
</>;
|
||||
};
|
||||
|
||||
export default AddDeviceModal;
|
81
client/src/pages/constellation/index.jsx
Normal file
81
client/src/pages/constellation/index.jsx
Normal file
|
@ -0,0 +1,81 @@
|
|||
import React from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import * as API from "../../api";
|
||||
import AddDeviceModal from "./addDevice";
|
||||
import PrettyTableView from "../../components/tableView/prettyTableView";
|
||||
import { DeleteButton } from "../../components/delete";
|
||||
import { CloudOutlined, DesktopOutlined, LaptopOutlined, MobileOutlined, TabletOutlined } from "@ant-design/icons";
|
||||
import IsLoggedIn from "../../isLoggedIn";
|
||||
|
||||
export const ConstellationIndex = () => {
|
||||
const [isAdmin, setIsAdmin] = useState(false);
|
||||
const [config, setConfig] = useState(null);
|
||||
const [devices, setDevices] = useState(null);
|
||||
|
||||
const refreshConfig = async () => {
|
||||
let configAsync = await API.config.get();
|
||||
setConfig(configAsync.data);
|
||||
setIsAdmin(configAsync.isAdmin);
|
||||
setDevices((await API.constellation.list()).data || []);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
refreshConfig();
|
||||
}, []);
|
||||
|
||||
const getIcon = (r) => {
|
||||
if (r.deviceName.toLowerCase().includes("mobile") || r.deviceName.toLowerCase().includes("phone")) {
|
||||
return <MobileOutlined />
|
||||
}
|
||||
else if (r.deviceName.toLowerCase().includes("laptop") || r.deviceName.toLowerCase().includes("computer")) {
|
||||
return <LaptopOutlined />
|
||||
} else if (r.deviceName.toLowerCase().includes("desktop")) {
|
||||
return <DesktopOutlined />
|
||||
} else if (r.deviceName.toLowerCase().includes("tablet")) {
|
||||
return <TabletOutlined />
|
||||
} else {
|
||||
return <CloudOutlined />
|
||||
}
|
||||
}
|
||||
|
||||
return <>
|
||||
<IsLoggedIn />
|
||||
{devices && config && <>
|
||||
<PrettyTableView
|
||||
data={devices}
|
||||
getKey={(r) => r.deviceName}
|
||||
buttons={[
|
||||
<AddDeviceModal isAdmin={isAdmin} config={config} refreshConfig={refreshConfig} devices={devices} />
|
||||
]}
|
||||
columns={[
|
||||
{
|
||||
title: '',
|
||||
field: getIcon,
|
||||
},
|
||||
{
|
||||
title: 'Device Name',
|
||||
field: (r) => <strong>{r.deviceName}</strong>,
|
||||
},
|
||||
{
|
||||
title: 'Owner',
|
||||
field: (r) => <strong>{r.nickname}</strong>,
|
||||
},
|
||||
{
|
||||
title: 'Constellation IP',
|
||||
screenMin: 'md',
|
||||
field: (r) => r.ip,
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
clickable: true,
|
||||
field: (r) => {
|
||||
return <DeleteButton onDelete={async () => {
|
||||
alert("caca")
|
||||
}}></DeleteButton>
|
||||
}
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</>}
|
||||
</>
|
||||
};
|
|
@ -15,6 +15,7 @@ import ContainerIndex from '../pages/servapps/containers';
|
|||
import NewDockerServiceForm from '../pages/servapps/containers/newServiceForm';
|
||||
import OpenIdList from '../pages/openid/openid-list';
|
||||
import MarketPage from '../pages/market/listing';
|
||||
import { ConstellationIndex } from '../pages/constellation';
|
||||
|
||||
|
||||
// render - dashboard
|
||||
|
@ -44,6 +45,10 @@ const MainRoutes = {
|
|||
path: '/cosmos-ui/dashboard',
|
||||
element: <DashboardDefault />
|
||||
},
|
||||
{
|
||||
path: '/cosmos-ui/constellation',
|
||||
element: <ConstellationIndex />
|
||||
},
|
||||
{
|
||||
path: '/cosmos-ui/servapps',
|
||||
element: <ServAppsIndex />
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { Button } from "@mui/material";
|
||||
|
||||
export const randomString = (length) => {
|
||||
let text = "";
|
||||
const possible =
|
||||
|
@ -45,4 +47,4 @@ export const redirectToLocal = (url) => {
|
|||
throw new Error("URL must be local");
|
||||
}
|
||||
window.location.href = url;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ WORKDIR /app
|
|||
COPY build/cosmos build/cosmos-arm64 ./
|
||||
|
||||
# Copy other resources
|
||||
COPY build/cosmos_gray.png build/Logo.png build/GeoLite2-Country.mmdb build/meta.json ./
|
||||
COPY build/* ./
|
||||
COPY static ./static
|
||||
|
||||
# Run the respective binary based on the BINARY_NAME
|
||||
|
|
|
@ -13,7 +13,8 @@ RUN apt-get update \
|
|||
|
||||
WORKDIR /app
|
||||
|
||||
COPY build/cosmos build/cosmos_gray.png build/Logo.png build/GeoLite2-Country.mmdb build/meta.json ./
|
||||
|
||||
COPY build/* ./
|
||||
COPY static ./static
|
||||
|
||||
CMD ["./cosmos"]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "cosmos-server",
|
||||
"version": "0.9.21",
|
||||
"version": "0.10.0-unstable",
|
||||
"description": "",
|
||||
"main": "test-server.js",
|
||||
"bugs": {
|
||||
|
@ -63,13 +63,12 @@
|
|||
"scripts": {
|
||||
"client": "vite",
|
||||
"client-build": "vite build --base=/cosmos-ui/",
|
||||
"start": "env CONFIG_FILE=./config_dev.json EZ=UTC ACME_STAGING=true build/cosmos",
|
||||
"start": "env COSMOS_CONFIG_FOLDER=/mnt/e/work/Cosmos-Server/zz_test_config/ CONFIG_FILE=./config_dev.json EZ=UTC ACME_STAGING=true build/cosmos",
|
||||
"build": "sh build.sh",
|
||||
"dev": "npm run build && npm run start",
|
||||
"dockerdevbuild": "sh build.sh && docker build -f dockerfile.local --tag cosmos-dev .",
|
||||
"dockerdevrun": "docker stop cosmos-dev; docker rm cosmos-dev; docker run -d -p 7200:443 -p 80:80 -p 443:443 -e DOCKER_HOST=tcp://host.docker.internal:2375 -e COSMOS_MONGODB=$MONGODB -e COSMOS_LOG_LEVEL=DEBUG -v /:/mnt/host --restart=unless-stopped -h cosmos-dev --name cosmos-dev cosmos-dev",
|
||||
"dockerdev": "npm run dockerdevbuild && npm run dockerdevrun",
|
||||
"dockerdevclient": "npm run client-build && npm run dockerdevbuild && npm run dockerdevrun",
|
||||
"dockerdevrun": "docker stop cosmos-dev; docker rm cosmos-dev; docker run --cap-add NET_ADMIN -d -p 7200:443 -p 80:80 -p 443:443 -p 4242:4242 -e DOCKER_HOST=tcp://host.docker.internal:2375 -e COSMOS_MONGODB=$MONGODB -e COSMOS_LOG_LEVEL=DEBUG -v /:/mnt/host --restart=unless-stopped -h cosmos-dev --name cosmos-dev cosmos-dev",
|
||||
"dockerdev": "npm run client-build && npm run dockerdevbuild && npm run dockerdevrun",
|
||||
"demo": "vite build --base=/cosmos-ui/ --mode demo",
|
||||
"devdemo": "vite --mode demo"
|
||||
},
|
||||
|
|
|
@ -54,7 +54,7 @@ func UploadBackground(w http.ResponseWriter, req *http.Request) {
|
|||
}
|
||||
|
||||
// create a new file in the config directory
|
||||
dst, err := os.Create("/config/background" + ext)
|
||||
dst, err := os.Create(utils.CONFIGFOLDER + "background" + ext)
|
||||
if err != nil {
|
||||
utils.HTTPError(w, "Error creating destination file", http.StatusInternalServerError, "FILE004")
|
||||
return
|
||||
|
@ -99,7 +99,7 @@ func GetBackground(w http.ResponseWriter, req *http.Request) {
|
|||
|
||||
if(req.Method == "GET") {
|
||||
// get the background image
|
||||
bg, err := ioutil.ReadFile("/config/background." + ext)
|
||||
bg, err := ioutil.ReadFile(utils.CONFIGFOLDER + "background." + ext)
|
||||
if err != nil {
|
||||
utils.HTTPError(w, "Error reading background image", http.StatusInternalServerError, "FILE003")
|
||||
return
|
||||
|
|
|
@ -42,6 +42,7 @@ func ConfigApiGet(w http.ResponseWriter, req *http.Request) {
|
|||
"data": config,
|
||||
"updates": utils.UpdateAvailable,
|
||||
"hostname": os.Getenv("HOSTNAME"),
|
||||
"isAdmin": isAdmin,
|
||||
})
|
||||
} else {
|
||||
utils.Error("SettingGet: Method not allowed" + req.Method, nil)
|
||||
|
|
129
src/constellation/api_devices_create.go
Normal file
129
src/constellation/api_devices_create.go
Normal file
|
@ -0,0 +1,129 @@
|
|||
package constellation
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"encoding/json"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
|
||||
"github.com/azukaar/cosmos-server/src/utils"
|
||||
)
|
||||
|
||||
type DeviceCreateRequestJSON struct {
|
||||
Nickname string `json:"nickname",validate:"required,min=3,max=32,alphanum"`
|
||||
DeviceName string `json:"deviceName",validate:"required,min=3,max=32,alphanum"`
|
||||
IP string `json:"ip",validate:"required,ipv4"`
|
||||
PublicKey string `json:"publicKey",omitempty`
|
||||
}
|
||||
|
||||
func DeviceCreate(w http.ResponseWriter, req *http.Request) {
|
||||
|
||||
if(req.Method == "POST") {
|
||||
var request DeviceCreateRequestJSON
|
||||
err1 := json.NewDecoder(req.Body).Decode(&request)
|
||||
if err1 != nil {
|
||||
utils.Error("ConstellationDeviceCreation: Invalid User Request", err1)
|
||||
utils.HTTPError(w, "Device Creation Error",
|
||||
http.StatusInternalServerError, "DC001")
|
||||
return
|
||||
}
|
||||
|
||||
errV := utils.Validate.Struct(request)
|
||||
if errV != nil {
|
||||
utils.Error("DeviceCreation: Invalid User Request", errV)
|
||||
utils.HTTPError(w, "Device Creation Error: " + errV.Error(),
|
||||
http.StatusInternalServerError, "DC002")
|
||||
return
|
||||
}
|
||||
|
||||
nickname := utils.Sanitize(request.Nickname)
|
||||
deviceName := utils.Sanitize(request.DeviceName)
|
||||
|
||||
if utils.AdminOrItselfOnly(w, req, nickname) != nil {
|
||||
return
|
||||
}
|
||||
|
||||
c, errCo := utils.GetCollection(utils.GetRootAppId(), "devices")
|
||||
if errCo != nil {
|
||||
utils.Error("Database Connect", errCo)
|
||||
utils.HTTPError(w, "Database", http.StatusInternalServerError, "DB001")
|
||||
return
|
||||
}
|
||||
|
||||
device := utils.Device{}
|
||||
|
||||
utils.Debug("ConstellationDeviceCreation: Creating Device " + deviceName)
|
||||
|
||||
err2 := c.FindOne(nil, map[string]interface{}{
|
||||
"DeviceName": deviceName,
|
||||
}).Decode(&device)
|
||||
|
||||
if err2 == mongo.ErrNoDocuments {
|
||||
cert, key, err := generateNebulaCert(deviceName, request.IP, false)
|
||||
|
||||
if err != nil {
|
||||
utils.Error("DeviceCreation: Error while creating Device", err)
|
||||
utils.HTTPError(w, "Device Creation Error: " + err.Error(),
|
||||
http.StatusInternalServerError, "DC001")
|
||||
return
|
||||
}
|
||||
|
||||
_, err3 := c.InsertOne(nil, map[string]interface{}{
|
||||
"Nickname": nickname,
|
||||
"DeviceName": deviceName,
|
||||
"PublicKey": cert,
|
||||
"PrivateKey": key,
|
||||
"IP": request.IP,
|
||||
})
|
||||
|
||||
if err3 != nil {
|
||||
utils.Error("DeviceCreation: Error while creating Device", err3)
|
||||
utils.HTTPError(w, "Device Creation Error: " + err.Error(),
|
||||
http.StatusInternalServerError, "DC004")
|
||||
return
|
||||
}
|
||||
|
||||
// read configYml from config/nebula.yml
|
||||
configYml, err := getYAMLClientConfig(deviceName, utils.CONFIGFOLDER + "nebula.yml")
|
||||
if err != nil {
|
||||
utils.Error("DeviceCreation: Error while reading config", err)
|
||||
utils.HTTPError(w, "Device Creation Error: " + err.Error(),
|
||||
http.StatusInternalServerError, "DC005")
|
||||
return
|
||||
}
|
||||
|
||||
capki, err := getCApki()
|
||||
if err != nil {
|
||||
utils.Error("DeviceCreation: Error while reading ca.crt", err)
|
||||
utils.HTTPError(w, "Device Creation Error: " + err.Error(),
|
||||
http.StatusInternalServerError, "DC006")
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"status": "OK",
|
||||
"data": map[string]interface{}{
|
||||
"Nickname": nickname,
|
||||
"DeviceName": deviceName,
|
||||
"PublicKey": cert,
|
||||
"PrivateKey": key,
|
||||
"IP": request.IP,
|
||||
"Config": configYml,
|
||||
"CA": capki,
|
||||
},
|
||||
})
|
||||
} else if err2 == nil {
|
||||
utils.Error("DeviceCreation: Device already exists", nil)
|
||||
utils.HTTPError(w, "Device name already exists", http.StatusConflict, "DC002")
|
||||
return
|
||||
} else {
|
||||
utils.Error("DeviceCreation: Error while finding device", err2)
|
||||
utils.HTTPError(w, "Device Creation Error: " + err2.Error(),
|
||||
http.StatusInternalServerError, "DC001")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
utils.Error("DeviceCreation: Method not allowed" + req.Method, nil)
|
||||
utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001")
|
||||
return
|
||||
}
|
||||
}
|
18
src/constellation/api_devices_index.go
Normal file
18
src/constellation/api_devices_index.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package constellation
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"github.com/azukaar/cosmos-server/src/utils"
|
||||
)
|
||||
|
||||
func ConstellationAPIDevices(w http.ResponseWriter, req *http.Request) {
|
||||
if (req.Method == "GET") {
|
||||
DeviceList(w, req)
|
||||
} else if (req.Method == "POST") {
|
||||
DeviceCreate(w, req)
|
||||
} else {
|
||||
utils.Error("UserRoute: Method not allowed" + req.Method, nil)
|
||||
utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001")
|
||||
return
|
||||
}
|
||||
}
|
83
src/constellation/api_devices_list.go
Normal file
83
src/constellation/api_devices_list.go
Normal file
|
@ -0,0 +1,83 @@
|
|||
package constellation
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"encoding/json"
|
||||
|
||||
|
||||
"github.com/azukaar/cosmos-server/src/utils"
|
||||
)
|
||||
|
||||
func DeviceList(w http.ResponseWriter, req *http.Request) {
|
||||
// Check for GET method
|
||||
if req.Method != "GET" {
|
||||
utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP002")
|
||||
return
|
||||
}
|
||||
|
||||
if utils.LoggedInOnly(w, req) != nil {
|
||||
return
|
||||
}
|
||||
|
||||
isAdmin := utils.IsAdmin(req)
|
||||
|
||||
// Connect to the collection
|
||||
c, errCo := utils.GetCollection(utils.GetRootAppId(), "devices")
|
||||
if errCo != nil {
|
||||
utils.Error("Database Connect", errCo)
|
||||
utils.HTTPError(w, "Database", http.StatusInternalServerError, "DB001")
|
||||
return
|
||||
}
|
||||
|
||||
var devices []utils.Device
|
||||
|
||||
// Check if user is an admin
|
||||
if isAdmin {
|
||||
// If admin, get all devices
|
||||
cursor, err := c.Find(nil, map[string]interface{}{})
|
||||
if err != nil {
|
||||
utils.Error("DeviceList: Error fetching devices", err)
|
||||
utils.HTTPError(w, "Error fetching devices", http.StatusInternalServerError, "DL001")
|
||||
return
|
||||
}
|
||||
defer cursor.Close(nil)
|
||||
|
||||
if err = cursor.All(nil, &devices); err != nil {
|
||||
utils.Error("DeviceList: Error decoding devices", err)
|
||||
utils.HTTPError(w, "Error decoding devices", http.StatusInternalServerError, "DL002")
|
||||
return
|
||||
}
|
||||
|
||||
// Remove the private key from the response
|
||||
for i := range devices {
|
||||
devices[i].PrivateKey = ""
|
||||
}
|
||||
} else {
|
||||
// If not admin, get user's devices based on their nickname
|
||||
nickname := req.Header.Get("x-cosmos-user")
|
||||
cursor, err := c.Find(nil, map[string]interface{}{"Nickname": nickname})
|
||||
if err != nil {
|
||||
utils.Error("DeviceList: Error fetching devices", err)
|
||||
utils.HTTPError(w, "Error fetching devices", http.StatusInternalServerError, "DL003")
|
||||
return
|
||||
}
|
||||
defer cursor.Close(nil)
|
||||
|
||||
if err = cursor.All(nil, &devices); err != nil {
|
||||
utils.Error("DeviceList: Error decoding devices", err)
|
||||
utils.HTTPError(w, "Error decoding devices", http.StatusInternalServerError, "DL004")
|
||||
return
|
||||
}
|
||||
|
||||
// Remove the private key from the response
|
||||
for i := range devices {
|
||||
devices[i].PrivateKey = ""
|
||||
}
|
||||
}
|
||||
|
||||
// Respond with the list of devices
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"status": "OK",
|
||||
"data": devices,
|
||||
})
|
||||
}
|
42
src/constellation/index.go
Normal file
42
src/constellation/index.go
Normal file
|
@ -0,0 +1,42 @@
|
|||
package constellation
|
||||
|
||||
import (
|
||||
"github.com/azukaar/cosmos-server/src/utils"
|
||||
"os"
|
||||
)
|
||||
|
||||
func Init() {
|
||||
// if Constellation is enabled
|
||||
if utils.GetMainConfig().ConstellationConfig.Enabled {
|
||||
InitConfig()
|
||||
|
||||
utils.Log("Initializing Constellation module...")
|
||||
|
||||
// check if ca.crt exists
|
||||
if _, err := os.Stat(utils.CONFIGFOLDER + "ca.crt"); os.IsNotExist(err) {
|
||||
utils.Log("Constellation: ca.crt not found, generating...")
|
||||
// generate ca.crt
|
||||
generateNebulaCACert("Cosmos - " + utils.GetMainConfig().HTTPConfig.Hostname)
|
||||
}
|
||||
|
||||
// check if cosmos.crt exists
|
||||
if _, err := os.Stat(utils.CONFIGFOLDER + "cosmos.crt"); os.IsNotExist(err) {
|
||||
utils.Log("Constellation: cosmos.crt not found, generating...")
|
||||
// generate cosmos.crt
|
||||
generateNebulaCert("cosmos", "192.168.201.0/24", true)
|
||||
}
|
||||
|
||||
// export nebula.yml
|
||||
utils.Log("Constellation: exporting nebula.yml...")
|
||||
ExportConfigToYAML(utils.GetMainConfig().ConstellationConfig, utils.CONFIGFOLDER + "nebula.yml")
|
||||
|
||||
// start nebula
|
||||
utils.Log("Constellation: starting nebula...")
|
||||
err := startNebulaInBackground()
|
||||
if err != nil {
|
||||
utils.Error("Constellation: error while starting nebula", err)
|
||||
}
|
||||
|
||||
utils.Log("Constellation module initialized")
|
||||
}
|
||||
}
|
283
src/constellation/nebula.go
Normal file
283
src/constellation/nebula.go
Normal file
|
@ -0,0 +1,283 @@
|
|||
package constellation
|
||||
|
||||
import (
|
||||
"github.com/azukaar/cosmos-server/src/utils"
|
||||
"os/exec"
|
||||
"os"
|
||||
"fmt"
|
||||
"errors"
|
||||
"runtime"
|
||||
"sync"
|
||||
"gopkg.in/yaml.v2"
|
||||
"strings"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var (
|
||||
process *exec.Cmd
|
||||
processMux sync.Mutex
|
||||
)
|
||||
|
||||
func binaryToRun() string {
|
||||
if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
|
||||
return "./nebula-arm"
|
||||
}
|
||||
return "./nebula"
|
||||
}
|
||||
|
||||
func startNebulaInBackground() error {
|
||||
processMux.Lock()
|
||||
defer processMux.Unlock()
|
||||
|
||||
if process != nil {
|
||||
return errors.New("nebula is already running")
|
||||
}
|
||||
|
||||
process = exec.Command(binaryToRun(), "-config", utils.CONFIGFOLDER + "nebula.yml")
|
||||
|
||||
process.Stderr = os.Stderr
|
||||
|
||||
if utils.LoggingLevelLabels[utils.GetMainConfig().LoggingLevel] == utils.DEBUG {
|
||||
process.Stdout = os.Stdout
|
||||
} else {
|
||||
process.Stdout = nil
|
||||
}
|
||||
|
||||
// Start the process in the background
|
||||
if err := process.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
utils.Log(fmt.Sprintf("%s started with PID %d\n", binaryToRun(), process.Process.Pid))
|
||||
return nil
|
||||
}
|
||||
|
||||
func stop() error {
|
||||
processMux.Lock()
|
||||
defer processMux.Unlock()
|
||||
|
||||
if process == nil {
|
||||
return errors.New("nebula is not running")
|
||||
}
|
||||
|
||||
if err := process.Process.Kill(); err != nil {
|
||||
return err
|
||||
}
|
||||
process = nil
|
||||
utils.Log("Stopped nebula.")
|
||||
return nil
|
||||
}
|
||||
|
||||
func restart() error {
|
||||
if err := stop(); err != nil {
|
||||
return err
|
||||
}
|
||||
return startNebulaInBackground()
|
||||
}
|
||||
|
||||
func ExportConfigToYAML(overwriteConfig utils.ConstellationConfig, outputPath string) error {
|
||||
// Combine defaultConfig and overwriteConfig
|
||||
finalConfig := NebulaDefaultConfig
|
||||
|
||||
finalConfig.StaticHostMap = map[string][]string{
|
||||
"192.168.201.0": []string{utils.GetMainConfig().HTTPConfig.Hostname + ":4242"},
|
||||
}
|
||||
|
||||
// Marshal the combined config to YAML
|
||||
yamlData, err := yaml.Marshal(finalConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write YAML data to the specified file
|
||||
yamlFile, err := os.Create(outputPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer yamlFile.Close()
|
||||
|
||||
_, err = yamlFile.Write(yamlData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getYAMLClientConfig(name, configPath string) (string, error) {
|
||||
utils.Log("Exporting YAML config for " + name + " with file " + configPath)
|
||||
|
||||
// Read the YAML config file
|
||||
yamlData, err := ioutil.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Unmarshal the YAML data into a map interface
|
||||
var configMap map[string]interface{}
|
||||
err = yaml.Unmarshal(yamlData, &configMap)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// set lightHouse to false
|
||||
if lighthouseMap, ok := configMap["lighthouse"].(map[interface{}]interface{}); ok {
|
||||
lighthouseMap["am_lighthouse"] = false
|
||||
|
||||
lighthouseMap["hosts"] = []string{
|
||||
"192.168.201.0",
|
||||
}
|
||||
} else {
|
||||
return "", errors.New("lighthouse not found in nebula.yml")
|
||||
}
|
||||
|
||||
if pkiMap, ok := configMap["pki"].(map[interface{}]interface{}); ok {
|
||||
pkiMap["ca"] = "ca.crt"
|
||||
pkiMap["cert"] = name + ".crt"
|
||||
pkiMap["key"] = name + ".key"
|
||||
} else {
|
||||
return "", errors.New("pki not found in nebula.yml")
|
||||
}
|
||||
|
||||
// export configMap as YML
|
||||
yamlData, err = yaml.Marshal(configMap)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(yamlData), nil
|
||||
}
|
||||
|
||||
func getCApki() (string, error) {
|
||||
// read config/ca.crt
|
||||
caCrt, err := ioutil.ReadFile(utils.CONFIGFOLDER + "ca.crt")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(caCrt), nil
|
||||
}
|
||||
|
||||
func killAllNebulaInstances() error {
|
||||
processMux.Lock()
|
||||
defer processMux.Unlock()
|
||||
|
||||
cmd := exec.Command("ps", "-e", "-o", "pid,command")
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lines := strings.Split(string(output), "\n")
|
||||
for _, line := range lines {
|
||||
if strings.Contains(line, binaryToRun()) {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) > 1 {
|
||||
pid := fields[0]
|
||||
pidInt, _ := strconv.Atoi(pid)
|
||||
process, err := os.FindProcess(pidInt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = process.Kill()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
utils.Log(fmt.Sprintf("Killed Nebula instance with PID %s\n", pid))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateNebulaCert(name, ip string, saveToFile bool) (string, string, error) {
|
||||
// Run the nebula-cert command
|
||||
cmd := exec.Command(binaryToRun() + "-cert",
|
||||
"sign",
|
||||
"-ca-crt", utils.CONFIGFOLDER + "ca.crt",
|
||||
"-ca-key", utils.CONFIGFOLDER + "ca.key",
|
||||
"-name", name,
|
||||
"-ip", ip,
|
||||
)
|
||||
utils.Debug(cmd.String())
|
||||
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
if utils.LoggingLevelLabels[utils.GetMainConfig().LoggingLevel] == utils.DEBUG {
|
||||
cmd.Stdout = os.Stdout
|
||||
} else {
|
||||
cmd.Stdout = nil
|
||||
}
|
||||
|
||||
cmd.Run()
|
||||
|
||||
if cmd.ProcessState.ExitCode() != 0 {
|
||||
return "", "", fmt.Errorf("nebula-cert exited with an error, check the Cosmos logs")
|
||||
}
|
||||
|
||||
// Read the generated certificate and key files
|
||||
certPath := fmt.Sprintf("./%s.crt", name)
|
||||
keyPath := fmt.Sprintf("./%s.key", name)
|
||||
|
||||
utils.Debug("Reading certificate from " + certPath)
|
||||
utils.Debug("Reading key from " + keyPath)
|
||||
|
||||
certContent, errCert := ioutil.ReadFile(certPath)
|
||||
if errCert != nil {
|
||||
return "", "", fmt.Errorf("failed to read certificate file: %s", errCert)
|
||||
}
|
||||
|
||||
keyContent, errKey := ioutil.ReadFile(keyPath)
|
||||
if errKey != nil {
|
||||
return "", "", fmt.Errorf("failed to read key file: %s", errKey)
|
||||
}
|
||||
|
||||
if saveToFile {
|
||||
cmd = exec.Command("mv", certPath, utils.CONFIGFOLDER + name + ".crt")
|
||||
utils.Debug(cmd.String())
|
||||
cmd.Run()
|
||||
cmd = exec.Command("mv", keyPath, utils.CONFIGFOLDER + name + ".key")
|
||||
utils.Debug(cmd.String())
|
||||
cmd.Run()
|
||||
} else {
|
||||
// Delete the generated certificate and key files
|
||||
if err := os.Remove(certPath); err != nil {
|
||||
return "", "", fmt.Errorf("failed to delete certificate file: %s", err)
|
||||
}
|
||||
|
||||
if err := os.Remove(keyPath); err != nil {
|
||||
return "", "", fmt.Errorf("failed to delete key file: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
return string(certContent), string(keyContent), nil
|
||||
}
|
||||
|
||||
func generateNebulaCACert(name string) (error) {
|
||||
// Run the nebula-cert command to generate CA certificate and key
|
||||
cmd := exec.Command(binaryToRun() + "-cert", "ca", "-name", "\""+name+"\"")
|
||||
|
||||
utils.Debug(cmd.String())
|
||||
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
if utils.LoggingLevelLabels[utils.GetMainConfig().LoggingLevel] == utils.DEBUG {
|
||||
cmd.Stdout = os.Stdout
|
||||
} else {
|
||||
cmd.Stdout = nil
|
||||
}
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("nebula-cert error: %s", err)
|
||||
}
|
||||
|
||||
// copy to /config/ca.*
|
||||
cmd = exec.Command("mv", "./ca.crt", utils.CONFIGFOLDER + "ca.crt")
|
||||
cmd.Run()
|
||||
cmd = exec.Command("mv", "./ca.key", utils.CONFIGFOLDER + "ca.key")
|
||||
cmd.Run()
|
||||
|
||||
return nil
|
||||
}
|
95
src/constellation/nebula_default.go
Normal file
95
src/constellation/nebula_default.go
Normal file
|
@ -0,0 +1,95 @@
|
|||
package constellation
|
||||
|
||||
import (
|
||||
"github.com/azukaar/cosmos-server/src/utils"
|
||||
)
|
||||
|
||||
var NebulaDefaultConfig utils.NebulaConfig
|
||||
|
||||
func InitConfig() {
|
||||
NebulaDefaultConfig = utils.NebulaConfig {
|
||||
PKI: struct {
|
||||
CA string `yaml:"ca"`
|
||||
Cert string `yaml:"cert"`
|
||||
Key string `yaml:"key"`
|
||||
}{
|
||||
CA: utils.CONFIGFOLDER + "ca.crt",
|
||||
Cert: utils.CONFIGFOLDER + "cosmos.crt",
|
||||
Key: utils.CONFIGFOLDER + "cosmos.key",
|
||||
},
|
||||
StaticHostMap: map[string][]string{
|
||||
|
||||
},
|
||||
Lighthouse: struct {
|
||||
AMLighthouse bool `yaml:"am_lighthouse"`
|
||||
Interval int `yaml:"interval"`
|
||||
Hosts []string `yaml:"hosts"`
|
||||
}{
|
||||
AMLighthouse: true,
|
||||
Interval: 60,
|
||||
Hosts: []string{},
|
||||
},
|
||||
Listen: struct {
|
||||
Host string `yaml:"host"`
|
||||
Port int `yaml:"port"`
|
||||
}{
|
||||
Host: "0.0.0.0",
|
||||
Port: 4242,
|
||||
},
|
||||
Punchy: struct {
|
||||
Punch bool `yaml:"punch"`
|
||||
}{
|
||||
Punch: true,
|
||||
},
|
||||
Relay: struct {
|
||||
AMRelay bool `yaml:"am_relay"`
|
||||
UseRelays bool `yaml:"use_relays"`
|
||||
}{
|
||||
AMRelay: false,
|
||||
UseRelays: true,
|
||||
},
|
||||
TUN: struct {
|
||||
Disabled bool `yaml:"disabled"`
|
||||
Dev string `yaml:"dev"`
|
||||
DropLocalBroadcast bool `yaml:"drop_local_broadcast"`
|
||||
DropMulticast bool `yaml:"drop_multicast"`
|
||||
TxQueue int `yaml:"tx_queue"`
|
||||
MTU int `yaml:"mtu"`
|
||||
Routes []string `yaml:"routes"`
|
||||
UnsafeRoutes []string `yaml:"unsafe_routes"`
|
||||
}{
|
||||
Disabled: false,
|
||||
Dev: "nebula1",
|
||||
DropLocalBroadcast: false,
|
||||
DropMulticast: false,
|
||||
TxQueue: 500,
|
||||
MTU: 1300,
|
||||
Routes: nil,
|
||||
UnsafeRoutes: nil,
|
||||
},
|
||||
Logging: struct {
|
||||
Level string `yaml:"level"`
|
||||
Format string `yaml:"format"`
|
||||
}{
|
||||
Level: "info",
|
||||
Format: "text",
|
||||
},
|
||||
Firewall: struct {
|
||||
OutboundAction string `yaml:"outbound_action"`
|
||||
InboundAction string `yaml:"inbound_action"`
|
||||
Conntrack utils.NebulaConntrackConfig `yaml:"conntrack"`
|
||||
Outbound []utils.NebulaFirewallRule `yaml:"outbound"`
|
||||
Inbound []utils.NebulaFirewallRule `yaml:"inbound"`
|
||||
}{
|
||||
OutboundAction: "drop",
|
||||
InboundAction: "drop",
|
||||
Conntrack: utils.NebulaConntrackConfig{
|
||||
TCPTimeout: "12m",
|
||||
UDPTimeout: "3m",
|
||||
DefaultTimeout: "10m",
|
||||
},
|
||||
Outbound: nil,
|
||||
Inbound: nil,
|
||||
},
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/azukaar/cosmos-server/src/docker"
|
||||
"github.com/azukaar/cosmos-server/src/authorizationserver"
|
||||
"github.com/azukaar/cosmos-server/src/market"
|
||||
"github.com/azukaar/cosmos-server/src/constellation"
|
||||
"github.com/gorilla/mux"
|
||||
"strconv"
|
||||
"time"
|
||||
|
@ -331,6 +332,7 @@ func InitServer() *mux.Router {
|
|||
srapi.HandleFunc("/api/background", UploadBackground)
|
||||
srapi.HandleFunc("/api/background/{ext}", GetBackground)
|
||||
|
||||
srapi.HandleFunc("/api/constellation/devices", constellation.ConstellationAPIDevices)
|
||||
|
||||
if(!config.HTTPConfig.AcceptAllInsecureHostname) {
|
||||
srapi.Use(utils.EnsureHostname)
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/azukaar/cosmos-server/src/utils"
|
||||
"github.com/azukaar/cosmos-server/src/authorizationserver"
|
||||
"github.com/azukaar/cosmos-server/src/market"
|
||||
"github.com/azukaar/cosmos-server/src/constellation"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -44,5 +45,7 @@ func main() {
|
|||
|
||||
authorizationserver.Init()
|
||||
|
||||
constellation.Init()
|
||||
|
||||
StartServer()
|
||||
}
|
||||
|
|
|
@ -2,12 +2,9 @@ package user
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
// "io"
|
||||
// "os"
|
||||
"encoding/json"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"time"
|
||||
// "golang.org/x/crypto/bcrypt"
|
||||
|
||||
"github.com/azukaar/cosmos-server/src/utils"
|
||||
)
|
||||
|
|
|
@ -181,20 +181,20 @@ func DoLetsEncrypt() (string, string) {
|
|||
}
|
||||
|
||||
err = client.Challenge.SetDNS01Provider(provider)
|
||||
}
|
||||
} else {
|
||||
err = client.Challenge.SetHTTP01Provider(http01.NewProviderServer("", config.HTTPConfig.HTTPPort))
|
||||
if err != nil {
|
||||
Error("LETSENCRYPT_HTTP01", err)
|
||||
LetsEncryptErrors = append(LetsEncryptErrors, err.Error())
|
||||
return "", ""
|
||||
}
|
||||
|
||||
err = client.Challenge.SetHTTP01Provider(http01.NewProviderServer("", config.HTTPConfig.HTTPPort))
|
||||
if err != nil {
|
||||
Error("LETSENCRYPT_HTTP01", err)
|
||||
LetsEncryptErrors = append(LetsEncryptErrors, err.Error())
|
||||
return "", ""
|
||||
}
|
||||
|
||||
err = client.Challenge.SetTLSALPN01Provider(tlsalpn01.NewProviderServer("", config.HTTPConfig.HTTPSPort))
|
||||
if err != nil {
|
||||
Error("LETSENCRYPT_TLS01", err)
|
||||
LetsEncryptErrors = append(LetsEncryptErrors, err.Error())
|
||||
return "", ""
|
||||
err = client.Challenge.SetTLSALPN01Provider(tlsalpn01.NewProviderServer("", config.HTTPConfig.HTTPSPort))
|
||||
if err != nil {
|
||||
Error("LETSENCRYPT_TLS01", err)
|
||||
LetsEncryptErrors = append(LetsEncryptErrors, err.Error())
|
||||
return "", ""
|
||||
}
|
||||
}
|
||||
|
||||
// New users will need to register
|
||||
|
|
|
@ -90,6 +90,7 @@ type Config struct {
|
|||
MarketConfig MarketConfig
|
||||
HomepageConfig HomepageConfig
|
||||
ThemeConfig ThemeConfig
|
||||
ConstellationConfig ConstellationConfig
|
||||
}
|
||||
|
||||
type HomepageConfig struct {
|
||||
|
@ -205,4 +206,84 @@ type MarketConfig struct {
|
|||
type MarketSource struct {
|
||||
Name string
|
||||
Url string
|
||||
}
|
||||
}
|
||||
|
||||
type ConstellationConfig struct {
|
||||
Enabled bool
|
||||
NebulaConfig NebulaConfig
|
||||
}
|
||||
|
||||
type NebulaFirewallRule struct {
|
||||
Port string `yaml:"port"`
|
||||
Proto string `yaml:"proto"`
|
||||
Host string `yaml:"host"`
|
||||
Groups []string `yaml:"groups,omitempty"omitempty"`
|
||||
}
|
||||
|
||||
type NebulaConntrackConfig struct {
|
||||
TCPTimeout string `yaml:"tcp_timeout"`
|
||||
UDPTimeout string `yaml:"udp_timeout"`
|
||||
DefaultTimeout string `yaml:"default_timeout"`
|
||||
}
|
||||
|
||||
type NebulaConfig struct {
|
||||
PKI struct {
|
||||
CA string `yaml:"ca"`
|
||||
Cert string `yaml:"cert"`
|
||||
Key string `yaml:"key"`
|
||||
} `yaml:"pki"`
|
||||
|
||||
StaticHostMap map[string][]string `yaml:"static_host_map"`
|
||||
|
||||
Lighthouse struct {
|
||||
AMLighthouse bool `yaml:"am_lighthouse"`
|
||||
Interval int `yaml:"interval"`
|
||||
Hosts []string `yaml:"hosts"`
|
||||
} `yaml:"lighthouse"`
|
||||
|
||||
Listen struct {
|
||||
Host string `yaml:"host"`
|
||||
Port int `yaml:"port"`
|
||||
} `yaml:"listen"`
|
||||
|
||||
Punchy struct {
|
||||
Punch bool `yaml:"punch"`
|
||||
} `yaml:"punchy"`
|
||||
|
||||
Relay struct {
|
||||
AMRelay bool `yaml:"am_relay"`
|
||||
UseRelays bool `yaml:"use_relays"`
|
||||
} `yaml:"relay"`
|
||||
|
||||
TUN struct {
|
||||
Disabled bool `yaml:"disabled"`
|
||||
Dev string `yaml:"dev"`
|
||||
DropLocalBroadcast bool `yaml:"drop_local_broadcast"`
|
||||
DropMulticast bool `yaml:"drop_multicast"`
|
||||
TxQueue int `yaml:"tx_queue"`
|
||||
MTU int `yaml:"mtu"`
|
||||
Routes []string `yaml:"routes"`
|
||||
UnsafeRoutes []string `yaml:"unsafe_routes"`
|
||||
} `yaml:"tun"`
|
||||
|
||||
Logging struct {
|
||||
Level string `yaml:"level"`
|
||||
Format string `yaml:"format"`
|
||||
} `yaml:"logging"`
|
||||
|
||||
Firewall struct {
|
||||
OutboundAction string `yaml:"outbound_action"`
|
||||
InboundAction string `yaml:"inbound_action"`
|
||||
Conntrack NebulaConntrackConfig `yaml:"conntrack"`
|
||||
Outbound []NebulaFirewallRule `yaml:"outbound"`
|
||||
Inbound []NebulaFirewallRule `yaml:"inbound"`
|
||||
} `yaml:"firewall"`
|
||||
}
|
||||
|
||||
type Device struct {
|
||||
DeviceName string `json:"deviceName",validate:"required,min=3,max=32,alphanum"`
|
||||
Nickname string `json:"nickname",validate:"required,min=3,max=32,alphanum"`
|
||||
PublicKey string `json:"publicKey",omitempty`
|
||||
PrivateKey string `json:"privateKey",omitempty`
|
||||
IP string `json:"ip",validate:"required,ipv4"`
|
||||
}
|
||||
|
|
|
@ -37,6 +37,8 @@ var ReBootstrapContainer func(string) error
|
|||
|
||||
var LetsEncryptErrors = []string{}
|
||||
|
||||
var CONFIGFOLDER = "/config/"
|
||||
|
||||
var DefaultConfig = Config{
|
||||
LoggingLevel: "INFO",
|
||||
NewInstall: true,
|
||||
|
@ -193,6 +195,10 @@ func LoadBaseMainConfig(config Config) {
|
|||
if os.Getenv("COSMOS_SERVER_COUNTRY") != "" {
|
||||
MainConfig.ServerCountry = os.Getenv("COSMOS_SERVER_COUNTRY")
|
||||
}
|
||||
if os.Getenv("COSMOS_CONFIG_FOLDER") != "" {
|
||||
Log("Overwriting config folder with " + os.Getenv("COSMOS_CONFIG_FOLDER"))
|
||||
CONFIGFOLDER = os.Getenv("COSMOS_CONFIG_FOLDER")
|
||||
}
|
||||
|
||||
if MainConfig.DockerConfig.DefaultDataPath == "" {
|
||||
MainConfig.DockerConfig.DefaultDataPath = "/usr"
|
||||
|
@ -219,7 +225,7 @@ func GetConfigFileName() string {
|
|||
configFile := os.Getenv("CONFIG_FILE")
|
||||
|
||||
if configFile == "" {
|
||||
configFile = "/config/cosmos.config.json"
|
||||
configFile = CONFIGFOLDER + "cosmos.config.json"
|
||||
}
|
||||
|
||||
return configFile
|
||||
|
|
Loading…
Add table
Reference in a new issue