├── LICENSE
├── README.md
├── client-heroku
├── .gitignore
├── client
│ ├── .env
│ ├── package.json
│ ├── public
│ │ ├── index.html
│ │ ├── logo.ico
│ │ ├── logo.png
│ │ ├── logo192.png
│ │ ├── manifest.json
│ │ └── robots.txt
│ ├── src
│ │ ├── App.js
│ │ ├── abis
│ │ │ └── .txt
│ │ ├── assests
│ │ │ ├── auth.svg
│ │ │ ├── forget.svg
│ │ │ ├── login.svg
│ │ │ ├── loginSADG.svg
│ │ │ ├── logo.svg
│ │ │ ├── reset.svg
│ │ │ ├── update.svg
│ │ │ └── welcome.svg
│ │ ├── index.js
│ │ └── screens
│ │ │ └── Certificate.jsx
│ └── truffle-config.js
├── config
│ └── config.env
├── models
│ └── certauth.model.js
├── package.json
└── server.js
├── client
├── .env
├── migrations
│ ├── 1_initial_migration.js
│ └── 2_deploy_contracts.js
├── package.json
├── public
│ ├── index.html
│ ├── logo.ico
│ ├── logo.png
│ ├── logo192.png
│ ├── manifest.json
│ └── robots.txt
├── src
│ ├── App.js
│ ├── Routes
│ │ ├── AdminRoute.jsx
│ │ └── PrivateRoute.jsx
│ ├── assests
│ │ ├── auth.svg
│ │ ├── forget.svg
│ │ ├── login-SADG.svg
│ │ ├── login.svg
│ │ ├── logo.svg
│ │ ├── reset.svg
│ │ ├── update.svg
│ │ └── welcome.svg
│ ├── contracts
│ │ ├── Certification.sol
│ │ └── Migrations.sol
│ ├── helpers
│ │ └── auth.js
│ ├── index.js
│ └── screens
│ │ ├── Activate.jsx
│ │ ├── Admin.jsx
│ │ ├── Certificate.jsx
│ │ ├── ForgetPassword.jsx
│ │ ├── Login.jsx
│ │ ├── Private.jsx
│ │ ├── PrivateProfile.jsx
│ │ ├── Register.jsx
│ │ └── ResetPassword.jsx
├── test
│ └── Certification.js
└── truffle-config.js
├── config
└── config.env
├── controllers
├── auth.controller.js
└── user.controller.js
├── helpers
├── dbErrorHandling.js
└── valid.js
├── models
├── auth.model.js
└── certauth.model.js
├── package.json
├── routes
├── auth.route.js
└── user.route.js
└── server.js
/README.md:
--------------------------------------------------------------------------------
1 |
2 | `OUTDATED REPO: CREATE PR IF YOU WISH TO CONTRIBUTE` :shipit:
3 |
4 |
5 | # Blockchain-based-Certificate-Authentication-System
6 | Decentralized Application to store and verify the authenticity of Academic Certificates
7 |
8 | > Built using Ethereum on local blockchain setup and deployed on Ropsten test network.
9 |
10 | | Contract deployed at | 0xAC677Fd653576A70b9fAde4396caEE4AE21fc95a |
11 | | -------------------- | ------------------------------------------ |
12 | | RPC Network | Ropsten Test Network |
13 |
14 | ## Steps to set up local development environment
15 |
16 | ### Setting local blockchain
17 |
18 | 1. We need to install Node, Ganache and Truffle.
19 |
20 | Download [Node.js](https://nodejs.org/en/download/)
21 |
22 | Download [Ganache](https://www.trufflesuite.com/ganache) & create a workspace.
23 |
24 | For Truffle
25 | ```bash
26 | npm i -g truffle
27 | ```
28 |
29 | 1. Install dependencies
30 |
31 | Launch cmd in project folder path
32 | ```bash
33 | npm install
34 | ```
35 | after completion
36 | ```bash
37 | cd client
38 | npm install
39 | ```
40 |
41 | 1. Deploy the smart contract to the local blockchain.
42 |
43 | ```bash
44 | truffle migrate
45 | ```
46 |
47 | > If the contracts are modified, then they should be re-migrated.
48 |
49 | ### Setting MongoDB
50 |
51 | 1. Create account in [MongoDB Atlas](https://www.mongodb.com/)
52 |
53 | 1. Create a cluster and get the URI key, add it to .env file.
54 |
55 | ### Setting Mail Service
56 |
57 | 1. Create an account in [Sendgrid](https://signup.sendgrid.com/)
58 |
59 | 1. Verify single sender email and get the API key, add them to .env file
60 |
61 | ### Now we can start the server
62 |
63 | > In project folder, for server
64 | ```bash
65 | npm run dev
66 | ```
67 | > In client folder
68 | ```bash
69 | npm start
70 | ```
71 |
72 | ## Deploying Smart Contract
73 |
74 | The contract can be deployed in any test networks. We are using Ropsten test network with the help of truffle.
75 |
76 | 1. First of all we need to have a metamask account. When we create an account in metamask a _mnemonic_ is given to us. [You can read how to get a mnemonic here.](https://support.dex.top/hc/en-us/articles/360004125614-How-to-Create-Mnemonic-Phrase-with-MetaMask-)
77 |
78 | 1. After that create a project in [Infura](https://infura.io). This will help us to use ropsten network through infura.
79 |
80 | 1. You will get an endpoint like this `https://ropsten.infura.io/yourapikey`.
81 |
82 | 1. Add this API key, Ropsten Account address and it's private key in .env files.
83 |
84 | 1. Now you can deploy the smart contract using a single command:
85 |
86 | ```BASH
87 | truffle migrate
88 | ```
89 | ### Deploy client to heroku
90 |
91 | [](https://heroku.com/deploy)
92 |
93 | Install [heroku-cli](https://devcenter.heroku.com/articles/heroku-cli#download-and-install) & follow the [steps](https://devcenter.heroku.com/articles/deploying-nodejs#deploy-your-application-to-heroku) to deploy.
94 |
95 | ## Youtube project demo video
96 |
97 | [](https://youtu.be/qj-LdkTO9Ic)
98 |
99 |
100 | ### Client side Heroku
101 |
102 | Certificate Id : b2a90ded903d7b07b47c1bec2b398fd788deef5f
103 |
104 | [Click here](https://sadg-university.herokuapp.com/) to view and verify certificate.
105 |
106 | ## Contributors
107 |
108 |
109 |
110 | | 
[Arun Kumar M](https://github.com/arun664) | 
[Dilip Vummaneni](https://github.com/vummanenidilip) | 
[Gnanendra Prasad T](https://github.com/gnanendraprasad) | 
[Shashidhara N](https://github.com/shashi9690)|
111 | | :---: | :---: | :---: | :---: |
112 |
113 |
114 | Happy coding!! :sunglasses:
115 |
--------------------------------------------------------------------------------
/client-heroku/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/client-heroku/client/.env:
--------------------------------------------------------------------------------
1 | ROPSTEN_PRIVATE_KEY= //Private key of ropsten account
2 |
--------------------------------------------------------------------------------
/client-heroku/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eth-marketplace",
3 | "version": "0.1.0",
4 | "private": true,
5 | "description": "Project 2020",
6 | "author": "SADG University",
7 | "dependencies": {
8 | "@testing-library/jest-dom": "^4.2.4",
9 | "@testing-library/react": "^9.5.0",
10 | "@testing-library/user-event": "^7.2.1",
11 | "@truffle/hdwallet-provider": "^1.0.35",
12 | "axios": "^0.19.2",
13 | "babel-polyfill": "6.26.0",
14 | "babel-preset-env": "1.7.0",
15 | "babel-preset-es2015": "6.24.1",
16 | "babel-preset-stage-2": "6.24.1",
17 | "babel-preset-stage-3": "6.24.1",
18 | "babel-register": "6.26.0",
19 | "bootstrap": "4.3.1",
20 | "react": "^16.13.1",
21 | "react-bootstrap": "1.0.0-beta.5",
22 | "react-confirm-alert": "^2.6.1",
23 | "react-dom": "^16.13.1",
24 | "react-loading": "^2.0.3",
25 | "react-router-dom": "^5.1.2",
26 | "react-scripts": "3.4.1",
27 | "react-toastify": "^5.5.0",
28 | "truffle": "^5.0.5",
29 | "web3": "^1.0.0-beta.26",
30 | "yarn": "^1.22.4"
31 | },
32 | "scripts": {
33 | "start": "react-scripts start",
34 | "build": "react-scripts build",
35 | "test": "react-scripts test",
36 | "eject": "react-scripts eject"
37 | },
38 | "eslintConfig": {
39 | "extends": "react-app"
40 | },
41 | "browserslist": [
42 | ">0.2%",
43 | "not dead",
44 | "not ie <= 11",
45 | "not op_mini all"
46 | ]
47 | }
48 |
--------------------------------------------------------------------------------
/client-heroku/client/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | SADG University
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/client-heroku/client/public/logo.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arun664/Blockchain-based-Certificate-Authentication-System/cef5aa13740816822102be73db5d9b97c45ea9e0/client-heroku/client/public/logo.ico
--------------------------------------------------------------------------------
/client-heroku/client/public/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arun664/Blockchain-based-Certificate-Authentication-System/cef5aa13740816822102be73db5d9b97c45ea9e0/client-heroku/client/public/logo.png
--------------------------------------------------------------------------------
/client-heroku/client/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arun664/Blockchain-based-Certificate-Authentication-System/cef5aa13740816822102be73db5d9b97c45ea9e0/client-heroku/client/public/logo192.png
--------------------------------------------------------------------------------
/client-heroku/client/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/client-heroku/client/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/client-heroku/client/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import loginSADG from '../src/assests/loginSADG.svg';
3 | import { ToastContainer, toast } from 'react-toastify';
4 | import axios from 'axios';
5 | import { Component } from 'react';
6 |
7 | import Certification from '../src/abis/Certification.json';
8 | import Web3 from 'web3';
9 |
10 |
11 | class App extends Component {
12 | constructor(props){
13 | super(props)
14 | this.state = {
15 | certid : ''
16 | }
17 | }
18 |
19 |
20 |
21 | handleChange = e => {
22 | e.preventDefault()
23 | this.setState({
24 | [e.target.name]:e.target.value
25 | })
26 | }
27 |
28 |
29 | handleSubmit = e => {
30 | e.preventDefault()
31 |
32 | const data = this.state.certid
33 |
34 | //this.props.history.push('src/screens/Certificate')
35 | this.props.history.push({
36 | pathname: '/Certificate',
37 | state: { id : data}
38 | })
39 |
40 | }
41 |
42 | render () {
43 | const { certid } = this.state
44 | return(
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | Enter the Certificate ID
53 |
54 |
55 |
85 |
86 |
87 |
93 |
94 |
95 |
98 |
99 | )
100 | }
101 | }
102 |
103 | export default App;
104 |
--------------------------------------------------------------------------------
/client-heroku/client/src/abis/.txt:
--------------------------------------------------------------------------------
1 | Add your abi files that were generated when migrated to ropsten network.
--------------------------------------------------------------------------------
/client-heroku/client/src/assests/forget.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client-heroku/client/src/assests/login.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client-heroku/client/src/assests/reset.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client-heroku/client/src/assests/update.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client-heroku/client/src/assests/welcome.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client-heroku/client/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import {BrowserRouter, Route, Redirect, Switch} from 'react-router-dom';
4 | import App from './App';
5 | import Certificate from './screens/Certificate';
6 | import 'react-toastify/dist/ReactToastify.css';
7 |
8 | ReactDOM.render(
9 |
10 |
11 |
12 | }/>
13 |
14 |
15 |
16 | ,
17 | document.getElementById('root')
18 | );
19 |
--------------------------------------------------------------------------------
/client-heroku/client/src/screens/Certificate.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, Component } from 'react';
2 | import { ToastContainer, toast } from 'react-toastify';
3 | import axios from 'axios';
4 |
5 | import Certification from '../abis/Certification.json';
6 | import Web3 from 'web3'
7 |
8 | import ReactLoading from "react-loading";
9 | import logo from '../assests/logo.svg'
10 |
11 | class Certificate extends Component {
12 |
13 | constructor(props){
14 | super(props)
15 | this.state = {
16 | txid : '',
17 | verifyc: false,
18 | buttonColor: '#667eea',
19 | verifyt:'Verify',
20 | dvisi:'hidden'
21 | }
22 | }
23 |
24 | async componentWillMount(){
25 | await this.loadData()
26 | //console.log(this.props.location.state.id)
27 | }
28 |
29 | async componentDidUpdate(){
30 | await this.transactionX()
31 | }
32 |
33 |
34 | async loadData(){
35 | const Rapi = await axios.get('/api/getrapi')
36 | //window.alert(Rapi.data)
37 | var web3 = new Web3(new Web3.providers.HttpProvider(
38 | `https://ropsten.infura.io/v3/${Rapi.data}`
39 | ));
40 |
41 | const RDapi = await axios.get('/api/rdefault')
42 |
43 | web3.eth.defaultAccount = `${RDapi.data}`;
44 | this.setState({account:web3.eth.defaultAccount})
45 |
46 | const networkData = Certification.networks[3]
47 | if(networkData){
48 | const certification = await new web3.eth.Contract(Certification.abi, networkData.address)
49 | this.setState({certification})
50 | //console.log("Account found!" + this.state.account);
51 | //console.log(this.state.certification);
52 | }
53 | else{
54 | window.alert('Error')
55 | }
56 |
57 | const cert = await this.state.certification.methods.getData(this.props.location.state.id).call()
58 | //console.log(cert)
59 |
60 | const usn = cert[0];
61 | const name = cert[1];
62 | const email = cert[2];
63 | const fname = cert[3];
64 | const branch = cert[4];
65 | const sem1 = cert[5][0]/100;
66 | const sem2 = cert[5][1]/100;
67 | const sem3 = cert[5][2]/100;
68 | const sem4 = cert[5][3]/100;
69 | const sem5 = cert[5][4]/100;
70 | const sem6 = cert[5][5]/100;
71 | const sem7 = cert[5][6]/100;
72 | const sem8 = cert[5][7]/100;
73 | const bdate = cert[6].toString()
74 |
75 | //changing date format
76 | const x = bdate[0]+bdate[1]+bdate[2]+bdate[3]
77 | const y = bdate[4]+bdate[5]
78 | const z = bdate[6]+bdate[7]
79 |
80 | //calculating cgpa
81 | const cgpa = ((parseFloat(sem1)+parseFloat(sem2)+parseFloat(sem3)+parseFloat(sem4)+parseFloat(sem5)+parseFloat(sem6)+parseFloat(sem7)+parseFloat(sem8))/(8.0)).toFixed(2)
82 |
83 | //calculating percentage & rank
84 | const per = (cgpa - 0.75) * 10
85 | //console.log(per)
86 | if(per>=70) this.setState({rank:"FCD"})
87 | else if(per>=60 && per<70) this.setState({rank:"First Class"})
88 | else this.setState({rank:"Second Class"})
89 |
90 | this.setState({usn, name, email, fname, branch, x, y, z, sem1, sem2, sem3, sem4, sem5, sem6, sem7, sem8, cgpa })
91 | //console.log(this.state)
92 |
93 | //fetching transaction id from mongo
94 | const id = this.state.usn
95 | const tixd = await axios.post('/api/idfetch', { id })
96 | this.setState({txid:tixd.data.tid})
97 | }
98 |
99 | async transactionX () {
100 | const Rapi = await axios.get('/api/getrapi')
101 |
102 | var web3 = new Web3(new Web3.providers.HttpProvider(
103 | `https://ropsten.infura.io/v3/${Rapi.data}`
104 | ));
105 | //console.log(this.state.txid)
106 | const certget = await web3.eth.getTransactionReceipt(this.state.txid)
107 | //console.log(certget)
108 | this.setState({newcert:certget})
109 | }
110 |
111 | handleSubmit = e => {
112 | e.preventDefault();
113 |
114 | //Fetching transaction details
115 | // console.log(this.state.newcert)
116 | if(this.state.newcert.status == true && this.state.newcert.transactionHash == this.state.txid ) {
117 | //toast.success("Authentication Successfull!!")
118 | toast.success("Certificate is present in Blockchain")
119 | toast.info("Ropsten Blocknumber : "+this.state.newcert.blockNumber)
120 | //console.log("Ropsten Blocknumber : "+this.state.newcert.blockNumber)
121 | this.setState({verifyc:true})
122 | this.setState({buttonColor:'#07bc0c'})
123 | this.setState({verifyt:'Verified'})
124 | this.setState({dvisi:'visible'})
125 | this.setState({blockurl:`https://ropsten.etherscan.io/block/${this.state.newcert.blockNumber}`})
126 | }
127 | else{
128 | toast.error("Failed to Authenticate Certificate");
129 | }
130 |
131 | }
132 |
133 | render()
134 | {
135 | {
136 | if(this.state.newcert)
137 | {
138 | return (
139 |
140 |
141 |
142 |
143 |
144 |
145 |

146 |
147 |
SADG University
148 | Blockchain Certificate Authentication System
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 | Student Name : {this.state.name}
162 |
163 |
164 |
165 |
166 |
167 | USN : {this.state.usn}
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 | Father Name : {this.state.fname}
176 |
177 |
178 |
179 |
180 | Date of Birth : {this.state.z}-{this.state.y}-{this.state.x}
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 | Semester |
192 | Total SGPA |
193 | Obtained SGPA |
194 |
195 |
196 |
197 |
198 | 1 |
199 | 10 |
200 | {this.state.sem1} |
201 |
202 |
203 | 2 |
204 | 10 |
205 | {this.state.sem2} |
206 |
207 |
208 | 3 |
209 | 10 |
210 | {this.state.sem3} |
211 |
212 |
213 | 4 |
214 | 10 |
215 | {this.state.sem4} |
216 |
217 |
218 | 5 |
219 | 10 |
220 | {this.state.sem5} |
221 |
222 |
223 | 6 |
224 | 10 |
225 | {this.state.sem6} |
226 |
227 |
228 | 7 |
229 | 10 |
230 | {this.state.sem7} |
231 |
232 |
233 | 8 |
234 | 10 |
235 | {this.state.sem8} |
236 |
237 |
238 |
239 |
240 |
Total CGPA
241 |
{this.state.cgpa}
242 |
Rank Obtained
243 |
{this.state.rank}
244 |
245 |
246 |
247 |
248 | Certifies that
249 |
{this.state.name}
250 | has been duly admitted to the degree of
251 | BACHELOR OF ENGINEERING
252 | in Department of
253 | {this.state.branch}
254 | for recognition of the fulfillment of requirements for the said degree.
255 |
256 |
257 | {/*
258 |
Director/Principal
259 |
Seal
260 |
*/}
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 | Verify Authenticity of Certificate in Blockchain Network
272 |
273 |
274 |
313 |
314 |
315 |
316 |
317 | )
318 | }
319 | else if(this.state.usn == '') {
320 | return(
321 |
322 |
323 |
324 |
325 |
326 |
327 |
Certificate Doesn't exist!!
328 | Please check your Certificate ID
329 |
330 |
331 |
332 |
343 |
344 |
345 |
346 | )
347 | }
348 | else {
349 | return (
350 |
355 | )
356 | }
357 | }
358 | }
359 | }
360 |
361 | export default Certificate;
362 |
--------------------------------------------------------------------------------
/client-heroku/client/truffle-config.js:
--------------------------------------------------------------------------------
1 | require('babel-register');
2 | require('babel-polyfill');
3 | require('dotenv').config()
4 |
5 | const HDWalletProvider = require('@truffle/hdwallet-provider')
6 |
7 | module.exports = {
8 | networks: {
9 | ropsten: {
10 | provider: function() {
11 | return new HDWalletProvider(
12 | process.env.ROPSTEN_PRIVATE_KEY,
13 | `https://ropsten.infura.io/v3/${process.env.INFURA_API_KEY}`
14 | )
15 | },
16 | gasPrice: 21,
17 | network_id: 3,
18 | },
19 | development: {
20 | host: "127.0.0.1",
21 | port: 7545,
22 | network_id: "*" //Match any network
23 | }
24 | },
25 | contracts_build_directory: './src/abis/',
26 | compilers: {
27 | solc: {
28 | optimizer: {
29 | enabled: true,
30 | runs: 200
31 | }
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/client-heroku/config/config.env:
--------------------------------------------------------------------------------
1 | NODE_ENV=production
2 | MONGO_URI= //MONGO_URI from MongoDB Atlas
3 | INFURA_API_KEY= //Infura Ropsten API key
4 | ROPSTEN_DEFAULT_ACCOUNT= //Ropsten Account address
--------------------------------------------------------------------------------
/client-heroku/models/certauth.model.js:
--------------------------------------------------------------------------------
1 | const mongoose = require ('mongoose')
2 |
3 | const TransactionSchema = new mongoose.Schema(
4 | {
5 | usn: {
6 | type: String,
7 | trim: true
8 | },
9 | tid: {
10 | type: String,
11 | trim: true
12 | }
13 | }
14 | );
15 |
16 | module.exports = mongoose.model('Certificate', TransactionSchema);
--------------------------------------------------------------------------------
/client-heroku/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "build": "cd client && npm run build",
8 | "install-client": "cd client && npm install",
9 | "heroku-postbuild": "npm run install-client && npm run build",
10 | "start": "node server.js",
11 | "client": "cd client && npm start",
12 | "dev": "concurrently -n 'server,client' -c 'red,green' \"nodemon server.js\" \"npm run client\""
13 | },
14 | "keywords": [],
15 | "author": "",
16 | "license": "ISC",
17 | "dependencies": {
18 | "body-parser": "^1.19.0",
19 | "cors": "^2.8.5",
20 | "dotenv": "^8.2.0",
21 | "express": "^4.17.1",
22 | "express-jwt": "^5.3.3",
23 | "express-validator": "^6.4.0",
24 | "mongoose": "^5.9.9",
25 | "morgan": "^1.10.0",
26 | "node-fetch": "^2.6.0",
27 | "nodemon": "^2.0.3",
28 | "object-hash": "^2.0.3"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/client-heroku/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express')
2 | const morgan = require('morgan')
3 | const bodyparser = require('body-parser')
4 | const app = express()
5 | const mongoose = require ('mongoose')
6 | const transaction = require('./models/certauth.model');
7 | const cors = require('cors')
8 | const path = require('path')
9 | //Config .env to ./config/config.env
10 | require('dotenv').config({
11 | path:'./config/config.env'
12 | })
13 |
14 |
15 | //Connect to Database
16 | const uri = process.env.MONGO_URI
17 | mongoose.connect(uri, {
18 | useNewUrlParser: true,
19 | useCreateIndex: true,
20 | useUnifiedTopology: true
21 | }
22 | );
23 |
24 | const connection = mongoose.connection;
25 | connection.once('open', () => {
26 | console.log ("MongoDB database connection established successfully");
27 | })
28 |
29 |
30 | //Use bodyParser
31 | app.use(bodyparser.json())
32 |
33 | //config for only development
34 | //config for only development
35 |
36 |
37 | //Morgan give information about each request
38 | //Cors it's allow to deal with react for localhost at port 3000 without any problem
39 | app.post('/api/idfetch', (req, res, next) => {
40 | const usn = req.body.id
41 | //console.log(usn)
42 | transaction.findOne({
43 | usn
44 | }).exec((err, tid) => {
45 | return res.send(tid)
46 | })
47 | });
48 |
49 | app.get('/api/getrapi', (req, res, next) => {
50 | return res.send(process.env.INFURA_API_KEY)
51 | });
52 |
53 | app.get('/api/rdefault', (req, res, next) => {
54 | return res.send(process.env.ROPSTEN_DEFAULT_ACCOUNT)
55 | });
56 |
57 |
58 |
59 | if (process.env.NODE_ENV === 'production') {
60 | // Serve any static files
61 | app.use(express.static(path.resolve(__dirname, 'client/build')));
62 | // Handle React routing, return all requests to React app
63 | app.get('*', function(req, res) {
64 | res.sendFile(path.resolve(__dirname, 'client/build', 'index.html'));
65 | });
66 | app.use(cors());
67 | }
68 |
69 | const PORT = process.env.PORT
70 |
71 | var listener = app.listen(PORT, function() {
72 | console.log(`App listening on port ${PORT}`); //Listening on port 8888
73 | });
74 |
--------------------------------------------------------------------------------
/client/.env:
--------------------------------------------------------------------------------
1 | REACT_APP_API_URL=http://localhost:5000/api
2 | ROPSTEN_PRIVATE_KEY= //Ropsten Account private key
--------------------------------------------------------------------------------
/client/migrations/1_initial_migration.js:
--------------------------------------------------------------------------------
1 | const Migrations = artifacts.require("Migrations");
2 |
3 | module.exports = function(deployer) {
4 | deployer.deploy(Migrations);
5 | };
6 |
--------------------------------------------------------------------------------
/client/migrations/2_deploy_contracts.js:
--------------------------------------------------------------------------------
1 | const Certification = artifacts.require("Certification");
2 |
3 | module.exports = function(deployer) {
4 | deployer.deploy(Certification);
5 | };
6 |
--------------------------------------------------------------------------------
/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eth-marketplace",
3 | "version": "0.1.0",
4 | "private": true,
5 | "description": "Project SADG 2020",
6 | "author": "SADG University",
7 | "dependencies": {
8 | "@testing-library/jest-dom": "^4.2.4",
9 | "@testing-library/react": "^9.5.0",
10 | "@testing-library/user-event": "^7.2.1",
11 | "@truffle/hdwallet-provider": "^1.0.35",
12 | "axios": "^0.19.2",
13 | "babel-polyfill": "6.26.0",
14 | "babel-preset-env": "1.7.0",
15 | "babel-preset-es2015": "6.24.1",
16 | "babel-preset-stage-2": "6.24.1",
17 | "babel-preset-stage-3": "6.24.1",
18 | "babel-register": "6.26.0",
19 | "bootstrap": "4.3.1",
20 | "chai": "4.2.0",
21 | "chai-as-promised": "7.1.1",
22 | "chai-bignumber": "3.0.0",
23 | "dotenv": "^8.2.0",
24 | "flatted": "^3.0.2",
25 | "jquery": ">=3.5.0",
26 | "js-cookie": "^2.2.1",
27 | "jsonwebtoken": "^8.5.1",
28 | "react": "^16.13.1",
29 | "react-bootstrap": "1.0.0-beta.5",
30 | "react-confirm-alert": "^2.6.1",
31 | "react-dom": "^16.13.1",
32 | "react-loading": "^2.0.3",
33 | "react-router-dom": "^5.1.2",
34 | "react-scripts": "3.4.1",
35 | "react-spinners": "^0.8.3",
36 | "react-toastify": "^5.5.0",
37 | "truffle": "^5.0.5",
38 | "web3": "^1.0.0-beta.26",
39 | "yarn": "^1.22.4"
40 | },
41 | "scripts": {
42 | "start": "react-scripts start",
43 | "build": "react-scripts build",
44 | "test": "react-scripts test",
45 | "eject": "react-scripts eject"
46 | },
47 | "eslintConfig": {
48 | "extends": "react-app"
49 | },
50 | "browserslist": [
51 | ">0.2%",
52 | "not dead",
53 | "not ie <= 11",
54 | "not op_mini all"
55 | ]
56 | }
57 |
--------------------------------------------------------------------------------
/client/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | SADG University
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/client/public/logo.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arun664/Blockchain-based-Certificate-Authentication-System/cef5aa13740816822102be73db5d9b97c45ea9e0/client/public/logo.ico
--------------------------------------------------------------------------------
/client/public/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arun664/Blockchain-based-Certificate-Authentication-System/cef5aa13740816822102be73db5d9b97c45ea9e0/client/public/logo.png
--------------------------------------------------------------------------------
/client/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arun664/Blockchain-based-Certificate-Authentication-System/cef5aa13740816822102be73db5d9b97c45ea9e0/client/public/logo192.png
--------------------------------------------------------------------------------
/client/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/client/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/client/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 | import { ToastContainer, toast } from 'react-toastify';
4 | import Logo from './assests/logo.svg';
5 |
6 |
7 | function App({ history }) {
8 | if ( sessionStorage.reloadAfterPageLoad ) {
9 | toast.error('Signout Successfull');
10 | sessionStorage.reloadAfterPageLoad = false;
11 | }
12 |
13 | return (
14 |
15 |
16 |
17 |
18 |
19 |
20 | Welcome to SADG University{' '}
21 |
22 |
23 | Blockchain Certificate Authentication System
24 |
25 |
26 |
27 |
28 | Sign up or Sign In
29 |
30 |
31 |
32 |
36 |
37 | Sign In
38 |
39 |
43 |
44 | Sign Up
45 |
46 | {/*
50 |
51 | Profile Dashbaord
52 |
53 |
57 |
58 | Admin Dashbaord
59 | */}
60 | {/* */}
72 |
73 |
74 |
75 |
76 |
82 |
83 |
84 | )
85 | }
86 |
87 | export default App;
--------------------------------------------------------------------------------
/client/src/Routes/AdminRoute.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Route, Redirect } from 'react-router-dom';
3 | import { isAuth } from '../helpers/auth';
4 |
5 | const AdminRoute = ({ component: Component, ...rest }) => (
6 |
9 | isAuth() && isAuth().role === 'admin' ? (
10 |
11 | ) : (
12 |
18 | )
19 | }
20 | >
21 | );
22 |
23 | export default AdminRoute;
--------------------------------------------------------------------------------
/client/src/Routes/PrivateRoute.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Route, Redirect } from 'react-router-dom';
3 | import { isAuth } from '../helpers/auth';
4 |
5 | const PrivateRoute = ({ component: Component, ...rest }) => (
6 |
9 | isAuth() ? (
10 |
11 | ) : (
12 |
18 | )
19 | }
20 | >
21 | );
22 |
23 | export default PrivateRoute;
--------------------------------------------------------------------------------
/client/src/assests/forget.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client/src/assests/login.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client/src/assests/reset.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client/src/assests/update.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client/src/assests/welcome.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client/src/contracts/Certification.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.0;
2 | contract Certification {
3 | constructor() public {}
4 | struct Certificate {
5 | string USN;
6 | string candidate_name;
7 | string Email;
8 | string father_name;
9 | string department;
10 | uint[8] sgpa;
11 | uint256 birth_date;
12 | }
13 | mapping(bytes32 => Certificate) public certificates;
14 | event certificateGenerated(bytes32 _certificateId);
15 |
16 | function stringToBytes32(string memory source) private pure returns (bytes32 result) {
17 | bytes memory tempEmptyStringTest = bytes(source);
18 | if (tempEmptyStringTest.length == 0) {
19 | return 0x0;
20 | }
21 | assembly {
22 | result := mload(add(source, 32))
23 | }
24 | }
25 |
26 | function generateCertificate(
27 | string memory _id,
28 | string memory _USN,
29 | string memory _candidate_name,
30 | string memory _Email,
31 | string memory _father_name,
32 | string memory _department,
33 | uint[8] memory _sgpa,
34 | uint256 _birth_date) public {
35 | bytes32 byte_id = stringToBytes32(_id);
36 | certificates[byte_id] = Certificate(_USN,_candidate_name,_Email, _father_name, _department, _sgpa, _birth_date);
37 | emit certificateGenerated(byte_id);
38 | }
39 | function getData(string memory _id) public view returns(string memory,string memory,string memory, string memory, string memory, uint[8] memory,uint256 _birth_date) {
40 | bytes32 byte_id = stringToBytes32(_id);
41 | Certificate memory temp = certificates[byte_id];
42 |
43 | return (temp.USN, temp.candidate_name, temp.Email,temp.father_name, temp.department, temp.sgpa, temp.birth_date);
44 | }
45 | }
--------------------------------------------------------------------------------
/client/src/contracts/Migrations.sol:
--------------------------------------------------------------------------------
1 | pragma solidity >=0.4.21 <0.6.0;
2 |
3 | contract Migrations {
4 | address public owner;
5 | uint public last_completed_migration;
6 |
7 | constructor() public {
8 | owner = msg.sender;
9 | }
10 |
11 | modifier restricted() {
12 | if (msg.sender == owner) _;
13 | }
14 |
15 | function setCompleted(uint completed) public restricted {
16 | last_completed_migration = completed;
17 | }
18 |
19 | function upgrade(address new_address) public restricted {
20 | Migrations upgraded = Migrations(new_address);
21 | upgraded.setCompleted(last_completed_migration);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/client/src/helpers/auth.js:
--------------------------------------------------------------------------------
1 | import cookie from 'js-cookie';
2 |
3 | // Set in Cookie
4 | export const setCookie = (key, value) => {
5 | if (window !== 'undefiend') {
6 | cookie.set(key, value, {
7 | // 1 Day
8 | expires: 1
9 | })
10 | }
11 | }
12 | // remove from cookie
13 | export const removeCookie = key => {
14 | if (window !== 'undefined') {
15 | cookie.remove(key, {
16 | expires: 1
17 | });
18 | }
19 | };
20 |
21 |
22 | // Get from cookie such as stored token
23 | // Will be useful when we need to make request to server with token
24 | export const getCookie = key => {
25 | if (window !== 'undefined') {
26 | return cookie.get(key);
27 | }
28 | };
29 |
30 | // Set in localstorage
31 | export const setLocalStorage = (key, value) => {
32 | if (window !== 'undefined') {
33 | localStorage.setItem(key, JSON.stringify(value));
34 | }
35 | };
36 |
37 | // Remove from localstorage
38 | export const removeLocalStorage = key => {
39 | if (window !== 'undefined') {
40 | localStorage.removeItem(key);
41 | }
42 | };
43 |
44 | // Auth enticate user by passing data to cookie and localstorage during signin
45 | export const authenticate = (response, next) => {
46 | //console.log('AUTHENTICATE HELPER ON SIGNIN RESPONSE', response);
47 | setCookie('token', response.data.token);
48 | setLocalStorage('user', response.data.user);
49 | next();
50 | };
51 |
52 | // Access user info from localstorage
53 | export const isAuth = () => {
54 | if (window !== 'undefined') {
55 | const cookieChecked = getCookie('token');
56 | if (cookieChecked) {
57 | if (localStorage.getItem('user')) {
58 | return JSON.parse(localStorage.getItem('user'));
59 | } else {
60 | return false;
61 | }
62 | }
63 | }
64 | };
65 |
66 | //Signout
67 | export const signout = next => {
68 | removeCookie('token');
69 | removeLocalStorage('user');
70 | next();
71 | };
72 |
73 | //Update user data in localstorage
74 | export const updateUser = (response, next) => {
75 | console.log('UPDATE USER IN LOCALSTORAGE HELPERS', response);
76 | if (typeof window !== 'undefined') {
77 | let auth = JSON.parse(localStorage.getItem('user'));
78 | auth = response.data;
79 | localStorage.setItem('user', JSON.stringify(auth));
80 | }
81 | next();
82 | };
--------------------------------------------------------------------------------
/client/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import {BrowserRouter, Route, Redirect, Switch} from 'react-router-dom';
4 | import App from './App';
5 | import Register from './screens/Register';
6 | import Activate from './screens/Activate';
7 | import Login from './screens/Login';
8 | import Private from './screens/Private.jsx';
9 | import PrivateProfile from './screens/PrivateProfile.jsx';
10 | import Admin from './screens/Admin.jsx';
11 | import ForgetPassword from './screens/ForgetPassword';
12 | import ResetPassword from './screens/ResetPassword';
13 | import Certificate from './screens/Certificate';
14 |
15 | import PrivateRoute from './Routes/PrivateRoute';
16 | import AdminRoute from './Routes/AdminRoute';
17 | import 'react-toastify/dist/ReactToastify.css';
18 |
19 | ReactDOM.render(
20 |
21 |
22 | }/>
23 | }/>
24 | }/>
25 | }/>
26 | }/>
27 | }/>
28 |
29 |
30 |
31 |
32 |
33 |
34 | ,
35 | document.getElementById('root')
36 | );
--------------------------------------------------------------------------------
/client/src/screens/Activate.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import authSvg from '../assests/welcome.svg';
3 | import { ToastContainer, toast } from 'react-toastify';
4 | import axios from 'axios';
5 | import jwt from 'jsonwebtoken';
6 | import { isAuth } from '../helpers/auth';
7 | import { Redirect } from 'react-router-dom';
8 |
9 | const Activate = ({ match }) => {
10 | const [formData, setFormData] = useState({
11 | name: '',
12 | token: '',
13 | show: true
14 | });
15 |
16 | useEffect(() => {
17 | /**get token from params like /active/token
18 | * then decide this token and get name
19 | */
20 | let token = match.params.token;
21 | let { name } = jwt.decode(token);
22 |
23 | if (token) {
24 | setFormData({ ...formData, name, token });
25 | }
26 |
27 | console.log(token, name);
28 | }, [match.params]);
29 | const { name, token, show } = formData;
30 |
31 | const handleSubmit = e => {
32 | e.preventDefault();
33 |
34 | axios
35 | .post(`${process.env.REACT_APP_API_URL}/activation`, {
36 | token
37 | })
38 | .then(res => {
39 | setFormData({
40 | ...formData,
41 | show: false
42 | });
43 |
44 | toast.success(res.data.message);
45 | })
46 | .catch(err => {
47 |
48 | toast.error(err.response.data.errors);
49 | });
50 | };
51 |
52 | return (
53 |
54 | {isAuth() ?
: null}
55 |
56 |
57 |
58 |
59 |
60 | Welcome {name}
61 |
62 |
63 |
93 |
94 |
95 |
101 |
102 |
103 | );
104 | };
105 |
106 | export default Activate;
107 |
--------------------------------------------------------------------------------
/client/src/screens/ForgetPassword.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import authSvg from '../assests/forget.svg';
3 | import { ToastContainer, toast } from 'react-toastify';
4 | import axios from 'axios';
5 |
6 | const ForgetPassword = ({history}) => {
7 | const [formData, setFormData] = useState({
8 | email: '',
9 | textChange: 'Submit'
10 | });
11 | const { email, textChange } = formData;
12 | const handleChange = text => e => {
13 | setFormData({ ...formData, [text]: e.target.value });
14 | };
15 | const handleSubmit = e => {
16 | e.preventDefault();
17 | if (email) {
18 | setFormData({ ...formData, textChange: 'Submitting' });
19 | axios
20 | .put(`${process.env.REACT_APP_API_URL}/password/forget`, {
21 | email
22 | })
23 | .then(res => {
24 |
25 | setFormData({
26 | ...formData,
27 | email: '',
28 | });
29 | toast.success(`Please check your email`);
30 |
31 | })
32 | .catch(err => {
33 | console.log(err.response)
34 | toast.error(err.response.data.error);
35 | });
36 | } else {
37 | toast.error('Please fill all fields');
38 | }
39 | };
40 | return (
41 |
42 |
43 |
44 |
45 |
46 |
47 | Forget Password
48 |
49 |
50 |
51 |
70 |
71 |
72 |
73 |
79 |
80 |
81 | );
82 | };
83 |
84 | export default ForgetPassword;
85 |
--------------------------------------------------------------------------------
/client/src/screens/Login.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import authSvg from '../assests/login-SADG.svg';
3 | import { ToastContainer, toast } from 'react-toastify';
4 | import axios from 'axios';
5 | import { authenticate, isAuth } from '../helpers/auth';
6 | import { Link, Redirect } from 'react-router-dom';
7 |
8 | const Login = ({ history }) => {
9 | const [formData, setFormData] = useState({
10 | email: '',
11 | password1: '',
12 | textChange: 'Sign In'
13 | });
14 | const { email, password1, textChange } = formData;
15 | const handleChange = text => e => {
16 | setFormData({ ...formData, [text]: e.target.value });
17 | };
18 |
19 | /**If not admin redirect to /private
20 | * if admin redirect to /admin
21 | */
22 | const informParent = response => {
23 | authenticate(response, () => {
24 | isAuth() && isAuth().role === 'admin'
25 | ? history.push('/admin')
26 | : history.push('/private');
27 | toast.success(`Hey ${response.data.user.name}, Welcome`);
28 | });
29 | };
30 |
31 | const handleSubmit = e => {
32 | console.log(process.env.REACT_APP_API_URL);
33 | e.preventDefault();
34 | if (email && password1) {
35 | setFormData({ ...formData, textChange: 'Submitting' });
36 | axios
37 | .post(`${process.env.REACT_APP_API_URL}/login`, {
38 | email,
39 | password: password1
40 | })
41 | .then(res => {
42 | authenticate(res, () => {
43 | setFormData({
44 | ...formData,
45 | email: '',
46 | password1: '',
47 | textChange: 'Submitted'
48 | });
49 | isAuth() && isAuth().role === 'admin'
50 | ? history.push('/admin')
51 | : history.push('/private');
52 | toast.success(`Hey ${res.data.user.name}, Welcome back!`);
53 | });
54 | })
55 | .catch(err => {
56 | setFormData({
57 | ...formData,
58 | email: '',
59 | password1: '',
60 | textChange: 'Sign In'
61 | });
62 | console.log(err.response);
63 | toast.error(err.response.data.errors);
64 | });
65 | } else {
66 | toast.error('Please fill all fields');
67 | }
68 | };
69 | return (
70 |
71 | {isAuth() ?
: null}
72 |
73 |
74 |
75 |
76 |
77 | Sign In
78 |
79 |
80 |
112 |
113 |
114 |
115 |
116 | Or sign In with e-mail
117 |
118 |
119 |
120 |
134 |
135 |
136 |
142 |
143 |
144 | );
145 | };
146 |
147 | export default Login;
148 |
--------------------------------------------------------------------------------
/client/src/screens/Private.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import authSvg from '../assests/update.svg';
3 | import { ToastContainer, toast } from 'react-toastify';
4 | import axios from 'axios';
5 | import { updateUser, isAuth, getCookie, signout } from '../helpers/auth';
6 | import { Component } from 'react';
7 |
8 | import Certification from '../abis/Certification.json';
9 | import Web3 from 'web3';
10 |
11 |
12 | class Private extends Component {
13 | constructor(props){
14 | super(props)
15 | this.state = {
16 | certid : ''
17 | }
18 | }
19 |
20 |
21 |
22 | handleChange = e => {
23 | e.preventDefault()
24 | this.setState({
25 | [e.target.name]:e.target.value
26 | })
27 | }
28 |
29 |
30 | handleSubmit = e => {
31 | e.preventDefault()
32 |
33 | const data = this.state.certid
34 |
35 | this.props.history.push('/private/certificate')
36 | this.props.history.push({
37 | pathname: '/private/certificate',
38 | state: { id : data}
39 | })
40 |
41 | }
42 |
43 | render () {
44 | const { certid } = this.state
45 | return(
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | Enter the Certificate ID
54 |
55 |
56 |
115 |
116 |
117 |
123 |
124 |
125 |
128 |
129 | )
130 | }
131 | }
132 |
133 | export default Private;
134 |
--------------------------------------------------------------------------------
/client/src/screens/PrivateProfile.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import authSvg from '../assests/update.svg';
3 | import { ToastContainer, toast } from 'react-toastify';
4 | import axios from 'axios';
5 | import { updateUser, isAuth, getCookie, signout } from '../helpers/auth';
6 |
7 | const PrivateProfile = ({ history }) => {
8 | const [formData, setFormData] = useState({
9 | name: '',
10 | email: '',
11 | password1: '',
12 | textChange: 'Update',
13 | role: ''
14 | });
15 |
16 | useEffect(() => {
17 | loadProfile();
18 | }, []);
19 |
20 | const loadProfile = () => {
21 | const token = getCookie('token');
22 | axios
23 | .get(`${process.env.REACT_APP_API_URL}/user/${isAuth()._id}`, {
24 | headers: {
25 | Authorization: `Bearer ${token}`
26 | }
27 | })
28 | .then(res => {
29 | const { role, name, email } = res.data;
30 | setFormData({ ...formData, role, name, email });
31 | })
32 | .catch(err => {
33 | toast.error(`Error To Your Information ${err.response.statusText}`);
34 | if (err.response.status === 401) {
35 | signout(() => {
36 | history.push('/login');
37 | });
38 | }
39 | });
40 | };
41 | const { name, email, password1, textChange, role } = formData;
42 | const handleChange = text => e => {
43 | setFormData({ ...formData, [text]: e.target.value });
44 | };
45 | const handleSubmit = e => {
46 | const token = getCookie('token');
47 | console.log(token);
48 | e.preventDefault();
49 | setFormData({ ...formData, textChange: 'Submitting' });
50 | axios
51 | .put(
52 | `${process.env.REACT_APP_API_URL}/user/update`,
53 | {
54 | name,
55 | email,
56 | password: password1
57 | },
58 | {
59 | headers: {
60 | Authorization: `Bearer ${token}`
61 | }
62 | }
63 | )
64 | .then(res => {
65 | updateUser(res, () => {
66 | toast.success('Profile Updated Successfully');
67 | setFormData({ ...formData, textChange: 'Update' });
68 | });
69 | })
70 | .catch(err => {
71 | console.log(err.response);
72 | });
73 | };
74 |
75 | return (
76 |
77 |
78 |
79 |
80 |
81 |
82 | Profile Update
83 |
84 |
85 |
145 |
146 |
147 |
153 |
154 |
155 | );
156 | };
157 |
158 | export default PrivateProfile;
159 |
--------------------------------------------------------------------------------
/client/src/screens/Register.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import authSvg from '../assests/auth.svg';
3 | import { ToastContainer, toast } from 'react-toastify';
4 | import axios from 'axios';
5 | import { isAuth } from '../helpers/auth';
6 | import { Redirect } from 'react-router-dom';
7 |
8 | const Register = () => {
9 | const [formData, setFormData] = useState({
10 | name: '',
11 | email: '',
12 | password1: '',
13 | password2: '',
14 | textChange: 'Sign Up'
15 | });
16 |
17 | const { name, email, password1, password2, textChange } = formData;
18 | const handleChange = text => e => {
19 | setFormData({ ...formData, [text]: e.target.value });
20 | };
21 | const handleSubmit = e => {
22 | e.preventDefault();
23 | if (name && email && password1) {
24 | if (password1 === password2) {
25 | setFormData({ ...formData, textChange: 'Submitting' });
26 | axios
27 | .post(`${process.env.REACT_APP_API_URL}/register`, {
28 | name,
29 | email,
30 | password: password1
31 | })
32 | .then(res => {
33 | setFormData({
34 | ...formData,
35 | name: '',
36 | email: '',
37 | password1: '',
38 | password2: '',
39 | textChange: 'Submitted'
40 | });
41 |
42 | toast.success(res.data.message);
43 | })
44 | .catch(err => {
45 | setFormData({
46 | ...formData,
47 | name: '',
48 | email: '',
49 | password1: '',
50 | password2: '',
51 | textChange: 'Sign Up'
52 | });
53 | console.log(err.response);
54 | toast.error(err.response.data.errors);
55 | });
56 | } else {
57 | toast.error("Passwords don't matches");
58 | }
59 | } else {
60 | toast.error('Please fill all fields');
61 | }
62 | };
63 |
64 | return (
65 |
66 | {isAuth() ?
: null}
67 |
68 |
69 |
70 |
71 |
72 | Sign Up
73 |
74 |
75 |
133 |
134 |
135 |
141 |
142 |
143 | );
144 | };
145 |
146 | export default Register;
147 |
--------------------------------------------------------------------------------
/client/src/screens/ResetPassword.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import authSvg from '../assests/reset.svg';
3 | import { ToastContainer, toast } from 'react-toastify';
4 | import axios from 'axios';
5 | const ResetPassword = ({match}) => {
6 | const [formData, setFormData] = useState({
7 | password1: '',
8 | password2: '',
9 | token: '',
10 | textChange: 'Submit'
11 | });
12 | const { password1, password2, textChange, token } = formData;
13 |
14 | useEffect(() => {
15 | let token = match.params.token
16 | if(token) {
17 | setFormData({...formData, token,})
18 | }
19 |
20 | }, [])
21 | const handleChange = text => e => {
22 | setFormData({ ...formData, [text]: e.target.value });
23 | };
24 | const handleSubmit = e => {
25 | console.log(password1, password2)
26 | e.preventDefault();
27 | if ((password1 === password2) && password1 && password2) {
28 | setFormData({ ...formData, textChange: 'Submitting' });
29 | axios
30 | .put(`${process.env.REACT_APP_API_URL}/password/reset`, {
31 | newPassword: password1,
32 | resetPasswordLink: token
33 | })
34 | .then(res => {
35 | console.log(res.data.message)
36 | setFormData({
37 | ...formData,
38 | password1: '',
39 | password2: ''
40 | });
41 | toast.success(res.data.message);
42 |
43 | })
44 | .catch(err => {
45 | toast.error('Something is wrong try again');
46 | });
47 | } else {
48 | toast.error('Passwords don\'t matches');
49 | }
50 | };
51 | return (
52 |
53 |
54 |
55 |
56 |
57 |
58 | Reset Your Password
59 |
60 |
61 |
62 |
88 |
89 |
90 |
91 |
97 |
98 |
99 | );
100 | };
101 |
102 | export default ResetPassword;
103 |
--------------------------------------------------------------------------------
/client/test/Certification.js:
--------------------------------------------------------------------------------
1 | const Certification = artifacts.require("./Certification.sol");
2 | require('chai')
3 | .use(require('chai-as-promised'))
4 | .should()
5 |
6 | contract('Certification', () => {
7 | let certification, cert,cert1
8 | before(async () => {
9 | certification= await Certification.deployed()
10 | })
11 | describe('deployment', async () =>{
12 | it('deploys Succesfully', async () =>{
13 | const address = await certification.address
14 | assert.notEqual(address, 0*0)
15 | assert.notEqual(address, '')
16 | assert.notEqual(address, null)
17 | assert.notEqual(address, undefined)
18 | })})
19 | describe('Certification', async () =>{
20 | it('generates a certificate', async () =>{
21 | cert =
22 | certification.generateCertificate('test','1KG16CS096','test','test@gmail.com','test’s father','CSE',[8,8,8,8,8,8,8,8],'09/05/1999')
23 | })
24 | })
25 | it('returns data', async ()=>{
26 | cert1 = certification.getData('test')
27 | })
28 | })
29 |
--------------------------------------------------------------------------------
/client/truffle-config.js:
--------------------------------------------------------------------------------
1 | require('babel-register');
2 | require('babel-polyfill');
3 | require('dotenv').config()
4 |
5 | const HDWalletProvider = require('@truffle/hdwallet-provider')
6 |
7 | module.exports = {
8 | networks: {
9 | ropsten: {
10 | provider: function() {
11 | return new HDWalletProvider(
12 | process.env.ROPSTEN_PRIVATE_KEY,
13 | `https://ropsten.infura.io/v3/${process.env.INFURA_API_KEY}`
14 | )
15 | },
16 | gasPrice: 21,
17 | network_id: 3,
18 | },
19 | development: {
20 | host: "127.0.0.1",
21 | port: 7545,
22 | network_id: "*" //Match any network
23 | }
24 | },
25 | contracts_directory: './src/contracts/',
26 | contracts_build_directory: './src/abis/',
27 | compilers: {
28 | solc: {
29 | optimizer: {
30 | enabled: true,
31 | runs: 200
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/config/config.env:
--------------------------------------------------------------------------------
1 | PORT=5000
2 | NODE_ENV=development
3 | CLIENT_URL=http://localhost:3000
4 | MONGO_URI= //MONGO_URI link from MongoDB Atlas
5 | JWT_ACCOUNT_ACTIVATION= //Random text code
6 | JWT_SECRET= //Random text code
7 | JWT_RESET_PASSWORD= //Random text code
8 | EMAIL_FROM= //Single sender verified mail from sendgrid
9 | MAIL_KEY= //Mail Api key from sendgrid
10 | INFURA_API_KEY= //Infura Api key for Ropsten Network
11 | ROPSTEN_DEFAULT_ACCOUNT= //Ropsten Account Address from Metamask
--------------------------------------------------------------------------------
/controllers/auth.controller.js:
--------------------------------------------------------------------------------
1 | const User = require('../models/auth.model');
2 | const expressJwt = require('express-jwt');
3 | const _ = require('lodash');
4 | const { OAuth2Client } = require('google-auth-library');
5 | const fetch = require('node-fetch');
6 |
7 | const { validationResult } = require('express-validator');
8 | const jwt = require('jsonwebtoken');
9 | const expressJWT = require('express-jwt');
10 | const { errorHandler } = require('../helpers/dbErrorHandling');
11 | const sgMail = require('@sendgrid/mail');
12 | sgMail.setApiKey(process.env.MAIL_KEY);
13 |
14 | exports.registerController = (req, res) => {
15 | const { name, email, password } = req.body;
16 | const errors = validationResult(req);
17 |
18 | if (!errors.isEmpty()) {
19 | const firstError = errors.array().map(error => error.msg)[0];
20 | return res.status(422).json({
21 | errors: firstError
22 | });
23 | } else {
24 | User.findOne({
25 | email
26 | }).exec((err, user) => {
27 | if (user) {
28 | return res.status(400).json({
29 | errors: 'Email is taken'
30 | });
31 | }
32 | });
33 |
34 | const token = jwt.sign(
35 | {
36 | name,
37 | email,
38 | password
39 | },
40 | process.env.JWT_ACCOUNT_ACTIVATION,
41 | {
42 | expiresIn: '15m'
43 | }
44 | );
45 | const emailData = {
46 | to: email,
47 | from: process.env.EMAIL_FROM,
48 | subject: 'Account activation link',
49 | html: `
50 | Please use the following to activate your account
51 | ${process.env.CLIENT_URL}/users/activate/${token}
52 |
53 | This email may containe sensitive information
54 | ${process.env.CLIENT_URL}
55 | `,
56 | };
57 |
58 | sgMail.send(emailData).then(sent => {
59 | return res.json({
60 | message: `Email has been sent to ${email}`
61 | });
62 | }).catch(err => {
63 | return res.status(400).json({
64 | success: false,
65 | errors: errorHandler(err)
66 | });
67 | });
68 | }
69 | };
70 |
71 | //Register for Backend is done.
72 |
73 |
74 | // Activation and save to database
75 |
76 | exports.activationController = (req, res) => {
77 | const { token } = req.body;
78 |
79 | if (token) {
80 | //Verify the token is valid or not or expired
81 | jwt.verify(token, process.env.JWT_ACCOUNT_ACTIVATION, (err, decoded) => {
82 | if (err) {
83 | console.log('Activation error');
84 | return res.status(401).json({
85 | errors: 'Expired link. Signup again'
86 | });
87 | } else {
88 | //If valid save to database
89 | //Get name, email, password from token
90 | const {
91 | name,
92 | email,
93 | password
94 | } = jwt.decode(token);
95 |
96 | console.log(email);
97 | const user = new User({
98 | name,
99 | email,
100 | password
101 | });
102 |
103 | user.save((err, user) => {
104 | if (err) {
105 | console.log('Save error', errorHandler(err));
106 | return res.status(401).json({
107 | errors: errorHandler(err)
108 | });
109 | } else {
110 | return res.json({
111 | success: true,
112 | message: 'Signup success',
113 | });
114 | }
115 | });
116 | }
117 | });
118 | } else {
119 | return res.json({
120 | message: 'Error Occured'
121 | });
122 | }
123 | };
124 |
125 | exports.loginController = (req, res) => {
126 | const { email, password } = req.body;
127 | const errors = validationResult(req);
128 | if (!errors.isEmpty()) {
129 | const firstError = errors.array().map(error => error.msg)[0];
130 | return res.status(422).json({
131 | errors: firstError
132 | });
133 | } else {
134 | // check if user exist
135 | User.findOne({
136 | email
137 | }).exec((err, user) => {
138 | if (err || !user) {
139 | return res.status(400).json({
140 | errors: 'User does not exist. Please signup'
141 | });
142 | }
143 | // authenticate
144 | if (!user.authenticate(password)) {
145 | return res.status(400).json({
146 | errors: 'Email and password do not match'
147 | });
148 | }
149 | // generate a token and send to client
150 | const token = jwt.sign(
151 | {
152 | _id: user._id
153 | },
154 | process.env.JWT_SECRET,
155 | {
156 | expiresIn: '7d'
157 | }
158 | );
159 | const { _id, name, email, role } = user;
160 |
161 | return res.json({
162 | token,
163 | user: {
164 | _id,
165 | name,
166 | email,
167 | role
168 | }
169 | });
170 | });
171 | }
172 | };
173 |
174 | exports.forgotPasswordController = (req, res) => {
175 | const { email } = req.body;
176 | const errors = validationResult(req);
177 |
178 | //Validation to req, body we will create custom validation in seconds
179 | if (!errors.isEmpty()) {
180 | const firstError = errors.array().map(error => error.msg)[0];
181 | return res.status(422).json({
182 | errors: firstError
183 | });
184 | } else {
185 | //Find if user already exists
186 | User.findOne(
187 | {
188 | email
189 | },
190 | (err, user) => {
191 | if (err || !user) {
192 | return res.status(400).json({
193 | error: 'User does not exist'
194 | });
195 | }
196 |
197 | const token = jwt.sign(
198 | {
199 | _id: user._id
200 | },
201 | process.env.JWT_RESET_PASSWORD,
202 | {
203 | expiresIn: '10m'
204 | }
205 | );
206 |
207 | const emailData = {
208 | from: process.env.EMAIL_FROM,
209 | to: email,
210 | subject: `Password Reset link`,
211 | html: `
212 | Please use the following link to reset your password
213 | ${process.env.CLIENT_URL}/users/password/reset/${token}
214 |
215 | This email may contain sensetive information
216 | ${process.env.CLIENT_URL}
217 | `
218 | };
219 |
220 | return user.updateOne(
221 | {
222 | resetPasswordLink: token
223 | },
224 | (err, success) => {
225 | if (err) {
226 | console.log('RESET PASSWORD LINK ERROR', err);
227 | return res.status(400).json({
228 | error:
229 | 'Database connection error on user password forgot request'
230 | });
231 | } else {
232 | sgMail
233 | .send(emailData)
234 | .then(sent => {
235 | // console.log('SIGNUP EMAIL SENT', sent)
236 | return res.json({
237 | message: `Email has been sent to ${email}. Follow the instruction to activate your account`
238 | });
239 | })
240 | .catch(err => {
241 | // console.log('SIGNUP EMAIL SENT ERROR', err)
242 | return res.json({
243 | message: err.message
244 | });
245 | });
246 | }
247 | }
248 | );
249 | }
250 | );
251 | }
252 | };
253 |
254 |
255 | exports.resetPasswordController = (req, res) => {
256 | const { resetPasswordLink, newPassword } = req.body;
257 |
258 | const errors = validationResult(req);
259 |
260 | if (!errors.isEmpty()) {
261 | const firstError = errors.array().map(error => error.msg)[0];
262 | return res.status(422).json({
263 | errors: firstError
264 | });
265 | } else {
266 | if (resetPasswordLink) {
267 | jwt.verify(resetPasswordLink, process.env.JWT_RESET_PASSWORD, function(
268 | err,
269 | decoded
270 | ) {
271 | if (err) {
272 | return res.status(400).json({
273 | error: 'Expired link. Try again'
274 | });
275 | }
276 |
277 | User.findOne(
278 | {
279 | resetPasswordLink
280 | },
281 | (err, user) => {
282 | if (err || !user) {
283 | return res.status(400).json({
284 | error: 'Something went wrong. Try later'
285 | });
286 | }
287 |
288 | const updatedFields = {
289 | password: newPassword,
290 | resetPasswordLink: ''
291 | };
292 |
293 | user = _.extend(user, updatedFields);
294 |
295 | user.save((err, result) => {
296 | if (err) {
297 | return res.status(400).json({
298 | error: 'Error resetting user password'
299 | });
300 | }
301 | res.json({
302 | message: `Great! Now you can login with your new password`
303 | });
304 | });
305 | }
306 | );
307 | });
308 | }
309 | }
310 | };
311 |
312 | exports.adminMiddleware = (req, res, next) => {
313 | User.findById({
314 | _id: req.user._id
315 | }).exec((err, user) => {
316 | if (err || !user) {
317 | return res.status(400).json({
318 | error: 'User not found'
319 | });
320 | }
321 |
322 | if (user.role !== 'admin') {
323 | return res.status(400).json({
324 | error: 'Admin resource. Access denied.'
325 | });
326 | }
327 |
328 | req.profile = user;
329 | next();
330 | });
331 | };
332 |
333 |
334 |
335 | exports.requireSignin = expressJwt({
336 | secret: process.env.JWT_SECRET // req.user._id
337 | });
338 |
--------------------------------------------------------------------------------
/controllers/user.controller.js:
--------------------------------------------------------------------------------
1 | const User = require('../models/auth.model');
2 | const expressJwt = require('express-jwt');
3 |
4 | exports.readController = (req, res) => {
5 | const userId = req.params.id;
6 | User.findById(userId).exec((err, user) => {
7 | if (err || !user) {
8 | return res.status(400).json({
9 | error: 'User not found'
10 | });
11 | }
12 | user.hashed_password = undefined;
13 | user.salt = undefined;
14 | res.json(user);
15 | });
16 | };
17 |
18 | exports.updateController = (req, res) => {
19 |
20 | // console.log('UPDATE USER - req.user', req.user, 'UPDATE DATA', req.body);
21 | const { name, password } = req.body;
22 |
23 | User.findOne({ _id: req.user._id }, (err, user) => {
24 | if (err || !user) {
25 | return res.status(400).json({
26 | error: 'User not found'
27 | });
28 | }
29 | if (!name) {
30 | return res.status(400).json({
31 | error: 'Name is required'
32 | });
33 | } else {
34 | user.name = name;
35 | }
36 |
37 | if (password) {
38 | if (password.length < 6) {
39 | return res.status(400).json({
40 | error: 'Password should be min 6 characters long'
41 | });
42 | } else {
43 | user.password = password;
44 | }
45 | }
46 |
47 | user.save((err, updatedUser) => {
48 | if (err) {
49 | console.log('USER UPDATE ERROR', err);
50 | return res.status(400).json({
51 | error: 'User update failed'
52 | });
53 | }
54 | updatedUser.hashed_password = undefined;
55 | updatedUser.salt = undefined;
56 | res.json(updatedUser);
57 | });
58 | });
59 | };
--------------------------------------------------------------------------------
/helpers/dbErrorHandling.js:
--------------------------------------------------------------------------------
1 | "use strict"
2 |
3 | /*
4 | Get Unique error field name
5 | */
6 |
7 | const uniqueMessage = error => {
8 | let output;
9 | try {
10 | let fieldName = error.message.split(".$")[1]
11 | field = field.split("dub key")[0]
12 | req.flash("errors",[{
13 | message: "An account with this"+ field +"already exists"
14 | }])
15 |
16 | output = fieldName.charAt(0).toUpperCase() + fieldName.slice(1) + "already exists"
17 | } catch(err) {
18 | output = "already exists"
19 | }
20 |
21 | return output
22 | }
23 |
24 | /*
25 | Get the error message from error object
26 | */
27 |
28 | exports.errorHandler = error => {
29 | let message = ''
30 | if(error.code) {
31 | switch(error.code) {
32 | case 11000:
33 | case 11001:
34 | message = uniqueMessage(error);
35 | break;
36 | default:
37 | message = "Something went wrong";
38 | }
39 | } else {
40 | for (let errorName in error.errors) {
41 | if(error.errors[errorName].message)
42 | message = error.errors[errorName].message;
43 | }
44 |
45 | return message;
46 | };
47 | }
--------------------------------------------------------------------------------
/helpers/valid.js:
--------------------------------------------------------------------------------
1 | //Validation Helpers
2 | const {
3 | check
4 | } = require('express-validator');
5 |
6 | //Register
7 | exports.validSign = [
8 | check('name', 'Name is required').notEmpty()
9 | .isLength({
10 | min: 4,
11 | max: 32
12 | }).withMessage('name must be between 3 to 32 characters'),
13 | check('email')
14 | .isEmail()
15 | .withMessage('Must be a valid email address'),
16 | check('password', 'password is required').notEmpty(),
17 | check('password').isLength({
18 | min: 6
19 | }).withMessage('Password must contain at least 6 characters').matches(/\d/).withMessage('password must contain a number')
20 | ]
21 |
22 | //Login
23 | exports.validLogin = [
24 | check('email')
25 | .isEmail()
26 | .withMessage('Must be a valid email address'),
27 | check('password', 'password is required').notEmpty(),
28 | check('password').isLength({
29 | min: 6
30 | }).withMessage('Password must contain at least 6 characters').matches(/\d/).withMessage('password must contain a number')
31 | ]
32 |
33 | //ForgetPassword
34 | exports.forgotPasswordValidator = [
35 | check('email')
36 | .not()
37 | .isEmpty()
38 | .isEmail()
39 | .withMessage('Must be a valid email address')
40 | ];
41 |
42 | //ResetPassword
43 | exports.resetPasswordValidator = [
44 | check('newPassword')
45 | .not()
46 | .isEmpty()
47 | .isLength({ min: 6 })
48 | .withMessage('Password must be at least 6 characters long')
49 | ];
--------------------------------------------------------------------------------
/models/auth.model.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 | const crypto = require('crypto');
3 | // user schema
4 | const userSchema = new mongoose.Schema(
5 | {
6 | email: {
7 | type: String,
8 | trim: true,
9 | required: true,
10 | unique: true,
11 | lowercase: true
12 | },
13 | name: {
14 | type: String,
15 | trim: true,
16 | required: true
17 | },
18 | hashed_password: {
19 | type: String,
20 | required: true
21 | },
22 | salt: String,
23 | role: {
24 | type: String,
25 | default: 'Employer'
26 | },
27 | resetPasswordLink: {
28 | data: String,
29 | default: ''
30 | }
31 | },
32 | {
33 | timestamps: true
34 | }
35 | );
36 |
37 | // virtual
38 | userSchema
39 | .virtual('password')
40 | .set(function(password) {
41 | this._password = password;
42 | this.salt = this.makeSalt();
43 | this.hashed_password = this.encryptPassword(password);
44 | })
45 | .get(function() {
46 | return this._password;
47 | });
48 |
49 | // methods
50 | userSchema.methods = {
51 | authenticate: function(plainText) {
52 | return this.encryptPassword(plainText) === this.hashed_password;
53 | },
54 |
55 | encryptPassword: function(password) {
56 | if (!password) return '';
57 | try {
58 | return crypto
59 | .createHmac('sha1', this.salt)
60 | .update(password)
61 | .digest('hex');
62 | } catch (err) {
63 | return '';
64 | }
65 | },
66 |
67 | makeSalt: function() {
68 | return Math.round(new Date().valueOf() * Math.random()) + '';
69 | }
70 | };
71 |
72 | module.exports = mongoose.model('User', userSchema);
73 |
--------------------------------------------------------------------------------
/models/certauth.model.js:
--------------------------------------------------------------------------------
1 | const mongoose = require ('mongoose')
2 |
3 | const TransactionSchema = new mongoose.Schema(
4 | {
5 | usn: {
6 | type: String,
7 | trim: true
8 | },
9 | tid: {
10 | type: String,
11 | trim: true
12 | },
13 | email: {
14 | type: String,
15 | trim: true
16 | },
17 | cert_id: {
18 | type: String,
19 | trim: true
20 | }
21 | }
22 | );
23 |
24 | module.exports = mongoose.model('Certificate', TransactionSchema);
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "NODE_ENV=production node server",
8 | "dev": "nodemon server"
9 | },
10 | "keywords": [],
11 | "author": "",
12 | "license": "ISC",
13 | "dependencies": {
14 | "@sendgrid/mail": "^7.0.1",
15 | "body-parser": "^1.19.0",
16 | "cors": "^2.8.5",
17 | "dotenv": "^8.2.0",
18 | "express": "^4.17.1",
19 | "express-jwt": "^5.3.3",
20 | "express-validator": "^6.4.0",
21 | "google-auth-library": "^6.0.0",
22 | "jsonwebtoken": "^8.5.1",
23 | "loadash": "^1.0.0",
24 | "lodash": "^4.17.15",
25 | "mongoose": "^5.9.9",
26 | "morgan": "^1.10.0",
27 | "node-fetch": "^2.6.0",
28 | "nodemon": "^2.0.3",
29 | "object-hash": "^2.0.3"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/routes/auth.route.js:
--------------------------------------------------------------------------------
1 | const express = require('express')
2 | const router = express.Router()
3 |
4 | //Validation
5 | const {
6 | validSign,
7 | validLogin,
8 | forgotPasswordValidator,
9 | resetPasswordValidator
10 | } = require('../helpers/valid')
11 |
12 | //Load controllers
13 | const {
14 | registerController,
15 | loginController,
16 | activationController,
17 | forgotPasswordController,
18 | resetPasswordController
19 | } = require('../controllers/auth.controller.js')
20 |
21 | router.post('/register', validSign, registerController)
22 | router.post('/login', validLogin, loginController)
23 | router.post('/activation', activationController)
24 | router.put('/password/forget', forgotPasswordValidator, forgotPasswordController)
25 | router.put('/password/reset', resetPasswordValidator, resetPasswordController)
26 | module.exports = router
--------------------------------------------------------------------------------
/routes/user.route.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const router = express.Router();
3 |
4 | // import controller
5 | const { requireSignin, adminMiddleware } = require('../controllers/auth.controller');
6 | const { readController, updateController } = require('../controllers/user.controller');
7 |
8 | router.get('/user/:id', requireSignin, readController);
9 | router.put('/user/update', requireSignin, updateController);
10 | router.put('/admin/update', requireSignin, adminMiddleware, updateController);
11 |
12 | module.exports = router;
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express')
2 | const morgan = require('morgan')
3 | const bodyparser = require('body-parser')
4 | const cors = require('cors')
5 | const app = express()
6 | const mongoose = require ('mongoose')
7 |
8 | const sgMail = require('@sendgrid/mail');
9 |
10 | const transaction = require('./models/certauth.model');
11 | const { errorHandler } = require('./helpers/dbErrorHandling')
12 |
13 | //Config .env to ./config/config.env
14 | require('dotenv').config({
15 | path:'./config/config.env'
16 | })
17 |
18 | //Connect to Database
19 | const uri = process.env.MONGO_URI
20 | mongoose.connect(uri, {
21 | useNewUrlParser: true,
22 | useCreateIndex: true,
23 | useUnifiedTopology: true
24 | }
25 | );
26 |
27 | const connection = mongoose.connection;
28 | connection.once('open', () => {
29 | console.log ("MongoDB database connection established successfully");
30 | })
31 |
32 | //Use bodyParser
33 | app.use(bodyparser.json())
34 |
35 | //Load all routes
36 | const authRouter = require('./routes/auth.route')
37 | const userRouter = require('./routes/user.route')
38 |
39 | //config for only development
40 | if(process.env.NODE_ENV === 'development') {
41 | app.use(cors({
42 | origin: process.env.CLIENT_URL
43 | }))
44 |
45 | app.use(morgan('dev'))
46 | //Morgan give information about each request
47 | //Cors it's allow to deal with react for localhost at port 3000 without any problem
48 | }
49 | //Use Routes
50 | app.use('/api/',authRouter);
51 | app.use('/api', userRouter);
52 |
53 |
54 | //client-mail
55 | app.post('/api/smail', (req, res, next) => {
56 | sgMail.setApiKey(process.env.MAIL_KEY);
57 | //console.log(req.body)
58 | //console.log(req.body.z)
59 | const email = req.body.z
60 | const emailData = {
61 | to: email,
62 | from: process.env.EMAIL_FROM,
63 | fromname: 'SADG University',
64 | subject: 'Graduation Certificate',
65 | html: `
66 | Greetings from SADG University
67 |
68 | Hello ${req.body.y}
69 |
70 | This is your certificate id : ${req.body.x}
71 |
72 | Click here to view Certificate
73 |
74 | Management, Principal, Faculty Congratulates you
75 |
76 | We wish you All the Best for your Future Endeavours
77 | <
78 | `,
79 | };
80 |
81 | sgMail.send(emailData).then(sent => {
82 | return res.json({
83 | message: `Email has been sent to ${email}`
84 | });
85 | }).catch(err => {
86 | return res.status(400).json({
87 | success: false
88 | });
89 | });
90 |
91 | const tid = req.body.t
92 | const usn = req.body.u
93 | const cert_id = req.body.x
94 |
95 | console.log(tid)
96 |
97 | const certx = new transaction({
98 | usn,
99 | tid,
100 | email,
101 | cert_id
102 | });
103 |
104 | certx.save((err, certx) => {
105 | if (err) {
106 | console.log('Save error', errorHandler(err));
107 | return res.status(401).json({
108 | errors: errorHandler(err)
109 | });
110 | } else {
111 | return res.json({
112 | success: true,
113 | message: 'Transaction details sent!!',
114 | });
115 | }
116 | });
117 | })
118 |
119 | app.post('/api/idfetch', (req, res, next) => {
120 | const usn = req.body.id
121 | //console.log(usn)
122 | transaction.findOne({
123 | usn
124 | }).exec((err, tid) => {
125 | return res.send(tid)
126 | })
127 | });
128 |
129 | app.get('/api/getrapi', (req, res, next) => {
130 | return res.send(process.env.INFURA_API_KEY)
131 | });
132 |
133 | app.get('/api/rdefault', (req, res, next) => {
134 | return res.send(process.env.ROPSTEN_DEFAULT_ACCOUNT)
135 | });
136 |
137 |
138 |
139 | app.use((req, res, next) => {
140 | res.status(404).json({
141 | success: false,
142 | message: "Page not found"
143 | })
144 | });
145 | const PORT = process.env.PORT
146 |
147 | var listener = app.listen(PORT, function() {
148 | console.log(`App listening on port ${PORT}`); //Listening on port 8888
149 | });
--------------------------------------------------------------------------------