import { ActionIcon, Box, Button, Checkbox, Code, Collapse, Group, Modal, NumberInput, Paper, Space, Table, Text, TextInput, Textarea, Title, Tooltip, FileButton } from "@mantine/core";
import { useForm } from "@mantine/form";
import { useDisclosure } from "@mantine/hooks";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useEffect, useState } from "react";
import { FaPlay, FaStop, FaTrash, FaPencilAlt } from "react-icons/fa";
import { MdAdd } from "react-icons/md";
import { getapi, postapi, putapi, deleteapi, errorNotify, okNotify } from "../../js/utils";
import PortAndInterface from "../../components/PortAndInterface";
import { TbShieldLock } from "react-icons/tb";
export const tlsStreamsQueryKey = ["tls_streams"];
interface TLSStream {
id: string;
name: string;
ip_int: string;
port: number;
cert: string;
key: string;
status: string;
ssl_port: number;
clear_port: number;
}
const StreamFormModal = ({ opened, close, editStream }: { opened: boolean, close: () => void, editStream?: TLSStream | null }) => {
const queryClient = useQueryClient();
const [loading, setLoading] = useState(false);
const isEdit = !!editStream;
const form = useForm({
initialValues: {
name: "",
ip_int: "",
port: 443,
cert: "",
key: ""
},
validate: {
name: (val) => val.length > 0 ? null : "Name is required",
ip_int: (val) => val.length > 0 ? null : "Target IP is required",
port: (val) => val > 0 && val <= 65535 ? null : "Invalid port",
cert: (val) => val.length > 0 ? null : "Certificate is required",
key: (val) => val.length > 0 ? null : "Private Key is required"
}
});
useEffect(() => {
if (opened) {
if (editStream) {
form.setValues({
name: editStream.name,
ip_int: editStream.ip_int,
port: editStream.port,
cert: editStream.cert,
key: editStream.key
});
} else {
form.reset();
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [opened, editStream?.id]);
const mutation = useMutation({
mutationFn: (values: typeof form.values) => {
return isEdit ? putapi(`tls/streams/${editStream!.id}`, values) : postapi("tls/streams", values);
},
onSuccess: () => {
okNotify(isEdit ? "Stream updated" : "Stream created", `The TLS stream was successfully ${isEdit ? "updated" : "created"}`);
queryClient.invalidateQueries({ queryKey: tlsStreamsQueryKey });
form.reset();
close();
},
onError: (err: any) => {
errorNotify(`Error ${isEdit ? "updating" : "creating"} stream`, err.toString());
},
onSettled: () => setLoading(false)
});
const handleFileUpload = (file: File | null, fieldName: string) => {
if (!file) return;
const reader = new FileReader();
reader.onload = (e) => {
const text = e.target?.result as string;
form.setFieldValue(fieldName, text);
};
reader.readAsText(file);
};
return (
{isEdit ? "Edit TLS Decrypt Stream" : "Add New TLS Decrypt Stream"}} centered styles={{ body: { maxHeight: 'calc(100vh - 150px)', overflowY: 'auto' } }}>
);
};
const TLSDecrypt = () => {
const queryClient = useQueryClient();
const [opened, { open, close }] = useDisclosure(false);
const [editStream, setEditStream] = useState(null);
const { data: streams, isLoading } = useQuery({
queryKey: tlsStreamsQueryKey,
queryFn: () => getapi("tls/streams")
});
const actionMutation = useMutation({
mutationFn: ({ action, id }: { action: string, id: string }) => {
if (action === "delete") return deleteapi(`tls/streams/${id}`);
return postapi(`tls/streams/${id}/${action}`);
},
onSuccess: (_, { action }) => {
okNotify("Success", `Stream ${action} successful`);
queryClient.invalidateQueries({ queryKey: tlsStreamsQueryKey });
},
onError: (err: any) => {
errorNotify("Error", err.toString());
}
});
const openAdd = () => { setEditStream(null); open(); };
const openEdit = (stream: TLSStream) => { setEditStream(stream); open(); };
return (
TLS Decryption Streams
} onClick={openAdd}>Add Stream
Manage central TLS decryption streams. These streams transparently decrypt inbound TLS traffic,
forward it to inspection services like NFProxy/NFRegex in cleartext, and re-encrypt the traffic
before sending it to the backend.
Name
Target
Status
Internal SSL Port
Internal Clear Port
Actions
{streams?.map(stream => (
{stream.name}
{stream.ip_int}:{stream.port}
{stream.status.toUpperCase()}
{stream.ssl_port}
{stream.clear_port}
{stream.status === "stop" ? (
actionMutation.mutate({ action: "start", id: stream.id })}>
) : (
actionMutation.mutate({ action: "stop", id: stream.id })}>
)}
openEdit(stream)}>
actionMutation.mutate({ action: "delete", id: stream.id })}>
))}
{streams?.length === 0 && (
No streams found
)}
{ close(); setEditStream(null); }} editStream={editStream} />
);
};
export default TLSDecrypt;