Skip to content
Open
Show file tree
Hide file tree
Changes from 5 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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions anonymousVoting/clientAnonymousVoting/src/App.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Navbar from './components/Navbar';
import Explorer from "./components/Explorer";
import { BrowserRouter as Router, Route, Routes,Navigate } from 'react-router-dom'
import 'bootstrap/dist/css/bootstrap.css';

Expand Down Expand Up @@ -31,6 +32,7 @@ function App() {
// }else{
ret =
<Routes>
<Route path="/explorer" element={<Explorer />} />
<Route path="/" element={<Navigate to="/auth" />} />
<Route path="/auth" element={<Register/>} />
<Route path="/voting/:id" element={<VotingPage/>} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useState } from 'react';
import { ethers } from 'ethers';

import { useDispatch, useSelector } from 'react-redux'
import { selectNetwork, selectCorrectNetwork, setNetwork, setCorrectNetwork } from '../store/home.slice';
import { selectNetwork, seColectCorrectNetwork, setNetwork, setCorrectNetwork } from '../store/home.slice';

import Modal from 'react-bootstrap/Modal';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import styles from './CreateProcessPage.module.css';
import {ethers} from 'ethers';

//web3 imports
import { deployVotingProcess, deployTestContract, getTestContract } from '../web3/contracts'
import { useState, useEffect, useRef } from 'react';
import { deployVotingProcess} from '../web3/contracts'
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';


Expand All @@ -27,35 +27,44 @@ const CreateProcess = () => {
const [open, setOpen] = useState(false);
const [transactionResult, setTransactionResult] = useState(null);

const refValue = useRef(false);
// const refValue = useRef(false);

const createProcess = async (e) => {
e.preventDefault();
console.log("name: ", name);
//format proposals
let proposalArray = formatProposals(proposals);
//check form inputs
if(!isFormValid()){
window.alert("Form is not valid");
return;
}
const createProcess = async (e) => {
e.preventDefault();

if (!isFormValid()) {
window.alert("Form is not valid");
return;
}

try {
setPending(true);
refValue.current = true;
//deploy new process contract
const result = await deployVotingProcess(name, description, proposalArray,1000000,1000000);

const proposalArray = formatProposals(proposals);
const result = await deployVotingProcess(
name,
description,
proposalArray,
1000000,
1000000
);

setTransactionResult(result);
setShow(true);

refValue.current = false;
} catch (err) {
console.error(err);
window.alert("Transaction failed");
} finally {
setPending(false);

setShow(true);
}
};


const isFormValid = () => {
if(proposals < 2)
return false;
return true;
}
return proposals.split(',').length >= 2;
};
Comment on lines 64 to +66
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Validation doesn't reject empty proposals after trimming.

The validation only counts commas but doesn't verify that trimmed proposals are non-empty. Input like "proposal1, , , proposal2" or " , , " would pass validation but result in empty proposal strings.

Filter and validate trimmed proposals.

🔎 Proposed fix
 const isFormValid = () => {
-    return proposals.split(',').length >= 2;
+    const trimmedProposals = proposals.split(',').map(p => p.trim()).filter(p => p.length > 0);
+    return trimmedProposals.length >= 2;
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const isFormValid = () => {
if(proposals < 2)
return false;
return true;
}
return proposals.split(',').length >= 2;
};
const isFormValid = () => {
const trimmedProposals = proposals.split(',').map(p => p.trim()).filter(p => p.length > 0);
return trimmedProposals.length >= 2;
};
🤖 Prompt for AI Agents
In anonymousVoting/clientAnonymousVoting/src/components/CreateProcessPage.js
around lines 64 to 66, the isFormValid function currently counts commas and can
treat empty or whitespace-only entries as valid; change the validation to split
proposals on commas, map over parts and trim each one, filter out any empty
strings, and then require that the resulting array has length >= 2 so only
non-empty trimmed proposals count as valid.



const formatProposals = (input) => {
let proposals = input.split(',');
Expand All @@ -67,9 +76,6 @@ const CreateProcess = () => {
}


useEffect(() => {
// setPending(!pending);
}, [pending])

return (
<div >
Expand Down Expand Up @@ -105,11 +111,27 @@ const CreateProcess = () => {
/>
</div>
<div>
<button className="baseButton">Create new process</button>
<button
className="baseButton"
type="submit"
disabled={pending}
>
{pending ? (
<>
<Spinner
animation="border"
size="sm"
style={{ marginRight: "8px" }}
/>
Creating...
</>
) : (
"Create new process"
)}
</button>

</div>
{refValue.current == true && <div style={{marginTop: "2em"}}>
<Spinner animation="border" />
</div>}

</form>
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton>
Expand Down
10 changes: 10 additions & 0 deletions anonymousVoting/clientAnonymousVoting/src/components/Explorer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
function Explorer() {
return (
<div style={{ padding: "20px" }}>
<h2>Explorer</h2>
<p>Blockchain explorer coming soon.</p>
</div>
);
}

export default Explorer;
25 changes: 22 additions & 3 deletions anonymousVoting/clientAnonymousVoting/src/components/Navbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,28 @@ function Navbar({header, infoText, pictureUrl}) {
</div>

<div className="navbarMenuOption">
<img src="/assets/settings.png" className="navbarMenuIcon navbarMenuLeft" alt="settings"/>
<Link to="/"><img src="/assets/logout.png" className="navbarMenuIcon" alt="logout"/></Link>
</div>
<img
src="/assets/settings.png"
className="navbarMenuIcon navbarMenuLeft"
alt="settings"
/>

<Link to="/explorer">
<img
src="/assets/explorer.png"
className="navbarMenuIcon"
alt="explorer"
/>
</Link>

<Link to="/">
<img
src="/assets/logout.png"
className="navbarMenuIcon"
alt="logout"
/>
</Link>
</div>
</nav>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,61 @@ import { useState } from 'react';
import { Flex, Modal, Button, Card } from "rimble-ui";
import { ethers } from "ethers";
import ElectionOrganiser from "../../build/ElectionOrganizer.json";
import {successtoast, dangertoast } from '../utilities/Toasts';
import { successtoast, dangertoast } from '../utilities/Toasts';
import { toast } from "react-toastify";
import {addProposal} from '../../web3/contracts';
import { addProposal } from '../../web3/contracts';

export function AddCandidateModal({ electionId }) {
const [isOpen, setIsOpen] = useState(false);

const [candidateDetail, setCandidateDetail] = useState({
name: '',
description: ''
});

// ADDED: terms acceptance state
const [acceptedTerms, setAcceptedTerms] = useState(false);

const handleCandidateDetailChange = (e) => {
const { name, value } = e.target;
setCandidateDetail({
...candidateDetail,
[name]: value
});
}

};

const handleSubmitCandidate = async (e) => {
let id ;
let id;
e.preventDefault();

// ✅ ADDED: enforce terms acceptance
if (!acceptedTerms) {
toast.error("You must accept the Terms & Conditions");
return;
}

try {


let tx = await addProposal(electionId,ethers.utils.toUtf8Bytes(candidateDetail.name.trim()));

await tx.wait();
console.log(tx);
// successtoast(id, "Candidate Added Successfully")


} catch(err) {
dangertoast(id ,"Candidate Addition Failed")
let tx = await addProposal(
electionId,
ethers.utils.toUtf8Bytes(candidateDetail.name.trim())
);

await tx.wait();
console.log(tx);

// successtoast(id, "Candidate Added Successfully")
setIsOpen(false);
setAcceptedTerms(false);
} catch (err) {
dangertoast(id, "Candidate Addition Failed");
console.log(err);
}

}
}
};

const closeModal = e => {
e.preventDefault();
setIsOpen(false);
setAcceptedTerms(false); // ✅ reset
};

const openModal = e => {
Expand All @@ -57,14 +66,14 @@ export function AddCandidateModal({ electionId }) {

return (
<div>
<div onClick={openModal} style={{cursor: "pointer"}}>
<font size = '2'>Add Candidate</font>
<div onClick={openModal} style={{ cursor: "pointer" }}>
<font size='2'>Add Candidate</font>
</div>

<Modal isOpen={isOpen}>
<Card width={"90%"} height={"max-content"} p={0} style={{maxWidth: "500px"}}>
<Card width={"90%"} height={"max-content"} p={0} style={{ maxWidth: "500px" }}>
<Button.Text
style={{margin: "0px"}}
style={{ margin: "0px" }}
icononly
icon={"Close"}
color={"moon-gray"}
Expand All @@ -76,49 +85,64 @@ export function AddCandidateModal({ electionId }) {
onClick={closeModal}
/>

<div style={{margin: "10px", maxWidth: "700px", width: "90%"}}>
<div style={{ margin: "10px", maxWidth: "700px", width: "90%" }}>
<h5>Add candidates</h5>

<br/>
<br />

<div>
<b>Canidate Name</b>
<br/>
<input
className="form-control"
<br />

<input
className="form-control"
placeholder="Name of the candidate"
name="name"
value={candidateDetail.name}
onChange={handleCandidateDetailChange}
style={{marginTop: "15px"}}
style={{ marginTop: "15px" }}
/>
<br /><br />

<b>Canidate Description</b>
<br/>
<br />

<textarea
className="form-control"
className="form-control"
placeholder="Name of the candidate"
name="description"
rows={6}
value={candidateDetail.description}
onChange={handleCandidateDetailChange}
style={{marginTop: "15px"}}
/>
style={{ marginTop: "15px" }}
/>

<br /><br />

{/* ADDED: Terms & Conditions checkbox */}
<div>
<label style={{ cursor: "pointer" }}>
<input
type="checkbox"
checked={acceptedTerms}
onChange={(e) => setAcceptedTerms(e.target.checked)}
style={{ marginRight: "8px" }}
/>
I accept the Terms & Conditions
</label>
</div>
</div>
</div>

<Flex
px={4}
py={3}
justifyContent={"flex-end"}
>

<Flex px={4} py={3} justifyContent={"flex-end"}>
<Button.Outline onClick={closeModal}>Cancel</Button.Outline>
<Button ml={3} type="submit" onClick={handleSubmitCandidate}>Confirm</Button>
<Button
ml={3}
type="submit"
onClick={handleSubmitCandidate}
disabled={!acceptedTerms} // ✅ ADDED
>
Confirm
</Button>
</Flex>
</Card>
</Modal>
Expand Down
2 changes: 1 addition & 1 deletion chatbot/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,4 @@ def chat():
return jsonify({"error": str(e)})

if __name__ == '__main__':
app.run(host="0.0.0.0", port=5000,debug=True)
app.run(host="0.0.0.0", port=5000,debug=True)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Security: Avoid debug=True and binding to all interfaces in production.

Running Flask with debug=True enables the interactive debugger, which can execute arbitrary code. Combined with host="0.0.0.0", this exposes the debugger to the network.

Proposed fix using environment variables
+import os
+
 if __name__ == '__main__':
-    app.run(host="0.0.0.0", port=5000,debug=True)
+    debug_mode = os.environ.get("FLASK_DEBUG", "false").lower() == "true"
+    host = os.environ.get("FLASK_HOST", "127.0.0.1")
+    port = int(os.environ.get("FLASK_PORT", 5000))
+    app.run(host=host, port=port, debug=debug_mode)
🧰 Tools
🪛 ast-grep (0.40.3)

[warning] 89-89: Detected Flask app with debug=True. Do not deploy to production with this flag enabled as it will leak sensitive information. Instead, consider using Flask configuration variables or setting 'debug' using system environment variables.
Context: app.run(host="0.0.0.0", port=5000,debug=True)
Note: [CWE-489] Active Debug Code. [REFERENCES]
- https://labs.detectify.com/2015/10/02/how-patreon-got-hacked-publicly-exposed-werkzeug-debugger/

(debug-enabled-python)


[warning] 89-89: Running flask app with host 0.0.0.0 could expose the server publicly.
Context: app.run(host="0.0.0.0", port=5000,debug=True)
Note: [CWE-668]: Exposure of Resource to Wrong Sphere [OWASP A01:2021]: Broken Access Control [REFERENCES]
https://owasp.org/Top10/A01_2021-Broken_Access_Control

(avoid_app_run_with_bad_host-python)

🪛 Ruff (0.14.10)

90-90: Possible binding to all interfaces

(S104)


90-90: Use of debug=True in Flask app detected

(S201)

🤖 Prompt for AI Agents
In chatbot/app.py around lines 89-90, running Flask with debug=True and
host="0.0.0.0" is unsafe for production; change the startup to read an
environment/config flag (e.g., FLASK_ENV or APP_ENV) and only set debug=True and
open bind when that flag equals "development"; otherwise set debug=False and
bind to 127.0.0.1 (or better, do not call app.run at all in production and run
under a WSGI server like gunicorn/uwsgi). Ensure the environment-controlled
logic avoids exposing the interactive debugger and restricting network exposure
in non-development environments.

4 changes: 2 additions & 2 deletions chatbot/intents.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
{
"intents": [
{
"tag": "greeting",
Expand Down Expand Up @@ -454,4 +454,4 @@
]
}
]
}
}
Loading