Skip to content

Commit

Permalink
feat(console): notify of potential risks when exposing endpoints (#6852)
Browse files Browse the repository at this point in the history
Resolves #6579
  • Loading branch information
polamoros authored Jul 5, 2024
1 parent 08d367e commit 13610b7
Show file tree
Hide file tree
Showing 25 changed files with 583 additions and 333 deletions.
3 changes: 3 additions & 0 deletions apps/wing-console/console/app/scripts/dev.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ const options = parseArgs({
async requireSignIn() {
return options.requireSignIn ?? false;
},
async getEndpointWarningAccepted() {
return options.getEndpointWarningAccepted ?? true;
},
});

const vite = await createViteServer({
Expand Down
8 changes: 8 additions & 0 deletions apps/wing-console/console/app/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ export interface CreateConsoleAppOptions {
stateDir?: string;
open?: boolean;
watchGlobs?: string[];
getEndpointWarningAccepted?: boolean;
notifyEndpointWarningAccepted?: () => void;
}

const staticDir = `${__dirname}/vite`;
Expand Down Expand Up @@ -79,6 +81,12 @@ export const createConsoleApp = async (options: CreateConsoleAppOptions) => {
async notifySignedIn() {
analyticsStorage.notifySignedIn();
},
async getEndpointWarningAccepted() {
return analyticsStorage.getEndpointWarningAccepted();
},
async notifyEndpointWarningAccepted() {
analyticsStorage.notifyEndpointWarningAccepted();
},
onExpressCreated(app) {
app.use(express.static(staticDir));
options.onExpressCreated?.(app);
Expand Down
17 changes: 17 additions & 0 deletions apps/wing-console/console/app/src/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export interface AnalyticsConfig {
optOut?: boolean;
/** whether sign in is required */
requireSignIn?: boolean;
/** whether the user has accepted the exposing endpoints risk warning */
endpointWarningAccepted?: boolean;
}

/**
Expand Down Expand Up @@ -96,6 +98,21 @@ export class AnalyticsStorage {
this.saveConfig(config);
}

public getEndpointWarningAccepted(): boolean {
let config = this.loadConfig();
if (config.endpointWarningAccepted == undefined) {
config.endpointWarningAccepted = false;
this.saveConfig(config);
}
return config.endpointWarningAccepted;
}

public notifyEndpointWarningAccepted() {
let config = this.loadConfig();
config.endpointWarningAccepted = true;
this.saveConfig(config);
}

private generateAnonymousId(): string {
return randomBytes(16).toString("hex");
}
Expand Down
6 changes: 5 additions & 1 deletion apps/wing-console/console/design-system/src/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,11 @@ export const Button = forwardRef<
theme.bgInputHover,
theme.textInput,
],
transparent && [theme.bgInputHover, theme.textInput],
transparent && [
theme.bgInputHover,
theme.textInput,
theme.text1Hover,
],
!transparent && "border shadow-sm",
{
[theme.borderInput]: !primary,
Expand Down
22 changes: 20 additions & 2 deletions apps/wing-console/console/design-system/src/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,25 @@ import { Fragment } from "react";

import { useTheme } from "./theme-provider.js";

export const ModalFooter = ({ children }: { children: ReactNode }) => {
return (
<div
className={classNames(
"-mt-2",
"px-4 py-3",
"bg-slate-50 dark:bg-slate-750",
"flex items-center justify-end gap-4",
)}
>
{children}
</div>
);
};

export const ModalBody = ({ children }: { children: ReactNode }) => {
return <div className="p-6">{children}</div>;
};

export interface ModalProps {
visible: boolean;
setVisible?: (visible: boolean) => void;
Expand Down Expand Up @@ -55,8 +74,7 @@ export const Modal = ({
<Dialog.Panel
className={classNames(
"relative transform overflow-hidden rounded-lg text-left shadow-xl transition-all",
"my-8 p-6",
theme.bg3,
"bg-white dark:bg-slate-700",
"border",
theme.border3,
className,
Expand Down
28 changes: 19 additions & 9 deletions apps/wing-console/console/design-system/src/notification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ import { useTheme } from "./theme-provider.js";

interface Notification {
title: string;
body?: string;
body?: string | React.ReactNode;
id: string;
show: boolean;
type?: "success" | "error";
type?: "success" | "error" | "info";
autoCloseTimeoutId?: ReturnType<typeof setTimeout>;
}

Expand All @@ -32,9 +32,9 @@ interface NotificationsContext {
showNotification(
title: string,
options?: {
body?: string;
body?: string | React.ReactNode;
autoCloseDelayMs?: number;
type?: "success" | "error";
type?: "success" | "error" | "info";
},
): void;
closeNotification(notificationId: string): void;
Expand Down Expand Up @@ -100,12 +100,20 @@ function NotificationsContainer() {
<div className="p-3">
<div className="flex items-start">
<div className="flex-shrink-0">
{notification.type === "error" ? (
{notification.type === "error" && (
<ExclamationCircleIcon
className={"h-6 w-6 text-red-400"}
aria-hidden="true"
/>
) : (
)}
{notification.type === "info" && (
<ExclamationCircleIcon
className={"h-6 w-6 text-blue-400"}
aria-hidden="true"
/>
)}
{(notification.type === "success" ||
notification.type === undefined) && (
<CheckCircleIcon
className="h-6 w-6 text-green-400"
aria-hidden="true"
Expand All @@ -122,9 +130,11 @@ function NotificationsContainer() {
{notification.title}
</p>
{notification.body && (
<p className={classNames("mt-1 text-sm", theme.text2)}>
<div
className={classNames("mt-1 text-sm", theme.text2)}
>
{notification.body}
</p>
</div>
)}
</div>
<div className="ml-4 flex-shrink-0 flex">
Expand Down Expand Up @@ -190,7 +200,7 @@ export function NotificationsProvider(props: PropsWithChildren) {
const showNotification = (
title: string,
options?: {
body?: string;
body?: string | React.ReactNode;
autoCloseDelayMs?: number;
type?: "success" | "error";
},
Expand Down
6 changes: 6 additions & 0 deletions apps/wing-console/console/server/src/expressServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ export interface CreateExpressServerOptions {
analytics?: Analytics;
requireSignIn?: () => Promise<boolean>;
notifySignedIn?: () => Promise<void>;
getEndpointWarningAccepted?: () => Promise<boolean>;
notifyEndpointWarningAccepted?: () => Promise<void>;
}

export const createExpressServer = async ({
Expand Down Expand Up @@ -79,6 +81,8 @@ export const createExpressServer = async ({
analytics,
requireSignIn,
notifySignedIn,
getEndpointWarningAccepted,
notifyEndpointWarningAccepted,
}: CreateExpressServerOptions) => {
const app = expressApp ?? express();
app.use(cors());
Expand Down Expand Up @@ -119,6 +123,8 @@ export const createExpressServer = async ({
analytics,
requireSignIn,
notifySignedIn,
getEndpointWarningAccepted,
notifyEndpointWarningAccepted,
};
};
app.use(
Expand Down
6 changes: 6 additions & 0 deletions apps/wing-console/console/server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ export interface CreateConsoleServerOptions {
requireSignIn?: () => Promise<boolean>;
notifySignedIn?: () => Promise<void>;
watchGlobs?: string[];
getEndpointWarningAccepted?: () => Promise<boolean>;
notifyEndpointWarningAccepted?: () => Promise<void>;
}

export const createConsoleServer = async ({
Expand All @@ -100,6 +102,8 @@ export const createConsoleServer = async ({
requireSignIn,
notifySignedIn,
watchGlobs,
getEndpointWarningAccepted,
notifyEndpointWarningAccepted,
}: CreateConsoleServerOptions) => {
const emitter = new Emittery<{
invalidateQuery: RouteNames;
Expand Down Expand Up @@ -329,6 +333,8 @@ export const createConsoleServer = async ({
analytics,
requireSignIn,
notifySignedIn,
getEndpointWarningAccepted,
notifyEndpointWarningAccepted,
});

const close = async (callback?: () => void) => {
Expand Down
15 changes: 15 additions & 0 deletions apps/wing-console/console/server/src/router/endpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@ const getEndpointDetails = async (

export const createEndpointRouter = () => {
return createRouter({
"endpoint.warningAccepted": createProcedure.query(async ({ ctx }) => {
const warningAccepted = await ctx.getEndpointWarningAccepted?.();
return {
warningAccepted: warningAccepted ?? true,
};
}),
"endpoint.notifyWarningAccepted": createProcedure.mutation(
async ({ ctx }) => {
await ctx.notifyEndpointWarningAccepted?.();
},
),
"endpoint.list": createProcedure.query(async ({ input, ctx }) => {
if (ctx.appState() !== "success") {
return [];
Expand Down Expand Up @@ -83,6 +94,8 @@ export const createEndpointRouter = () => {
const simulator = await ctx.simulator();
const client = simulator.getResource(input.resourcePath) as Endpoint;
await client.expose();

// We need to reload the simulator because the endpoints are read during the simulator initialization.
await simulator.reload(false);
}),
"endpoint.hide": createProcedure
Expand All @@ -95,6 +108,8 @@ export const createEndpointRouter = () => {
const simulator = await ctx.simulator();
const client = simulator.getResource(input.resourcePath) as Endpoint;
await client.hide();

// We need to reload the simulator because the endpoints are read during the simulator initialization.
await simulator.reload(false);
}),
});
Expand Down
2 changes: 2 additions & 0 deletions apps/wing-console/console/server/src/utils/createRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ export interface RouterContext {
requireSignIn?: () => Promise<boolean>;
notifySignedIn?: () => Promise<void>;
analytics?: Analytics;
getEndpointWarningAccepted?: () => Promise<boolean>;
notifyEndpointWarningAccepted?: () => Promise<void>;
}

const t = initTRPC.context<RouterContext>().meta<RouterMeta>().create();
Expand Down

This file was deleted.

Loading

0 comments on commit 13610b7

Please sign in to comment.