Capability.php
Current file: /Users/kevin/code/twilio-php/Services/Twilio/Capability.php
Legend: executed not executed dead code

  Coverage
  Classes Functions / Methods Lines
Total
0.00% 0 / 3
58.82% 10 / 17 CRAP
70.59% 84 / 119
Services_Twilio_Capability
0.00% 0 / 1
83.33% 5 / 6 11.02
94.74% 36 / 38
 __construct($accountSid, $authToken)
100.00% 1 / 1 1
100.00% 5 / 5
 allowClientIncoming($clientName)
0.00% 0 / 1 3.07
80.00% 8 / 10
 allowClientOutgoing($appSid, array $appParams=array()
100.00% 1 / 1 1
100.00% 4 / 4
 allowEventStream(array $filters=array()
100.00% 1 / 1 1
100.00% 5 / 5
 generateToken($ttl = 3600)
100.00% 1 / 1 4
100.00% 12 / 12
 allow($service, $privilege, $params)
100.00% 1 / 1 1
100.00% 2 / 2
ScopeURI
0.00% 0 / 1
66.67% 2 / 3 18.05
39.13% 9 / 23
 __construct($service, $privilege, $params = array()
100.00% 1 / 1 1
100.00% 4 / 4
 toString()
100.00% 1 / 1 2
100.00% 5 / 5
 parse($uri)
0.00% 0 / 1 20
0.00% 0 / 14
JWT
0.00% 0 / 1
37.50% 3 / 8 44.25
67.24% 39 / 58
 decode($jwt, $key = null, $verify = true)
0.00% 0 / 1 8.05
72.22% 13 / 18
 encode($payload, $key, $algo = 'HS256')
100.00% 1 / 1 1
100.00% 8 / 8
 sign($msg, $key, $method = 'HS256')
0.00% 0 / 1 2.01
85.71% 6 / 7
 jsonDecode($input)
0.00% 0 / 1 6.97
57.14% 4 / 7
 jsonEncode($input)
0.00% 0 / 1 6.97
57.14% 4 / 7
 urlsafeB64Decode($input)
100.00% 1 / 1 1
100.00% 3 / 3
 urlsafeB64Encode($input)
100.00% 1 / 1 1
100.00% 1 / 1
 handleJsonError($errno)
0.00% 0 / 1 6
0.00% 0 / 7


       1                 : <?php                                                                               
       2                 :                                                                                     
       3                 : /**                                                                                 
       4                 :  * Twilio Capability Token generator                                                
       5                 :  *                                                                                  
       6                 :  * @category Services                                                               
       7                 :  * @package  Services_Twilio                                                        
       8                 :  * @author Jeff Lindsay <jeff.lindsay@twilio.com>                                   
       9                 :  * @license  http://creativecommons.org/licenses/MIT/ MIT                           
      10                 :  */                                                                                 
      11                 : class Services_Twilio_Capability                                                    
      12                 : {                                                                                   
      13                 :     public $accountSid;                                                             
      14                 :     public $authToken;                                                              
      15                 :     public $scopes;                                                                 
      16                 :                                                                                     
      17                 :     /**                                                                             
      18                 :      * Create a new TwilioCapability with zero permissions. Next steps are to       
      19                 :      * grant access to resources by configuring this token through the              
      20                 :      * functions allowXXXX.                                                         
      21                 :      *                                                                              
      22                 :      * @param $accountSid the account sid to which this token is granted access     
      23                 :      * @param $authToken the secret key used to sign the token. Note, this auth     
      24                 :      *        token is not visible to the user of the token.                        
      25                 :      */                                                                             
      26                 :     public function __construct($accountSid, $authToken)                            
      27                 :     {                                                                               
      28               9 :         $this->accountSid = $accountSid;                                            
      29               9 :         $this->authToken = $authToken;                                              
      30               9 :         $this->scopes = array();                                                    
      31               9 :         $this->clientName = false;                                                  
      32               9 :     }                                                                               
      33                 :                                                                                     
      34                 :     /**                                                                             
      35                 :      * If the user of this token should be allowed to accept incoming               
      36                 :      * connections then configure the TwilioCapability through this method and      
      37                 :      * specify the client name.                                                     
      38                 :      *                                                                              
      39                 :      * @param $clientName                                                           
      40                 :      */                                                                             
      41                 :     public function allowClientIncoming($clientName)                                
      42                 :     {                                                                               
      43                 :                                                                                     
      44                 :         // clientName must be a non-zero length alphanumeric string                 
      45               3 :         if (preg_match('/\W/', $clientName)) {                                      
      46               1 :             throw new InvalidArgumentException(                                     
      47               1 :                 'Only alphanumeric characters allowed in client name.');            
      48                 :         }                                                                           
      49                 :                                                                                     
      50               2 :         if (strlen($clientName) == 0) {                                             
      51               0 :             throw new InvalidArgumentException(                                     
      52               0 :                 'Client name must not be a zero length string.');                   
      53                 :         }                                                                           
      54                 :                                                                                     
      55               2 :         $this->clientName = $clientName;                                            
      56               2 :         $this->allow('client', 'incoming',                                          
      57               2 :             array('clientName' => $clientName));                                    
      58               2 :     }                                                                               
      59                 :                                                                                     
      60                 :     /**                                                                             
      61                 :      * Allow the user of this token to make outgoing connections.                   
      62                 :      *                                                                              
      63                 :      * @param $appSid the application to which this token grants access             
      64                 :      * @param $appParams signed parameters that the user of this token cannot       
      65                 :      *        overwrite.                                                            
      66                 :      */                                                                             
      67                 :     public function allowClientOutgoing($appSid, array $appParams=array())          
      68                 :     {                                                                               
      69               3 :         $this->allow('client', 'outgoing', array(                                   
      70               3 :             'appSid' => $appSid,                                                    
      71               3 :             'appParams' => http_build_query($appParams)));                          
      72               3 :     }                                                                               
      73                 :                                                                                     
      74                 :     /**                                                                             
      75                 :      * Allow the user of this token to access their event stream.                   
      76                 :      *                                                                              
      77                 :      * @param $filters key/value filters to apply to the event stream               
      78                 :      */                                                                             
      79                 :     public function allowEventStream(array $filters=array())                        
      80                 :     {                                                                               
      81               3 :         $this->allow('stream', 'subscribe', array(                                  
      82               3 :             'path' => '/2010-04-01/Events',                                         
      83               3 :             'params' => http_build_query($filters),                                 
      84               3 :         ));                                                                         
      85               3 :     }                                                                               
      86                 :                                                                                     
      87                 :     /**                                                                             
      88                 :      * Generates a new token based on the credentials and permissions that          
      89                 :      * previously has been granted to this token.                                   
      90                 :      *                                                                              
      91                 :      * @param $ttl the expiration time of the token (in seconds). Default           
      92                 :      *        value is 3600 (1hr)                                                   
      93                 :      * @return the newly generated token that is valid for $ttl seconds             
      94                 :      */                                                                             
      95                 :     public function generateToken($ttl = 3600)                                      
      96                 :     {                                                                               
      97                 :         $payload = array(                                                           
      98               8 :             'scope' => array(),                                                     
      99               8 :             'iss' => $this->accountSid,                                             
     100               8 :             'exp' => time() + $ttl,                                                 
     101               8 :         );                                                                          
     102               8 :         $scopeStrings = array();                                                    
     103                 :                                                                                     
     104               8 :         foreach ($this->scopes as $scope) {                                         
     105               6 :             if ($scope->privilege == "outgoing" && $this->clientName)               
     106               6 :                 $scope->params["clientName"] = $this->clientName;                   
     107               6 :             $scopeStrings[] = $scope->toString();                                   
     108               8 :         }                                                                           
     109                 :                                                                                     
     110               8 :         $payload['scope'] = implode(' ', $scopeStrings);                            
     111               8 :         return JWT::encode($payload, $this->authToken, 'HS256');                    
     112                 :     }                                                                               
     113                 :                                                                                     
     114                 :     protected function allow($service, $privilege, $params) {                       
     115               6 :         $this->scopes[] = new ScopeURI($service, $privilege, $params);              
     116               6 :     }                                                                               
     117                 : }                                                                                   
     118                 :                                                                                     
     119                 : /**                                                                                 
     120                 :  * Scope URI implementation                                                         
     121                 :  *                                                                                  
     122                 :  * Simple way to represent configurable privileges in an OAuth                      
     123                 :  * friendly way. For our case, they look like this:                                 
     124                 :  *                                                                                  
     125                 :  * scope:<service>:<privilege>?<params>                                             
     126                 :  *                                                                                  
     127                 :  * For example:                                                                     
     128                 :  * scope:client:incoming?name=jonas                                                 
     129                 :  *                                                                                  
     130                 :  * @author Jeff Lindsay <jeff.lindsay@twilio.com>                                   
     131                 :  */                                                                                 
     132                 : class ScopeURI                                                                      
     133                 : {                                                                                   
     134                 :     public $service;                                                                
     135                 :     public $privilege;                                                              
     136                 :     public $params;                                                                 
     137                 :                                                                                     
     138                 :     public function __construct($service, $privilege, $params = array())            
     139                 :     {                                                                               
     140               6 :         $this->service = $service;                                                  
     141               6 :         $this->privilege = $privilege;                                              
     142               6 :         $this->params = $params;                                                    
     143               6 :     }                                                                               
     144                 :                                                                                     
     145                 :     public function toString()                                                      
     146                 :     {                                                                               
     147               6 :         $uri = "scope:{$this->service}:{$this->privilege}";                         
     148               6 :         if (count($this->params)) {                                                 
     149               6 :             $uri .= "?".http_build_query($this->params);                            
     150               6 :         }                                                                           
     151               6 :         return $uri;                                                                
     152                 :     }                                                                               
     153                 :                                                                                     
     154                 :     /**                                                                             
     155                 :      * Parse a scope URI into a ScopeURI object                                     
     156                 :      *                                                                              
     157                 :      * @param string    $uri  The scope URI                                         
     158                 :      * @return ScopeURI The parsed scope uri                                        
     159                 :      */                                                                             
     160                 :     public static function parse($uri)                                              
     161                 :     {                                                                               
     162               0 :         if (strpos($uri, 'scope:') !== 0) {                                         
     163               0 :             throw new UnexpectedValueException(                                     
     164               0 :                 'Not a scope URI according to scheme');                             
     165                 :         }                                                                           
     166                 :                                                                                     
     167               0 :         $parts = explode('?', $uri, 1);                                             
     168               0 :         $params = null;                                                             
     169                 :                                                                                     
     170               0 :         if (count($parts) > 1) {                                                    
     171               0 :             parse_str($parts[1], $params);                                          
     172               0 :         }                                                                           
     173                 :                                                                                     
     174               0 :         $parts = explode(':', $parts[0], 2);                                        
     175                 :                                                                                     
     176               0 :         if (count($parts) != 3) {                                                   
     177               0 :             throw new UnexpectedValueException(                                     
     178               0 :                 'Not enough parts for scope URI');                                  
     179                 :         }                                                                           
     180                 :                                                                                     
     181               0 :         list($scheme, $service, $privilege) = $parts;                               
     182               0 :         return new ScopeURI($service, $privilege, $params);                         
     183                 :     }                                                                               
     184                 :                                                                                     
     185                 : }                                                                                   
     186                 :                                                                                     
     187                 : /**                                                                                 
     188                 :  * JSON Web Token implementation                                                    
     189                 :  *                                                                                  
     190                 :  * Minimum implementation used by Realtime auth, based on this spec:                
     191                 :  * http://self-issued.info/docs/draft-jones-json-web-token-01.html.                 
     192                 :  *                                                                                  
     193                 :  * @author Neuman Vong <neuman@twilio.com>                                          
     194                 :  */                                                                                 
     195                 : class JWT                                                                           
     196                 : {                                                                                   
     197                 :     /**                                                                             
     198                 :      * @param string      $jwt    The JWT                                           
     199                 :      * @param string|null $key    The secret key                                    
     200                 :      * @param bool        $verify Don't skip verification process                   
     201                 :      *                                                                              
     202                 :      * @return object The JWT's payload as a PHP object                             
     203                 :      */                                                                             
     204                 :     public static function decode($jwt, $key = null, $verify = true)                
     205                 :     {                                                                               
     206               8 :         $tks = explode('.', $jwt);                                                  
     207               8 :         if (count($tks) != 3) {                                                     
     208               0 :             throw new UnexpectedValueException('Wrong number of segments');         
     209                 :         }                                                                           
     210               8 :         list($headb64, $payloadb64, $cryptob64) = $tks;                             
     211               8 :         if (null === ($header = JWT::jsonDecode(JWT::urlsafeB64Decode($headb64)))   
     212               8 :         ) {                                                                         
     213               0 :             throw new UnexpectedValueException('Invalid segment encoding');         
     214                 :         }                                                                           
     215               8 :         if (null === $payload = JWT::jsonDecode(JWT::urlsafeB64Decode($payloadb64)) 
     216               8 :         ) {                                                                         
     217               0 :             throw new UnexpectedValueException('Invalid segment encoding');         
     218                 :         }                                                                           
     219               8 :         $sig = JWT::urlsafeB64Decode($cryptob64);                                   
     220               8 :         if ($verify) {                                                              
     221               8 :             if (empty($header->alg)) {                                              
     222               0 :                 throw new DomainException('Empty algorithm');                       
     223                 :             }                                                                       
     224               8 :             if ($sig != JWT::sign("$headb64.$payloadb64", $key, $header->alg)) {    
     225               0 :                 throw new UnexpectedValueException('Signature verification failed');
     226                 :             }                                                                       
     227               8 :         }                                                                           
     228               8 :         return $payload;                                                            
     229                 :     }                                                                               
     230                 :                                                                                     
     231                 :     /**                                                                             
     232                 :       * @param object|array $payload PHP object or array                            
     233                 :       * @param string       $key     The secret key                                 
     234                 :       * @param string       $algo    The signing algorithm                          
     235                 :       *                                                                             
     236                 :       * @return string A JWT                                                        
     237                 :       */                                                                            
     238                 :     public static function encode($payload, $key, $algo = 'HS256')                  
     239                 :     {                                                                               
     240               8 :         $header = array('typ' => 'JWT', 'alg' => $algo);                            
     241                 :                                                                                     
     242               8 :         $segments = array();                                                        
     243               8 :         $segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($header));              
     244               8 :         $segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($payload));             
     245               8 :         $signing_input = implode('.', $segments);                                   
     246                 :                                                                                     
     247               8 :         $signature = JWT::sign($signing_input, $key, $algo);                        
     248               8 :         $segments[] = JWT::urlsafeB64Encode($signature);                            
     249                 :                                                                                     
     250               8 :         return implode('.', $segments);                                             
     251                 :     }                                                                               
     252                 :                                                                                     
     253                 :     /**                                                                             
     254                 :      * @param string $msg    The message to sign                                    
     255                 :      * @param string $key    The secret key                                         
     256                 :      * @param string $method The signing algorithm                                  
     257                 :      *                                                                              
     258                 :      * @return string An encrypted message                                          
     259                 :      */                                                                             
     260                 :     public static function sign($msg, $key, $method = 'HS256')                      
     261                 :     {                                                                               
     262                 :         $methods = array(                                                           
     263               8 :             'HS256' => 'sha256',                                                    
     264               8 :             'HS384' => 'sha384',                                                    
     265               8 :             'HS512' => 'sha512',                                                    
     266               8 :         );                                                                          
     267               8 :         if (empty($methods[$method])) {                                             
     268               0 :             throw new DomainException('Algorithm not supported');                   
     269                 :         }                                                                           
     270               8 :         return hash_hmac($methods[$method], $msg, $key, true);                      
     271                 :     }                                                                               
     272                 :                                                                                     
     273                 :     /**                                                                             
     274                 :      * @param string $input JSON string                                             
     275                 :      *                                                                              
     276                 :      * @return object Object representation of JSON string                          
     277                 :      */                                                                             
     278                 :     public static function jsonDecode($input)                                       
     279                 :     {                                                                               
     280               8 :         $obj = json_decode($input);                                                 
     281               8 :         if (function_exists('json_last_error') && $errno = json_last_error()) {     
     282               0 :             JWT::handleJsonError($errno);                                           
     283               0 :         }                                                                           
     284               8 :         else if ($obj === null && $input !== 'null') {                              
     285               0 :             throw new DomainException('Null result with non-null input');           
     286                 :         }                                                                           
     287               8 :         return $obj;                                                                
     288                 :     }                                                                               
     289                 :                                                                                     
     290                 :     /**                                                                             
     291                 :      * @param object|array $input A PHP object or array                             
     292                 :      *                                                                              
     293                 :      * @return string JSON representation of the PHP object or array                
     294                 :      */                                                                             
     295                 :     public static function jsonEncode($input)                                       
     296                 :     {                                                                               
     297               8 :         $json = json_encode($input);                                                
     298               8 :         if (function_exists('json_last_error') && $errno = json_last_error()) {     
     299               0 :             JWT::handleJsonError($errno);                                           
     300               0 :         }                                                                           
     301               8 :         else if ($json === 'null' && $input !== null) {                             
     302               0 :             throw new DomainException('Null result with non-null input');           
     303                 :         }                                                                           
     304               8 :         return $json;                                                               
     305                 :     }                                                                               
     306                 :                                                                                     
     307                 :     /**                                                                             
     308                 :      * @param string $input A base64 encoded string                                 
     309                 :      *                                                                              
     310                 :      * @return string A decoded string                                              
     311                 :      */                                                                             
     312                 :     public static function urlsafeB64Decode($input)                                 
     313                 :     {                                                                               
     314               8 :         $padlen = 4 - strlen($input) % 4;                                           
     315               8 :         $input .= str_repeat('=', $padlen);                                         
     316               8 :         return base64_decode(strtr($input, '-_', '+/'));                            
     317                 :     }                                                                               
     318                 :                                                                                     
     319                 :     /**                                                                             
     320                 :      * @param string $input Anything really                                         
     321                 :      *                                                                              
     322                 :      * @return string The base64 encode of what you passed in                       
     323                 :      */                                                                             
     324                 :     public static function urlsafeB64Encode($input)                                 
     325                 :     {                                                                               
     326               8 :         return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));      
     327                 :     }                                                                               
     328                 :                                                                                     
     329                 :     /**                                                                             
     330                 :      * @param int $errno An error number from json_last_error()                     
     331                 :      *                                                                              
     332                 :      * @return void                                                                 
     333                 :      */                                                                             
     334                 :     private static function handleJsonError($errno)                                 
     335                 :     {                                                                               
     336                 :         $messages = array(                                                          
     337               0 :             JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',                     
     338               0 :             JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',           
     339                 :             JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON'                     
     340               0 :         );                                                                          
     341               0 :         throw new DomainException(isset($messages[$errno])                          
     342               0 :             ? $messages[$errno]                                                     
     343               0 :             : 'Unknown JSON error: ' . $errno                                       
     344               0 :         );                                                                          
     345                 :     }                                                                               

Generated by PHP_CodeCoverage 1.1.2 using PHP 5.3.13 and PHPUnit 3.6.11 at Mon Jun 4 22:46:14 PDT 2012.