-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
19 changed files
with
7,898 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
*.sol linguist-language=Solidity |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
build/ | ||
.tern-port | ||
.DS_Store | ||
node_modules/ | ||
.idea/ | ||
|
||
*.log | ||
*.bac | ||
coverage.json | ||
coverage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
module.exports = { | ||
copyNodeModules: true, | ||
skipFiles: [ | ||
'Migrations.sol', | ||
'helpers/StubStorageManager.sol' | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
sudo: required | ||
dist: trusty | ||
language: node_js | ||
node_js: | ||
- '9' | ||
before_install: | ||
- export NODE_OPTIONS="--max_old_space_size=4096" | ||
- export PATH=$PATH:$(pwd)/node_modules/.bin | ||
install: | ||
- npm install | ||
script: | ||
- npm test | ||
before_script: | ||
- ganache-cli > /dev/null & | ||
- sleep 5 | ||
after_script: | ||
- travis_wait 30 npm run coverage && cat coverage/lcov.info | coveralls |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
# solidity-roles-lib | ||
# solidity-roles-lib [![Build Status](https://travis-ci.org/ChronoBank/solidity-roles-lib.svg?branch=master)](https://travis-ci.org/ChronoBank/solidity-roles-lib) [![Coverage Status](https://coveralls.io/repos/github/ChronoBank/solidity-roles-lib/badge.svg?branch=master)](https://coveralls.io/github/ChronoBank/solidity-roles-lib?branch=master) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
const errorScope = { | ||
roles: 20000 | ||
} | ||
|
||
const errorCodes = { | ||
UNAUTHORIZED: 0, | ||
OK: 1, | ||
|
||
ROLES_ALREADY_EXISTS: errorScope.roles + 1, | ||
ROLES_INVALID_INVOCATION: errorScope.roles + 2, | ||
ROLES_NOT_FOUND: errorScope.roles + 3 | ||
} | ||
|
||
module.exports = errorCodes |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
pragma solidity ^0.4.23; | ||
|
||
|
||
// Provided by Truffle. | ||
contract Migrations { | ||
address public owner; | ||
uint public last_completed_migration; | ||
|
||
modifier restricted() { | ||
if (msg.sender == owner) _; | ||
} | ||
|
||
constructor() public { | ||
owner = msg.sender; | ||
} | ||
|
||
function setCompleted(uint completed) restricted public { | ||
last_completed_migration = completed; | ||
} | ||
|
||
function upgrade(address new_address) restricted public { | ||
Migrations upgraded = Migrations(new_address); | ||
upgraded.setCompleted(last_completed_migration); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,223 @@ | ||
/** | ||
* Copyright 2017–2018, LaborX PTY | ||
* Licensed under the AGPL Version 3 license. | ||
*/ | ||
|
||
pragma solidity ^0.4.21; | ||
|
||
import 'solidity-storage-lib/contracts/StorageAdapter.sol'; | ||
import 'solidity-shared-lib/contracts/Owned.sol'; | ||
|
||
|
||
contract Roles2Library is StorageAdapter, Owned { | ||
|
||
uint constant OK = 1; | ||
|
||
uint constant ROLES_SCOPE = 20000; | ||
uint constant ROLES_ALREADY_EXISTS = ROLES_SCOPE + 1; | ||
uint constant ROLES_INVALID_INVOCATION = ROLES_SCOPE + 2; | ||
uint constant ROLES_NOT_FOUND = ROLES_SCOPE + 3; | ||
|
||
event Error(address indexed self, uint errorCode); | ||
event RoleAdded(address indexed self, address indexed user, uint8 indexed role); | ||
event RoleRemoved(address indexed self, address indexed user, uint8 indexed role); | ||
event CapabilityAdded(address indexed self, address indexed code, bytes4 sig, uint8 indexed role); | ||
event CapabilityRemoved(address indexed self, address indexed code, bytes4 sig, uint8 indexed role); | ||
event PublicCapabilityAdded(address indexed self, address indexed code, bytes4 sig); | ||
event PublicCapabilityRemoved(address indexed self, address indexed code, bytes4 sig); | ||
|
||
StorageInterface.AddressBoolMapping rootUsers; | ||
StorageInterface.AddressBytes32Mapping userRoles; | ||
StorageInterface.AddressBytes4Bytes32Mapping capabilityRoles; | ||
StorageInterface.AddressBytes4BoolMapping publicCapabilities; | ||
|
||
address public eventsHistory; | ||
|
||
modifier authorized { | ||
if (msg.sender != contractOwner && !canCall(msg.sender, this, msg.sig)) { | ||
return; | ||
} | ||
_; | ||
} | ||
|
||
constructor(Storage _store, bytes32 _crate) StorageAdapter(_store, _crate) public { | ||
rootUsers.init('rootUsers'); | ||
userRoles.init('userRoles'); | ||
capabilityRoles.init('capabilityRoles'); | ||
publicCapabilities.init('publicCapabilities'); | ||
} | ||
|
||
function setupEventsHistory(address _eventsHistory) onlyContractOwner external returns (uint) { | ||
eventsHistory = _eventsHistory; | ||
} | ||
|
||
function getEventsHistory() public view returns (address) { | ||
return eventsHistory != address(0) ? eventsHistory : address(this); | ||
} | ||
|
||
function getUserRoles(address _user) public view returns (bytes32) { | ||
return store.get(userRoles, _user); | ||
} | ||
|
||
function getCapabilityRoles(address _code, bytes4 _sig) public view returns (bytes32) { | ||
return store.get(capabilityRoles, _code, _sig); | ||
} | ||
|
||
function canCall(address _user, address _code, bytes4 _sig) public view returns (bool) { | ||
if (isUserRoot(_user) || isCapabilityPublic(_code, _sig)) { | ||
return true; | ||
} | ||
return bytes32(0) != getUserRoles(_user) & getCapabilityRoles(_code, _sig); | ||
} | ||
|
||
function bitNot(bytes32 _input) public pure returns (bytes32) { | ||
return (_input ^ bytes32(uint(-1))); | ||
} | ||
|
||
function setRootUser(address _user, bool _enabled) onlyContractOwner external returns (uint) { | ||
store.set(rootUsers, _user, _enabled); | ||
return OK; | ||
} | ||
|
||
function addUserRole(address _user, uint8 _role) authorized external returns (uint) { | ||
if (hasUserRole(_user, _role)) { | ||
return _emitErrorCode(ROLES_ALREADY_EXISTS); | ||
} | ||
|
||
return _setUserRole(_user, _role, true); | ||
} | ||
|
||
function removeUserRole(address _user, uint8 _role) authorized external returns (uint) { | ||
if (!hasUserRole(_user, _role)) { | ||
return _emitErrorCode(ROLES_NOT_FOUND); | ||
} | ||
|
||
return _setUserRole(_user, _role, false); | ||
} | ||
|
||
function setPublicCapability(address _code, bytes4 _sig, bool _enabled) onlyContractOwner external returns (uint) { | ||
store.set(publicCapabilities, _code, _sig, _enabled); | ||
|
||
if (_enabled) { | ||
_emitPublicCapabilityAdded(_code, _sig); | ||
} else { | ||
_emitPublicCapabilityRemoved(_code, _sig); | ||
} | ||
return OK; | ||
} | ||
|
||
function addRoleCapability(uint8 _role, address _code, bytes4 _sig) onlyContractOwner public returns (uint) { | ||
return _setRoleCapability(_role, _code, _sig, true); | ||
} | ||
|
||
function removeRoleCapability(uint8 _role, address _code, bytes4 _sig) onlyContractOwner public returns (uint) { | ||
if (getCapabilityRoles(_code, _sig) == 0) { | ||
return _emitErrorCode(ROLES_NOT_FOUND); | ||
} | ||
|
||
return _setRoleCapability(_role, _code, _sig, false); | ||
} | ||
|
||
function isUserRoot(address _user) public view returns (bool) { | ||
return store.get(rootUsers, _user); | ||
} | ||
|
||
function isCapabilityPublic(address _code, bytes4 _sig) public view returns (bool) { | ||
return store.get(publicCapabilities, _code, _sig); | ||
} | ||
|
||
function hasUserRole(address _user, uint8 _role) public view returns (bool) { | ||
return bytes32(0) != getUserRoles(_user) & _shift(_role); | ||
} | ||
|
||
function _setUserRole(address _user, uint8 _role, bool _enabled) internal returns (uint) { | ||
bytes32 lastRoles = getUserRoles(_user); | ||
bytes32 shifted = _shift(_role); | ||
|
||
if (_enabled) { | ||
store.set(userRoles, _user, lastRoles | shifted); | ||
_emitRoleAdded(_user, _role); | ||
return OK; | ||
} | ||
|
||
store.set(userRoles, _user, lastRoles & bitNot(shifted)); | ||
_emitRoleRemoved(_user, _role); | ||
return OK; | ||
} | ||
|
||
function _setRoleCapability(uint8 _role, address _code, bytes4 _sig, bool _enabled) internal returns (uint) { | ||
bytes32 lastRoles = getCapabilityRoles(_code, _sig); | ||
bytes32 shifted = _shift(_role); | ||
|
||
if (_enabled) { | ||
store.set(capabilityRoles, _code, _sig, lastRoles | shifted); | ||
_emitCapabilityAdded(_code, _sig, _role); | ||
} else { | ||
store.set(capabilityRoles, _code, _sig, lastRoles & bitNot(shifted)); | ||
_emitCapabilityRemoved(_code, _sig, _role); | ||
} | ||
|
||
return OK; | ||
} | ||
|
||
function _shift(uint8 _role) pure internal returns (bytes32) { | ||
return bytes32(uint(uint(2) ** uint(_role))); | ||
} | ||
|
||
function _emitErrorCode(uint _errorCode) internal returns (uint) { | ||
Roles2Library(getEventsHistory()).emitError(_errorCode); | ||
return _errorCode; | ||
} | ||
|
||
function _emitRoleAdded(address _user, uint8 _role) internal { | ||
Roles2Library(getEventsHistory()).emitRoleAdded(_user, _role); | ||
} | ||
|
||
function _emitRoleRemoved(address _user, uint8 _role) internal { | ||
Roles2Library(getEventsHistory()).emitRoleRemoved(_user, _role); | ||
} | ||
|
||
function _emitCapabilityAdded(address _code, bytes4 _sig, uint8 _role) internal { | ||
Roles2Library(getEventsHistory()).emitCapabilityAdded(_code, _sig, _role); | ||
} | ||
|
||
function _emitCapabilityRemoved(address _code, bytes4 _sig, uint8 _role) internal { | ||
Roles2Library(getEventsHistory()).emitCapabilityRemoved(_code, _sig, _role); | ||
} | ||
|
||
function _emitPublicCapabilityAdded(address _code, bytes4 _sig) internal { | ||
Roles2Library(getEventsHistory()).emitPublicCapabilityAdded(_code, _sig); | ||
} | ||
|
||
function _emitPublicCapabilityRemoved(address _code, bytes4 _sig) internal { | ||
Roles2Library(getEventsHistory()).emitPublicCapabilityRemoved(_code, _sig); | ||
} | ||
|
||
function emitError(uint _errorCode) public { | ||
emit Error(msg.sender, _errorCode); | ||
} | ||
|
||
function emitRoleAdded(address _user, uint8 _role) public { | ||
emit RoleAdded(msg.sender, _user, _role); | ||
} | ||
|
||
function emitRoleRemoved(address _user, uint8 _role) public { | ||
emit RoleRemoved(msg.sender, _user, _role); | ||
} | ||
|
||
function emitCapabilityAdded(address _code, bytes4 _sig, uint8 _role) public { | ||
emit CapabilityAdded(msg.sender, _code, _sig, _role); | ||
} | ||
|
||
function emitCapabilityRemoved(address _code, bytes4 _sig, uint8 _role) public { | ||
emit CapabilityRemoved(msg.sender, _code, _sig, _role); | ||
} | ||
|
||
function emitPublicCapabilityAdded(address _code, bytes4 _sig) public { | ||
emit PublicCapabilityAdded(msg.sender, _code, _sig); | ||
} | ||
|
||
function emitPublicCapabilityRemoved(address _code, bytes4 _sig) public { | ||
emit PublicCapabilityRemoved(msg.sender, _code, _sig); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/** | ||
* Copyright 2017–2018, LaborX PTY | ||
* Licensed under the AGPL Version 3 license. | ||
*/ | ||
|
||
pragma solidity ^0.4.18; | ||
|
||
|
||
contract Roles2LibraryInterface { | ||
function addUserRole(address _user, uint8 _role) public returns (uint); | ||
function canCall(address _src, address _code, bytes4 _sig) public view returns (bool); | ||
} | ||
|
||
|
||
contract Roles2LibraryAdapter { | ||
|
||
uint constant UNAUTHORIZED = 0; | ||
uint constant OK = 1; | ||
|
||
event AuthFailedError(address code, address sender, bytes4 sig); | ||
|
||
Roles2LibraryInterface roles2Library; | ||
|
||
modifier auth { | ||
if (!_isAuthorized(msg.sender, msg.sig)) { | ||
emit AuthFailedError(this, msg.sender, msg.sig); | ||
return; | ||
} | ||
_; | ||
} | ||
|
||
constructor(address _roles2Library) public { | ||
roles2Library = Roles2LibraryInterface(_roles2Library); | ||
} | ||
|
||
function setRoles2Library(Roles2LibraryInterface _roles2Library) auth external returns (uint) { | ||
roles2Library = _roles2Library; | ||
return OK; | ||
} | ||
|
||
function _isAuthorized(address _src, bytes4 _sig) internal view returns (bool) { | ||
if (_src == address(this)) { | ||
return true; | ||
} | ||
if (address(roles2Library) == 0) { | ||
return false; | ||
} | ||
|
||
return roles2Library.canCall(_src, this, _sig); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
pragma solidity ^0.4.23; | ||
|
||
|
||
contract StubStorageManager { | ||
function isAllowed(address _actor, bytes32 _role) public view returns (bool) { | ||
return true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
var Migrations = artifacts.require("./Migrations.sol"); | ||
|
||
module.exports = function(deployer,network) { | ||
deployer.deploy(Migrations); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
const Storage = artifacts.require('Storage') | ||
const StubStorageManager = artifacts.require('StubStorageManager') | ||
const Roles2Library = artifacts.require('Roles2Library') | ||
|
||
module.exports = function(deployer, network) { | ||
if (network === 'development') { | ||
deployer.then(async () => { | ||
await deployer.deploy(Storage) | ||
await deployer.deploy(StubStorageManager) | ||
|
||
const storage = await Storage.deployed() | ||
await storage.setManager(StubStorageManager.address) | ||
|
||
await deployer.deploy(Roles2Library, Storage.address, "Roles2Library") | ||
|
||
console.log("[MIGRATION] Test contracts: #done") | ||
}) | ||
} | ||
} |
Oops, something went wrong.