Browse Source

clean up, add `auth_as'

Daniel Brockman 4 years ago
parent
commit
03f9df9aa5
4 changed files with 59 additions and 95 deletions
  1. 2 2
      Dappfile
  2. 4 7
      README.md
  3. 36 67
      src/auth.sol
  4. 17 19
      src/auth.t.sol

+ 2 - 2
Dappfile

@@ -1,6 +1,6 @@
 name            ds-auth
-description     Basic authorization framework
-version         K99
+description     Simple access control pattern
+version         K75
 
 author          Nikolai Mushegian <nikolai@nexusdev.us>
 author          Daniel Brockman <daniel@brockman.se>

+ 4 - 7
README.md

@@ -6,21 +6,18 @@ The `DSAuth` mixin is a widely-used Ethereum access control pattern.
 The critical functionality is summarized by this part of the code:
 
     modifier auth {
-        if (!isAuthorized()) throw;
+        assert(isAuthorized(msg.sender, msg.sig));
         _;
     }
 
-    function isAuthorized() internal returns (bool) {
-        if (address(authority) == msg.sender) {
+    function isAuthorized(address src, bytes4 sig) internal returns (bool) {
+        if (src == address(authority)) {
             return true;
-        } else if (address(authority) == 0) {
-            return false;
         } else {
-            return authority.canCall(msg.sender, this, msg.sig);
+            return authority.canCall(src, this, sig);
         }
     }
 
-
 The `canCall` interface is defined on `DSIAuthority`:
 
     contract DSAuthority {

+ 36 - 67
src/auth.sol

@@ -1,45 +1,27 @@
-/*
-   Copyright 2016-2017 Nexus Development, LLC
+/// auth.sol -- widely-used access control pattern for Ethereum
 
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
+// Copyright (C) 2015, 2016, 2017  Nexus Development, LLC
 
-       http://www.apache.org/licenses/LICENSE-2.0
+// Licensed under the Apache License, Version 2.0 (the "License").
+// You may not use this file except in compliance with the License.
 
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND (express or implied).
 
 pragma solidity ^0.4.8;
 
-contract DSAuthEvents {
-    event LogSetAuthority (address indexed authority);
-}
-
-contract DSIAuth {
-    function setAuthority(DSIAuthority newAuthority);
-}
-
-// `DSAuthority` is the interface which `DSAuth`-derived objects expect
-// their authority to be when it is defined.
 contract DSIAuthority {
-    // `canCall` will be called with these arguments in the caller's
-    // scope if it is coming from an `auth` check (`isAuthorized` internal function):
-    // `DSAuthority(_ds_authority).canCall(msg.sender, address(this), msg.sig);`
-    function canCall( address caller
-                    , address code
-                    , bytes4 sig )
-             constant
-             returns (bool);
+    function canCall(
+        address src, address dst, bytes4 sig
+    ) constant returns (bool);
+}
 
-    function release(DSIAuth what);
+contract DSAuthEvents {
+    event LogSetAuthority(address indexed authority);
 }
 
-contract DSAuth is DSIAuth, DSAuthEvents {
+contract DSAuth is DSAuthEvents {
     DSIAuthority  public  authority;
 
     function DSAuth() {
@@ -47,54 +29,41 @@ contract DSAuth is DSIAuth, DSAuthEvents {
         LogSetAuthority(authority);
     }
 
-    function setAuthority(DSIAuthority newAuthority)
+    function setAuthority(address authority_)
         auth
     {
-        authority = newAuthority;
+        authority = DSIAuthority(authority_);
         LogSetAuthority(authority);
     }
 
     modifier auth {
-        if (!isAuthorized()) throw;
+        assert(isAuthorized(msg.sender, msg.sig));
         _;
     }
 
-    function isAuthorized() internal returns (bool)
-    {
-        if ( address(authority) == msg.sender ) {
+    modifier auth_as(string sig) {
+        assert(isAuthorized(msg.sender, bytes4(sha3(sig))));
+        _;
+    }
+
+    function isAuthorized(address src, bytes4 sig) internal returns (bool) {
+        if (src == address(authority)) {
             return true;
-        } else if ( address(authority) == 0 ) {
-            return false;
         } else {
-            // WARNING, this must throw if calling empty code. This is only works
-            // as of a recent compiler version. This is not clearly defined in 
-            // Solidity semantics so this behavior must have a dedicated test.
-            return authority.canCall(msg.sender, this, msg.sig);
+            // WARNING:
+            //
+            // This must throw if `authority' points to either (1) zero,
+            // or (2) an address which has no code attached to it.
+            //
+            // This is not clearly defined in the semantics of Solidity
+            // and only works as of a recent compiler version, so this
+            // behavior must be tested explicitly.
+            //
+            return authority.canCall(src, this, sig);
         }
     }
-}
 
-// An DSIAuthority implementation with standard `release`. 
-// TODO possible leave canCall undefined?
-contract DSAuthority is DSIAuthority
-                      , DSAuth
-{
-    // `canCall` will be called with these arguments in the caller's
-    // scope if it is coming from an `auth` check (`isAuthorized` internal function):
-    // `DSAuthority(_ds_authority).canCall(msg.sender, address(this), msg.sig);`
-    function canCall( address caller
-                    , address code
-                    , bytes4 sig )
-             constant
-             returns (bool)
-    {
-        return false;
-    }
-
-    function release(DSIAuth what)
-        auth
-    {
-        what.setAuthority(DSIAuthority(msg.sender));
+    function assert(bool x) {
+        if (!x) throw;
     }
 }
-

+ 17 - 19
src/auth.t.sol

@@ -19,13 +19,17 @@ contract FakeVault is DSAuth {
     function access() auth {}
 }
 
-contract BooleanAuthority is DSAuthority {
-    bool value;
-    function BooleanAuthority(bool _value) { value = _value; }
+contract BooleanAuthority is DSIAuthority {
+    bool yes;
+    
+    function BooleanAuthority(bool _yes) {
+        yes = _yes;
+    }
+    
     function canCall(
-        address caller, address code, bytes4 sig
+        address src, address dst, bytes4 sig
     ) constant returns (bool) {
-        return value;
+        return yes;
     }
 }
 
@@ -36,18 +40,18 @@ contract DSAuthTest is DSTest, DSAuthEvents {
     function test_owner() {
         expectEventsExact(vault);
         vault.access();
-        vault.setAuthority(DSAuthority(0));
-        LogSetAuthority(DSAuthority(0));
+        vault.setAuthority(0);
+        LogSetAuthority(0);
     }
 
     function testFail_non_owner_1() {
-        vault.setAuthority(DSAuthority(0));
+        vault.setAuthority(0);
         vault.access();
     }
 
     function testFail_non_owner_2() {
-        vault.setAuthority(DSAuthority(0));
-        vault.setAuthority(DSAuthority(0));
+        vault.setAuthority(0);
+        vault.setAuthority(0);
     }
 
     function test_accepting_authority() {    
@@ -57,20 +61,14 @@ contract DSAuthTest is DSTest, DSAuthEvents {
 
     function testFail_rejecting_authority_1() {
         vault.setAuthority(new BooleanAuthority(false));
-        vault.setAuthority(DSAuthority(0));
+        vault.setAuthority(0);
         vault.access();
     }
 
     function testFail_rejecting_authority_2() {
         vault.setAuthority(new BooleanAuthority(false));
-        vault.setAuthority(DSAuthority(0));
-        vault.setAuthority(DSAuthority(0));
-    }
-
-    function testFail_rejecting_authority_3() {
-        vault.setAuthority(new BooleanAuthority(false));
-        vault.setAuthority(DSAuthority(0));
-        vault.setAuthority(DSAuthority(0));
+        vault.setAuthority(0);
+        vault.setAuthority(0);
     }
 }