mirror of
https://github.com/moghtech/komodo.git
synced 2026-07-23 21:46:36 -05:00
no access to deployments / updates outside of users scope
This commit is contained in:
@@ -66,6 +66,18 @@ const deployments = fp((app: FastifyInstance, _: {}, done: () => void) => {
|
||||
res.send("could not find deployment");
|
||||
return;
|
||||
}
|
||||
const user = await app.users.findById(
|
||||
req.user.id,
|
||||
"username permissions"
|
||||
);
|
||||
if (
|
||||
!user ||
|
||||
(user?.permissions! < 2 && !deployment.owners.includes(user.username))
|
||||
) {
|
||||
res.status(403);
|
||||
res.send("user does not have permissions to view this information");
|
||||
return;
|
||||
}
|
||||
const onCore = deployment.serverID === app.core._id;
|
||||
const server = onCore
|
||||
? app.core
|
||||
@@ -90,13 +102,25 @@ const deployments = fp((app: FastifyInstance, _: {}, done: () => void) => {
|
||||
const { tail } = req.query as { tail?: number };
|
||||
const deployment = await app.deployments.findById(
|
||||
id,
|
||||
"serverID containerName"
|
||||
"serverID containerName owners"
|
||||
);
|
||||
if (!deployment) {
|
||||
res.status(400);
|
||||
res.send("could not find deployment");
|
||||
return;
|
||||
}
|
||||
const user = await app.users.findById(
|
||||
req.user.id,
|
||||
"username permissions"
|
||||
);
|
||||
if (
|
||||
!user ||
|
||||
(user?.permissions! < 2 && !deployment.owners.includes(user.username))
|
||||
) {
|
||||
res.status(403);
|
||||
res.send("user does not have permissions to view this log");
|
||||
return;
|
||||
}
|
||||
const onCore = deployment.serverID === app.core._id;
|
||||
const server = onCore
|
||||
? app.core
|
||||
@@ -141,6 +165,7 @@ const deployments = fp((app: FastifyInstance, _: {}, done: () => void) => {
|
||||
) {
|
||||
res.status(403);
|
||||
res.send("user not authorized for this action");
|
||||
return;
|
||||
}
|
||||
const server = await app.servers.findById(deployment.serverID!);
|
||||
if (!server) {
|
||||
|
||||
+103
-11
@@ -1,5 +1,6 @@
|
||||
import { FastifyInstance } from "fastify";
|
||||
import fp from "fastify-plugin";
|
||||
import removeServer from "../messages/servers/remove";
|
||||
|
||||
const updates = fp((app: FastifyInstance, _: {}, done: () => void) => {
|
||||
app.get(
|
||||
@@ -13,18 +14,109 @@ const updates = fp((app: FastifyInstance, _: {}, done: () => void) => {
|
||||
serverID?: string;
|
||||
deploymentID?: string;
|
||||
};
|
||||
const updates = await app.updates.getMostRecent(
|
||||
10,
|
||||
buildID
|
||||
? { buildID }
|
||||
: deploymentID
|
||||
? { deploymentID }
|
||||
: serverID
|
||||
? { serverID }
|
||||
: {},
|
||||
offset
|
||||
const user = await app.users.findById(
|
||||
req.user.id,
|
||||
"username permissions"
|
||||
);
|
||||
res.send(updates);
|
||||
if (!user) {
|
||||
res.status(400);
|
||||
res.send("user not found");
|
||||
return;
|
||||
}
|
||||
if (user.permissions! < 1) {
|
||||
res.status(403);
|
||||
res.send("user does not have permission to access this information");
|
||||
return;
|
||||
}
|
||||
if (user.permissions! > 1) {
|
||||
const updates = await app.updates.getMostRecent(
|
||||
10,
|
||||
buildID
|
||||
? { buildID }
|
||||
: deploymentID
|
||||
? { deploymentID }
|
||||
: serverID
|
||||
? { serverID }
|
||||
: {},
|
||||
offset
|
||||
);
|
||||
res.send(updates);
|
||||
return;
|
||||
}
|
||||
if (buildID) {
|
||||
const build = await app.builds.findById(buildID, "owners");
|
||||
if (!build || !build.owners.includes(user.username)) {
|
||||
res.status(403);
|
||||
res.send("user does not have permission to access this data");
|
||||
return;
|
||||
}
|
||||
const updates = await app.updates.getMostRecent(
|
||||
10,
|
||||
{ buildID },
|
||||
offset
|
||||
);
|
||||
res.send(updates);
|
||||
} else if (deploymentID) {
|
||||
const deployment = await app.deployments.findById(
|
||||
deploymentID,
|
||||
"owners"
|
||||
);
|
||||
if (!deployment || !deployment.owners.includes(user.username)) {
|
||||
res.status(403);
|
||||
res.send("user does not have permission to access this data");
|
||||
return;
|
||||
}
|
||||
const updates = await app.updates.getMostRecent(
|
||||
10,
|
||||
{ deploymentID },
|
||||
offset
|
||||
);
|
||||
res.send(updates);
|
||||
} else if (serverID) {
|
||||
const server = await app.servers.findById(serverID, "owners");
|
||||
if (!server || !server.owners.includes(user.username)) {
|
||||
res.status(403);
|
||||
res.send("user does not have permission to access this data");
|
||||
return;
|
||||
}
|
||||
const updates = await app.updates.getMostRecent(
|
||||
10,
|
||||
{ serverID },
|
||||
offset
|
||||
);
|
||||
res.send(updates);
|
||||
} else {
|
||||
const deploymentIDs = (
|
||||
await app.deployments.find(
|
||||
{ owners: { $elemMatch: { $eq: user.username } } },
|
||||
"_id"
|
||||
)
|
||||
).map((dep) => dep._id);
|
||||
const buildIDs = (
|
||||
await app.builds.find(
|
||||
{ owners: { $elemMatch: { $eq: user.username } } },
|
||||
"_id"
|
||||
)
|
||||
).map((build) => build._id);
|
||||
const serverIDs = (
|
||||
await app.servers.find(
|
||||
{ owners: { $elemMatch: { $eq: user.username } } },
|
||||
"_id"
|
||||
)
|
||||
).map((server) => server._id);
|
||||
const updates = await app.updates.getMostRecent(
|
||||
10,
|
||||
{
|
||||
$or: [
|
||||
{ deploymentID: { $in: deploymentIDs } },
|
||||
{ buildID: { $in: buildIDs } },
|
||||
{ serverID: { $in: serverIDs } },
|
||||
],
|
||||
},
|
||||
offset
|
||||
);
|
||||
res.send(updates);
|
||||
}
|
||||
}
|
||||
);
|
||||
done();
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Component, Show } from "solid-js";
|
||||
import { useAppDimensions } from "../../state/DimensionProvider";
|
||||
import { useAppState } from "../../state/StateProvider";
|
||||
import { useTheme } from "../../state/ThemeProvider";
|
||||
import { useUser } from "../../state/UserProvider";
|
||||
import { combineClasses } from "../../util/helpers";
|
||||
import NotFound from "../NotFound";
|
||||
import Grid from "../util/layout/Grid";
|
||||
@@ -16,6 +17,16 @@ const Build: Component<{}> = (p) => {
|
||||
const build = () => builds.get(selected.id())!;
|
||||
const { themeClass } = useTheme();
|
||||
const { isMobile } = useAppDimensions();
|
||||
const { permissions, username } = useUser();
|
||||
const userCanUpdate = () => {
|
||||
if (permissions() > 1) {
|
||||
return true;
|
||||
} else if (permissions() > 0 && build()!.owners.includes(username()!)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Show when={build()} fallback={<NotFound type="build" />}>
|
||||
<ActionStateProvider>
|
||||
@@ -24,7 +35,7 @@ const Build: Component<{}> = (p) => {
|
||||
<Grid class="left-content">
|
||||
<Header />
|
||||
<Actions />
|
||||
<Show when={!isMobile()}>
|
||||
<Show when={!isMobile() && userCanUpdate()}>
|
||||
<Updates />
|
||||
</Show>
|
||||
</Grid>
|
||||
|
||||
@@ -23,6 +23,15 @@ const Header: Component<{}> = (p) => {
|
||||
const { isMobile } = useAppDimensions();
|
||||
const [showUpdates, toggleShowUpdates] =
|
||||
useLocalStorageToggle("show-updates");
|
||||
const userCanUpdate = () => {
|
||||
if (permissions() > 1) {
|
||||
return true;
|
||||
} else if (permissions() > 0 && build()!.owners.includes(username()!)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Flex
|
||||
@@ -31,17 +40,17 @@ const Header: Component<{}> = (p) => {
|
||||
alignItems="center"
|
||||
style={{
|
||||
position: "relative",
|
||||
cursor: isMobile() ? "pointer" : undefined,
|
||||
cursor: isMobile() && userCanUpdate() ? "pointer" : undefined,
|
||||
}}
|
||||
onClick={() => {
|
||||
if (isMobile()) toggleShowUpdates();
|
||||
if (isMobile() && userCanUpdate()) toggleShowUpdates();
|
||||
}}
|
||||
>
|
||||
<Grid gap="0.1rem">
|
||||
<h1>{build().name}</h1>
|
||||
<div style={{ opacity: 0.8 }}>{getSub(build())}</div>
|
||||
</Grid>
|
||||
<Show when={permissions() >= 2 || build().owners.includes(username()!)}>
|
||||
<Show when={userCanUpdate()}>
|
||||
<Show
|
||||
when={!actions.deleting}
|
||||
fallback={
|
||||
@@ -60,7 +69,7 @@ const Header: Component<{}> = (p) => {
|
||||
</ConfirmButton>
|
||||
</Show>
|
||||
</Show>
|
||||
<Show when={isMobile()}>
|
||||
<Show when={isMobile() && userCanUpdate()}>
|
||||
<Flex gap="0.5rem" alignItems="center" class="show-updates-indicator">
|
||||
updates{" "}
|
||||
<Icon
|
||||
@@ -70,7 +79,7 @@ const Header: Component<{}> = (p) => {
|
||||
</Flex>
|
||||
</Show>
|
||||
</Flex>
|
||||
<Show when={isMobile() && showUpdates()}>
|
||||
<Show when={isMobile() && userCanUpdate() && showUpdates()}>
|
||||
<Updates />
|
||||
</Show>
|
||||
</>
|
||||
|
||||
@@ -2,13 +2,14 @@ import { Component, Show } from "solid-js";
|
||||
import { useAppDimensions } from "../../state/DimensionProvider";
|
||||
import { useAppState } from "../../state/StateProvider";
|
||||
import { useTheme } from "../../state/ThemeProvider";
|
||||
import { useUser } from "../../state/UserProvider";
|
||||
import { combineClasses } from "../../util/helpers";
|
||||
import NotFound from "../NotFound";
|
||||
import Grid from "../util/layout/Grid";
|
||||
import Loading from "../util/loading/Loading";
|
||||
import Actions from "./Actions";
|
||||
import { ActionStateProvider } from "./ActionStateProvider";
|
||||
import Header from "./Header";
|
||||
import { ConfigProvider } from "./tabs/config/Provider";
|
||||
import DeploymentTabs from "./tabs/Tabs";
|
||||
import Updates from "./Updates";
|
||||
|
||||
@@ -18,6 +19,19 @@ const Deployment: Component<{}> = (p) => {
|
||||
const server = () => deployment() && servers.get(deployment()?.serverID!);
|
||||
const { themeClass } = useTheme();
|
||||
const { isMobile } = useAppDimensions();
|
||||
const { permissions, username } = useUser();
|
||||
const userCanUpdate = () => {
|
||||
if (permissions() > 1) {
|
||||
return true;
|
||||
} else if (
|
||||
permissions() > 0 &&
|
||||
deployment()!.owners.includes(username()!)
|
||||
) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Show
|
||||
when={deployment() && server()}
|
||||
@@ -29,12 +43,23 @@ const Deployment: Component<{}> = (p) => {
|
||||
<Grid class="left-content">
|
||||
<Header />
|
||||
<Actions />
|
||||
<Show when={!isMobile()}>
|
||||
<Show when={!isMobile() && userCanUpdate()}>
|
||||
<Updates />
|
||||
</Show>
|
||||
</Grid>
|
||||
{/* right / tabs */}
|
||||
<DeploymentTabs />
|
||||
<Show
|
||||
when={userCanUpdate()}
|
||||
fallback={
|
||||
<h2 class={combineClasses("card tabs shadow", themeClass())}>
|
||||
you do not have permission to view this deployment
|
||||
</h2>
|
||||
}
|
||||
>
|
||||
<ConfigProvider>
|
||||
<DeploymentTabs />
|
||||
</ConfigProvider>
|
||||
</Show>
|
||||
</Grid>
|
||||
</ActionStateProvider>
|
||||
</Show>
|
||||
|
||||
@@ -39,6 +39,19 @@ const Header: Component<{ exiting?: boolean }> = (p) => {
|
||||
const { isMobile } = useAppDimensions();
|
||||
const [showUpdates, toggleShowUpdates] =
|
||||
useLocalStorageToggle("show-updates");
|
||||
|
||||
const userCanUpdate = () => {
|
||||
if (permissions() > 1) {
|
||||
return true;
|
||||
} else if (
|
||||
permissions() > 0 &&
|
||||
deployment()!.owners.includes(username()!)
|
||||
) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Grid
|
||||
@@ -46,10 +59,10 @@ const Header: Component<{ exiting?: boolean }> = (p) => {
|
||||
class={combineClasses("card shadow", themeClass())}
|
||||
style={{
|
||||
position: "relative",
|
||||
cursor: isMobile() ? "pointer" : undefined,
|
||||
cursor: (isMobile() && userCanUpdate()) ? "pointer" : undefined,
|
||||
}}
|
||||
onClick={() => {
|
||||
if (isMobile()) toggleShowUpdates();
|
||||
if (isMobile() && userCanUpdate()) toggleShowUpdates();
|
||||
}}
|
||||
>
|
||||
<Flex alignItems="center" justifyContent="space-between">
|
||||
@@ -104,7 +117,7 @@ const Header: Component<{ exiting?: boolean }> = (p) => {
|
||||
<div style={{ opacity: 0.7 }}>{status()}</div>
|
||||
</Show>
|
||||
</Flex>
|
||||
<Show when={isMobile()}>
|
||||
<Show when={isMobile() && userCanUpdate()}>
|
||||
<Flex gap="0.5rem" alignItems="center" class="show-updates-indicator">
|
||||
updates{" "}
|
||||
<Icon
|
||||
@@ -114,7 +127,7 @@ const Header: Component<{ exiting?: boolean }> = (p) => {
|
||||
</Flex>
|
||||
</Show>
|
||||
</Grid>
|
||||
<Show when={isMobile() && showUpdates()}>
|
||||
<Show when={isMobile() && userCanUpdate() && showUpdates()}>
|
||||
<Updates />
|
||||
</Show>
|
||||
</>
|
||||
|
||||
@@ -14,12 +14,13 @@ const Updates: Component<{}> = (p) => {
|
||||
const selectedUpdates = useArray(() =>
|
||||
getUpdates({ deploymentID: selected.id() })
|
||||
);
|
||||
const unsub = ws.subscribe([ADD_UPDATE], ({ update }) => {
|
||||
if (update.deploymentID === selected.id()) {
|
||||
selectedUpdates.add(update);
|
||||
}
|
||||
});
|
||||
onCleanup(unsub);
|
||||
onCleanup(
|
||||
ws.subscribe([ADD_UPDATE], ({ update }) => {
|
||||
if (update.deploymentID === selected.id()) {
|
||||
selectedUpdates.add(update);
|
||||
}
|
||||
})
|
||||
);
|
||||
const [noMoreUpdates, setNoMore] = createSignal(false);
|
||||
const loadMore = async () => {
|
||||
const offset = selectedUpdates.collection()?.length;
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
import Tabs from "../../util/tabs/Tabs";
|
||||
import Config from "./config/Config";
|
||||
import Log from "./log/Log";
|
||||
import { ConfigProvider } from "./config/Provider";
|
||||
import { useAppState } from "../../../state/StateProvider";
|
||||
import { getDeploymentLog } from "../../../util/query";
|
||||
import Icon from "../../util/Icon";
|
||||
@@ -33,7 +32,7 @@ const DeploymentTabs: Component<{}> = () => {
|
||||
deployment()!.status === "not deployed"
|
||||
? "not deployed"
|
||||
: (deployment()!.status as ContainerStatus).State;
|
||||
const load = async () => {
|
||||
const loadLog = async () => {
|
||||
console.log("load log");
|
||||
if (deployment()?.status !== "not deployed") {
|
||||
const log = await getDeploymentLog(selected.id(), logTail());
|
||||
@@ -42,75 +41,74 @@ const DeploymentTabs: Component<{}> = () => {
|
||||
setLog({});
|
||||
}
|
||||
};
|
||||
createEffect(load);
|
||||
const unsub = ws.subscribe([ADD_UPDATE], ({ update }: { update: Update }) => {
|
||||
if (
|
||||
update.deploymentID === selected.id() &&
|
||||
(update.operation === DEPLOY ||
|
||||
update.operation === START_CONTAINER ||
|
||||
update.operation === STOP_CONTAINER ||
|
||||
update.operation === DELETE_CONTAINER)
|
||||
) {
|
||||
// console.log("updating log");
|
||||
setTimeout(() => {
|
||||
getDeploymentLog(selected.id()).then(setLog);
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
onCleanup(unsub);
|
||||
createEffect(loadLog);
|
||||
onCleanup(
|
||||
ws.subscribe([ADD_UPDATE], ({ update }: { update: Update }) => {
|
||||
if (
|
||||
update.deploymentID === selected.id() &&
|
||||
(update.operation === DEPLOY ||
|
||||
update.operation === START_CONTAINER ||
|
||||
update.operation === STOP_CONTAINER ||
|
||||
update.operation === DELETE_CONTAINER)
|
||||
) {
|
||||
// console.log("updating log");
|
||||
setTimeout(() => {
|
||||
getDeploymentLog(selected.id()).then(setLog);
|
||||
}, 2000);
|
||||
}
|
||||
})
|
||||
);
|
||||
const { themeClass } = useTheme();
|
||||
return (
|
||||
<Show when={deployment()}>
|
||||
<ConfigProvider>
|
||||
<Tabs
|
||||
containerClass={combineClasses("card tabs shadow", themeClass())}
|
||||
containerStyle={{ gap: "0.5rem" }}
|
||||
tabs={[
|
||||
<Tabs
|
||||
containerClass={combineClasses("card tabs shadow", themeClass())}
|
||||
containerStyle={{ gap: "0.5rem" }}
|
||||
tabs={[
|
||||
{
|
||||
title: "config",
|
||||
element: <Config />,
|
||||
},
|
||||
status() !== "not deployed" && [
|
||||
{
|
||||
title: "config",
|
||||
element: <Config />,
|
||||
title: "log",
|
||||
element: (
|
||||
<Log
|
||||
reload={loadLog}
|
||||
log={log()}
|
||||
logTail={logTail()}
|
||||
setLogTail={setLogTail}
|
||||
/>
|
||||
),
|
||||
},
|
||||
status() !== "not deployed" && [
|
||||
{
|
||||
title: "log",
|
||||
element: (
|
||||
<Log
|
||||
reload={load}
|
||||
log={log()}
|
||||
logTail={logTail()}
|
||||
setLogTail={setLogTail}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "error log",
|
||||
titleElement: (
|
||||
<Flex gap="0.5rem" alignItems="center">
|
||||
error log{" "}
|
||||
<Show
|
||||
when={
|
||||
deployment()!.status !== "not deployed" && log().stderr
|
||||
}
|
||||
>
|
||||
<Icon type="error" />
|
||||
</Show>
|
||||
</Flex>
|
||||
),
|
||||
element: (
|
||||
<Log
|
||||
reload={load}
|
||||
log={log()}
|
||||
logTail={logTail()}
|
||||
setLogTail={setLogTail}
|
||||
error
|
||||
/>
|
||||
),
|
||||
},
|
||||
],
|
||||
].flat()}
|
||||
localStorageKey="deployment-tab"
|
||||
/>
|
||||
</ConfigProvider>
|
||||
status() !== "not deployed" && {
|
||||
title: "error log",
|
||||
titleElement: (
|
||||
<Flex gap="0.5rem" alignItems="center">
|
||||
error log{" "}
|
||||
<Show
|
||||
when={
|
||||
deployment()!.status !== "not deployed" && log().stderr
|
||||
}
|
||||
>
|
||||
<Icon type="error" />
|
||||
</Show>
|
||||
</Flex>
|
||||
),
|
||||
element: (
|
||||
<Log
|
||||
reload={loadLog}
|
||||
log={log()}
|
||||
logTail={logTail()}
|
||||
setLogTail={setLogTail}
|
||||
error
|
||||
/>
|
||||
),
|
||||
},
|
||||
],
|
||||
].flat()}
|
||||
localStorageKey="deployment-tab"
|
||||
/>
|
||||
</Show>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -27,6 +27,15 @@ const Header: Component<{}> = (p) => {
|
||||
const { isMobile } = useAppDimensions();
|
||||
const [showUpdates, toggleShowUpdates] =
|
||||
useLocalStorageToggle("show-updates");
|
||||
const userCanUpdate = () => {
|
||||
if (permissions() > 1) {
|
||||
return true;
|
||||
} else if (permissions() > 0 && server()!.owners.includes(username()!)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Flex
|
||||
@@ -35,10 +44,10 @@ const Header: Component<{}> = (p) => {
|
||||
alignItems="center"
|
||||
style={{
|
||||
position: "relative",
|
||||
cursor: isMobile() ? "pointer" : undefined,
|
||||
cursor: isMobile() && userCanUpdate() ? "pointer" : undefined,
|
||||
}}
|
||||
onClick={() => {
|
||||
if (isMobile()) toggleShowUpdates();
|
||||
if (isMobile() && userCanUpdate()) toggleShowUpdates();
|
||||
}}
|
||||
>
|
||||
<Grid gap="0.1rem">
|
||||
@@ -64,7 +73,7 @@ const Header: Component<{}> = (p) => {
|
||||
</Show>
|
||||
</Flex>
|
||||
</Show>
|
||||
<Show when={isMobile()}>
|
||||
<Show when={isMobile() && userCanUpdate()}>
|
||||
<Flex gap="0.5rem" alignItems="center" class="show-updates-indicator">
|
||||
updates{" "}
|
||||
<Icon
|
||||
@@ -74,7 +83,7 @@ const Header: Component<{}> = (p) => {
|
||||
</Flex>
|
||||
</Show>
|
||||
</Flex>
|
||||
<Show when={isMobile() && showUpdates()}>
|
||||
<Show when={isMobile() && userCanUpdate() && showUpdates()}>
|
||||
<Updates />
|
||||
</Show>
|
||||
</>
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Component, Show } from "solid-js";
|
||||
import { useAppDimensions } from "../../state/DimensionProvider";
|
||||
import { useAppState } from "../../state/StateProvider";
|
||||
import { useTheme } from "../../state/ThemeProvider";
|
||||
import { useUser } from "../../state/UserProvider";
|
||||
import { combineClasses } from "../../util/helpers";
|
||||
import NotFound from "../NotFound";
|
||||
import Grid from "../util/layout/Grid";
|
||||
@@ -16,6 +17,16 @@ const Server: Component<{}> = (p) => {
|
||||
const server = () => servers.get(selected.id())!;
|
||||
const { themeClass } = useTheme();
|
||||
const { isMobile } = useAppDimensions();
|
||||
const { permissions, username } = useUser();
|
||||
const userCanUpdate = () => {
|
||||
if (permissions() > 1) {
|
||||
return true;
|
||||
} else if (permissions() > 0 && server()!.owners.includes(username()!)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Show when={server()} fallback={<NotFound type="server" />}>
|
||||
<ActionStateProvider>
|
||||
@@ -24,7 +35,7 @@ const Server: Component<{}> = (p) => {
|
||||
<Grid class="left-content">
|
||||
<Header />
|
||||
<Actions />
|
||||
<Show when={!isMobile()}>
|
||||
<Show when={!isMobile() && userCanUpdate()}>
|
||||
<Updates />
|
||||
</Show>
|
||||
</Grid>
|
||||
|
||||
@@ -23,16 +23,13 @@ import { State } from "./StateProvider";
|
||||
import { createSignal } from "solid-js";
|
||||
import ReconnectingWebSocket from "reconnecting-websocket";
|
||||
|
||||
function socket(
|
||||
user: User,
|
||||
state: State,
|
||||
) {
|
||||
function socket(user: User, state: State) {
|
||||
const ws = new ReconnectingWebSocket(WS_URL);
|
||||
|
||||
const [isOpen, setOpen] = createSignal(false);
|
||||
|
||||
ws.addEventListener("open", () => {
|
||||
console.log("connection opened")
|
||||
console.log("connection opened");
|
||||
ws.send(JSON.stringify({ token: client.token }));
|
||||
setOpen(true);
|
||||
});
|
||||
@@ -154,6 +151,19 @@ function handleMessage(
|
||||
/* Updates */
|
||||
case ADD_UPDATE:
|
||||
const { update } = message as { update: Update };
|
||||
if (
|
||||
(update.deploymentID &&
|
||||
!deployments
|
||||
.get(update.deploymentID)
|
||||
?.owners.includes(user.username)) ||
|
||||
(update.buildID &&
|
||||
!builds.get(update.buildID)?.owners.includes(user.username)) ||
|
||||
(update.serverID &&
|
||||
!servers.get(update.serverID)?.owners.includes(user.username))
|
||||
) {
|
||||
// dont respond to updates outside of users scope. not airtight for protecting sensitive data.
|
||||
return;
|
||||
}
|
||||
updates.add(update);
|
||||
pushNotification(
|
||||
update.isError ? "bad" : "good",
|
||||
|
||||
Reference in New Issue
Block a user