mirror of
https://github.com/beestat/app.git
synced 2025-07-09 03:04:07 -04:00
Fixes API-E. Fixes API-K. Fixes API-J.
Cleaned up some logic related to how tokens and refreshing works. Lots of stuff was broken.
This commit is contained in:
parent
5fb835737f
commit
279d97d72f
@ -271,6 +271,10 @@ final class cora {
|
||||
$session = session::get_instance();
|
||||
$session_is_valid = $session->touch($this->api_user['session_key']);
|
||||
|
||||
// Make sure the updated session timestamp doesn't get rolled back on
|
||||
// exception.
|
||||
$this->database->commit_transaction();
|
||||
|
||||
// Process each request.
|
||||
foreach($this->api_calls as $api_call) {
|
||||
// Store the currently running API call for tracking if an error occurs.
|
||||
@ -291,7 +295,7 @@ final class cora {
|
||||
// If the request requires a session, make sure it's valid.
|
||||
if($call_type === 'private') {
|
||||
if($session_is_valid === false) {
|
||||
throw new \Exception('Session is expired.', 1004);
|
||||
throw new exception('Session is expired.', 1004, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -638,7 +642,8 @@ final class cora {
|
||||
$error_code,
|
||||
$error_file,
|
||||
$error_line,
|
||||
debug_backtrace(false)
|
||||
debug_backtrace(false),
|
||||
true
|
||||
);
|
||||
die(); // Do not continue execution; shutdown handler will now run.
|
||||
}
|
||||
@ -655,7 +660,8 @@ final class cora {
|
||||
$e->getCode(),
|
||||
$e->getFile(),
|
||||
$e->getLine(),
|
||||
$e->getTrace()
|
||||
$e->getTrace(),
|
||||
(method_exists($e, 'getReportable') === true ? $e->getReportable() : true)
|
||||
);
|
||||
die(); // Do not continue execution; shutdown handler will now run.
|
||||
}
|
||||
@ -671,7 +677,7 @@ final class cora {
|
||||
* @param int $error_line The line of the file the error happened on.
|
||||
* @param array $error_trace The stack trace for the error.
|
||||
*/
|
||||
public function set_error_response($error_message, $error_code, $error_file, $error_line, $error_trace) {
|
||||
public function set_error_response($error_message, $error_code, $error_file, $error_line, $error_trace, $reportable) {
|
||||
// There are a few places that call this function to set an error response,
|
||||
// so this can't just be done in the exception handler alone. If an error
|
||||
// occurs, rollback the current transaction. Also only attempt to roll back
|
||||
@ -706,43 +712,45 @@ final class cora {
|
||||
|
||||
// Send data to Sentry for error logging.
|
||||
// https://docs.sentry.io/development/sdk-dev/event-payloads/
|
||||
$data = [
|
||||
'event_id' => str_replace('-', '', exec('uuidgen -r')),
|
||||
'timestamp' => date('c'),
|
||||
'logger' => 'cora',
|
||||
'platform' => 'php',
|
||||
'level' => 'error',
|
||||
'tags' => [
|
||||
'error_code' => $error_code
|
||||
],
|
||||
'extra' => [
|
||||
'api_user_id' => $api_user_id,
|
||||
'error_file' => $error_file,
|
||||
'error_line' => $error_line,
|
||||
'error_trace' => $error_trace
|
||||
],
|
||||
'exception' => [
|
||||
'type' => 'Exception',
|
||||
'value' => $error_message,
|
||||
'handled' => false
|
||||
],
|
||||
'user' => [
|
||||
'id' => $user_id,
|
||||
'ip_address' => $_SERVER['REMOTE_ADDR']
|
||||
]
|
||||
];
|
||||
if ($reportable === true) {
|
||||
$data = [
|
||||
'event_id' => str_replace('-', '', exec('uuidgen -r')),
|
||||
'timestamp' => date('c'),
|
||||
'logger' => 'cora',
|
||||
'platform' => 'php',
|
||||
'level' => 'error',
|
||||
'tags' => [
|
||||
'error_code' => $error_code
|
||||
],
|
||||
'extra' => [
|
||||
'api_user_id' => $api_user_id,
|
||||
'error_file' => $error_file,
|
||||
'error_line' => $error_line,
|
||||
'error_trace' => $error_trace
|
||||
],
|
||||
'exception' => [
|
||||
'type' => 'Exception',
|
||||
'value' => $error_message,
|
||||
'handled' => false
|
||||
],
|
||||
'user' => [
|
||||
'id' => $user_id,
|
||||
'ip_address' => $_SERVER['REMOTE_ADDR']
|
||||
]
|
||||
];
|
||||
|
||||
exec(
|
||||
'curl ' .
|
||||
'-H "Content-Type: application/json" ' .
|
||||
'-H "X-Sentry-Auth: Sentry sentry_version=7, sentry_key=' . $this->setting->get('sentry_key') . '" ' .
|
||||
'--silent ' . // silent; keeps logs out of stderr
|
||||
'--show-error ' . // override silent on failure
|
||||
'--max-time 10 ' .
|
||||
'--connect-timeout 5 ' .
|
||||
'--data \'' . json_encode($data) . '\' ' .
|
||||
'"https://sentry.io/api/' . $this->setting->get('sentry_project_id') . '/store/" > /dev/null &'
|
||||
);
|
||||
exec(
|
||||
'curl ' .
|
||||
'-H "Content-Type: application/json" ' .
|
||||
'-H "X-Sentry-Auth: Sentry sentry_version=7, sentry_key=' . $this->setting->get('sentry_key') . '" ' .
|
||||
'--silent ' . // silent; keeps logs out of stderr
|
||||
'--show-error ' . // override silent on failure
|
||||
'--max-time 10 ' .
|
||||
'--connect-timeout 5 ' .
|
||||
'--data \'' . json_encode($data) . '\' ' .
|
||||
'"https://sentry.io/api/' . $this->setting->get('sentry_project_id') . '/store/" > /dev/null &'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -779,7 +787,8 @@ final class cora {
|
||||
$error['type'],
|
||||
$error['file'],
|
||||
$error['line'],
|
||||
debug_backtrace(false)
|
||||
debug_backtrace(false),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
@ -824,7 +833,8 @@ final class cora {
|
||||
$e->getCode(),
|
||||
$e->getFile(),
|
||||
$e->getLine(),
|
||||
$e->getTrace()
|
||||
$e->getTrace(),
|
||||
(method_exists($e, 'getReportable') === true ? $e->getReportable() : true)
|
||||
);
|
||||
$this->set_default_headers();
|
||||
$this->output_headers();
|
||||
|
@ -695,18 +695,21 @@ final class database extends \mysqli {
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually delete a row from a table by the primary key.
|
||||
* Set deleted = 1 on the database row.
|
||||
*
|
||||
* @param string $table The table to delete from.
|
||||
* @param string $resource The table to delete from.
|
||||
* @param int $id The value of the primary key to delete.
|
||||
*
|
||||
* @return int The number of rows affected by the delete (could be 0).
|
||||
*/
|
||||
public function delete($table, $id) {
|
||||
$query = 'delete from ' . $this->escape_identifier($table) .
|
||||
' where ' . $this->escape_identifier($table . '_id') . ' = ' .
|
||||
$this->escape($id);
|
||||
$this->query($query);
|
||||
public function delete($resource, $id) {
|
||||
$table = $this->get_table($resource);
|
||||
|
||||
$attributes = [];
|
||||
$attributes[$table . '_id'] = $id;
|
||||
$attributes['deleted'] = true;
|
||||
|
||||
$this->update($resource, $attributes);
|
||||
|
||||
return $this->affected_rows;
|
||||
}
|
||||
|
25
api/cora/exception.php
Normal file
25
api/cora/exception.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace cora;
|
||||
|
||||
/**
|
||||
* Custom exception class. Requires message, code, and replaces $previous with
|
||||
* $reportable to indicate if the exception should be reported to a logging
|
||||
* service or not.
|
||||
*
|
||||
* The class name was made lowercase to simplify autoincludes, but the
|
||||
* interface was otherwise left alone because I still need to support catching
|
||||
* regular exceptions.
|
||||
*
|
||||
* @author Jon Ziebell
|
||||
*/
|
||||
final class exception extends \Exception {
|
||||
public function __construct($message, $code, $reportable = true) {
|
||||
$this->reportable = $reportable;
|
||||
return parent::__construct($message, $code, null);
|
||||
}
|
||||
|
||||
public function getReportable() {
|
||||
return $this->reportable;
|
||||
}
|
||||
}
|
@ -225,13 +225,7 @@ final class session {
|
||||
|
||||
$sessions = $database->read('cora\session', ['session_key' => $session_key]);
|
||||
if(count($sessions) === 1) {
|
||||
$database->update(
|
||||
'cora\session',
|
||||
[
|
||||
'session_id' => $sessions[0]['session_id'],
|
||||
'deleted' => 1
|
||||
]
|
||||
);
|
||||
$database->delete('cora\session', $sessions[0]['session_id']);
|
||||
// Remove these if the current session got logged out.
|
||||
if($session_key === $this->session_key) {
|
||||
$this->session_key = null;
|
||||
|
@ -187,7 +187,8 @@ class ecobee extends external_api {
|
||||
[]
|
||||
);
|
||||
if(count($ecobee_tokens) !== 1) {
|
||||
throw new Exception('No token for this user');
|
||||
$this->api('user', 'log_out', ['all' => true]);
|
||||
throw new cora\exception('No ecobee access for this user.', 10501, false);
|
||||
}
|
||||
$ecobee_token = $ecobee_tokens[0];
|
||||
}
|
||||
@ -236,6 +237,15 @@ class ecobee extends external_api {
|
||||
throw new Exception($response['status']['message']);
|
||||
}
|
||||
}
|
||||
else if (isset($response['status']) === true && $response['status']['code'] === 16) {
|
||||
// Token has been deauthorized by user. You must re-request authorization.
|
||||
if($this::$log_mysql !== 'all') {
|
||||
$this->log_mysql($curl_response);
|
||||
}
|
||||
$this->api('ecobee_token', 'delete', $ecobee_token['ecobee_token_id']);
|
||||
$this->api('user', 'log_out', ['all' => true]);
|
||||
throw new cora\exception('Ecobee access was revoked by user.', 10500, false);
|
||||
}
|
||||
else if (isset($response['status']) === true && $response['status']['code'] !== 0) {
|
||||
// Any other error
|
||||
if($this::$log_mysql !== 'all') {
|
||||
|
@ -68,7 +68,8 @@ class ecobee_token extends cora\crud {
|
||||
$ecobee_tokens = $database->read(
|
||||
'ecobee_token',
|
||||
[
|
||||
'user_id' => $this->session->get_user_id()
|
||||
'user_id' => $this->session->get_user_id(),
|
||||
'deleted' => false
|
||||
]
|
||||
);
|
||||
if(count($ecobee_tokens) === 0) {
|
||||
@ -94,6 +95,7 @@ class ecobee_token extends cora\crud {
|
||||
isset($response['refresh_token']) === false
|
||||
) {
|
||||
$this->delete($ecobee_token['ecobee_token_id']);
|
||||
$this->api('user', 'log_out', ['all' => true]);
|
||||
$database->release_lock($lock_name);
|
||||
throw new Exception('Could not refresh ecobee token; ecobee returned no token.', 10002);
|
||||
}
|
||||
@ -125,10 +127,7 @@ class ecobee_token extends cora\crud {
|
||||
$database = cora\database::get_transactionless_instance();
|
||||
|
||||
// Need to delete the token before logging out or else the delete fails.
|
||||
$return = $database->delete('ecobee_token', $id);
|
||||
|
||||
// Log out
|
||||
$this->api('user', 'log_out', ['all' => true]);
|
||||
$return = $database->delete($this->resource, $id);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
@ -74,11 +74,11 @@ class patreon_token extends cora\crud {
|
||||
$lock_name = 'patreon_token->refresh(' . $this->session->get_user_id() . ')';
|
||||
$database->get_lock($lock_name, 3);
|
||||
|
||||
// $patreon_tokens = $this->read();
|
||||
$patreon_tokens = $database->read(
|
||||
'patreon_token',
|
||||
[
|
||||
'user_id' => $this->session->get_user_id()
|
||||
'user_id' => $this->session->get_user_id(),
|
||||
'deleted' => false
|
||||
]
|
||||
);
|
||||
if(count($patreon_tokens) === 0) {
|
||||
@ -130,7 +130,7 @@ class patreon_token extends cora\crud {
|
||||
*/
|
||||
public function delete($id) {
|
||||
$database = cora\database::get_transactionless_instance();
|
||||
$return = $database->delete('patreon_token', $id);
|
||||
$return = $database->delete($this->resource, $id);
|
||||
return $return;
|
||||
}
|
||||
|
||||
|
@ -144,7 +144,9 @@ class user extends cora\crud {
|
||||
}
|
||||
|
||||
if($all === true) {
|
||||
$database = cora\database::get_instance();
|
||||
// Sometimes I need to log out and then throw an exception. Using the
|
||||
// transactionless instance makes sure that actually works.
|
||||
$database = cora\database::get_transactionless_instance();
|
||||
$sessions = $database->read(
|
||||
'cora\session',
|
||||
[
|
||||
@ -154,7 +156,7 @@ class user extends cora\crud {
|
||||
);
|
||||
$success = true;
|
||||
foreach($sessions as $session) {
|
||||
$success &= $this->session->delete($session['session_key']);
|
||||
$success &= $database->delete('cora\session', $session['session_id']);
|
||||
}
|
||||
return $success;
|
||||
}
|
||||
|
@ -46,10 +46,6 @@ beestat.api.prototype.send = function(opt_api_call) {
|
||||
self.load_(this.responseText);
|
||||
});
|
||||
|
||||
// var endpoint = (window.environment === 'live')
|
||||
// ? 'https://api.beestat.io/'
|
||||
// : 'http://' + window.environment + '.api.beestat.io/';
|
||||
// this.xhr_.open('POST', endpoint + '?' + query_string);
|
||||
this.xhr_.open('POST', 'api/?' + query_string);
|
||||
this.xhr_.send();
|
||||
} else {
|
||||
@ -172,10 +168,12 @@ beestat.api.prototype.load_ = function(response_text) {
|
||||
if (
|
||||
response.data &&
|
||||
(
|
||||
response.data.error_code === 1004 || // Session is expired.
|
||||
response.data.error_code === 10001 || // Could not get first token.
|
||||
response.data.error_code === 10002 || // Could not refresh ecobee token; no token found.
|
||||
response.data.error_code === 10003 // Could not refresh ecobee token; ecobee returned no token.
|
||||
response.data.error_code === 1004 || // Session is expired.
|
||||
response.data.error_code === 10000 || // Could not get first token.
|
||||
response.data.error_code === 10001 || // Could not refresh ecobee token; no token found.
|
||||
response.data.error_code === 10002 || // Could not refresh ecobee token; ecobee returned no token.
|
||||
response.data.error_code === 10500 || // Ecobee access was revoked by user.
|
||||
response.data.error_code === 10501 // No ecobee access for this user.
|
||||
)
|
||||
) {
|
||||
window.location.href = '/';
|
||||
|
Loading…
x
Reference in New Issue
Block a user