Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 183 additions & 12 deletions packages/web2/app/components/profile/errorScan.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,195 @@
import { FC } from "react";
import { FC, ReactNode } from "react";
import { Scan, ScanProfile } from "../../api/types.js";
import { DnsErrorView } from "./errorScans/dnsErrorView.js";
import { CertificateErrorView } from "./errorScans/certificateErrorView.js";
import { DefaultErrorView } from "./errorScans/defaultErrorView.js";
import { ErrorViewWithEditDomain } from "./errorScans/ErrorViewWithEditDomain.js";
import { ErrorViewWithoutEditDomain } from "./errorScans/ErrorViewWithoutEditDomain.js";

export const ErrorScan: FC<{
profile: ScanProfile;
lastScan: Scan;
}> = ({ lastScan, profile }) => {
if (lastScan.error?.startsWith("net::ERR_NAME_NOT_RESOLVED")) {
return <DnsErrorView profile={profile} scanId={lastScan._id} />;
interface ErrorTexts {
headline: string;
description: ReactNode;
showEditDomain: boolean;
}

const getErrorTexts = (
error: string,
): ErrorTexts | undefined => {
if (error.includes("ERR_NAME_NOT_RESOLVED")) {
return {
headline: "Domain nicht erreichbar",
description: (
<>
Der Scan wurde abgebrochen, da die Website nicht gefunden werden konnte.
Bitte überprüfe die eingegebene Adresse und versuche es erneut.
</>
),
showEditDomain: true,
};
}

if (error.includes("ERR_CERT_COMMON_NAME_INVALID")) {
return {
headline: "SSL-Zertifikat passt nicht zur URL",
description: (
<>
Der Scan wurde abgebrochen, da das SSL-Zertifikat nicht zur aufgerufenen Adresse passt.
Bitte überprüfe die Adresse sowie das Zertifikat der Website und versuche es erneut.
</>
),
showEditDomain: true,
};
}

if (error.includes("ERR_CONNECTION_REFUSED")) {
return {
headline: "Domain nicht erreichbar",
description: (
<>
Der Scan wurde abgebrochen, da die Verbindung zur Website vom Server abgelehnt wurde.
Bitte überprüfe die Adresse und starte den Scan erneut.
</>
),
showEditDomain: true,
};
}

if (error.includes("ERR_TOO_MANY_REDIRECTS")) {
return {
headline: "Domain nicht erreichbar",
description: (
<>
Der Scan wurde abgebrochen, da die Website zu viele Weiterleitungen enthält.
Bitte überprüfe die Adresse und starte den Scan erneut.
</>
),
showEditDomain: true,
};
}

if (error.includes("ERR_TIMED_OUT")) {
return {
headline: "Domain nicht erreichbar",
description: (
<>
Der Scan wurde abgebrochen, da beim Verbindungsaufbau keine Antwort von der Website eingegangen ist.
Bitte überprüfe die Adresse und starte den Scan erneut.
</>
),
showEditDomain: true,
};
}

if (error.includes("ERR_INVALID_AUTH_CREDENTIALS")) {
return {
headline: "Domain nicht erreichbar",
description: (
<>
Der Scan wurde abgebrochen, da die Website durch einen Passwortschutz oder eine Zugangsbeschränkung gesichert ist.
Bitte nutze eine öffentlich erreichbare Adresse oder entferne die Zugriffsbeschränkung und starte den Scan erneut.
</>
),
showEditDomain: false,
};
}

if (error.includes("ERR_CERT_AUTHORITY_INVALID")) {
return {
headline: "SSL-Zertifikat abgelaufen",
description: (
<>
Der Scan wurde abgebrochen, da die Zertifizierungsstelle (CA) des SSL-Zertifikates nicht vertrauenswürdig oder das Zertifikat abgelaufen ist.
Bitte überprüfe das Zertifikat und starte den Scan erneut.
</>
),
showEditDomain: false,
};
}

if (error.includes("ERR_BLOCKED_BY_CLIENT")) {
return {
headline: "Domain nicht erreichbar",
description: (
<>
Der Scan wurde abgebrochen, da eine Ressource der Website blockiert wurde – zum Beispiel durch einen Werbe-, Tracking- oder Script-Blocker im Browser.
Bitte überprüfe die Ursache und versuche es anschließend erneut.
</>
),
showEditDomain: false,
};
}

if (error.includes("ERR_SSL_PROTOCOL_ERROR")) {
return {
headline: "Sichere Verbindung fehlgeschlagen",
description: (
<>
Der Scan wurde abgebrochen, da keine sichere Verbindung zur Website hergestellt werden konnte.
Bitte überprüfe das SSL-Zertifikat sowie die Servereinstellungen und starte den Scan erneut.
</>
),
showEditDomain: false,
};
}

if (error.includes("ERR_CERT_DATE_INVALID")) {
return {
headline: "SSL-Zertifikat ungültig",
description: (
<>
Der Scan wurde abgebrochen, da das SSL-Zertifikat der Website abgelaufen oder ungültig ist.
Bitte überprüfe das Zertifikat und versuche es erneut.
</>
),
showEditDomain: false,
};
}

if (error.includes("ERR_SSL_UNRECOGNIZED_NAME_ALERT")) {
return {
headline: "SSL-Zertifikat ungültig",
description: (
<>
Der Scan wurde abgebrochen, da das SSL-Zertifikat der Website nicht erkannt oder validiert werden konnte.
Bitte überprüfe das Zertifikat und starte den Scan erneut.
</>
),
showEditDomain: false,
};
}

return undefined;
};

export const ErrorScan: FC<{ profile: ScanProfile; lastScan: Scan }> = ({
lastScan,
profile,
}) => {
const errorInfos = lastScan.error ? getErrorTexts(lastScan.error) : undefined;

if (errorInfos?.showEditDomain) {
return (
<ErrorViewWithEditDomain
profile={profile}
scanId={lastScan._id}
headline={errorInfos.headline}
description={errorInfos.description}
/>
);
}
if (lastScan.error?.startsWith("net::ERR_CERT_")) {
return <CertificateErrorView profile={profile} scanId={lastScan._id} />;
if (errorInfos) {
return (
<ErrorViewWithoutEditDomain
profile={profile}
scanId={lastScan._id}
headline={errorInfos.headline}
description={errorInfos.description}
/>
);
}

return (
<DefaultErrorView
profile={profile}
message={lastScan.error!}
message={lastScan.error ?? ""}
scanId={lastScan._id}
/>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FC } from "react";
import { Props } from "./types.js";
import { DetailedErrorProps } from "./types.js";
import {
Action,
ActionGroup,
Expand All @@ -13,24 +13,31 @@ import {
import { RestartScanButton } from "./restartScanButton.js";
import { ChangeDomainModal } from "../modals/changeDomainModal.js";

export const DnsErrorView: FC<Props> = ({ profile, scanId }) => {
export const ErrorViewWithEditDomain: FC<DetailedErrorProps> = ({
profile,
scanId,
headline,
description,
}) => {
const controller = useOverlayController("Modal");
const editLabel = "Domain bearbeiten";
const content = description;

return (
<IllustratedMessage color="danger">
<IconDanger />
<Heading>Domain nicht erreichbar</Heading>
<Text>
Die Domain <strong>{profile.domain}</strong> ist nicht erreichbar.{" "}
<br /> Bitte überprüfe die Schreibweise oder versuche es erneut.
</Text>
<Heading>{headline}</Heading>
<Text>{content}</Text>
<ActionGroup>
<RestartScanButton profile={profile} scanId={scanId} />
<Action onAction={() => controller.open()}>
<Button color="primary">Domain bearbeiten</Button>
<Button color="primary">{editLabel}</Button>
</Action>
</ActionGroup>
<ChangeDomainModal profile={profile} controller={controller} />
<ChangeDomainModal
profile={profile}
controller={controller}
/>
</IllustratedMessage>
);
};
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FC } from "react";
import { Props } from "./types.js";
import { DetailedErrorProps } from "./types.js";
import {
Heading,
IconDanger,
Expand All @@ -8,16 +8,17 @@ import {
} from "@mittwald/flow-remote-react-components";
import { RestartScanButton } from "./restartScanButton.js";

export const CertificateErrorView: FC<Props> = ({ profile, scanId }) => {
export const ErrorViewWithoutEditDomain: FC<DetailedErrorProps> = ({
profile,
headline,
description,
scanId,
}) => {
return (
<IllustratedMessage color="danger">
<IconDanger />
<Heading>SSL-Zertifikat ungültig</Heading>
<Text>
Das SSL-Zertifikat der Domain <strong>{profile.domain}</strong> ist
ungültig. <br /> Binde ein gültiges Zertifikat ein und starte den Scan
erneut.
</Text>
<Heading>{headline}</Heading>
<Text>{description}</Text>
<RestartScanButton profile={profile} scanId={scanId} />
</IllustratedMessage>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FC } from "react";
import { Props } from "./types.js";
import { BaseProps } from "./types.js";
import {
Heading,
IconDanger,
Expand All @@ -8,10 +8,10 @@ import {
} from "@mittwald/flow-remote-react-components";
import { RestartScanButton } from "./restartScanButton.js";

export const DefaultErrorView: FC<Props & { message: string }> = ({
export const DefaultErrorView: FC<BaseProps & { message: string }> = ({
profile,
message,
scanId,
message,
}) => {
return (
<IllustratedMessage color="danger">
Expand All @@ -25,4 +25,4 @@ export const DefaultErrorView: FC<Props & { message: string }> = ({
<RestartScanButton profile={profile} scanId={scanId} />
</IllustratedMessage>
);
};
};
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { FC } from "react";
import { Props } from "./types.js";
import { BaseProps } from "./types.js";
import { useRouter } from "@tanstack/react-router";
import { Action, Button } from "@mittwald/flow-remote-react-components";
import { startScan } from "../../../actions/scan.js";

export const RestartScanButton: FC<Props> = ({ profile, scanId }) => {
export const RestartScanButton: FC<BaseProps> = ({ profile, scanId }) => {
const router = useRouter();
return (
<Action
Expand Down
8 changes: 7 additions & 1 deletion packages/web2/app/components/profile/errorScans/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { ReactNode } from "react";
import { ScanProfile } from "../../../api/types.js";

export interface Props {
export interface BaseProps {
profile: ScanProfile;
scanId: string;
}

export interface DetailedErrorProps extends BaseProps {
headline: string;
description: ReactNode;
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ interface FormValues {
domain: string;
}

export const ChangeDomainModal = ({
controller,
profile,
}: {
interface ChangeDomainModalProps {
controller: OverlayController;
profile: ScanProfile;
}) => {
}

export const ChangeDomainModal = ({
controller,
profile
}: ChangeDomainModalProps) => {
const router = useRouter();

const form = useForm<FormValues>({
Expand Down Expand Up @@ -73,4 +75,4 @@ export const ChangeDomainModal = ({
</Form>
</Modal>
);
};
};