diff options
-rw-r--r-- | application/config/migration.php | 2 | ||||
-rw-r--r-- | application/controllers/file.php | 10 | ||||
-rw-r--r-- | application/controllers/user.php | 65 | ||||
-rw-r--r-- | application/libraries/Duser/Duser.php | 1 | ||||
-rw-r--r-- | application/migrations/009_add_apikeys.php | 24 | ||||
-rw-r--r-- | application/models/mfile.php | 2 | ||||
-rw-r--r-- | application/models/muser.php | 67 | ||||
-rw-r--r-- | application/views/user/apikeys.php | 36 |
8 files changed, 191 insertions, 16 deletions
diff --git a/application/config/migration.php b/application/config/migration.php index 943ff0880..5fef0ad40 100644 --- a/application/config/migration.php +++ b/application/config/migration.php @@ -21,7 +21,7 @@ $config['migration_enabled'] = true; | be upgraded / downgraded to. | */ -$config['migration_version'] = 8; +$config['migration_version'] = 9; /* diff --git a/application/controllers/file.php b/application/controllers/file.php index c133539f7..7629b809b 100644 --- a/application/controllers/file.php +++ b/application/controllers/file.php @@ -282,7 +282,7 @@ class File extends CI_Controller { "lexer" => $lexer )); $this->session->set_flashdata("uri", "file/claim_id"); - $this->muser->require_access(); + $this->muser->require_access("apikey"); } foreach ($ids as $id) { @@ -444,7 +444,7 @@ class File extends CI_Controller { function upload_history() { - $this->muser->require_access(); + $this->muser->require_access("apikey"); $user = $this->muser->get_userid(); @@ -523,7 +523,7 @@ class File extends CI_Controller { function do_delete() { - $this->muser->require_access(); + $this->muser->require_access("apikey"); $ids = $this->input->post("ids"); $errors = array(); @@ -563,7 +563,7 @@ class File extends CI_Controller { function delete() { - $this->muser->require_access(); + $this->muser->require_access("apikey"); if (!is_cli_client()) { echo "Not a listed cli client, please use the history to delete uploads.\n"; @@ -634,7 +634,7 @@ class File extends CI_Controller { { // desktop clients get a cookie to claim the ID later if (is_cli_client()) { - $this->muser->require_access(); + $this->muser->require_access("apikey"); } $ids = array(); diff --git a/application/controllers/user.php b/application/controllers/user.php index 21b58cf93..009188648 100644 --- a/application/controllers/user.php +++ b/application/controllers/user.php @@ -84,6 +84,71 @@ class User extends CI_Controller { } } + function create_apikey() + { + $this->muser->require_access(); + + $userid = $this->muser->get_userid(); + $comment = $this->input->post("comment"); + + + if (strlen($comment) > 255 || !preg_match("/^[a-zA-Z0-9 ]*$/", $comment)) { + // display better error for + show_error("Comment invalid. Only 255 chars of a-zA-Z0-9 and space allowed"); + } + + $key = random_alphanum(32); + + $this->db->query(" + INSERT INTO `apikeys` + (`key`, `user`, `comment`) + VALUES (?, ?, ?) + ", array($key, $userid, $comment)); + + if (is_cli_client()) { + echo "$key\n"; + } else { + redirect("user/apikeys"); + } + } + + function delete_apikey() + { + $this->muser->require_access(); + + $userid = $this->muser->get_userid(); + $key = $this->input->post("key"); + + var_dump($userid, $key); + + $this->db->query(" + DELETE FROM `apikeys` + WHERE `user` = ? + AND `key` = ? + ", array($userid, $key)); + + redirect("user/apikeys"); + } + + function apikeys() + { + $this->muser->require_access(); + + $userid = $this->muser->get_userid(); + + $query = $this->db->query(" + SELECT `key`, UNIX_TIMESTAMP(`created`) `created`, `comment` + FROM `apikeys` + WHERE `user` = ? order by created desc + ", array($userid))->result_array(); + + $this->data["query"] = $query; + + $this->load->view('header', $this->data); + $this->load->view($this->var->view_dir.'apikeys', $this->data); + $this->load->view('footer', $this->data); + } + function create_invitation_key() { $this->duser->require_implemented("can_register_new_users"); diff --git a/application/libraries/Duser/Duser.php b/application/libraries/Duser/Duser.php index 19d1bfa09..733616b40 100644 --- a/application/libraries/Duser/Duser.php +++ b/application/libraries/Duser/Duser.php @@ -78,6 +78,7 @@ class Duser extends CI_Driver_Library { $CI->session->set_userdata('logged_in', true); $CI->session->set_userdata('username', $login_info["username"]); $CI->session->set_userdata('userid', $login_info["userid"]); + $CI->session->set_userdata('access_level', 'full'); return true; } diff --git a/application/migrations/009_add_apikeys.php b/application/migrations/009_add_apikeys.php new file mode 100644 index 000000000..8e88260a8 --- /dev/null +++ b/application/migrations/009_add_apikeys.php @@ -0,0 +1,24 @@ +<?php +defined('BASEPATH') OR exit('No direct script access allowed'); + +class Migration_Add_apikeys extends CI_Migration { + + public function up() + { + $this->db->query(" + CREATE TABLE `apikeys` ( + `key` varchar(64) COLLATE utf8_bin NOT NULL, + `user` int(8) unsigned NOT NULL, + `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `comment` varchar(255) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, + PRIMARY KEY (`key`), + KEY `user` (`user`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin + "); + } + + public function down() + { + $this->dbforge->drop_table('apikeys'); + } +} diff --git a/application/models/mfile.php b/application/models/mfile.php index a7bab5d51..aaeebccaf 100644 --- a/application/models/mfile.php +++ b/application/models/mfile.php @@ -310,7 +310,7 @@ class Mfile extends CI_Model { function delete_id($id) { - $this->muser->require_access(); + $this->muser->require_access("apikey"); $filedata = $this->get_filedata($id); $userid = $this->muser->get_userid(); diff --git a/application/models/muser.php b/application/models/muser.php index 639b5ee3a..312d895e5 100644 --- a/application/models/muser.php +++ b/application/models/muser.php @@ -67,6 +67,14 @@ class Muser extends CI_Model { { $username = $this->input->post("username"); $password = $this->input->post("password"); + $apikey = $this->input->post("apikey"); + + if ($apikey !== false) { + if ($this->apilogin(trim($apikey))) { + return true; + } + show_error("API key login failed", 401); + } // prefer post parameters if either (username or password) is set if ($username === false && $password === false) { @@ -76,18 +84,39 @@ class Muser extends CI_Model { } } - if ($username !== false && $password !== false) { + if ($apikey === false && $username !== false && $password !== false) { if ($this->login($username, $password)) { return true; } else { - // TODO: better message - $this->output->set_status_header(401); - echo "login failed.\n"; - exit; + show_error("Login failed", 401); } } } + function apilogin($apikey) + { + $this->require_session(); + + // FIXME: get username/id from duser or move them to apikeys table + // (users is empty when using any other driver than duser_db) + $query = $this->db->query(" + SELECT a.user userid, u.username + FROM apikeys a + JOIN users u on a.user = u.id + WHERE a.key = ? + ", array($apikey))->row_array(); + + if (isset($query["userid"])) { + $this->session->set_userdata('logged_in', true); + $this->session->set_userdata('username', $query["username"]); + $this->session->set_userdata('userid', $query["userid"]); + $this->session->set_userdata('access_level', 'apikey'); + return true; + } + + return false; + } + function logout() { $this->require_session(); @@ -124,16 +153,36 @@ class Muser extends CI_Model { return $this->duser->get_email($userid); } - function require_access() + private function check_access_level($wanted_level) { - if ($this->logged_in()) { + $session_level = $this->session->userdata("access_level"); + + // last level has the most access + $levels = array("apikey", "full"); + + $wanted = array_search($wanted_level, $levels); + $have = array_search($session_level, $levels); + + if ($wanted === false || $have === false) { + show_error("Failed to determine access level"); + } + + if ($have >= $wanted) { return true; } - // handle cli clients + show_error("Access denied", 403); + } + + function require_access($wanted_level = "full") + { + if ($this->logged_in()) { + return $this->check_access_level($wanted_level); + } + if (is_cli_client()) { if ($this->login_cli_client()) { - return true; + return $this->check_access_level($wanted_level); } echo "FileBin requires you to have an account, please go to the homepage for more information.\n"; diff --git a/application/views/user/apikeys.php b/application/views/user/apikeys.php new file mode 100644 index 000000000..14d829ffa --- /dev/null +++ b/application/views/user/apikeys.php @@ -0,0 +1,36 @@ +<h2>API keys</h2> +<table class="table table-striped"> + <thead> + <tr> + <th>#</th> + <th>Key</th> + <th style="width: 30%;">Comment</th> + <th>Created on</th> + <th></th> + </tr> + </thead> + <tbody> + <?php $i = 1; ?> + <?php foreach($query as $key => $item): ?> + <tr> + <td><?php echo $i++; ?></td> + <td><?php echo $item["key"]; ?></td> + <td><?php echo $item["comment"]; ?></td> + <td><?php echo date("Y/m/d H:i", $item["created"]); ?></td> + <td> + <?php echo form_open("user/delete_apikey", array("style" => "margin-bottom: 0")); ?> + <?php echo form_hidden("key", $item["key"]); ?> + <button class="btn btn-danger btn-mini" type="submit">Delete</input> + </form> + </td> + </tr> + <?php endforeach; ?> + </tbody> +</table> + +<p> + <?php echo form_open('user/create_apikey', array("class" => "form-horizontal")); ?> + <input type="text" name="comment" placeholder="Comment" /> + <input class="btn btn-primary" type="submit" value="Create a new key" name="process" /> + </form> +</p> |