token support, api fixes and security, dark mode
This commit is contained in:
@ -145,22 +145,6 @@ class Sessions extends DatabaseModel {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkToken( $apiToken, $create = false ) {
|
||||
$user = new User;
|
||||
if ( $apiToken === false ) {
|
||||
return false;
|
||||
}
|
||||
$result = $user->findByToken( $apiToken );
|
||||
if ( $result === false ) {
|
||||
Debug::info( 'sessions->checkToken - could not find user by token.' );
|
||||
return false;
|
||||
}
|
||||
if ( $create ) {
|
||||
return $this->newSession( null, false, false, $result->ID );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new session from the data provided. The
|
||||
* expiration time is optional and will be set to the
|
||||
|
198
app/models/token.php
Normal file
198
app/models/token.php
Normal file
@ -0,0 +1,198 @@
|
||||
<?php
|
||||
/**
|
||||
* app/models/token.php
|
||||
*
|
||||
* This class is used for the manipulation of the tokens database table.
|
||||
*
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Models;
|
||||
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Canary\Bin\Canary as Debug;
|
||||
use TheTempusProject\Classes\DatabaseModel;
|
||||
use TheTempusProject\Bedrock\Classes\Config;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
|
||||
class Token extends DatabaseModel {
|
||||
public $tableName = 'tokens';
|
||||
public $modelVersion = '1.0';
|
||||
public $configName = 'api';
|
||||
public $databaseMatrix = [
|
||||
[ 'name', 'varchar', '128' ],
|
||||
[ 'token_type', 'varchar', '8' ],
|
||||
[ 'notes', 'text', '' ],
|
||||
[ 'token', 'varchar', '64' ],
|
||||
[ 'secret', 'varchar', '256' ],
|
||||
[ 'createdAt', 'int', '10' ],
|
||||
[ 'createdBy', 'int', '10' ],
|
||||
[ 'expiresAt', 'int', '10' ],
|
||||
];
|
||||
public $permissionMatrix = [
|
||||
'addAppToken' => [
|
||||
'pretty' => 'Add Application Tokens',
|
||||
'default' => false,
|
||||
],
|
||||
'addAppToken' => [
|
||||
'pretty' => 'Add Personal Tokens',
|
||||
'default' => false,
|
||||
],
|
||||
];
|
||||
public $configMatrix = [
|
||||
'apiAccessApp' => [
|
||||
'type' => 'radio',
|
||||
'pretty' => 'Enable Api Access for Personal Tokens.',
|
||||
'default' => true,
|
||||
],
|
||||
'apiAccessPersonal' => [
|
||||
'type' => 'radio',
|
||||
'pretty' => 'Enable Api Access for Personal Tokens.',
|
||||
'default' => true,
|
||||
],
|
||||
'AppAccessTokenExpiration' => [
|
||||
'type' => 'text',
|
||||
'pretty' => 'How long before app tokens expire (in seconds)',
|
||||
'default' => 2592000,
|
||||
],
|
||||
'UserAccessTokenExpiration' => [
|
||||
'type' => 'text',
|
||||
'pretty' => 'How long before user tokens expire (in seconds)',
|
||||
'default' => 604800,
|
||||
],
|
||||
];
|
||||
|
||||
public function create( $name, $note, $token_type = 'app' ) {
|
||||
if ( 'app' == $token_type ) {
|
||||
$expiration = Config::getValue( 'api/AppAccessTokenExpiration' );
|
||||
if ( empty( $expiration ) ) {
|
||||
$expiration = $this->configMatrix['AppAccessTokenExpiration']['default'];
|
||||
}
|
||||
} else {
|
||||
$expiration = Config::getValue( 'api/UserAccessTokenExpiration' );
|
||||
if ( empty( $expiration ) ) {
|
||||
$expiration = $this->configMatrix['UserAccessTokenExpiration']['default'];
|
||||
}
|
||||
}
|
||||
$expireTime = time() + $expiration;
|
||||
|
||||
$fields = [
|
||||
'name' => $name,
|
||||
'notes' => $note,
|
||||
'token_type' => $token_type,
|
||||
'createdBy' => App::$activeUser->ID,
|
||||
'createdAt' => time(),
|
||||
'expiresAt' => $expireTime,
|
||||
'token' => generateToken(),
|
||||
'secret' => generateRandomString(256),
|
||||
];
|
||||
if ( self::$db->insert( $this->tableName, $fields ) ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function findOrCreateUserToken( $user_id ) {
|
||||
$test = $this->findUserToken( $user_id );
|
||||
if ( ! empty( $test ) ) {
|
||||
return $test->token;
|
||||
}
|
||||
|
||||
$expiration = Config::getValue( 'api/UserAccessTokenExpiration' );
|
||||
if ( empty( $expiration ) ) {
|
||||
$expiration = $this->configMatrix['UserAccessTokenExpiration']['default'];
|
||||
}
|
||||
$expireTime = time() + $expiration;
|
||||
$token = generateToken();
|
||||
$fields = [
|
||||
'name' => 'Browser Token',
|
||||
'notes' => 'findOrCreateUserToken',
|
||||
'token_type' => 'user',
|
||||
'createdBy' => $user_id,
|
||||
'createdAt' => time(),
|
||||
'expiresAt' => $expireTime,
|
||||
'token' => $token,
|
||||
'secret' => generateRandomString(256),
|
||||
];
|
||||
if ( self::$db->insert( $this->tableName, $fields ) ) {
|
||||
return $token;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function update( $id, $name, $note, $token_type = 'app' ) {
|
||||
$fields = [
|
||||
'name' => $name,
|
||||
'notes' => $note,
|
||||
'token_type' => $token_type,
|
||||
];
|
||||
if ( self::$db->update( $this->tableName, $id, $fields ) ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function refresh( $id, $token_type = 'app' ) {
|
||||
if ( 'app' == $token_type ) {
|
||||
$expiration = Config::getValue( 'api/AppAccessTokenExpiration' );
|
||||
if ( empty( $expiration ) ) {
|
||||
$expiration = $this->configMatrix['AppAccessTokenExpiration']['default'];
|
||||
}
|
||||
} else {
|
||||
$expiration = Config::getValue( 'api/UserAccessTokenExpiration' );
|
||||
if ( empty( $expiration ) ) {
|
||||
$expiration = $this->configMatrix['UserAccessTokenExpiration']['default'];
|
||||
}
|
||||
}
|
||||
$expireTime = time() + $expiration;
|
||||
$token = generateToken();
|
||||
|
||||
$fields = [
|
||||
'expiresAt' => $expireTime,
|
||||
'token' => $token,
|
||||
];
|
||||
if ( self::$db->update( $this->tableName, $id, $fields ) ) {
|
||||
return $token;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function findByforwardedUrl( $url ) {
|
||||
if ( !Check::url( $url ) ) {
|
||||
Debug::warn( "Invalid forwarded_url: $url" );
|
||||
return false;
|
||||
}
|
||||
$routeData = self::$db->get( $this->tableName, [ 'forwarded_url', '=', $url ] );
|
||||
if ( !$routeData->count() ) {
|
||||
Debug::warn( "Could not find route by forwarded url: $url" );
|
||||
return false;
|
||||
}
|
||||
return $this->filter( $routeData->first() );
|
||||
}
|
||||
|
||||
public function findByToken( $token ) {
|
||||
$data = self::$db->get( $this->tableName, [ 'token', '=', $token ] );
|
||||
if ( ! $data->count() ) {
|
||||
return false;
|
||||
}
|
||||
return $data->first();
|
||||
}
|
||||
|
||||
public function findBySecret( $secret ) {
|
||||
$data = self::$db->get( $this->tableName, [ 'secret', '=', $secret ] );
|
||||
if ( ! $data->count() ) {
|
||||
return false;
|
||||
}
|
||||
return $data->first();
|
||||
}
|
||||
|
||||
public function findUserToken( $user_id ) {
|
||||
$data = self::$db->get( $this->tableName, [ 'createdBy', '=', $user_id, 'AND', 'token_type', '=', 'user' ] );
|
||||
if ( ! $data->count() ) {
|
||||
return false;
|
||||
}
|
||||
return $data->first();
|
||||
}
|
||||
}
|
@ -43,7 +43,6 @@ class User extends DatabaseModel {
|
||||
[ 'name', 'varchar', '20' ],
|
||||
[ 'confirmationCode', 'varchar', '80' ],
|
||||
[ 'prefs', 'text', '' ],
|
||||
[ 'auth_token', 'text', '' ],
|
||||
];
|
||||
public $permissionMatrix = [
|
||||
'uploadImages' => [
|
||||
@ -694,33 +693,45 @@ class User extends DatabaseModel {
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
public function findByToken( $token ) {
|
||||
$data = self::$db->get( $this->tableName, [ 'auth_token', '=', $token ] );
|
||||
if ( ! $data->count() ) {
|
||||
public function authorize( $username, $password ) {
|
||||
if ( !isset( self::$log ) ) {
|
||||
self::$log = new Log;
|
||||
}
|
||||
if ( !$this->get( $username ) ) {
|
||||
self::$log->login( 0, "API: User not found: $username" );
|
||||
return false;
|
||||
}
|
||||
return $data->first();
|
||||
}
|
||||
|
||||
public function addAccessToken( $id, $length = 64 ) {
|
||||
if ( ! Check::id( $id ) ) {
|
||||
// login attempts protection.
|
||||
$timeLimit = ( time() - 3600 );
|
||||
$limit = Config::getValue( 'main/loginLimit' );
|
||||
$user = $this->data();
|
||||
if ( $limit > 0 ) {
|
||||
$limitCheck = self::$db->get(
|
||||
'logs',
|
||||
[
|
||||
'source', '=', 'login',
|
||||
'AND',
|
||||
'userID', '=', $user->ID,
|
||||
'AND',
|
||||
'time', '>=', $timeLimit,
|
||||
'AND',
|
||||
'action', '!=', 'pass',
|
||||
]
|
||||
);
|
||||
if ( $limitCheck->count() >= $limit ) {
|
||||
self::$log->login( $user->ID, 'API: Too many failed attempts.' );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ( !Check::password( $password ) ) {
|
||||
self::$log->login( $user->ID, 'API: Invalid Password.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [ 'auth_token' => $this->generateRandomString( $length ) ];
|
||||
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
|
||||
Debug::error( "User: $id not updated." );
|
||||
if ( !Hash::check( $password, $user->password ) ) {
|
||||
self::$log->login( $user->ID, 'API: Wrong Password.' );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private function generateRandomString( $length = 10 ) {
|
||||
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
$charactersLength = strlen( $characters );
|
||||
$randomString = '';
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$randomString .= $characters[random_int(0, $charactersLength - 1)];
|
||||
}
|
||||
return $randomString;
|
||||
self::$log->login( $this->data()->ID, 'API: pass' );
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user