index_more.php

This commit is contained in:
Mike Schwörer 2018-11-12 12:41:59 +01:00
parent 083945852b
commit 2163ae4dbf
Signed by: Mikescher
GPG Key ID: D3C7172E0A70F8CF
7 changed files with 366 additions and 110 deletions

View File

@ -22,12 +22,24 @@ body
#mainpnl #mainpnl
{ {
box-shadow: 0 0 32px #DDD; box-shadow: 0 0 32px #DDD;
animation:blink-shadow ease-in-out 4s infinite; //animation:blink-shadow ease-in-out 4s infinite;
width: 87%; width: 87%;
min-width: 300px; min-width: 300px;
max-width: 900px; max-width: 900px;
position: relative; position: relative;
min-height: 485px; min-height: 570px;
background: var(--form-back-color);
color: var(--form-fore-color);
border: .0625rem solid var(--form-border-color);
border-radius: var(--universal-border-radius);
margin: 32px .5rem;
padding: calc(2 * var(--universal-padding)) var(--universal-padding);
}
.red-code
{
border-left: .25rem solid #E53935;
} }
#mainpnl input, #mainpnl input,
@ -178,6 +190,7 @@ input::-webkit-inner-spin-button {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
align-content: center; align-content: center;
pointer-events: none;
} }
a.card, a.card,
@ -193,3 +206,23 @@ a.card:hover
{ {
box-shadow: 0 0 16px #AAA; box-shadow: 0 0 16px #AAA;
} }
table.scode_table {
max-height: none;
}
table.scode_table td:nth-child(2) {
flex-grow: 3;
}
table.scode_table th:nth-child(2) {
flex-grow: 3;
}
#mainpnl h2 {
margin-top: 1.75rem;
}
.linkcaption:hover {
text-decoration: none;
}

View File

@ -16,7 +16,7 @@
<a href="https://play.google.com/store/apps/details?id=com.blackforestbytes.simplecloudnotifier" class="button bordered" id="tl_link"><span class="icn-google-play"></span></a> <a href="https://play.google.com/store/apps/details?id=com.blackforestbytes.simplecloudnotifier" class="button bordered" id="tl_link"><span class="icn-google-play"></span></a>
<a href="/index_api.php" class="button bordered" id="tr_link">API</a> <a href="/index_api.php" class="button bordered" id="tr_link">API</a>
<h1>Simple Cloud Notifier</h1> <a href="/" class="linkcaption"><h1>Simple Cloud Notifier</h1></a>
<div class="row responsive-label"> <div class="row responsive-label">
<div class="col-sm-12 col-md-3"><label for="uid" class="doc">UserID</label></div> <div class="col-sm-12 col-md-3"><label for="uid" class="doc">UserID</label></div>
@ -46,7 +46,7 @@
<div class="row responsive-label"> <div class="row responsive-label">
<div class="col-sm-12 col-md-3"><label for="txt" class="doc">Message Content</label></div> <div class="col-sm-12 col-md-3"><label for="txt" class="doc">Message Content</label></div>
<div class="col-sm-12 col-md"><textarea id="txt" class="doc" <?php echo (isset($_GET['preset_content']) ? (' value="'.$_GET['preset_content'].'" '):(''));?> rows="5"></textarea></div> <div class="col-sm-12 col-md"><textarea id="txt" class="doc" <?php echo (isset($_GET['preset_content']) ? (' value="'.$_GET['preset_content'].'" '):(''));?> rows="8"></textarea></div>
</div> </div>
<div class="row"> <div class="row">

View File

@ -2,7 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<link rel="stylesheet" href="/css/mini-default.min.css"> <link rel="stylesheet" href="/css/mini-default.min.css"> <!-- https://minicss.org/docs -->
<title>Simple Cloud Notifications - API</title> <title>Simple Cloud Notifications - API</title>
<!--<link rel="stylesheet" href="/css/mini-nord.min.css">--> <!--<link rel="stylesheet" href="/css/mini-nord.min.css">-->
<!--<link rel="stylesheet" href="/css/mini-dark.min.css">--> <!--<link rel="stylesheet" href="/css/mini-dark.min.css">-->
@ -10,27 +10,31 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
</head> </head>
<body> <body>
<form id="mainpnl"> <div id="mainpnl">
<a href="https://play.google.com/store/apps/details?id=com.blackforestbytes.simplecloudnotifier" class="button bordered" id="tl_link"><span class="icn-google-play"></span></a> <a href="https://play.google.com/store/apps/details?id=com.blackforestbytes.simplecloudnotifier" class="button bordered" id="tl_link"><span class="icn-google-play"></span></a>
<a href="/index.php" class="button bordered" id="tr_link">Send</a> <a href="/index.php" class="button bordered" id="tr_link">Send</a>
<h1>Simple Cloud Notifier</h1> <a href="/" class="linkcaption"><h1>Simple Cloud Notifier</h1></a>
<p>Get your user-id and user-key from the app and send notifications to your phone by performing a POST request against <code>https://simplecloudnotifier.blackforestbytes.com/send.php</code></p> <p>Get your user-id and user-key from the app and send notifications to your phone by performing a POST request against <code>https://simplecloudnotifier.blackforestbytes.com/send.php</code></p>
<pre>curl \ <pre>curl \
--data "user_id={userid}" \ --data "user_id={userid}" \
--data "user_key={userkey}" \ --data "user_key={userkey}" \
--data "priority={0|1|2}" \
--data "title={message_title}" \ --data "title={message_title}" \
--data "content={message_content}" \ --data "content={message_body}" \
--data "priority={0|1|2}" \
--data "msg_id={unique_message_id}" \
https://scn.blackforestbytes.com/send.php</pre> https://scn.blackforestbytes.com/send.php</pre>
<p>The <code>content</code> and <code>priority</code> parameters are optional, you can also send message with only a title and the default priority</p> <p>The <code>content</code>, <code>priority</code> and <code>msg_id</code> parameters are optional, you can also send message with only a title and the default priority</p>
<pre>curl \ <pre>curl \
--data "user_id={userid}" \ --data "user_id={userid}" \
--data "user_key={userkey}" \ --data "user_key={userkey}" \
--data "title={message_title}" \ --data "title={message_title}" \
https://scn.blackforestbytes.com/send.php</pre> https://scn.blackforestbytes.com/send.php</pre>
</form>
<a href="/index_more.php" class="button bordered tertiary" style="float: right; min-width: 100px; text-align: center">More</a>
</div>
<div id="copyinfo"> <div id="copyinfo">
<a href="https://www.blackforestbytes.com">&#169; blackforestbytes</a> <a href="https://www.blackforestbytes.com">&#169; blackforestbytes</a>

186
web/index_more.php Normal file
View File

@ -0,0 +1,186 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="/css/mini-default.min.css"> <!-- https://minicss.org/docs -->
<title>Simple Cloud Notifications - API</title>
<!--<link rel="stylesheet" href="/css/mini-nord.min.css">-->
<!--<link rel="stylesheet" href="/css/mini-dark.min.css">-->
<link rel="stylesheet" href="/css/style.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div id="mainpnl">
<a href="https://play.google.com/store/apps/details?id=com.blackforestbytes.simplecloudnotifier" class="button bordered" id="tl_link"><span class="icn-google-play"></span></a>
<a href="/index.php" class="button bordered" id="tr_link">Send</a>
<a href="/" class="linkcaption"><h1>Simple Cloud Notifier</h1></a>
<h2>Introduction</h2>
<div class="section">
<p>
With this API you can send push notifications to your phone.
</p>
<p>
To recieve them you will need to install the <a href="https://play.google.com/store/apps/details?id=com.blackforestbytes.simplecloudnotifier">SimpleCloudNotifier</a> app from the play store.
When you open the app you can click on the account tab to see you unique <code>user_id</code> and <code>user_key</code>.
These two values are used to identify and authenticate your device so that send messages can be routed to your phone.
</p>
<p>
You can at any time generate a new <code>user_key</code> in the app and invalidate the old one.
</p>
<p>
There is also a <a href="/index.php">web interface</a> for this API to manually send notifications to your phone or to test your setup.
</p>
</div>
<h2>Quota</h2>
<div class="section">
<p>
By default you can send up to 100 messages per day per device.
If you need more you can upgrade your account in the app to get 1000 messages per day, this has the additional benefit of removing ads and supporting the development of the app (and making sure I can pay the server costs).
</p>
</div>
<h2>API Requests</h2>
<div class="section">
<p>
To send a new notification you send a <code>POST</code> request to the URL <code>https://scn.blackforestbytes.com/send.php</code>.
All Parameters can either directly be submitted as URL parameters or they can be put into the POST body.
</p>
<p>
You <i>need</i> to supply a valid <code>user_id</code> - <code>user_key</code> pair and a <code>title</code> for your message, all other parameter are optional.
</p>
</div>
<h2>API Response</h2>
<div class="section">
<p>
If the operation was successful the API will respond with an HTTP statuscode 200 and an JSON payload indicating the send message and your remaining quota
</p>
<pre class="red-code">{
"success":true,
"message":"Message sent",
"response":
{
"multicast_id":8000000000000000006,
"success":1,
"failure":0,
"canonical_ids":0,
"results": [{"message_id":"0:10000000000000000000000000000000d"}]
},
"messagecount":623,
"quota":17,
"quota_max":100
}</pre>
<p>
If the operation is <b>not</b> successful the API will respond with an 4xx HTTP statuscode.
</p>
<table class="scode_table">
<thead>
<tr>
<th>Statuscode</th>
<th>Explanation</th>
</tr>
</thead>
<tbody>
<tr>
<td data-label="Statuscode">200 (OK)</td>
<td data-label="Explanation">Message sent</td>
</tr>
<tr>
<td data-label="Statuscode">400 (Bad Request)</td>
<td data-label="Explanation">The request is invalid (missing parameters or wrong values)</td>
</tr>
<tr>
<td data-label="Statuscode">401 (Unauthorized)</td>
<td data-label="Explanation">The user_id was not found or the user_key is wrong</td>
</tr>
<tr>
<td data-label="Statuscode">403 (Forbidden)</td>
<td data-label="Explanation">The user has exceeded its daily quota - wait 24 hours or upgrade your account</td>
</tr>
<tr>
<td data-label="Statuscode">500 (Internal Server Error)</td>
<td data-label="Explanation">There was an internal error while sending your data - try again later</td>
</tr>
</tbody>
</table>
<p>
There is also always a JSON payload with additional information.
The <code>success</code> field is always there and in the error state you the <code>message</code> field to get a descritpion of the problem.
</p>
<pre class="red-code">{
"success":false,
"error":2101,
"errhighlight":-1,
"message":"Daily quota reached (100)"
}</pre>
</div>
<h2>Message Content</h2>
<div class="section">
<p>
Every message must have a title set.
But you also (optionally) add more content, while the title has a max length of 120 characters, the conntent can be up to 10.000 characters.
You can see the whole message with title and content in the app or when clicking on the notification.
</p>
<p>
If needed the content can be supplied in the <code>content</code> parameter.
</p>
<pre>curl \
--data "user_id={userid}" \
--data "user_key={userkey}" \
--data "title={message_title}" \
--data "content={message_content}" \
https://scn.blackforestbytes.com/send.php</pre>
</div>
<h2>Message Priority</h2>
<div class="section">
<p>
Currently you can send a message with three different priorities: 0 (low), 1 (normal) and 2 (high).
In the app you can then configure a different behaviour for different priorities, e.g. only playing a sound if the notification is high priority.
</p>
<p>
Priorites are either 0, 1 or 2 and are supplied in the <code>priority</code> parameter.
If no priority is supplied the message will get the default priority of 1.
</p>
<pre>curl \
--data "user_id={userid}" \
--data "user_key={userkey}" \
--data "title={message_title}" \
--data "priority={0|1|2}" \
https://scn.blackforestbytes.com/send.php</pre>
</div>
<h2>Message Uniqueness</h2>
<div class="section">
<p>
Sometimes your script can run in an environment with an unstable connection and you want to implement an automatic re-try mechanism to send a message again if the last try failed due to bad connectivity.
</p>
<p>
To ensure that a message is only send once you can generate a unique id for your message (I would recommend a simple <code>uuidgen</code>).
If you send a message with an UUID that was already used in the near past the API still returns OK, but no new message is sent.
</p>
<p>
The message_id is optional - but if you want to use it you need to supply it via the <code>msg_id</code> parameter.
</p>
<pre>curl \
--data "user_id={userid}" \
--data "user_key={userkey}" \
--data "title={message_title}" \
--data "msg_id={message_id}" \
https://scn.blackforestbytes.com/send.php</pre>
<p>
Be aware that the server only saves send messages for a short amount of time. Because of that you can only use this to prevent duplicates in a short time-frame, older messages with the same ID are probably already deleted and the message will be send again.
</p>
</div>
</div>
<div id="copyinfo">
<a href="https://www.blackforestbytes.com">&#169; blackforestbytes</a>
</div>
</body>
</html>

View File

@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Simple Cloud Notifications</title> <title>Simple Cloud Notifications</title>
<link rel="stylesheet" href="/css/mini-default.min.css"> <link rel="stylesheet" href="/css/mini-default.min.css"> <!-- https://minicss.org/docs -->
<!--<link rel="stylesheet" href="/css/mini-nord.min.css">--> <!--<link rel="stylesheet" href="/css/mini-nord.min.css">-->
<!--<link rel="stylesheet" href="/css/mini-dark.min.css">--> <!--<link rel="stylesheet" href="/css/mini-dark.min.css">-->
<link rel="stylesheet" href="/css/style.css"> <link rel="stylesheet" href="/css/style.css">
@ -12,7 +12,7 @@
<body> <body>
<form id="mainpnl"> <div id="mainpnl">
<div class="fullcenterflex"> <div class="fullcenterflex">
@ -42,9 +42,9 @@
<a href="https://play.google.com/store/apps/details?id=com.blackforestbytes.simplecloudnotifier" class="button bordered" id="tl_link"><span class="icn-google-play"></span></a> <a href="https://play.google.com/store/apps/details?id=com.blackforestbytes.simplecloudnotifier" class="button bordered" id="tl_link"><span class="icn-google-play"></span></a>
<a href="/index.php" class="button bordered" id="tr_link">Send</a> <a href="/index.php" class="button bordered" id="tr_link">Send</a>
<h1>Simple Cloud Notifier</h1> <a href="/" class="linkcaption"><h1>Simple Cloud Notifier</h1></a>
</form> </div>
<div id="copyinfo"> <div id="copyinfo">
<a href="https://www.blackforestbytes.com">&#169; blackforestbytes</a> <a href="https://www.blackforestbytes.com">&#169; blackforestbytes</a>

View File

@ -17,8 +17,14 @@ function getConfig()
return Statics::$CFG = require "config.php"; return Statics::$CFG = require "config.php";
} }
function reportError($msg) /**
* @param String $msg
* @param Exception $e
*/
function reportError($msg, $e = null)
{ {
if ($e != null) $msg = ($msg."\n\n[[EXCEPTION]]\n" . $e . "\n" . $e->getMessage() . "\n" . $e->getTraceAsString());
$subject = "SCN_Server has encountered an Error at " . date("Y-m-d H:i:s") . "] "; $subject = "SCN_Server has encountered an Error at " . date("Y-m-d H:i:s") . "] ";
$content = ""; $content = "";
@ -37,6 +43,16 @@ function reportError($msg)
if (getConfig()['error_reporting']['send-mail']) sendMail($subject, $content, getConfig()['error_reporting']['email-error-target'], getConfig()['error_reporting']['email-error-sender']); if (getConfig()['error_reporting']['send-mail']) sendMail($subject, $content, getConfig()['error_reporting']['email-error-target'], getConfig()['error_reporting']['email-error-sender']);
} }
/**
* @param string $subject
* @param string $content
* @param string $to
* @param string $from
*/
function sendMail($subject, $content, $to, $from) {
mail($to, $subject, $content, 'From: ' . $from);
}
/** /**
* @param string $idx * @param string $idx
* @return string * @return string
@ -93,6 +109,7 @@ function generateRandomAuthKey()
* @param $header * @param $header
* @return array|object|string * @return array|object|string
* @throws \Httpful\Exception\ConnectionErrorException * @throws \Httpful\Exception\ConnectionErrorException
* @throws Exception
*/ */
function sendPOST($url, $body, $header) function sendPOST($url, $body, $header)
{ {
@ -153,7 +170,7 @@ function verifyOrderToken($tok)
} }
catch (Exception $e) catch (Exception $e)
{ {
reportError("VerifyOrder token threw exception: " . $e . "\n" . $e->getMessage() . "\n" . $e->getTraceAsString()); reportError("VerifyOrder token threw exception", $e);
return false; return false;
} }
} }
@ -173,3 +190,10 @@ function refreshVerifyToken()
return $obj->access_token; return $obj->access_token;
} }
function api_return($http_code, $message)
{
http_response_code($http_code);
echo $message;
die();
}

View File

@ -2,18 +2,22 @@
include_once 'model.php'; include_once 'model.php';
try
{
//------------------------------------------------------------------ //------------------------------------------------------------------
sleep(1); //sleep(1);
//------------------------------------------------------------------ //------------------------------------------------------------------
$INPUT = array_merge($_GET, $_POST); $INPUT = array_merge($_GET, $_POST);
if (!isset($INPUT['user_id'])) die(json_encode(['success' => false, 'errhighlight' => 101, 'message' => 'Missing parameter [[user_id]]'])); if (!isset($INPUT['user_id'])) api_return(400, json_encode(['success' => false, 'error' => 1101, 'errhighlight' => 101, 'message' => 'Missing parameter [[user_id]]']));
if (!isset($INPUT['user_key'])) die(json_encode(['success' => false, 'errhighlight' => 102, 'message' => 'Missing parameter [[user_token]]'])); if (!isset($INPUT['user_key'])) api_return(400, json_encode(['success' => false, 'error' => 1102, 'errhighlight' => 102, 'message' => 'Missing parameter [[user_token]]']));
if (!isset($INPUT['title'])) die(json_encode(['success' => false, 'errhighlight' => 103, 'message' => 'Missing parameter [[title]]'])); if (!isset($INPUT['title'])) api_return(400, json_encode(['success' => false, 'error' => 1103, 'errhighlight' => 103, 'message' => 'Missing parameter [[title]]']));
//------------------------------------------------------------------ //------------------------------------------------------------------
$user_id = $INPUT['user_id']; $user_id = $INPUT['user_id'];
$user_key = $INPUT['user_key']; $user_key = $INPUT['user_key'];
$message = $INPUT['title']; $message = $INPUT['title'];
@ -22,11 +26,11 @@ $priority = isset($INPUT['priority']) ? $INPUT['priority'] : '1';
//------------------------------------------------------------------ //------------------------------------------------------------------
if ($priority !== '0' && $priority !== '1' && $priority !== '2') die(json_encode(['success' => false, 'errhighlight' => 105, 'message' => 'Invalid priority'])); if ($priority !== '0' && $priority !== '1' && $priority !== '2') api_return(400, json_encode(['success' => false, 'error' => 1104, 'errhighlight' => 105, 'message' => 'Invalid priority']));
if (strlen(trim($message)) == 0) die(json_encode(['success' => false, 'errhighlight' => 103, 'message' => 'No title specified'])); if (strlen(trim($message)) == 0) api_return(400, json_encode(['success' => false, 'error' => 1201, 'errhighlight' => 103, 'message' => 'No title specified']));
if (strlen($message) > 120) die(json_encode(['success' => false, 'errhighlight' => 103, 'message' => 'Title too long (120 characters)'])); if (strlen($message) > 120) api_return(400, json_encode(['success' => false, 'error' => 1202, 'errhighlight' => 103, 'message' => 'Title too long (120 characters)']));
if (strlen($content) > 10000) die(json_encode(['success' => false, 'errhighlight' => 104, 'message' => 'Content too long (10000 characters)'])); if (strlen($content) > 10000) api_return(400, json_encode(['success' => false, 'error' => 1203, 'errhighlight' => 104, 'message' => 'Content too long (10000 characters)']));
//------------------------------------------------------------------ //------------------------------------------------------------------
@ -36,18 +40,18 @@ $stmt = $pdo->prepare('SELECT user_id, user_key, fcm_token, messages_sent, quota
$stmt->execute(['uid' => $user_id]); $stmt->execute(['uid' => $user_id]);
$datas = $stmt->fetchAll(PDO::FETCH_ASSOC); $datas = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (count($datas)<=0) die(json_encode(['success' => false, 'errhighlight' => 101, 'message' => 'User not found'])); if (count($datas)<=0) die(json_encode(['success' => false, 'error' => 1301, 'errhighlight' => 101, 'message' => 'User not found']));
$data = $datas[0]; $data = $datas[0];
if ($data === null) die(json_encode(['success' => false, 'errhighlight' => 101, 'message' => 'User not found'])); if ($data === null) api_return(401, json_encode(['success' => false, 'error' => 1301, 'errhighlight' => 101, 'message' => 'User not found']));
if ($data['user_id'] !== (int)$user_id) die(json_encode(['success' => false, 'errhighlight' => 101, 'message' => 'UserID not found'])); if ($data['user_id'] !== (int)$user_id) api_return(401, json_encode(['success' => false, 'error' => 1302, 'errhighlight' => 101, 'message' => 'UserID not found']));
if ($data['user_key'] !== $user_key) die(json_encode(['success' => false, 'errhighlight' => 102, 'message' => 'Authentification failed'])); if ($data['user_key'] !== $user_key) api_return(401, json_encode(['success' => false, 'error' => 1303, 'errhighlight' => 102, 'message' => 'Authentification failed']));
$fcm = $data['fcm_token']; $fcm = $data['fcm_token'];
$new_quota = $data['quota_today'] + 1; $new_quota = $data['quota_today'] + 1;
if ($data['quota_day'] === null || $data['quota_day'] !== date("Y-m-d")) $new_quota=1; if ($data['quota_day'] === null || $data['quota_day'] !== date("Y-m-d")) $new_quota=1;
if ($new_quota > Statics::quota_max($data['is_pro'])) die(json_encode(['success' => false, 'errhighlight' => -1, 'message' => 'Daily quota reached ('.Statics::quota_max($data['is_pro']).')'])); if ($new_quota > Statics::quota_max($data['is_pro'])) api_return(403, json_encode(['success' => false, 'error' => 2101, 'errhighlight' => -1, 'message' => 'Daily quota reached ('.Statics::quota_max($data['is_pro']).')']));
//------------------------------------------------------------------ //------------------------------------------------------------------
@ -82,13 +86,14 @@ try
} }
catch (Exception $e) catch (Exception $e)
{ {
die(json_encode(['success' => false, 'message' => 'Exception: ' . $e->getMessage()])); reportError("FCM communication failed", $e);
api_return(403, json_encode(['success' => false, 'error' => 9901, 'errhighlight' => -1, 'message' => 'Communication with firebase service failed.'."\n\n".'Exception: ' . $e->getMessage()]));
} }
$stmt = $pdo->prepare('UPDATE users SET timestamp_accessed=NOW(), messages_sent=messages_sent+1, quota_today=:q, quota_day=NOW() WHERE user_id = :uid'); $stmt = $pdo->prepare('UPDATE users SET timestamp_accessed=NOW(), messages_sent=messages_sent+1, quota_today=:q, quota_day=NOW() WHERE user_id = :uid');
$stmt->execute(['uid' => $user_id, 'q' => $new_quota]); $stmt->execute(['uid' => $user_id, 'q' => $new_quota]);
echo (json_encode( api_return(200, json_encode(
[ [
'success' => true, 'success' => true,
'message' => 'Message sent', 'message' => 'Message sent',
@ -98,4 +103,8 @@ echo (json_encode(
'is_pro' => $data['is_pro'], 'is_pro' => $data['is_pro'],
'quota_max' => Statics::quota_max($data['is_pro']), 'quota_max' => Statics::quota_max($data['is_pro']),
])); ]));
return 0; }
catch (Exception $mex)
{
reportError("Root try-catch triggered", $mex);
}