├── .gitignore ├── backend ├── .gitignore ├── migrations │ ├── 2_election_migration.js │ └── 1_initial_migration.js ├── src │ ├── controllers │ │ ├── auth │ │ │ ├── logout.ts │ │ │ ├── signup.ts │ │ │ ├── check.ts │ │ │ └── login.ts │ │ ├── polls │ │ │ ├── status.ts │ │ │ ├── reset.ts │ │ │ ├── end.ts │ │ │ ├── votes.ts │ │ │ ├── fetch.ts │ │ │ ├── start.ts │ │ │ └── vote.ts │ │ └── users │ │ │ ├── not-verified.ts │ │ │ ├── delete.ts │ │ │ └── verify.ts │ ├── index.ts │ ├── entity │ │ ├── Candidate.ts │ │ ├── Poll.ts │ │ └── User.ts │ ├── web3.ts │ ├── routers │ │ ├── users.ts │ │ ├── auth.ts │ │ └── polls.ts │ ├── migration │ │ ├── 1645187823173-users.ts │ │ ├── 1645175354681-user-update.ts │ │ └── 1645167790939-initial.ts │ ├── middlewares │ │ └── cache.ts │ ├── server.ts │ └── seed │ │ └── users.ts ├── ormconfig.json ├── contracts │ ├── Migrations.sol │ └── Election.sol ├── Readme.md ├── package.json ├── truffle-config.js └── tsconfig.json ├── frontend ├── src │ ├── react-app-env.d.ts │ ├── styles │ │ ├── pages │ │ │ ├── Admin │ │ │ │ ├── Polls.scss │ │ │ │ └── Create.scss │ │ │ ├── View.scss │ │ │ ├── Features.scss │ │ │ ├── User │ │ │ │ └── Profile.scss │ │ │ └── Landing.scss │ │ ├── components │ │ │ ├── Back.scss │ │ │ ├── Features │ │ │ │ └── Feature.scss │ │ │ ├── Polls │ │ │ │ ├── Panel.scss │ │ │ │ └── Chart.scss │ │ │ └── Waiting.scss │ │ ├── layouts │ │ │ ├── Users.scss │ │ │ ├── Polls.scss │ │ │ ├── Login.scss │ │ │ ├── Boxes.scss │ │ │ └── Default.scss │ │ ├── vote-status.scss │ │ ├── form.scss │ │ └── index.scss │ ├── axios.ts │ ├── pages │ │ ├── Start.tsx │ │ ├── Home.tsx │ │ ├── Result.tsx │ │ ├── Polls.tsx │ │ ├── Admin │ │ │ ├── Verify.tsx │ │ │ ├── Home.tsx │ │ │ ├── Polls.tsx │ │ │ ├── Result.tsx │ │ │ ├── Users.tsx │ │ │ └── Start.tsx │ │ ├── User │ │ │ ├── Profile.tsx │ │ │ └── Polls.tsx │ │ ├── View.tsx │ │ ├── Login.tsx │ │ └── Signup.tsx │ ├── components │ │ ├── Polls │ │ │ ├── Running.tsx │ │ │ ├── Finished.tsx │ │ │ ├── Panel.tsx │ │ │ └── Chart.tsx │ │ ├── Footer.tsx │ │ ├── Waiting.tsx │ │ ├── Back.tsx │ │ ├── Home │ │ │ ├── Landing.tsx │ │ │ └── Features.tsx │ │ ├── Features │ │ │ └── Feature.tsx │ │ ├── Navbar.tsx │ │ └── CustomRoutes.tsx │ ├── setupTests.ts │ ├── App.tsx │ ├── reportWebVitals.ts │ ├── index.tsx │ ├── layouts │ │ ├── Login.tsx │ │ └── Default.tsx │ └── contexts │ │ └── Auth.tsx ├── public │ ├── robots.txt │ ├── logo.png │ ├── mobile.png │ ├── vote.gif │ ├── favicon.ico │ ├── logo192.png │ ├── logo512.png │ ├── logo-green.png │ ├── manifest.json │ └── index.html ├── .gitignore ├── tsconfig.json ├── package.json └── README.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | node_modules 3 | node_modules/**/* 4 | .env -------------------------------------------------------------------------------- /backend/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | node_modules 3 | node_modules/**/* 4 | .env -------------------------------------------------------------------------------- /frontend/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /frontend/src/styles/pages/Admin/Polls.scss: -------------------------------------------------------------------------------- 1 | .end-election-button { 2 | margin-top: 50px; 3 | } 4 | -------------------------------------------------------------------------------- /frontend/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /frontend/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/romanshilpakar/Blockchain-Based-Voting-System/HEAD/frontend/public/logo.png -------------------------------------------------------------------------------- /frontend/public/mobile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/romanshilpakar/Blockchain-Based-Voting-System/HEAD/frontend/public/mobile.png -------------------------------------------------------------------------------- /frontend/public/vote.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/romanshilpakar/Blockchain-Based-Voting-System/HEAD/frontend/public/vote.gif -------------------------------------------------------------------------------- /frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/romanshilpakar/Blockchain-Based-Voting-System/HEAD/frontend/public/favicon.ico -------------------------------------------------------------------------------- /frontend/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/romanshilpakar/Blockchain-Based-Voting-System/HEAD/frontend/public/logo192.png -------------------------------------------------------------------------------- /frontend/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/romanshilpakar/Blockchain-Based-Voting-System/HEAD/frontend/public/logo512.png -------------------------------------------------------------------------------- /frontend/public/logo-green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/romanshilpakar/Blockchain-Based-Voting-System/HEAD/frontend/public/logo-green.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Blockchain-Based-Voting-System 2 | 3 | # Watch the demo how it works here: 4 | https://www.youtube.com/watch?v=f22rJ1m7JBs&ab_channel=ROOMYAN 5 | -------------------------------------------------------------------------------- /frontend/src/axios.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | export default axios.create({ 4 | baseURL: "http://localhost:8000", 5 | withCredentials: true, 6 | }); 7 | -------------------------------------------------------------------------------- /frontend/src/styles/pages/View.scss: -------------------------------------------------------------------------------- 1 | .view-container { 2 | padding: 100px 100px 0 100px; 3 | margin-left: 50px; 4 | margin-right: 50px; 5 | position: relative; 6 | } 7 | -------------------------------------------------------------------------------- /backend/migrations/2_election_migration.js: -------------------------------------------------------------------------------- 1 | const Election = artifacts.require("Election"); 2 | 3 | module.exports = function (deployer) { 4 | deployer.deploy(Election); 5 | }; 6 | -------------------------------------------------------------------------------- /backend/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | const Migrations = artifacts.require("Migrations"); 2 | 3 | module.exports = function (deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /frontend/src/pages/Start.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Waiting from "../components/Waiting"; 3 | 4 | const Start = () => { 5 | return ; 6 | }; 7 | 8 | export default Start; 9 | -------------------------------------------------------------------------------- /backend/src/controllers/auth/logout.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | 3 | export default (req: Request, res: Response) => { 4 | res.clearCookie("refreshToken"); 5 | res.end(); 6 | }; 7 | -------------------------------------------------------------------------------- /frontend/src/styles/components/Back.scss: -------------------------------------------------------------------------------- 1 | .back { 2 | position: absolute; 3 | left: 0px; 4 | top: 50px; 5 | cursor: pointer; 6 | display: flex; 7 | align-items: center; 8 | 9 | // .icon { 10 | // } 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/styles/layouts/Users.scss: -------------------------------------------------------------------------------- 1 | .users-wrapper { 2 | @include boxes-wrapper; 3 | 4 | .user-wrapper { 5 | @include box-wrapper; 6 | display: flex; 7 | justify-content: space-between; 8 | align-items: center; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/components/Polls/Running.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Running = () => { 4 | return ( 5 |
6 |
7 |
8 | ); 9 | }; 10 | 11 | export default Running; 12 | -------------------------------------------------------------------------------- /frontend/src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /frontend/src/styles/layouts/Polls.scss: -------------------------------------------------------------------------------- 1 | .polls-wrapper { 2 | @include boxes-wrapper; 3 | 4 | .poll-wrapper { 5 | @include box-wrapper; 6 | 7 | .candidates-wrapper { 8 | @include inner-box-wrapper; 9 | 10 | .candidate-name { 11 | @include inner-box-name; 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/styles/components/Features/Feature.scss: -------------------------------------------------------------------------------- 1 | .feature-container { 2 | display: flex; 3 | align-items: center; 4 | 5 | .align-left { 6 | text-align: left; 7 | } 8 | .align-right { 9 | text-align: right; 10 | } 11 | 12 | .icon-container { 13 | font-size: 4rem; 14 | padding: 20px; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /frontend/src/styles/components/Polls/Panel.scss: -------------------------------------------------------------------------------- 1 | .polls-container { 2 | @include box-shadow; 3 | margin-top: 50px; 4 | text-align: center; 5 | padding: 50px; 6 | border-radius: 10px; 7 | display: flex; 8 | flex-direction: column; 9 | position: relative; 10 | 11 | .votes-wrapper { 12 | padding-top: 50px; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /backend/src/controllers/polls/status.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import ElectionContract from "../../web3"; 3 | 4 | export default async (_: Request, res: Response) => { 5 | const instance = await ElectionContract.deployed(); 6 | 7 | const status = await instance.getStatus(); 8 | 9 | return res.send({ status }); 10 | }; 11 | -------------------------------------------------------------------------------- /backend/src/index.ts: -------------------------------------------------------------------------------- 1 | import { createConnection } from "typeorm"; 2 | import app from "./server"; 3 | import "dotenv/config"; 4 | 5 | const port = process.env.PORT || 8000; 6 | 7 | createConnection() 8 | .then(async (connection) => { 9 | app.listen(port, () => console.log(`listening on port ${port} ... `)); 10 | }) 11 | .catch((error) => console.log(error)); 12 | -------------------------------------------------------------------------------- /frontend/src/components/Footer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Footer = () => { 4 | return ( 5 |
9 |
Copyright © 2022 BBVS. All rights reserved.
10 |
11 | ); 12 | }; 13 | 14 | export default Footer; 15 | -------------------------------------------------------------------------------- /backend/src/controllers/users/not-verified.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { User } from "../../entity/User"; 3 | 4 | export default async (req: Request, res: Response) => { 5 | const users = await User.find({ 6 | select: ["id", "name", "citizenshipNumber", "email"], 7 | where: { verified: false }, 8 | }); 9 | 10 | return res.send({ users }); 11 | }; 12 | -------------------------------------------------------------------------------- /frontend/src/components/Polls/Finished.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Finished = () => { 4 | return ( 5 |
6 | 7 | 8 | Finished 9 | 10 |
11 | ); 12 | }; 13 | 14 | export default Finished; 15 | -------------------------------------------------------------------------------- /frontend/src/components/Waiting.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Waiting = () => { 4 | return ( 5 |
6 |
7 | 8 |
9 | 10 |
WAITING FOR THE ELECTION TO START
11 |
12 | ); 13 | }; 14 | 15 | export default Waiting; 16 | -------------------------------------------------------------------------------- /frontend/src/pages/Home.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { RouteProps } from "react-router"; 3 | import Features from "../components/Home/Features"; 4 | import Landing from "../components/Home/Landing"; 5 | 6 | const Home = (props: RouteProps): JSX.Element => { 7 | return ( 8 | <> 9 | 10 | 11 | 12 | ); 13 | }; 14 | 15 | export default Home; 16 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /backend/ormconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "mysql", 3 | "host": "localhost", 4 | "port": 3306, 5 | "username": "bbvs", 6 | "password": "Password$$", 7 | "database": "bbvs", 8 | "synchronize": false, 9 | "logging": true, 10 | "cli": { 11 | "migrationsDir": "src/migration" 12 | }, 13 | "entities": ["src/entity/**/*.ts"], 14 | "migrations": ["src/migration/**/*.ts"], 15 | "subscribers": ["src/subscriber/**/*.ts"] 16 | } 17 | -------------------------------------------------------------------------------- /backend/src/entity/Candidate.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BaseEntity, 3 | Column, 4 | Entity, 5 | ManyToOne, 6 | PrimaryGeneratedColumn, 7 | } from "typeorm"; 8 | import { Poll } from "./Poll"; 9 | 10 | @Entity() 11 | export class Candidate extends BaseEntity { 12 | @PrimaryGeneratedColumn() 13 | id!: number; 14 | 15 | @Column() 16 | name!: string; 17 | 18 | @ManyToOne(() => Poll, (poll) => poll.candidates) 19 | poll!: Poll; 20 | } 21 | -------------------------------------------------------------------------------- /backend/src/web3.ts: -------------------------------------------------------------------------------- 1 | import Web3 from "web3"; 2 | import data from "../build/contracts/Election.json"; 3 | 4 | export const web3 = new Web3("http://localhost:7545"); 5 | 6 | const provider = new Web3.providers.HttpProvider("http://localhost:7545"); 7 | const contract = require("@truffle/contract"); 8 | 9 | const ElectionContract = contract(data); 10 | 11 | ElectionContract.setProvider(provider); 12 | 13 | export default ElectionContract; 14 | -------------------------------------------------------------------------------- /backend/src/entity/Poll.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BaseEntity, 3 | Column, 4 | Entity, 5 | OneToMany, 6 | PrimaryGeneratedColumn, 7 | } from "typeorm"; 8 | import { Candidate } from "./Candidate"; 9 | 10 | @Entity() 11 | export class Poll extends BaseEntity { 12 | @PrimaryGeneratedColumn() 13 | id!: number; 14 | 15 | @Column() 16 | name!: string; 17 | 18 | @OneToMany(() => Candidate, (candidate) => candidate.poll) 19 | candidates!: Candidate[]; 20 | } 21 | -------------------------------------------------------------------------------- /frontend/src/components/Back.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { IoIosArrowBack } from "react-icons/io"; 3 | 4 | interface BackProps { 5 | call: (any: any) => any; 6 | } 7 | 8 | const Back = (props: BackProps) => { 9 | return ( 10 |
11 | 12 | 13 | 14 | BACK 15 |
16 | ); 17 | }; 18 | 19 | export default Back; 20 | -------------------------------------------------------------------------------- /backend/src/controllers/users/delete.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { User } from "../../entity/User"; 3 | 4 | export default async (req: Request, res: Response) => { 5 | const { id } = req.params; 6 | 7 | if (!id) return res.status(400).send("no id found"); 8 | 9 | try { 10 | await User.delete(id); 11 | } catch (error) { 12 | return res.status(400).send({ error }); 13 | } 14 | 15 | return res.send({ userId: id }); 16 | }; 17 | -------------------------------------------------------------------------------- /backend/src/routers/users.ts: -------------------------------------------------------------------------------- 1 | import { Router } from "express"; 2 | import notVerifiedController from "../controllers/users/not-verified"; 3 | import verifyController from "../controllers/users/verify"; 4 | import deleteController from "../controllers/users/delete"; 5 | 6 | const router = Router(); 7 | 8 | router.get("/all", notVerifiedController); 9 | router.post("/verify", verifyController); 10 | router.delete("/delete/:id", deleteController); 11 | 12 | export default router; 13 | -------------------------------------------------------------------------------- /backend/src/migration/1645187823173-users.ts: -------------------------------------------------------------------------------- 1 | import { MigrationInterface, QueryRunner } from "typeorm"; 2 | import { User } from "../entity/User"; 3 | import usersData from "../seed/users"; 4 | 5 | export class users1645187823173 implements MigrationInterface { 6 | public async up(queryRunner: QueryRunner): Promise { 7 | const users = User.create(usersData); 8 | await User.save(users); 9 | } 10 | 11 | public async down(queryRunner: QueryRunner): Promise {} 12 | } 13 | -------------------------------------------------------------------------------- /frontend/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { BrowserRouter } from "react-router-dom"; 3 | import Footer from "./components/Footer"; 4 | import AuthProvider from "./contexts/Auth"; 5 | import CustomRoutes from "./components/CustomRoutes"; 6 | 7 | const App = () => { 8 | return ( 9 | 10 | 11 | 12 | 13 |