Untitled
unknown
plain_text
2 years ago
10 kB
2
Indexable
//SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; import "hardhat/console.sol"; //A shared struct inherited by both Data usage and Agreement smart contract contract SharedStructs { struct Service { address actorID; string serviceName; string servicePurpose; string operation; string[] personalData; } } contract DataUsage is SharedStructs { mapping(address => Service[]) public services; address[] public actorAddresses; function addService(string memory _serviceName, string memory _servicePurpose, string memory _operation, string[] memory _personalData) public { Service memory newService = Service(msg.sender, _serviceName, _servicePurpose, _operation, _personalData); services[msg.sender].push(newService); bool actorExists = false; for (uint256 i = 0; i < actorAddresses.length; i++) { if (actorAddresses[i] == msg.sender) { actorExists = true; break; } } if (!actorExists) { actorAddresses.push(msg.sender); } } function getService(address _actorID, uint256 index) public view returns (Service memory) { require(index < services[_actorID].length, "Index out of bounds"); return services[_actorID][index]; } function getServicesCount(address _actorID) public view returns (uint256) { return services[_actorID].length; } function getActorAddressesCount() public view returns (uint256) { return actorAddresses.length; } } // 'Banking Transactions', 'Banking Services', 'Write', ['Account Number', 'Transaction History'] 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db // 'Financial Transactions', 'Financial Services', 'Read', ['Phone Number', 'Account History'] 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db // 'Medical Transactions', 'Financial Services', 'Transfer', ['Phone Number', 'Account History'] 0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB //0xc5075f64488d32a067f76bd1d177b5376e72e8a9e3f0fb2395c1014b928d0181, 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db, 'Write', ['Account Number', 'Transaction History'], true //0x5B38Da6a701c568545dCfcB03FcB875f56beddC4 //0xc5075f64488d32a067f76bd1d177b5376e72e8a9e3f0fb2395c1014b928d0181, 0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB, 'Read', ['Phone Number', 'Account History'], true //0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db, 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4, 'Write', ['Account Number', 'Transaction History'], 'Banking Services' //0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB, 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4, 'Transfer', ['Phone Number', 'Account History'], 'Medical Services' contract Agreement is SharedStructs { struct Consent { bytes32 purposeHash; address actorID; string operation; string[] personalData; address userId; string serviceName; bool isPositive; } event LogServiceParams( address indexed actorID, string serviceName, string servicePurpose, string operation, string[] personalData ); mapping(address => mapping(address => Consent[])) public consents; function giveConsent(bytes32 _purposeHash, address _actorID, string memory _operation, string[] memory _personalData, string memory _serviceName, bool _isPositive) public { Consent memory newConsent = Consent(_purposeHash, _actorID, _operation, _personalData, msg.sender, _serviceName, _isPositive); consents[_actorID][msg.sender].push(newConsent); } function getConsents(address actorID, address userId) public view returns (Consent[] memory) { return consents[actorID][userId]; } function callGetService(address dataUsageContractAddress) public { DataUsage dataUsage = DataUsage(dataUsageContractAddress); uint256 numActors = dataUsage.getActorAddressesCount(); for (uint256 i = 0; i < numActors; i++) { address actorAddress = dataUsage.actorAddresses(i); uint256 numServices = dataUsage.getServicesCount(actorAddress); for (uint256 j = 0; j < numServices; j++) { Service memory service = dataUsage.getService(actorAddress, j); emit LogServiceParams( service.actorID, service.serviceName, service.servicePurpose, service.operation, service.personalData ); } } } } contract Log { struct LogEntry { address actorId; address userId; string operation; string[] processedData; string serviceName; } mapping(uint256 => LogEntry) public logEntries; uint256 public entryCount; function addLogEntry(address _actorId, address _userId, string memory _operation, string[] memory _processedData, string memory _serviceName) public { LogEntry memory newEntry = LogEntry(_actorId, _userId, _operation, _processedData, _serviceName); logEntries[entryCount] = newEntry; entryCount++; } function getLogEntry(uint256 index) public view returns (LogEntry memory) { return logEntries[index]; } } contract Verification { DataUsage dataUsage; Agreement agreement; Log log; constructor(address _dataUsageAddress, address _agreementAddress, address _logAddress) { dataUsage = DataUsage(_dataUsageAddress); agreement = Agreement(_agreementAddress); log = Log(_logAddress); } function checkLog() public view returns (address[] memory){ uint256 numActors = dataUsage.getActorAddressesCount(); uint256 numLogEntries = log.entryCount(); address[] memory violatingActors = new address[](numLogEntries); uint256 violatingCount = 0; //Iterating through log entries for (uint256 i = 0; i < numLogEntries; i++) { Log.LogEntry memory logEntry = log.getLogEntry(i); bool consentFound = false; //Iterating through actor count for (uint16 j = 0; j < numActors; j++) { address actorAddress = dataUsage.actorAddresses(j); Agreement.Consent[] memory userConsents = agreement.getConsents(actorAddress, logEntry.userId); //Iterating through user consent (actoraddress, index) for (uint16 k = 0; k < userConsents.length; k++) { Agreement.Consent memory consent = userConsents[k]; // Check if the serviceName in Consent and LogEntry are the same if (keccak256(abi.encodePacked(logEntry.serviceName)) == keccak256(abi.encodePacked(consent.serviceName))) { // verification contract - 1 if (logEntry.actorId == consent.actorID) { SharedStructs.Service memory service = dataUsage.getService(actorAddress, k); // verification contract - 2, 3 if (keccak256(abi.encodePacked(logEntry.operation)) == keccak256(abi.encodePacked(service.operation)) && keccak256(abi.encodePacked(logEntry.operation)) == keccak256(abi.encodePacked(consent.operation)) && isSubset(logEntry.processedData, consent.personalData)) { // break from the inner loop once a matching consent is found. consentFound = true; break; } } } } } if (!consentFound) { violatingActors[violatingCount] = logEntry.actorId; violatingCount++; } } //creating a new array that will store the address of the violating actors address[] memory result; //If no violations, print to console "no violations found" and return an empty array if (violatingCount == 0) { console.log("No violations found!"); return new address[](0); } else { console.log("Violations found!"); // Creating a temporary array to store unique addresses address[] memory uniqueAddresses = new address[](violatingCount); // Counting the number of unique addresses uint uniqueCount = 0; // Iterating through the violatingActors array and counting unique addresses for (uint i = 0; i < violatingCount; i++) { bool isNewAddress = true; for (uint j = 0; j < uniqueCount; j++) { if (uniqueAddresses[j] == violatingActors[i]) { isNewAddress = false; break; } } if (isNewAddress) { uniqueAddresses[uniqueCount] = violatingActors[i]; uniqueCount++; } } // Creating a new array with the size of unique addresses result = new address[](uniqueCount); // Appending the unique addresses to the result array for (uint i = 0; i < uniqueCount; i++) { result[i] = uniqueAddresses[i]; } console.log("The violating actors are:"); for (uint i = 0; i < result.length; i++) { console.log(result[i]); } return result; } } //verification contract-3, check if the processed personal data is a subset of consented personal data function isSubset(string[] memory subset, string[] memory superset) private pure returns (bool) { for (uint256 i = 0; i < subset.length; i++) { bool found = false; for (uint256 j = 0; j < superset.length; j++) { if (keccak256(abi.encodePacked(subset[i])) == keccak256(abi.encodePacked(superset[j]))) { found = true; break; } } if (!found) { return false; } } return true; } }
Editor is loading...