diff --git a/README.md b/README.md
index 2116a55a..7d5743b8 100644
--- a/README.md
+++ b/README.md
@@ -88,14 +88,6 @@ Sometimes this can take a little bit because of the entropy of keys.
[http://127.0.0.1:81](http://127.0.0.1:81)
-Default Admin User:
-```
-Email: admin@example.com
-Password: changeme
-```
-
-Immediately after logging in with this default user you will be asked to modify your details and change your password.
-
## Contributing
diff --git a/backend/internal/dead-host.js b/backend/internal/dead-host.js
index 0cbb0105..21b12012 100644
--- a/backend/internal/dead-host.js
+++ b/backend/internal/dead-host.js
@@ -63,7 +63,7 @@ const internalDeadHost = {
action: "created",
object_type: "dead-host",
object_id: row.id,
- meta: _.assign({}, data.meta || {}, row.meta),
+ meta: thisData,
});
if (createCertificate) {
@@ -240,6 +240,7 @@ const internalDeadHost = {
// Delete Nginx Config
await internalNginx.deleteConfig("dead_host", row);
await internalNginx.reload();
+
// Add to audit log
await internalAuditLog.add(access, {
action: "deleted",
@@ -247,6 +248,7 @@ const internalDeadHost = {
object_id: row.id,
meta: _.omit(row, omissions()),
});
+ return true;
},
/**
diff --git a/backend/internal/nginx.js b/backend/internal/nginx.js
index c4216fb5..4870874d 100644
--- a/backend/internal/nginx.js
+++ b/backend/internal/nginx.js
@@ -301,8 +301,11 @@ const internalNginx = {
* @param {String} filename
*/
deleteFile: (filename) => {
- logger.debug(`Deleting file: ${filename}`);
+ if (!fs.existsSync(filename)) {
+ return;
+ }
try {
+ logger.debug(`Deleting file: ${filename}`);
fs.unlinkSync(filename);
} catch (err) {
logger.debug("Could not delete file:", JSON.stringify(err, null, 2));
diff --git a/backend/routes/nginx/dead_hosts.js b/backend/routes/nginx/dead_hosts.js
index 7fc64a07..5323c731 100644
--- a/backend/routes/nginx/dead_hosts.js
+++ b/backend/routes/nginx/dead_hosts.js
@@ -121,7 +121,7 @@ router
/**
* PUT /api/nginx/dead-hosts/123
*
- * Update and existing dead-host
+ * Update an existing dead-host
*/
.put(async (req, res, next) => {
try {
@@ -138,7 +138,7 @@ router
/**
* DELETE /api/nginx/dead-hosts/123
*
- * Update and existing dead-host
+ * Delete a dead-host
*/
.delete(async (req, res, next) => {
try {
diff --git a/frontend/src/components/Table/Formatter/DomainsFormatter.tsx b/frontend/src/components/Table/Formatter/DomainsFormatter.tsx
index 6f5a037f..ca7735f1 100644
--- a/frontend/src/components/Table/Formatter/DomainsFormatter.tsx
+++ b/frontend/src/components/Table/Formatter/DomainsFormatter.tsx
@@ -4,14 +4,32 @@ interface Props {
domains: string[];
createdOn?: string;
}
+
+const DomainLink = ({ domain }: { domain: string }) => {
+ // when domain contains a wildcard, make the link go nowhere.
+ let onClick: ((e: React.MouseEvent) => void) | undefined;
+ if (domain.includes("*")) {
+ onClick = (e: React.MouseEvent) => e.preventDefault();
+ }
+ return (
+
+ {domain}
+
+ );
+};
+
export function DomainsFormatter({ domains, createdOn }: Props) {
return (
{createdOn ? (
diff --git a/frontend/src/components/Table/Formatter/EventFormatter.tsx b/frontend/src/components/Table/Formatter/EventFormatter.tsx
index 77892b3d..b248dbfb 100644
--- a/frontend/src/components/Table/Formatter/EventFormatter.tsx
+++ b/frontend/src/components/Table/Formatter/EventFormatter.tsx
@@ -10,6 +10,8 @@ const getEventValue = (event: AuditLog) => {
switch (event.objectType) {
case "user":
return event.meta?.name;
+ case "dead-host":
+ return event.meta?.domainNames?.join(", ") || "N/A";
default:
return `UNKNOWN EVENT TYPE: ${event.objectType}`;
}
diff --git a/frontend/src/locale/lang/en.json b/frontend/src/locale/lang/en.json
index 0844b59b..6e785f08 100644
--- a/frontend/src/locale/lang/en.json
+++ b/frontend/src/locale/lang/en.json
@@ -41,6 +41,8 @@
"column.status": "Status",
"created-on": "Created: {date}",
"dashboard.title": "Dashboard",
+ "dead-host.delete.content": "Are you sure you want to delete this 404 host?",
+ "dead-host.delete.title": "Delete 404 Host",
"dead-host.edit": "Edit 404 Host",
"dead-host.new": "New 404 Host",
"dead-hosts.actions-title": "404 Host #{id}",
@@ -67,8 +69,11 @@
"error.max-domains": "Too many domains, max is {max}",
"error.passwords-must-match": "Passwords must match",
"error.required": "This is required",
+ "event.created-dead-host": "Created 404 Host",
"event.created-user": "Created User",
"event.deleted-user": "Deleted User",
+ "event.disabled-dead-host": "Disabled 404 Host",
+ "event.enabled-dead-host": "Enabled 404 Host",
"event.updated-user": "Updated User",
"footer.github-fork": "Fork me on Github",
"hosts.title": "Hosts",
@@ -84,6 +89,9 @@
"notfound.title": "Oops… You just found an error page",
"notification.dead-host-saved": "404 Host has been saved",
"notification.error": "Error",
+ "notification.host-deleted": "Host has been deleted",
+ "notification.host-disabled": "Host has been disabled",
+ "notification.host-enabled": "Host has been enabled",
"notification.success": "Success",
"notification.user-deleted": "User has been deleted",
"notification.user-saved": "User has been saved",
diff --git a/frontend/src/locale/src/en.json b/frontend/src/locale/src/en.json
index a8f21e64..be7f2a17 100644
--- a/frontend/src/locale/src/en.json
+++ b/frontend/src/locale/src/en.json
@@ -134,12 +134,18 @@
"dead-hosts.count": {
"defaultMessage": "{count} 404 Hosts"
},
- "dead-host.edit": {
- "defaultMessage": "Edit 404 Host"
- },
"dead-hosts.empty": {
"defaultMessage": "There are no 404 Hosts"
},
+ "dead-host.delete.content": {
+ "defaultMessage": "Are you sure you want to delete this 404 host?"
+ },
+ "dead-host.delete.title": {
+ "defaultMessage": "Delete 404 Host"
+ },
+ "dead-host.edit": {
+ "defaultMessage": "Edit 404 Host"
+ },
"dead-host.new": {
"defaultMessage": "New 404 Host"
},
@@ -200,12 +206,21 @@
"error.required": {
"defaultMessage": "This is required"
},
+ "event.created-dead-host": {
+ "defaultMessage": "Created 404 Host"
+ },
"event.created-user": {
"defaultMessage": "Created User"
},
"event.deleted-user": {
"defaultMessage": "Deleted User"
},
+ "event.disabled-dead-host": {
+ "defaultMessage": "Disabled 404 Host"
+ },
+ "event.enabled-dead-host": {
+ "defaultMessage": "Enabled 404 Host"
+ },
"event.updated-user": {
"defaultMessage": "Updated User"
},
@@ -254,9 +269,18 @@
"notification.error": {
"defaultMessage": "Error"
},
+ "notification.host-deleted": {
+ "defaultMessage": "Host has been deleted"
+ },
"notification.user-deleted": {
"defaultMessage": "User has been deleted"
},
+ "notification.host-disabled": {
+ "defaultMessage": "Host has been disabled"
+ },
+ "notification.host-enabled": {
+ "defaultMessage": "Host has been enabled"
+ },
"notification.user-saved": {
"defaultMessage": "User has been saved"
},
diff --git a/frontend/src/pages/Nginx/DeadHosts/Table.tsx b/frontend/src/pages/Nginx/DeadHosts/Table.tsx
index 2ee15b34..23007a29 100644
--- a/frontend/src/pages/Nginx/DeadHosts/Table.tsx
+++ b/frontend/src/pages/Nginx/DeadHosts/Table.tsx
@@ -12,9 +12,10 @@ interface Props {
isFetching?: boolean;
onEdit?: (id: number) => void;
onDelete?: (id: number) => void;
+ onDisableToggle?: (id: number, enabled: boolean) => void;
onNew?: () => void;
}
-export default function Table({ data, isFetching, onEdit, onDelete, onNew }: Props) {
+export default function Table({ data, isFetching, onEdit, onDelete, onDisableToggle, onNew }: Props) {
const columnHelper = createColumnHelper
();
const columns = useMemo(
() => [
@@ -83,9 +84,18 @@ export default function Table({ data, isFetching, onEdit, onDelete, onNew }: Pro
{intl.formatMessage({ id: "action.edit" })}
-
+ {
+ e.preventDefault();
+ onDisableToggle?.(info.row.original.id, !info.row.original.enabled);
+ }}
+ >
- {intl.formatMessage({ id: "action.disable" })}
+ {intl.formatMessage({
+ id: info.row.original.enabled ? "action.disable" : "action.enable",
+ })}
({
diff --git a/frontend/src/pages/Nginx/DeadHosts/TableWrapper.tsx b/frontend/src/pages/Nginx/DeadHosts/TableWrapper.tsx
index 665483e3..f627b650 100644
--- a/frontend/src/pages/Nginx/DeadHosts/TableWrapper.tsx
+++ b/frontend/src/pages/Nginx/DeadHosts/TableWrapper.tsx
@@ -1,6 +1,8 @@
import { IconSearch } from "@tabler/icons-react";
+import { useQueryClient } from "@tanstack/react-query";
import { useState } from "react";
import Alert from "react-bootstrap/Alert";
+import { deleteDeadHost, toggleDeadHost } from "src/api/backend";
import { Button, LoadingPage } from "src/components";
import { useDeadHosts } from "src/hooks";
import { intl } from "src/locale";
@@ -9,6 +11,7 @@ import { showSuccess } from "src/notifications";
import Table from "./Table";
export default function TableWrapper() {
+ const queryClient = useQueryClient();
const [deleteId, setDeleteId] = useState(0);
const [editId, setEditId] = useState(0 as number | "new");
const { isFetching, isLoading, isError, error, data } = useDeadHosts(["owner", "certificate"]);
@@ -22,10 +25,17 @@ export default function TableWrapper() {
}
const handleDelete = async () => {
- // await deleteUser(deleteId);
+ await deleteDeadHost(deleteId);
showSuccess(intl.formatMessage({ id: "notification.host-deleted" }));
};
+ const handleDisableToggle = async (id: number, enabled: boolean) => {
+ await toggleDeadHost(id, enabled);
+ queryClient.invalidateQueries({ queryKey: ["dead-hosts"] });
+ queryClient.invalidateQueries({ queryKey: ["dead-host", id] });
+ showSuccess(intl.formatMessage({ id: enabled ? "notification.host-enabled" : "notification.host-disabled" }));
+ };
+
return (
@@ -60,17 +70,18 @@ export default function TableWrapper() {
isFetching={isFetching}
onEdit={(id: number) => setEditId(id)}
onDelete={(id: number) => setDeleteId(id)}
+ onDisableToggle={handleDisableToggle}
onNew={() => setEditId("new")}
/>
{editId ?
setEditId(0)} /> : null}
{deleteId ? (
setDeleteId(0)}
invalidations={[["dead-hosts"], ["dead-host", deleteId]]}
>
- {intl.formatMessage({ id: "user.delete.content" })}
+ {intl.formatMessage({ id: "dead-host.delete.content" })}
) : null}