+ Student Listing
+ Issuer Listing
+ Back
+
+
+
+
\ No newline at end of file
diff --git a/bs-config.json b/bs-config.json
new file mode 100644
index 0000000..b71247e
--- /dev/null
+++ b/bs-config.json
@@ -0,0 +1,4 @@
+{
+ "port": 80,
+ "open": false
+}
\ No newline at end of file
diff --git a/certificate.html b/certificate.html
new file mode 100644
index 0000000..b5c5b71
--- /dev/null
+++ b/certificate.html
@@ -0,0 +1,38 @@
+
+
+
+ Create Certificate
+
+
+
+
+
+
+
Create Certificate
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/contracts/Master.sol b/contracts/Master.sol
new file mode 100644
index 0000000..7fa9f6f
--- /dev/null
+++ b/contracts/Master.sol
@@ -0,0 +1,238 @@
+pragma solidity ^0.4.23;
+
+contract Master {
+
+ struct Certificate {
+ address student;
+ address issuer;
+ string courseTitle;
+ string completionDate;
+ string expiryDate;
+ }
+
+ struct Student {
+ string name;
+ }
+
+ struct Issuer {
+ string issuerName;
+ string logoUrl;
+ string issuerAddress;
+ }
+
+ mapping (address => Student) private students;
+ address[] private studentAddresses;
+
+ mapping (address => Issuer) private issuers;
+ address[] private issuerAddresses;
+
+ Certificate[] private certificates;
+
+ address private adminOwner;
+
+ constructor() public {
+ adminOwner = msg.sender;
+ }
+
+ // create new student (admin)
+ function createStudent(address _address, string _name) public {
+
+ // Check current user is admin
+ require(adminOwner == msg.sender);
+
+ // Check if account already exists
+ validateAddress(_address);
+
+ // Add a new student contract to students map
+ students[_address] = Student({
+ name: _name
+ });
+
+ // Add the address to studentAddresses array
+ studentAddresses.push(_address);
+ }
+
+ function listStudentAddresses() public view returns (address[]) {
+
+ return studentAddresses;
+ }
+
+ function listIssuerAddresses() public view returns (address[]) {
+
+ return issuerAddresses;
+ }
+
+ function getStudentName(address _address) public view returns (string) {
+
+ for (uint count = 0; count < studentAddresses.length; count++) {
+ if (studentAddresses[count] == _address) {
+ return students[_address].name;
+ }
+ }
+
+ revert();
+ }
+
+ function getIssuerName(address _address) public view returns (string) {
+
+ for (uint count = 0; count < issuerAddresses.length; count++) {
+ if (issuerAddresses[count] == _address) {
+ return issuers[_address].issuerName;
+ }
+ }
+
+ revert();
+ }
+
+ function getIssuerDetails(address _address) public view returns (string, string, string) {
+
+ for (uint count = 0; count < issuerAddresses.length; count++) {
+ if (issuerAddresses[count] == _address) {
+ Issuer storage issuer = issuers[_address];
+ return (issuer.issuerName, issuer.logoUrl, issuer.issuerAddress);
+ }
+ }
+
+ revert();
+ }
+
+ // create new issuer (admin)
+ function createIssuer(address _address, string _name, string _issuerAddress, string _logoUrl) public {
+
+ // Check current user is admin
+ require(adminOwner == msg.sender);
+
+ // Check if account already exists
+ validateAddress(_address);
+
+ // Add a new issuer contract to issuers map
+ issuers[_address] = Issuer({
+ issuerName: _name,
+ issuerAddress: _issuerAddress,
+ logoUrl: _logoUrl
+ });
+
+ // Add the address to issuerAddresses array
+ issuerAddresses.push(_address);
+ }
+
+ function validateAddress(address _address) view private {
+
+ // Check if account already exists
+ for (uint count = 0; count < studentAddresses.length; count++) {
+ if (studentAddresses[count] == _address) {
+ revert();
+ }
+ }
+
+ for (count = 0; count < issuerAddresses.length; count++) {
+ if (issuerAddresses[count] == _address) {
+ revert();
+ }
+ }
+
+ if (_address == adminOwner) {
+ revert();
+ }
+ }
+
+ // create new certificate (issuer)
+ function createCertificate(address student, string courseTitle, string completionDate, string expiryDate) public {
+
+ for (uint studentCount = 0; studentCount < studentAddresses.length; studentCount++) {
+ if (studentAddresses[studentCount] == student) {
+ for (uint issuerCount = 0; issuerCount < issuerAddresses.length; issuerCount++) {
+ if (issuerAddresses[issuerCount] == msg.sender) {
+ certificates.push(Certificate({
+ student: student,
+ issuer: msg.sender,
+ courseTitle: courseTitle,
+ completionDate: completionDate,
+ expiryDate: expiryDate
+ }));
+ return;
+ }
+ }
+ }
+ }
+
+ revert();
+ }
+
+ // Verify a certificate
+ function verifyCertificate(address student, address issuer, string courseTitle) public view returns (uint) {
+
+ for (uint count = 0; count < certificates.length; count++) {
+ Certificate storage certificate = certificates[count];
+ if (certificate.student == student && certificate.issuer == issuer && equal(certificate.courseTitle, courseTitle)) {
+ return count + 1;
+ }
+ }
+
+ // validate expiry date
+
+ return 0;
+ }
+
+ // Student to query his/her own certificates
+ function getStudentCertificates() public view returns (uint[]) {
+
+ uint[] memory studentCertificates = new uint[](certificates.length);
+ uint index = 0;
+ for (uint count = 0; count < certificates.length; count++) {
+ if (certificates[count].student == msg.sender) {
+ studentCertificates[index++] = count;
+ }
+ }
+ return studentCertificates;
+ }
+
+ // Issuer to query issued certificates
+ function getIssuerCertificates() public view returns (uint[]) {
+
+ uint[] memory issuedCertificates = new uint[](certificates.length);
+ uint index = 0;
+ for (uint count = 0; count < certificates.length; count++) {
+ if (certificates[count].issuer == msg.sender) {
+ issuedCertificates[index++] = count;
+ }
+ }
+ return issuedCertificates;
+ }
+
+ function getCertificateDetails(uint index) public view returns (string, string, string, string, string) {
+
+ require(index < certificates.length);
+ Certificate storage certificate = certificates[index];
+ return (issuers[certificate.issuer].issuerName, students[certificate.student].name, certificate.courseTitle, certificate.completionDate, certificate.expiryDate);
+ }
+
+ function compare(string _a, string _b) private pure returns (int) {
+
+ bytes memory a = bytes(_a);
+ bytes memory b = bytes(_b);
+ uint minLength = a.length;
+ if (b.length < minLength) minLength = b.length;
+ for (uint i = 0; i < minLength; i ++)
+ if (a[i] < b[i])
+ return -1;
+ else if (a[i] > b[i])
+ return 1;
+ if (a.length < b.length)
+ return -1;
+ else if (a.length > b.length)
+ return 1;
+ else
+ return 0;
+ }
+
+ function equal(string _a, string _b) private pure returns (bool) {
+
+ return compare(_a, _b) == 0;
+ }
+
+ // edit new student (admin / student)
+ // edit new issuer (admin / issuer)
+ // revoke new certificate (issuer)
+
+}
\ No newline at end of file
diff --git a/deploy-contract.js b/deploy-contract.js
new file mode 100644
index 0000000..c47dfb9
--- /dev/null
+++ b/deploy-contract.js
@@ -0,0 +1,33 @@
+console.log('Deploy started on ' + new Date());
+console.log('Loading libraries');
+
+var fs = require('fs');
+var Web3 = require('web3');
+var solc = require('solc');
+var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
+
+console.log('Compiling Solidity contracts');
+
+var compiled = solc.compile(fs.readFileSync('contracts/Master.sol').toString());
+var abiDefinition = compiled.contracts[':Master'].interface;
+console.log('ABI Definition: ' + abiDefinition);
+
+var byteCode = compiled.contracts[':Master'].bytecode;
+var estimatedGas = web3.eth.estimateGas({data: byteCode});
+console.log('Deploying contracts using estimated gas ' + estimatedGas);
+
+var contract = web3.eth.contract(JSON.parse(abiDefinition)).new(null, {data: byteCode, from: web3.eth.accounts[0], gas: estimatedGas});
+
+new Promise((resolve) => setTimeout(resolve, 1000)).then(() => {
+
+ console.log('Contract address: ' + contract.address);
+ console.log('Writing dummy data');
+ console.log('Creating issuer');
+ contract.createIssuer(web3.eth.accounts[1], 'HKU', 'Pokfulam Road, HK', 'http://avuou.hku.hk/guestpage/HKUbw2.gif', {from: web3.eth.accounts[0], gas: contract.createIssuer.estimateGas(web3.eth.accounts[1], 'HKU', 'Pokfulam Road, HK', 'http://avuou.hku.hk/guestpage/HKUbw2.gif')});
+ console.log('Creating student');
+ contract.createStudent(web3.eth.accounts[2], 'Simon Chan', {from: web3.eth.accounts[0], gas: contract.createStudent.estimateGas(web3.eth.accounts[2], 'Simon Chan')});
+ console.log('Creating certificate');
+ web3.eth.defaultAccount = web3.eth.accounts[1];
+ contract.createCertificate(web3.eth.accounts[2], 'Introduction to Blockchain', '2018-07-01', '2028-08-31', {from: web3.eth.accounts[1], gas: contract.createCertificate.estimateGas(web3.eth.accounts[2], 'Introduction to Blockchain', '2018-07-01', '2028-08-31')});
+ console.log('Deploy complete at ' + new Date());
+});
\ No newline at end of file
diff --git a/images/cert-template.gif b/images/cert-template.gif
new file mode 100644
index 0000000..daf2eb3
Binary files /dev/null and b/images/cert-template.gif differ
diff --git a/images/certificate.ico b/images/certificate.ico
new file mode 100644
index 0000000..fee78c3
Binary files /dev/null and b/images/certificate.ico differ
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..168a76c
--- /dev/null
+++ b/index.html
@@ -0,0 +1,20 @@
+
+
+
+ Certificate Blockchain Apps
+
+
+
+
+
+
+
Welcome to Certificate Blockchain Apps
+
+ Verify Certificate
+ I am a student
+ I am an issuer
+ I am the administrator
+
+
+
+
\ No newline at end of file
diff --git a/issuer-certificates.html b/issuer-certificates.html
new file mode 100644
index 0000000..084efb7
--- /dev/null
+++ b/issuer-certificates.html
@@ -0,0 +1,57 @@
+
+
+
+ Issued Certificates
+
+
+
+
+
+
+
+
+
+