      1: <?php
      2:
      3: defined('BASEPATH') OR exit('No direct script access allowed');
      4:
      5: // This can be removed if you use __autoload() in config.php OR use Modular Extensions
      6: require APPPATH . '/libraries/REST_Controller.php';
      7:
      8: /**
      9:  * Keys Controller
     10:  * This is a basic Key Management REST controller to make and delete keys
     11:  *
     12:  * @package         CodeIgniter
     13:  * @subpackage      Rest Server
     14:  * @category        Controller
     15:  * @author          Phil Sturgeon, Chris Kacerguis
     16:  * @license         MIT
     17:  * @link            https://github.com/chriskacerguis/codeigniter-restserver
     18:  */
     19: class Key extends REST_Controller {
     20:
     21:     protected $methods = [
     22:             'index_put' => ['level' => 10, 'limit' => 10],
     23:             'index_delete' => ['level' => 10],
     24:             'level_post' => ['level' => 10],
     25:             'regenerate_post' => ['level' => 10],
     26:         ];
     27:
     28:     /**
     29:      * Insert a key into the database
     30:      *
     31:      * @access public
     32:      * @return void
     33:      */
     34:     public function index_put()
     35:     {
     36:         // Build a new key
     37:         $key = $this->_generate_key();
     38:
     39:         // If no key level provided, provide a generic key
     40:         $level = $this->put('level') ? $this->put('level') : 1;
     41:         $ignore_limits = ctype_digit($this->put('ignore_limits')) ? (int) $this->put('ignore_limits') : 1;
     42:
     43:         // Insert the new key
     44:         if ($this->_insert_key($key, ['level' => $level, 'ignore_limits' => $ignore_limits]))
     45:         {
     46:             $this->response([
     47:                 'status' => TRUE,
     48:                 'key' => $key
     49:             ], REST_Controller::HTTP_CREATED); // CREATED (201) being the HTTP response code
     50:         }
     51:         else
     52:         {
     53:             $this->response([
     54:                 'status' => FALSE,
     55:                 'message' => 'Could not save the key'
     56:             ], REST_Controller::HTTP_INTERNAL_SERVER_ERROR); // INTERNAL_SERVER_ERROR (500) being the HTTP response code
     57:         }
     58:     }
     59:
     60:     /**
     61:      * Remove a key from the database to stop it working
     62:      *
     63:      * @access public
     64:      * @return void
     65:      */
     66:     public function index_delete()
     67:     {
     68:         $key = $this->delete('key');
     69:
     70:         // Does this key exist?
     71:         if (!$this->_key_exists($key))
     72:         {
     73:             // It doesn't appear the key exists
     74:             $this->response([
     75:                 'status' => FALSE,
     76:                 'message' => 'Invalid API key'
     77:             ], REST_Controller::HTTP_BAD_REQUEST); // BAD_REQUEST (400) being the HTTP response code
     78:         }
     79:
     80:         // Destroy it
     81:         $this->_delete_key($key);
     82:
     83:         // Respond that the key was destroyed
     84:         $this->response([
     85:             'status' => TRUE,
     86:             'message' => 'API key was deleted'
     87:             ], REST_Controller::HTTP_NO_CONTENT); // NO_CONTENT (204) being the HTTP response code
     88:     }
     89:
     90:     /**
     91:      * Change the level
     92:      *
     93:      * @access public
     94:      * @return void
     95:      */
     96:     public function level_post()
     97:     {
     98:         $key = $this->post('key');
     99:         $new_level = $this->post('level');
    100:
    101:         // Does this key exist?
    102:         if (!$this->_key_exists($key))
    103:         {
    104:             // It doesn't appear the key exists
    105:             $this->response([
    106:                 'status' => FALSE,
    107:                 'message' => 'Invalid API key'
    108:             ], REST_Controller::HTTP_BAD_REQUEST); // BAD_REQUEST (400) being the HTTP response code
    109:         }
    110:
    111:         // Update the key level
    112:         if ($this->_update_key($key, ['level' => $new_level]))
    113:         {
    114:             $this->response([
    115:                 'status' => TRUE,
    116:                 'message' => 'API key was updated'
    117:             ], REST_Controller::HTTP_OK); // OK (200) being the HTTP response code
    118:         }
    119:         else
    120:         {
    121:             $this->response([
    122:                 'status' => FALSE,
    123:                 'message' => 'Could not update the key level'
    124:             ], REST_Controller::HTTP_INTERNAL_SERVER_ERROR); // INTERNAL_SERVER_ERROR (500) being the HTTP response code
    125:         }
    126:     }
    127:
    128:     /**
    129:      * Suspend a key
    130:      *
    131:      * @access public
    132:      * @return void
    133:      */
    134:     public function suspend_post()
    135:     {
    136:         $key = $this->post('key');
    137:
    138:         // Does this key exist?
    139:         if (!$this->_key_exists($key))
    140:         {
    141:             // It doesn't appear the key exists
    142:             $this->response([
    143:                 'status' => FALSE,
    144:                 'message' => 'Invalid API key'
    145:             ], REST_Controller::HTTP_BAD_REQUEST); // BAD_REQUEST (400) being the HTTP response code
    146:         }
    147:
    148:         // Update the key level
    149:         if ($this->_update_key($key, ['level' => 0]))
    150:         {
    151:             $this->response([
    152:                 'status' => TRUE,
    153:                 'message' => 'Key was suspended'
    154:             ], REST_Controller::HTTP_OK); // OK (200) being the HTTP response code
    155:         }
    156:         else
    157:         {
    158:             $this->response([
    159:                 'status' => FALSE,
    160:                 'message' => 'Could not suspend the user'
    161:             ], REST_Controller::HTTP_INTERNAL_SERVER_ERROR); // INTERNAL_SERVER_ERROR (500) being the HTTP response code
    162:         }
    163:     }
    164:
    165:     /**
    166:      * Regenerate a key
    167:      *
    168:      * @access public
    169:      * @return void
    170:      */
    171:     public function regenerate_post()
    172:     {
    173:         $old_key = $this->post('key');
    174:         $key_details = $this->_get_key($old_key);
    175:
    176:         // Does this key exist?
    177:         if (!$key_details)
    178:         {
    179:             // It doesn't appear the key exists
    180:             $this->response([
    181:                 'status' => FALSE,
    182:                 'message' => 'Invalid API key'
    183:             ], REST_Controller::HTTP_BAD_REQUEST); // BAD_REQUEST (400) being the HTTP response code
    184:         }
    185:
    186:         // Build a new key
    187:         $new_key = $this->_generate_key();
    188:
    189:         // Insert the new key
    190:         if ($this->_insert_key($new_key, ['level' => $key_details->level, 'ignore_limits' => $key_details->ignore_limits]))
    191:         {
    192:             // Suspend old key
    193:             $this->_update_key($old_key, ['level' => 0]);
    194:
    195:             $this->response([
    196:                 'status' => TRUE,
    197:                 'key' => $new_key
    198:             ], REST_Controller::HTTP_CREATED); // CREATED (201) being the HTTP response code
    199:         }
    200:         else
    201:         {
    202:             $this->response([
    203:                 'status' => FALSE,
    204:                 'message' => 'Could not save the key'
    205:             ], REST_Controller::HTTP_INTERNAL_SERVER_ERROR); // INTERNAL_SERVER_ERROR (500) being the HTTP response code
    206:         }
    207:     }
    208:
    209:     /* Helper Methods */
    210:
    211:     private function _generate_key()
    212:     {
    213:         do
    214:         {
    215:             // Generate a random salt
    216:             $salt = base_convert(bin2hex($this->security->get_random_bytes(64)), 16, 36);
    217:
    218:             // If an error occurred, then fall back to the previous method
    219:             if ($salt === FALSE)
    220:             {
    221:                 $salt = hash('sha256', time() . mt_rand());
    222:             }
    223:
    224:             $new_key = substr($salt, 0, config_item('rest_key_length'));
    225:         }
    226:         while ($this->_key_exists($new_key));
    227:
    228:         return $new_key;
    229:     }
    230:
    231:     /* Private Data Methods */
    232:
    233:     private function _get_key($key)
    234:     {
    235:         return $this->db
    236:             ->where(config_item('rest_key_column'), $key)
    237:             ->get(config_item('rest_keys_table'))
    238:             ->row();
    239:     }
    240:
    241:     private function _key_exists($key)
    242:     {
    243:         return $this->db
    244:             ->where(config_item('rest_key_column'), $key)
    245:             ->count_all_results(config_item('rest_keys_table')) > 0;
    246:     }
    247:
    248:     private function _insert_key($key, $data)
    249:     {
    250:         $data[config_item('rest_key_column')] = $key;
    251:         $data['date_created'] = function_exists('now') ? now() : time();
    252:
    253:         return $this->db
    254:             ->set($data)
    255:             ->insert(config_item('rest_keys_table'));
    256:     }
    257:
    258:     private function _update_key($key, $data)
    259:     {
    260:         return $this->db
    261:             ->where(config_item('rest_key_column'), $key)
    262:             ->update(config_item('rest_keys_table'), $data);
    263:     }
    264:
    265:     private function _delete_key($key)
    266:     {
    267:         return $this->db
    268:             ->where(config_item('rest_key_column'), $key)
    269:             ->delete(config_item('rest_keys_table'));
    270:     }
    271:
    272: }
    273: