Skip to content

Commit 13d431a

Browse files
committed
feat: add adminAddRole, adminRemoveRole, and make hasRole/checkRole public
1 parent a92470f commit 13d431a

File tree

5 files changed

+85
-88
lines changed

5 files changed

+85
-88
lines changed

contracts/examples/RBACExample.sol

Lines changed: 0 additions & 61 deletions
This file was deleted.

contracts/ownership/rbac/RBAC.sol

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,23 @@ contract RBAC {
1717

1818
mapping (string => Roles.Role) internal roles;
1919

20+
event LogRoleAdded(address addr, string roleName);
21+
event LogRoleRemoved(address addr, string roleName);
22+
23+
/**
24+
* A constant role name for indicating admins.
25+
*/
26+
string public constant ROLE_ADMIN = "admin";
27+
28+
/**
29+
* @dev constructor. Sets msg.sender as admin by default
30+
*/
31+
function RBAC()
32+
public
33+
{
34+
addRole(msg.sender, ROLE_ADMIN);
35+
}
36+
2037
/**
2138
* @dev add a role to an address
2239
* @param addr address
@@ -26,6 +43,7 @@ contract RBAC {
2643
internal
2744
{
2845
roles[roleName].add(addr);
46+
LogRoleAdded(addr, roleName);
2947
}
3048

3149
/**
@@ -37,6 +55,7 @@ contract RBAC {
3755
internal
3856
{
3957
roles[roleName].remove(addr);
58+
LogRoleRemoved(addr, roleName);
4059
}
4160

4261
/**
@@ -47,7 +66,7 @@ contract RBAC {
4766
*/
4867
function checkRole(address addr, string roleName)
4968
view
50-
internal
69+
public
5170
{
5271
roles[roleName].check(addr);
5372
}
@@ -60,12 +79,37 @@ contract RBAC {
6079
*/
6180
function hasRole(address addr, string roleName)
6281
view
63-
internal
82+
public
6483
returns (bool)
6584
{
6685
return roles[roleName].has(addr);
6786
}
6887

88+
/**
89+
* @dev add a role to an address
90+
* @param addr address
91+
* @param roleName the name of the role
92+
*/
93+
function adminAddRole(address addr, string roleName)
94+
onlyAdmin
95+
public
96+
{
97+
addRole(addr, roleName);
98+
}
99+
100+
/**
101+
* @dev remove a role from an address
102+
* @param addr address
103+
* @param roleName the name of the role
104+
*/
105+
function adminRemoveRole(address addr, string roleName)
106+
onlyAdmin
107+
public
108+
{
109+
removeRole(addr, roleName);
110+
}
111+
112+
69113
/**
70114
* @dev modifier to scope access to a single role (uses msg.sender as addr)
71115
* @param roleName the name of the role
@@ -77,12 +121,22 @@ contract RBAC {
77121
_;
78122
}
79123

124+
/**
125+
* @dev modifier to scope access to admins
126+
* // reverts
127+
*/
128+
modifier onlyAdmin()
129+
{
130+
checkRole(msg.sender, ROLE_ADMIN);
131+
_;
132+
}
133+
80134
/**
81135
* @dev modifier to scope access to a set of roles (uses msg.sender as addr)
82136
* @param roleNames the names of the roles to scope access to
83137
* // reverts
84138
*
85-
* @TODO - when solidity supports dynamic arrays as arguments, provide this
139+
* @TODO - when solidity supports dynamic arrays as arguments to modifiers, provide this
86140
* see: https://github.com/ethereum/solidity/issues/2467
87141
*/
88142
// modifier onlyRoles(string[] roleNames) {

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/RBAC.js

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,39 +10,39 @@ contract('RBAC', function(accounts) {
1010
let mock
1111

1212
const [
13-
owner,
13+
admin,
1414
anyone,
1515
...advisors
1616
] = accounts
1717

1818
before(async () => {
19-
mock = await RBACMock.new(advisors, { from: owner })
19+
mock = await RBACMock.new(advisors, { from: admin })
2020
})
2121

2222
context('in normal conditions', () => {
23-
it('allows owner to call #onlyOwnersCanDoThis', async () => {
24-
await mock.onlyOwnersCanDoThis({ from: owner })
23+
it('allows admin to call #onlyAdminsCanDoThis', async () => {
24+
await mock.onlyAdminsCanDoThis({ from: admin })
2525
.should.be.fulfilled
2626
})
27-
it('allows owner to call #onlyAdvisorsCanDoThis', async () => {
28-
await mock.onlyAdvisorsCanDoThis({ from: owner })
27+
it('allows admin to call #onlyAdvisorsCanDoThis', async () => {
28+
await mock.onlyAdvisorsCanDoThis({ from: admin })
2929
.should.be.fulfilled
3030
})
3131
it('allows advisors to call #onlyAdvisorsCanDoThis', async () => {
3232
await mock.onlyAdvisorsCanDoThis({ from: advisors[0] })
3333
.should.be.fulfilled
3434
})
35-
it('allows owner to call #eitherOwnerOrAdvisorCanDoThis', async () => {
36-
await mock.eitherOwnerOrAdvisorCanDoThis({ from: owner })
35+
it('allows admin to call #eitherAdminOrAdvisorCanDoThis', async () => {
36+
await mock.eitherAdminOrAdvisorCanDoThis({ from: admin })
3737
.should.be.fulfilled
3838
})
39-
it('allows advisors to call #eitherOwnerOrAdvisorCanDoThis', async () => {
40-
await mock.eitherOwnerOrAdvisorCanDoThis({ from: advisors[0] })
39+
it('allows advisors to call #eitherAdminOrAdvisorCanDoThis', async () => {
40+
await mock.eitherAdminOrAdvisorCanDoThis({ from: advisors[0] })
4141
.should.be.fulfilled
4242
})
43-
it('does not allow owners to call #nobodyCanDoThis', async () => {
43+
it('does not allow admins to call #nobodyCanDoThis', async () => {
4444
expectThrow(
45-
mock.nobodyCanDoThis({ from: owner })
45+
mock.nobodyCanDoThis({ from: admin })
4646
)
4747
})
4848
it('does not allow advisors to call #nobodyCanDoThis', async () => {
@@ -55,8 +55,12 @@ contract('RBAC', function(accounts) {
5555
mock.nobodyCanDoThis({ from: anyone })
5656
)
5757
})
58-
it('allows an owner to remove an advisor\'s role', async () => {
59-
await mock.removeAdvisor(advisors[0], { from: owner })
58+
it('allows an admin to remove an advisor\'s role', async () => {
59+
await mock.removeAdvisor(advisors[0], { from: admin })
60+
.should.be.fulfilled
61+
})
62+
it('allows admins to #adminRemoveRole', async () => {
63+
await mock.adminRemoveRole(advisors[3], 'advisor', { from: admin })
6064
.should.be.fulfilled
6165
})
6266
})

test/helpers/RBACMock.sol

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import '../../contracts/ownership/rbac/RBAC.sol';
55

66
contract RBACMock is RBAC {
77

8-
modifier onlyOwnerOrAdvisor()
8+
modifier onlyAdminOrAdvisor()
99
{
1010
require(
11-
hasRole(msg.sender, "owner") ||
11+
hasRole(msg.sender, "admin") ||
1212
hasRole(msg.sender, "advisor")
1313
);
1414
_;
@@ -17,16 +17,16 @@ contract RBACMock is RBAC {
1717
function RBACMock(address[] _advisors)
1818
public
1919
{
20-
addRole(msg.sender, "owner");
20+
addRole(msg.sender, "admin");
2121
addRole(msg.sender, "advisor");
2222

2323
for (uint256 i = 0; i < _advisors.length; i++) {
2424
addRole(_advisors[i], "advisor");
2525
}
2626
}
2727

28-
function onlyOwnersCanDoThis()
29-
onlyRole("owner")
28+
function onlyAdminsCanDoThis()
29+
onlyRole("admin")
3030
view
3131
external
3232
{
@@ -39,8 +39,8 @@ contract RBACMock is RBAC {
3939
{
4040
}
4141

42-
function eitherOwnerOrAdvisorCanDoThis()
43-
onlyOwnerOrAdvisor
42+
function eitherAdminOrAdvisorCanDoThis()
43+
onlyAdminOrAdvisor
4444
view
4545
external
4646
{
@@ -53,9 +53,9 @@ contract RBACMock is RBAC {
5353
{
5454
}
5555

56-
// owners can remove advisor's role
56+
// admins can remove advisor's role
5757
function removeAdvisor(address _addr)
58-
onlyRole("owner")
58+
onlyAdmin
5959
public
6060
{
6161
// revert if the user isn't an advisor

0 commit comments

Comments
 (0)