Skip to content

Commit

Permalink
Fix GUI bug for basic auth, add option to follow robot.txt rules and …
Browse files Browse the repository at this point in the history
…minor changes to error page (#82)

* Set loading state for scan form components after users enter credentials for basic auth 
* Add checkbox for users to follow robots.txt rules 
* Display more specific error message when there is no pages scanned
* Fix button placement on error page 
* Bump package version and package-lock version

---------

Co-authored-by: younglim <[email protected]>
Co-authored-by: jodichoo <[email protected]>
  • Loading branch information
3 people authored Dec 22, 2023
1 parent 88e048c commit dbb6009
Show file tree
Hide file tree
Showing 11 changed files with 116 additions and 77 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "purplea11ydesktop",
"productName": "Purple A11y",
"version": "0.9.40",
"version": "0.9.41",
"private": true,
"dependencies": {
"axios": "^1.6.0",
Expand Down
5 changes: 5 additions & 0 deletions public/electron/scanManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const getScanOptions = (details) => {
falsePositive,
includeScreenshots,
includeSubdomains,
followRobots,
metadata,
} = details;
const options = ["-c", scanType, "-u", url, "-k", `${name}:${email}`, "-i", fileTypes];
Expand Down Expand Up @@ -108,6 +109,10 @@ const getScanOptions = (details) => {
options.push("-f", "true");
}

if (followRobots) {
options.push("-r", "yes");
}

if (metadata) {
options.push("-q", metadata);
}
Expand Down
4 changes: 2 additions & 2 deletions src/MainWindow/CustomFlow/index.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect, useState } from "react";
import { useLocation, useNavigate } from "react-router";
import { cliErrorCodes, cliErrorTypes } from "../../common/constants";
import { cliErrorCodes, cliErrorTypes, errorStates } from "../../common/constants";
import services from "../../services";
import './CustomFlow.scss';
import arrowLeft from "../../assets/arrow-left-purple.svg";
Expand Down Expand Up @@ -195,7 +195,7 @@ const CustomFlowPage = ({ completedScanId, setCompletedScanId }) => {
return;
}

navigate("/error", {state: { isCustomScan: true }});
navigate("/error", {state: { errorState: errorStates.customScanError }});
return;
}

Expand Down
3 changes: 2 additions & 1 deletion src/MainWindow/ErrorPage/ErrorPage.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@
background-color: transparent;
}

.actions {
.btn-container {
display: flex;
align-items: center;
justify-content: center;
}
}
72 changes: 39 additions & 33 deletions src/MainWindow/ErrorPage/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,15 @@ import returnIcon from "../../assets/return-purple.svg";
import { useNavigate, useLocation } from "react-router";
import { ReactComponent as ExclamationCircleIcon } from "../../assets/exclamation-circle.svg";
import { useState, useEffect } from "react";
import { errorStates } from "../../common/constants";

const ErrorPage = () => {
const { state } = useLocation();
const navigate = useNavigate();
const [isCustomScan, setIsCustomScan] = useState(false);
const [isBrowserError, setIsBrowserError] = useState(false);
const [ errorState, setErrorState ] = useState('');

useEffect(() => {
if (state?.isCustomScan) {
setIsCustomScan(state.isCustomScan);
}

if (state?.isBrowserError) {
setIsBrowserError(state.isBrowserError);
}
if (state?.errorState) setErrorState(state.errorState);
}, []);

const replayCustomFlow = async () => {
Expand All @@ -28,7 +22,7 @@ const ErrorPage = () => {
};

const handleBackToHome = () => {
if (isCustomScan) {
if (errorState === errorStates.customScanError) {
window.services.cleanUpCustomFlowScripts();
window.localStorage.removeItem("latestCustomFlowGeneratedScript");
window.localStorage.removeItem("latestCustomFlowScanDetails");
Expand All @@ -37,35 +31,47 @@ const ErrorPage = () => {
return;
}

const errorMessageToDisplay = () => {
switch (errorState) {
case errorStates.browserError:
return (
<>
<h1>Unable to use browser to scan</h1>
<p>Please close either Google Chrome or Microsoft Edge browser.</p>
</>
)
case errorStates.noPagesScannedError:
return (<><h1>No pages were scanned.</h1></>)
default:
return (<><h1>Something went wrong! Please try again.</h1></>)
}

}

return (
<div id="error-page">
<ButtonSvgIcon
className={`exclamation-circle-icon`}
svgIcon={<ExclamationCircleIcon />}
/>
{isBrowserError
? <>
<h1>Unable to use browser to scan</h1>
<p>Please close either Google Chrome or Microsoft Edge browser.</p>
</>
: <h1>Something went wrong! Please try again.</h1>
}
<div class="actions">
{isCustomScan
? (
<>
<button role="link" id='back-to-home-btn' onClick={handleBackToHome}>
<img src={returnIcon}></img>
&nbsp;Back To Home
</button>
<Button id="replay-btn" type="btn-primary" onClick={replayCustomFlow}>
Replay
</Button>
</>
)
: <Button role="link" type="btn-primary" onClick={handleBackToHome}>
Try Again
</Button>}
{errorMessageToDisplay()}
<div class='btn-container'>
{errorState === errorStates.customScanError
? (
<>
<button role="link" id='back-to-home-btn' onClick={handleBackToHome}>
<img src={returnIcon}></img>
&nbsp;Back To Home
</button>
<Button id="replay-btn" type="btn-primary" onClick={replayCustomFlow}>
Replay
</Button>
</>
)
: <Button role="link" type="btn-primary" onClick={handleBackToHome}>
Try Again
</Button>
}
</div>
</div>
);
Expand Down
82 changes: 49 additions & 33 deletions src/MainWindow/HomePage/AdvancedScanOptions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -226,42 +226,58 @@ const AdvancedScanOptions = ({
</label>
</div>
{advancedOptions.scanType !== scanTypeOptions[3] && (
<div id="max-concurrency-toggle-group" class="advanced-options-toggle-group">
<input
type="checkbox"
id="max-concurrency-toggle"
class="advanced-options-toggle"
aria-describedby="max-concurrency-tooltip"
checked={advancedOptions.maxConcurrency}
onFocus={() => handleMaxConcurrencyOnFocus()}
onBlur={() => setShowMaxConcurrencyTooltip(false)}
onMouseEnter={() => handleMaxConcurrencyOnMouseEnter()}
onMouseLeave={() => setIsMaxConcurrencyMouseEvent(false)}
onChange={handleSetAdvancedOption(
"maxConcurrency",
(e) => e.target.checked
)}
/>

<label htmlFor="max-concurrency-toggle">Slow Scan Mode</label>
<div className="custom-tooltip-container">
<ToolTip
description={
"Scan 1 page at a time instead of multiple pages concurrently."
}
id="max-concurrency-tooltip"
showToolTip={showMaxConcurrencyTooltip}
/>
<img
className="tooltip-img"
src={questionMarkIcon}
<>
<div id="max-concurrency-toggle-group" class="advanced-options-toggle-group">
<input
type="checkbox"
id="max-concurrency-toggle"
class="advanced-options-toggle"
aria-describedby="max-concurrency-tooltip"
onMouseEnter={() => setShowMaxConcurrencyTooltip(true)}
onMouseLeave={() => setShowMaxConcurrencyTooltip(false)}
alt="tooltip icon for slow scan mode"
checked={advancedOptions.maxConcurrency}
onFocus={() => handleMaxConcurrencyOnFocus()}
onBlur={() => setShowMaxConcurrencyTooltip(false)}
onMouseEnter={() => handleMaxConcurrencyOnMouseEnter()}
onMouseLeave={() => setIsMaxConcurrencyMouseEvent(false)}
onChange={handleSetAdvancedOption(
"maxConcurrency",
(e) => e.target.checked
)}
/>
<label htmlFor="max-concurrency-toggle">Slow Scan Mode</label>
<div className="custom-tooltip-container">
<ToolTip
description={
"Scan 1 page at a time instead of multiple pages concurrently."
}
id="max-concurrency-tooltip"
showToolTip={showMaxConcurrencyTooltip}
/>
<img
className="tooltip-img"
src={questionMarkIcon}
aria-describedby="max-concurrency-tooltip"
onMouseEnter={() => setShowMaxConcurrencyTooltip(true)}
onMouseLeave={() => setShowMaxConcurrencyTooltip(false)}
alt="tooltip icon for slow scan mode"
/>
</div>
</div>
</div>
<div id='follow-robots-toggle-group' class="advanced-options-toggle-group">
<input
type="checkbox"
id="follow-robots-toggle"
class="advanced-options-toggle"
checked={advancedOptions.followRobots}
onChange={handleSetAdvancedOption(
"followRobots",
(e) => e.target.checked
)}
/>
<label htmlFor="follow-robots-toggle">
Adhere to robots.txt
</label>
</div>
</>
)}
<hr />
<div className="user-input-group">
Expand Down
3 changes: 2 additions & 1 deletion src/MainWindow/HomePage/HomePage.scss
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@

#false-positive-toggle-group,
#screenshots-toggle-group,
#subdomain-toggle-group {
#subdomain-toggle-group,
#max-concurrency-toggle-group {
margin-bottom: 1rem;
}

Expand Down
7 changes: 4 additions & 3 deletions src/MainWindow/HomePage/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import labModeOn from "../../assets/lab-icon-on.svg";
import InitScanForm from "./InitScanForm";
import "./HomePage.scss";
import services from "../../services";
import { cliErrorCodes, cliErrorTypes, versionComparator } from "../../common/constants";
import { cliErrorCodes, cliErrorTypes, errorStates, versionComparator } from "../../common/constants";
import Modal from "../../common/components/Modal";
import { BasicAuthForm, BasicAuthFormFooter } from "./BasicAuthForm";
import EditUserDetailsModal from "./EditUserDetailsModal";
Expand Down Expand Up @@ -195,7 +195,7 @@ const HomePage = ({ isProxy, appVersionInfo, setCompletedScanId }) => {
} else {
/* When no pages were scanned (e.g. out of domain upon redirects when valid URL was entered),
redirects user to error page to going to result page with empty result */
navigate("/error");
navigate("/error", { state: { errorState: errorStates.noPagesScannedError }});
return;
}
}
Expand Down Expand Up @@ -223,7 +223,7 @@ const HomePage = ({ isProxy, appVersionInfo, setCompletedScanId }) => {
errorMessageToShow = "Invalid sitemap.";
break;
case cliErrorTypes.browserError:
navigate('/error', { state: { isBrowserError: true }});
navigate('/error', { state: { errorState: errorStates.browserError }});
return;
case cliErrorTypes.systemError:
default:
Expand All @@ -250,6 +250,7 @@ const HomePage = ({ isProxy, appVersionInfo, setCompletedScanId }) => {
const scanDetails = JSON.parse(window.localStorage.getItem("scanDetails"));
const splitUrl = scanDetails.scanUrl.split("://");
scanDetails.scanUrl = `${splitUrl[0]}://${username}:${password}@${splitUrl[1]}`;
setScanButtonIsClicked(true);
startScan(scanDetails);
setShowBasicAuthModal(false);
return;
Expand Down
9 changes: 8 additions & 1 deletion src/common/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ export const getDefaultAdvancedOptions = (isProxy) => {
maxConcurrency: false,
falsePositive: false,
includeScreenshots: true,
includeSubdomains: true
includeSubdomains: true,
followRobots: false,
}
};

Expand All @@ -104,6 +105,12 @@ export const cliErrorTypes = {
browserError: 17,
};

export const errorStates = {
browserError: 'browserError',
customScanError: 'customScanError',
noPagesScannedError: 'noPagesScannedError'
}

export const userDataFormDetails = {
// production form
// formUrl: "https://form.gov.sg/6453387735eb0c00128becdc",
Expand Down
2 changes: 2 additions & 0 deletions src/services.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ const startScan = async (scanDetails) => {
falsePositive,
includeScreenshots,
includeSubdomains,
followRobots,
scanMetadata,
} = scanDetails;

Expand All @@ -85,6 +86,7 @@ const startScan = async (scanDetails) => {
fileTypes: fileTypes[selectedFileTypes],
includeScreenshots,
includeSubdomains,
followRobots,
metadata: JSON.stringify(scanMetadata),
};

Expand Down

0 comments on commit dbb6009

Please sign in to comment.