Browse Source

improve security, formatting, validators, add code comments

main
ghost 3 years ago
parent
commit
e1b2366ace
  1. 89
      src/application/controller/api/user/avatar.php
  2. 88
      src/application/controller/api/user/profile.php
  3. 2
      src/system/helper/filter.php
  4. 26
      src/system/helper/format.php
  5. 32
      src/system/helper/valid.php
  6. 109
      src/system/twister.php

89
src/application/controller/api/user/avatar.php

@ -1,70 +1,82 @@ @@ -1,70 +1,82 @@
<?php
// Default response
$response = [
'success' => false,
'message' => _('Internal server error'),
'avatar' => false
];
// Access allowed for authorized users only
if (isset($_SESSION['userName'])) {
// Prepare user request, authorized user by default
$userName = isset($_GET['userName']) ? Filter::userName($_GET['userName']) : $_SESSION['userName'];
if ($avatar = $_memcache->get('api.user.avatar.' . $userName)) {
// Check user exists in the database
if ($userId = $_modelUser->getUserId($userName)) {
/*
* Step 1: try to obtain avatar from cache
*
* */
if ($mcAvatar = $_memcache->get('api.user.avatar.' . $userName)) {
$response = [
'success' => true,
'message' => _('Avatar successfully received from Cache'),
'avatar' => $avatar
'avatar' => $mcAvatar
];
} else if ($avatarVersions = $_twister->getDHT($userName, 'avatar', 's')) {
// Check avatar exists
if ($userId = $_modelUser->getUserId($userName)) {
/*
* Step 2: try to obtain profile from DHT
*
* */
} else if ($dhtAvatarRevisions = $_twister->getDHTAvatarRevisions($userName)) {
// Add DHT version if not exists
foreach ($avatarVersions as $avatarVersion) {
foreach ((array) $dhtAvatarRevisions as $dhtAvatarRevision) {
if (!$_modelAvatar->versionExists($userId,
Filter::int($avatarVersion['p']['height']),
Filter::int($avatarVersion['p']['seq']))) {
$_modelAvatar->add( $userId,
Filter::int($avatarVersion['p']['height']),
Filter::int($avatarVersion['p']['seq']),
Filter::int($avatarVersion['p']['time']),
Filter::string($avatarVersion['p']['v']));
$dhtAvatarRevision['height'],
$dhtAvatarRevision['seq'])) {
$_modelAvatar->add($userId,
$dhtAvatarRevision['height'],
$dhtAvatarRevision['seq'],
$dhtAvatarRevision['time'],
$dhtAvatarRevision['data']);
}
}
}
// Get latest version available
if ($avatarInfo = $_modelAvatar->get($userId)) {
/*
* Step 3: Select latest version available from DB revisions
*
* */
$dbAvatarRevision = $_modelAvatar->get($userId);
if ($dbAvatarRevision && Valid::base64image($dbAvatarRevision['data'])) {
// Response
$response = [
'success' => true,
'message' => _('Avatar successfully received from DHT'),
'avatar' => $avatarInfo['data']
'message' => _('Avatar successfully received from DHT/DB'),
'avatar' => $dbAvatarRevision['data'] // format
];
$_memcache->set('api.user.avatar.' . $userName, $avatarInfo['data'], MEMCACHE_COMPRESS, MEMCACHE_DHT_AVATAR_TIMEOUT);
// Save request into the cache pool
$_memcache->set('api.user.avatar.' . $userName, $dbAvatarRevision['data'], MEMCACHE_COMPRESS, MEMCACHE_DHT_AVATAR_TIMEOUT);
// Cache, DHT, DB not contain any the avatar details about user requested,
// Generate and return identity icon
} else {
$response = [
'success' => false,
'message' => _('Avatar data not available'),
'avatar' => false
];
}
// Generate identity icon
} else {
$fileName = md5($userName);
$filePath = PROJECT_DIR . '/cache/image/' . $fileName . '.jpeg';
// Identity icons supports file cache
if (!file_exists($filePath)) {
$icon = new Icon();
@ -73,16 +85,29 @@ if (isset($_SESSION['userName'])) { @@ -73,16 +85,29 @@ if (isset($_SESSION['userName'])) {
file_put_contents($filePath, $image);
}
$image = file_get_contents($filePath);
$identityIcon = 'data:image/jpeg;base64,' . base64_encode(file_get_contents($filePath));
$response = [
'success' => true,
'message' => _('Avatar successfully received from Identity'),
'avatar' => 'data:image/jpeg;base64,' . base64_encode($image)
'message' => _('Could not receive any avatar details, generated identity icon'),
'avatar' => $identityIcon
];
// Save identity icon into the cache pool
$_memcache->set('api.user.avatar.' . $userName, $identityIcon, MEMCACHE_COMPRESS, MEMCACHE_DHT_AVATAR_TIMEOUT);
}
// User not found in the local database registry
} else {
$response = [
'success' => false,
'message' => _('Requested user not found'),
'profile' => []
];
}
// Session expired response
} else {
$response = [

88
src/application/controller/api/user/profile.php

@ -1,92 +1,110 @@ @@ -1,92 +1,110 @@
<?php
// Default response
$response = [
'success' => false,
'message' => _('Internal server error'),
'profile' => []
];
// Access allowed for authorized users only
if (isset($_SESSION['userName'])) {
// Prepare user request, authorized user by default
$userName = isset($_GET['userName']) ? Filter::userName($_GET['userName']) : $_SESSION['userName'];
if ($profile = $_memcache->get('api.user.profile.' . $userName)) {
// Check user exists in the database
if ($userId = $_modelUser->getUserId($userName)) {
/*
* Step 1: try to obtain profile from cache
*
* */
if ($mcProfile = $_memcache->get('api.user.profile.' . $userName)) {
$response = [
'success' => true,
'message' => _('Profile successfully received from Cache'),
'profile' => $profile
'profile' => $mcProfile
];
} else if ($userProfileVersions = $_twister->getDHT($userName, 'profile', 's')) {
// Check user exists
if ($userId = $_modelUser->getUserId($userName)) {
/*
* Step 2: try to obtain profile from DHT
*
* */
} else if ($dhtProfileRevisions = $_twister->getDHTProfileRevisions($userName)) {
// Add DHT version if not exists
foreach ($userProfileVersions as $userProfileVersion) {
foreach ((array) $dhtProfileRevisions as $dhtProfileRevision) {
// Save revision into the database if not exists
if (!$_modelProfile->versionExists($userId,
Filter::int($userProfileVersion['p']['height']),
Filter::int($userProfileVersion['p']['seq']))) {
$profile = $userProfileVersion['p']['v'];
$dhtProfileRevision['height'],
$dhtProfileRevision['seq'])) {
$_modelProfile->add($userId,
Filter::int($userProfileVersion['p']['height']),
Filter::int($userProfileVersion['p']['seq']),
Filter::int($userProfileVersion['p']['time']),
isset($profile['fullname']) ? Filter::string($profile['fullname']) : '',
isset($profile['bio']) ? Filter::string($profile['bio']) : '',
isset($profile['location']) ? Filter::string($profile['location']) : '',
isset($profile['url']) ? Filter::string($profile['url']) : '',
isset($profile['bitmessage']) ? Filter::string($profile['bitmessage']) : '',
isset($profile['tox']) ? Filter::string($profile['tox']) : '');
$dhtProfileRevision['height'],
$dhtProfileRevision['seq'],
$dhtProfileRevision['time'],
$dhtProfileRevision['fullName'],
$dhtProfileRevision['bio'],
$dhtProfileRevision['location'],
$dhtProfileRevision['url'],
$dhtProfileRevision['bitMessage'],
$dhtProfileRevision['tox']);
}
}
}
// Get latest version available
if ($profileInfo = $_modelProfile->get($userId)) {
/*
* Step 3: Select latest version available from DB revisions
*
* */
if ($dbProfileRevision = $_modelProfile->get($userId)) {
// Format output
$profile = [
'userName' => $userName,
'fullName' => Filter::string($profileInfo['fullName']),
'location' => Filter::string($profileInfo['location']),
'url' => Filter::string($profileInfo['url']),
'bitMessage' => Filter::string($profileInfo['bitMessage']),
'tox' => Filter::string($profileInfo['tox']),
'bio' => nl2br(Filter::string($profileInfo['bio'])),
'fullName' => Format::text($dbProfileRevision['fullName']),
'location' => Format::text($dbProfileRevision['location']),
'url' => Format::text($dbProfileRevision['url']),
'bitMessage' => Format::text($dbProfileRevision['bitMessage']),
'tox' => Format::text($dbProfileRevision['tox']),
'bio' => Format::text($dbProfileRevision['bio']),
];
// Save request into the cache pool
$_memcache->set('api.user.profile.' . $userName, $profile, MEMCACHE_COMPRESS, MEMCACHE_DHT_PROFILE_TIMEOUT);
// Response
$response = [
'success' => true,
'message' => _('Profile successfully received from DHT'),
'message' => _('Profile successfully received from DHT/DB'),
'profile' => $profile
];
$_memcache->set('api.user.profile.' . $userName, $profile, MEMCACHE_COMPRESS, MEMCACHE_DHT_PROFILE_TIMEOUT);
// Cache, DHT, DB not contain any the details about user requested
} else {
$response = [
'success' => false,
'message' => _('Profile data not available'),
'message' => _('Could not receive any profile details'),
'profile' => []
];
}
// User not found in the local database registry
} else {
$response = [
'success' => false,
'message' => _('Could not receive profile details'),
'message' => _('Requested user not found'),
'profile' => []
];
}
// Session expired response
} else {
$response = [

2
src/system/helper/filter.php

@ -19,7 +19,7 @@ class Filter { @@ -19,7 +19,7 @@ class Filter {
public static function string(mixed $string) {
return htmlentities($string, ENT_QUOTES, 'UTF-8');
return (string) $string;
}
public static function int(mixed $int) {

26
src/system/helper/format.php

@ -40,24 +40,26 @@ class Format { @@ -40,24 +40,26 @@ class Format {
} else {
return sprintf(_('%s %s later'), $r, self::plural($r, $v));
}
}
}
}
public static function post(string $text) {
public static function text(string $string) {
$string = html_entity_decode($string, ENT_QUOTES, 'UTF-8');
$string = htmlentities($string, ENT_QUOTES, 'UTF-8');
$string = preg_replace("|\*([\S]+)\*|i", "<b>$1</b>", $string);
$string = preg_replace("|\~([\S]+)\~|i", "<i>$1</i>", $string);
$string = preg_replace("|\_([\S]+)\_|i", "<u>$1</u>", $string);
$string = preg_replace("|\-([\S]+)\-|i", "<s>$1</s>", $string);
$string = preg_replace("|\`([\S]+)\`|i", "<samp>$1</samp>", $string);
$text = preg_replace("|\*([\S]+)\*|i", "<b>$1</b>", $text);
$text = preg_replace("|\~([\S]+)\~|i", "<i>$1</i>", $text);
$text = preg_replace("|\_([\S]+)\_|i", "<u>$1</u>", $text);
$text = preg_replace("|\-([\S]+)\-|i", "<s>$1</s>", $text);
$text = preg_replace("|\`([\S]+)\`|i", "<samp>$1</samp>", $text);
$string = preg_replace("|@([a-zA-Z0-9_]+)|i", "<a href=\"people/$1\">@$1</a>", $string);
$string = preg_replace("|((https?://)+([\d\w\.-]+\.[\w\.]{2,6})[^\s\]\[\<\>]*/?)|i", "<a href=\"$1\" target=\"_blank\">$3</a>", $string);
$text = preg_replace("|@([a-zA-Z0-9_]+)|i", "<a href=\"people/$1\">@$1</a>", $text);
$text = preg_replace("|((https?://)+([\d\w\.-]+\.[\w\.]{2,6})[^\s\]\[\<\>]*/?)|i", "<a href=\"$1\" target=\"_blank\">$3</a>", $text);
$text = nl2br($text);
$string = nl2br($string);
return $text;
return $string;
}
}

32
src/system/helper/valid.php

@ -17,6 +17,38 @@ class Valid { @@ -17,6 +17,38 @@ class Valid {
}
}
public static function base64(string $string) {
if (base64_encode(base64_decode($string, true)) === $string) {
return true;
} else {
return false;
}
}
public static function base64image(string $string) {
$string = str_replace([
'data:image/jpeg;base64,',
'data:image/jpg;base64,',
'data:image/gif;base64,',
'data:image/png;base64,',
'data:image/webp;base64,',
], '', $string);
if (self::base64($string) && imagecreatefromstring(base64_decode($string))) {
return true;
} else {
return false;
}
}
public static function userName(string $userName) {
if (preg_match('/[^a-zA-Z0-9_]+/u', $userName)) {

109
src/system/twister.php

@ -243,6 +243,115 @@ class Twister { @@ -243,6 +243,115 @@ class Twister {
return false;
}
public function getDHTProfileRevisions(string $userName) {
$this->_curl->prepare(
'/',
'POST',
30,
[
'jsonrpc' => '2.0',
'method' => 'dhtget',
'params' => [
$userName,
'profile',
's'
],
'id' => time() + rand()
]
);
if ($response = $this->_curl->execute()) {
if ($response['error']) {
$this->_error = _($response['error']['message']);
} else {
$dhtProfileVersions = [];
foreach ((array) $response['result'] as $dhtProfileVersion) {
// Required fields validation needed to make the DB revision compare
if (isset($dhtProfileVersion['p']['height']) &&
isset($dhtProfileVersion['p']['seq']) &&
isset($dhtProfileVersion['p']['time'])) {
// Format revision response
$dhtProfileVersions[] = [
'height' => (int) $dhtProfileVersion['p']['height'],
'seq' => (int) $dhtProfileVersion['p']['seq'],
'time' => (int) $dhtProfileVersion['p']['time'],
'fullName' => isset($dhtProfileVersion['p']['v']['fullname']) ? (string) $dhtProfileVersion['p']['v']['fullname'] : '',
'bio' => isset($dhtProfileVersion['p']['v']['bio']) ? (string) $dhtProfileVersion['p']['v']['bio'] : '',
'location' => isset($dhtProfileVersion['p']['v']['location']) ? (string) $dhtProfileVersion['p']['v']['location'] : '',
'url' => isset($dhtProfileVersion['p']['v']['url']) ? (string) $dhtProfileVersion['p']['v']['url'] : '',
'bitMessage' => isset($dhtProfileVersion['p']['v']['bitmessage']) ? (string) $dhtProfileVersion['p']['v']['bitmessage'] : '',
'tox' => isset($dhtProfileVersion['p']['v']['tox']) ? (string) $dhtProfileVersion['p']['v']['tox'] : '',
];
}
}
return $dhtProfileVersions; // Formatted array
}
}
return [];
}
public function getDHTAvatarRevisions(string $userName) {
$this->_curl->prepare(
'/',
'POST',
30,
[
'jsonrpc' => '2.0',
'method' => 'dhtget',
'params' => [
$userName,
'avatar',
's'
],
'id' => time() + rand()
]
);
if ($response = $this->_curl->execute()) {
if ($response['error']) {
$this->_error = _($response['error']['message']);
} else {
$dhtAvatarVersions = [];
foreach ((array) $response['result'] as $dhtAvatarVersion) {
// Required fields validation needed to make the DB revision compare
if (isset($dhtAvatarVersion['p']['height']) &&
isset($dhtAvatarVersion['p']['seq']) &&
isset($dhtAvatarVersion['p']['time'])) {
// Format revision response
$dhtAvatarVersions[] = [
'height' => (int) $dhtAvatarVersion['p']['height'],
'seq' => (int) $dhtAvatarVersion['p']['seq'],
'time' => (int) $dhtAvatarVersion['p']['time'],
'data' => isset($dhtAvatarVersion['p']['v']) ? (string) $dhtAvatarVersion['p']['v'] : '',
];
}
}
return $dhtAvatarVersions; // Formatted array
}
}
return [];
}
public function getDHT(string $userName, string $command, string $flag) {
$this->_curl->prepare(

Loading…
Cancel
Save