in-app-purchase: pro-mode

This commit is contained in:
2018-11-12 00:15:50 +01:00
parent e69b1232d7
commit 083945852b
38 changed files with 1134 additions and 62 deletions

3
web/.gitignore vendored
View File

@@ -180,4 +180,5 @@ $RECYCLE.BIN/
#################
config.php
config.php
.verify_accesstoken

View File

@@ -15,7 +15,7 @@ $user_key = $INPUT['user_key'];
$pdo = getDatabase();
$stmt = $pdo->prepare('SELECT user_id, user_key, quota_today, quota_max, quota_day FROM users WHERE user_id = :uid LIMIT 1');
$stmt = $pdo->prepare('SELECT user_id, user_key, quota_today, is_pro, quota_day FROM users WHERE user_id = :uid LIMIT 1');
$stmt->execute(['uid' => $user_id]);
$datas = $stmt->fetchAll(PDO::FETCH_ASSOC);
@@ -27,16 +27,17 @@ if ($data['user_id'] !== (int)$user_id) die(json_encode(['success' => false, 'er
if ($data['user_key'] !== $user_key) die(json_encode(['success' => false, 'errid'=>204, 'message' => 'Authentification failed']));
$quota = $data['quota_today'];
$quota_max = $data['quota_max'];
$is_pro = $data['is_pro'];
if ($data['quota_day'] === null || $data['quota_day'] !== date("Y-m-d")) $quota=0;
echo json_encode(
[
'success' => true,
'user_id' => $user_id,
'quota' => $quota,
'quota_max'=> $quota_max,
'message' => 'ok'
'success' => true,
'user_id' => $user_id,
'quota' => $quota,
'quota_max' => Statics::quota_max($is_pro),
'is_pro' => $is_pro,
'message' => 'ok'
]);
return 0;

View File

@@ -6,6 +6,8 @@ class Statics
{
public static $DB = NULL;
public static $CFG = NULL;
public static function quota_max($is_pro) { return $is_pro ? 1000 : 100; }
}
function getConfig()
@@ -15,6 +17,34 @@ function getConfig()
return Statics::$CFG = require "config.php";
}
function reportError($msg)
{
$subject = "SCN_Server has encountered an Error at " . date("Y-m-d H:i:s") . "] ";
$content = "";
$content .= 'HTTP_HOST: ' . ParamServerOrUndef('HTTP_HOST') . "\n";
$content .= 'REQUEST_URI: ' . ParamServerOrUndef('REQUEST_URI') . "\n";
$content .= 'TIME: ' . date('Y-m-d H:i:s') . "\n";
$content .= 'REMOTE_ADDR: ' . ParamServerOrUndef('REMOTE_ADDR') . "\n";
$content .= 'HTTP_X_FORWARDED_FOR: ' . ParamServerOrUndef('HTTP_X_FORWARDED_FOR') . "\n";
$content .= 'HTTP_USER_AGENT: ' . ParamServerOrUndef('HTTP_USER_AGENT') . "\n";
$content .= 'MESSAGE:' . "\n" . $msg . "\n";
$content .= '$_GET:' . "\n" . print_r($_GET, true) . "\n";
$content .= '$_POST:' . "\n" . print_r($_POST, true) . "\n";
$content .= '$_FILES:' . "\n" . print_r($_FILES, true) . "\n";
if (getConfig()['error_reporting']['send-mail'])sendMail($subject, $content, getConfig()['error_reporting']['email-error-target'], getConfig()['error_reporting']['email-error-sender']);
}
/**
* @param string $idx
* @return string
*/
function ParamServerOrUndef($idx) {
return isset($_SERVER[$idx]) ? $_SERVER[$idx] : 'NOT_SET';
}
function getDatabase()
{
if (Statics::$DB !== NULL) return Statics::$DB;
@@ -57,6 +87,13 @@ function generateRandomAuthKey()
return $random;
}
/**
* @param $url
* @param $body
* @param $header
* @return array|object|string
* @throws \Httpful\Exception\ConnectionErrorException
*/
function sendPOST($url, $body, $header)
{
$builder = \Httpful\Request::post($url);
@@ -71,3 +108,68 @@ function sendPOST($url, $body, $header)
return $response->body;
}
function verifyOrderToken($tok)
{
// https://developers.google.com/android-publisher/api-ref/purchases/products/get
try
{
$package = getConfig()['verify_api']['package_name'];
$product = getConfig()['verify_api']['product_id'];
$acctoken = getConfig()['verify_api']['accesstoken'];
if ($acctoken == '') $acctoken = refreshVerifyToken();
$url = 'https://www.googleapis.com/androidpublisher/v3/applications/'.$package.'/purchases/products/'.$product.'/tokens/'.$tok.'?access_token='.$acctoken;
$json = sendPOST($url, "", []);
$obj = json_decode($json);
if ($obj === null || $obj === false)
{
reportError('verify-token returned NULL');
return false;
}
if (isset($obj['error']) && isset($obj['error']['code']) && $obj['error']['code'] == 401) // "Invalid Credentials" -- refresh acces_token
{
$acctoken = refreshVerifyToken();
$url = 'https://www.googleapis.com/androidpublisher/v3/applications/'.$package.'/purchases/products/'.$product.'/tokens/'.$tok.'?access_token='.$acctoken;
$json = sendPOST($url, "", []);
$obj = json_decode($json);
if ($obj === null || $obj === false)
{
reportError('verify-token returned NULL');
return false;
}
}
if (isset($obj['purchaseState']) && $obj['purchaseState'] === 0) return true;
return false;
}
catch (Exception $e)
{
reportError("VerifyOrder token threw exception: " . $e . "\n" . $e->getMessage() . "\n" . $e->getTraceAsString());
return false;
}
}
/** @throws Exception */
function refreshVerifyToken()
{
$url = 'https://accounts.google.com/o/oauth2/token'.
'?grant_type=refresh_token'.
'&refresh_token='.getConfig()['verify_api']['refreshtoken'].
'&client_id='.getConfig()['verify_api']['clientid'].
'&client_secret='.getConfig()['verify_api']['clientsecret'];
$json = sendPOST($url, "", []);
$obj = json_decode($json);
file_put_contents('.verify_accesstoken', $obj['access_token']);
return $obj->access_token;
}

View File

@@ -5,24 +5,34 @@ include_once 'model.php';
$INPUT = array_merge($_GET, $_POST);
if (!isset($INPUT['fcm_token'])) die(json_encode(['success' => false, 'message' => 'Missing parameter [[fcm_token]]']));
if (!isset($INPUT['pro'])) die(json_encode(['success' => false, 'message' => 'Missing parameter [[pro]]']));
if (!isset($INPUT['pro_token'])) die(json_encode(['success' => false, 'message' => 'Missing parameter [[pro_token]]']));
$fcmtoken = $INPUT['fcm_token'];
$ispro = $INPUT['pro'] == 'true';
$pro_token = $INPUT['pro_token'];
$user_key = generateRandomAuthKey();
$pdo = getDatabase();
$stmt = $pdo->prepare('INSERT INTO users (user_key, fcm_token, timestamp_accessed) VALUES (:key, :token, NOW())');
$stmt->execute(['key' => $user_key, 'token' => $fcmtoken]);
if ($ispro)
{
if (!verifyOrderToken($pro_token)) die(json_encode(['success' => false, 'message' => 'Purchase token could not be verified']));
}
$stmt = $pdo->prepare('INSERT INTO users (user_key, fcm_token, is_pro, pro_token, timestamp_accessed) VALUES (:key, :token, :bpro, :spro, NOW())');
$stmt->execute(['key' => $user_key, 'token' => $fcmtoken, 'bpro' => $ispro, 'spro' => $ispro ? $pro_token : null]);
$user_id = $pdo->lastInsertId('user_id');
echo json_encode(
[
'success' => true,
'user_id' => $user_id,
'user_key' => $user_key,
'quota' => 0,
'quota_max'=> 100,
'message' => 'New user registered'
'success' => true,
'user_id' => $user_id,
'user_key' => $user_key,
'quota' => 0,
'quota_max' => Statics::quota_max($ispro),
'is_pro' => $ispro,
'message' => 'New user registered'
]);
return 0;

View File

@@ -9,7 +9,9 @@ CREATE TABLE `users`
`quota_today` INT(11) NOT NULL DEFAULT '0',
`quota_day` DATE NULL DEFAULT NULL,
`quota_max` INT(11) NOT NULL DEFAULT '100',
`is_pro` BIT NOT NULL DEFAULT 0,
`pro_token` VARCHAR(256) NULL DEFAULT NULL,
PRIMARY KEY (`user_id`)
);

View File

@@ -32,7 +32,7 @@ if (strlen($content) > 10000) die(json_encode(['success' => false, 'errhighli
$pdo = getDatabase();
$stmt = $pdo->prepare('SELECT user_id, user_key, fcm_token, messages_sent, quota_today, quota_max, quota_day FROM users WHERE user_id = :uid LIMIT 1');
$stmt = $pdo->prepare('SELECT user_id, user_key, fcm_token, messages_sent, quota_today, is_pro, quota_day FROM users WHERE user_id = :uid LIMIT 1');
$stmt->execute(['uid' => $user_id]);
$datas = $stmt->fetchAll(PDO::FETCH_ASSOC);
@@ -47,7 +47,7 @@ $fcm = $data['fcm_token'];
$new_quota = $data['quota_today'] + 1;
if ($data['quota_day'] === null || $data['quota_day'] !== date("Y-m-d")) $new_quota=1;
if ($new_quota > $data['quota_max']) die(json_encode(['success' => false, 'errhighlight' => -1, 'message' => 'Daily quota reached ('.$data['quota_max'].')']));
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']).')']));
//------------------------------------------------------------------
@@ -90,11 +90,12 @@ $stmt->execute(['uid' => $user_id, 'q' => $new_quota]);
echo (json_encode(
[
'success' => true,
'message' => 'Message sent',
'response' => $httpresult,
'success' => true,
'message' => 'Message sent',
'response' => $httpresult,
'messagecount' => $data['messages_sent']+1,
'quota'=>$new_quota,
'quota_max'=>$data['quota_max'],
'quota' => $new_quota,
'is_pro' => $data['is_pro'],
'quota_max' => Statics::quota_max($data['is_pro']),
]));
return 0;

View File

@@ -16,7 +16,7 @@ $fcm_token = isset($INPUT['fcm_token']) ? $INPUT['fcm_token'] : null;
$pdo = getDatabase();
$stmt = $pdo->prepare('SELECT user_id, user_key, quota_today, quota_max, quota_day FROM users WHERE user_id = :uid LIMIT 1');
$stmt = $pdo->prepare('SELECT user_id, user_key, quota_today, quota_day, is_pro FROM users WHERE user_id = :uid LIMIT 1');
$stmt->execute(['uid' => $user_id]);
$datas = $stmt->fetchAll(PDO::FETCH_ASSOC);
@@ -28,7 +28,7 @@ if ($data['user_id'] !== (int)$user_id) die(json_encode(['success' => false, 'me
if ($data['user_key'] !== $user_key) die(json_encode(['success' => false, 'message' => 'Authentification failed']));
$quota = $data['quota_today'];
$quota_max = $data['quota_max'];
$is_pro = $data['is_pro'];
$new_userkey = generateRandomAuthKey();
@@ -39,12 +39,13 @@ if ($fcm_token === null)
echo json_encode(
[
'success' => true,
'user_id' => $user_id,
'success' => true,
'user_id' => $user_id,
'user_key' => $new_userkey,
'quota' => $quota,
'quota_max'=> $quota_max,
'message' => 'user updated'
'quota_max'=> Statics::quota_max($data['is_pro']),
'is_pro' => $is_pro,
'message' => 'user updated'
]);
return 0;
}
@@ -59,7 +60,8 @@ else
'user_id' => $user_id,
'user_key' => $new_userkey,
'quota' => $quota,
'quota_max'=> $quota_max,
'quota_max'=> Statics::quota_max($data['is_pro']),
'is_pro' => $is_pro,
'message' => 'user updated'
]);
return 0;

78
web/upgrade.php Normal file
View File

@@ -0,0 +1,78 @@
<?php
include_once 'model.php';
$INPUT = array_merge($_GET, $_POST);
if (!isset($INPUT['user_id'])) die(json_encode(['success' => false, 'message' => 'Missing parameter [[user_id]]']));
if (!isset($INPUT['user_key'])) die(json_encode(['success' => false, 'message' => 'Missing parameter [[user_key]]']));
if (!isset($INPUT['pro'])) die(json_encode(['success' => false, 'message' => 'Missing parameter [[pro]]']));
if (!isset($INPUT['pro_token'])) die(json_encode(['success' => false, 'message' => 'Missing parameter [[pro_token]]']));
$user_id = $INPUT['user_id'];
$user_key = $INPUT['user_key'];
$ispro = $INPUT['pro'] == 'true';
$pro_token = $INPUT['pro_token'];
//----------------------
$pdo = getDatabase();
$stmt = $pdo->prepare('SELECT user_id, user_key, quota_today, quota_day, is_pro, pro_token FROM users WHERE user_id = :uid LIMIT 1');
$stmt->execute(['uid' => $user_id]);
$datas = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (count($datas)<=0) die(json_encode(['success' => false, 'message' => 'User not found']));
$data = $datas[0];
if ($data === null) die(json_encode(['success' => false, 'message' => 'User not found']));
if ($data['user_id'] !== (int)$user_id) die(json_encode(['success' => false, 'message' => 'UserID not found']));
if ($data['user_key'] !== $user_key) die(json_encode(['success' => false, 'message' => 'Authentification failed']));
if ($ispro)
{
// set pro=true
if ($data['pro_token'] != $pro_token)
{
if (!verifyOrderToken($pro_token)) die(json_encode(['success' => false, 'message' => 'Purchase token could not be verified']));
}
$stmt = $pdo->prepare('UPDATE users SET timestamp_accessed=NOW(), is_pro=1, pro_token=:ptk WHERE user_id = :uid');
$stmt->execute(['uid' => $user_id, 'ptk' => $pro_token]);
$stmt = $pdo->prepare('UPDATE users SET is_pro=0, pro_token=NULL WHERE user_id <> :uid AND pro_token = :ptk');
$stmt->execute(['uid' => $user_id, 'ptk' => $pro_token]);
echo json_encode(
[
'success' => true,
'user_id' => $user_id,
'user_key' => $new_userkey,
'quota' => $data['quota'],
'quota_max'=> Statics::quota_max(true),
'is_pro' => true,
'message' => 'user updated'
]);
return 0;
}
else
{
// set pro=false
$stmt = $pdo->prepare('UPDATE users SET timestamp_accessed=NOW(), is_pro=0, pro_token=NULL WHERE user_id = :uid');
$stmt->execute(['uid' => $user_id]);
echo json_encode(
[
'success' => true,
'user_id' => $user_id,
'user_key' => $new_userkey,
'quota' => $data['quota'],
'quota_max'=> Statics::quota_max(false),
'is_pro' => false,
'message' => 'user updated'
]);
return 0;
}