...
 
Commits (15)
......@@ -7,13 +7,13 @@
*/
namespace Minds\Controllers\api\v1\media;
use Minds\Api\Factory;
use Minds\Common;
use Minds\Core;
use Minds\Core\Di\Di;
use Minds\Helpers;
use Minds\Core\Features\Manager as FeaturesManager;
use Minds\Entities;
use Minds\Interfaces;
use Minds\Api\Factory;
use Minds\Core\Features\Manager as FeaturesManager;
class thumbnails implements Interfaces\Api, Interfaces\ApiIgnorePam
{
......@@ -29,24 +29,33 @@ class thumbnails implements Interfaces\Api, Interfaces\ApiIgnorePam
exit;
}
$featuresManager = new FeaturesManager();
$guid = $pages[0];
if ($featuresManager->has('cdn-jwt')) {
error_log("{$_SERVER['REQUEST_URI']} was hit, and should not have been");
Core\Security\ACL::$ignore = true;
$size = isset($pages[1]) ? $pages[1] : null;
$last_cache = isset($pages[2]) ? $pages[2] : time();
$entity = Entities\Factory::build($guid);
if (!$entity) {
return Factory::response([
'status' => 'error',
'message' => 'This endpoint has been deprecated. Please use fs/v1/thumbnail',
'message' => 'Entity not found'
]);
}
$guid = $pages[0];
Core\Security\ACL::$ignore = true;
$featuresManager = new FeaturesManager();
$size = isset($pages[1]) ? $pages[1] : null;
if ($entity->access_id !== Common\Access::PUBLIC && $featuresManager->has('cdn-jwt')) {
error_log("{$_SERVER['REQUEST_URI']} was hit, and should not have been");
$last_cache = isset($pages[2]) ? $pages[2] : time();
return Factory::response([
'status' => 'error',
'message' => 'This endpoint has been deprecated. Please use fs/v1/thumbnail',
]);
}
$etag = $last_cache . $guid;
if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag) {
......@@ -54,7 +63,7 @@ class thumbnails implements Interfaces\Api, Interfaces\ApiIgnorePam
exit;
}
$thumbnail = Di::_()->get('Media\Thumbnails')->get($guid, $size);
$thumbnail = Di::_()->get('Media\Thumbnails')->get($entity, $size);
if ($thumbnail instanceof \ElggFile) {
$thumbnail->open('read');
......
......@@ -7,9 +7,7 @@
namespace Minds\Controllers\api\v1\minds;
use Minds;
use Minds\Core;
use Minds\Core\Rewards\Contributions\ContributionValues;
use Minds\Interfaces;
use Minds\Api\Factory;
......@@ -22,33 +20,10 @@ class config implements Interfaces\Api, Interfaces\ApiIgnorePam
*/
public function get($pages)
{
$minds = [
"cdn_url" => Minds\Core\Config::_()->get('cdn_url') ?: Minds\Core\Config::_()->cdn_url,
"cinemr_url" => Minds\Core\Config::_()->get('cinemr_url') ?: Minds\Core\Config::_()->cinemr_url,
"site_url" => Minds\Core\Config::_()->get('site_url') ?: Minds\Core\Config::_()->site_url,
"socket_server" => Minds\Core\Config::_()->get('sockets-server-uri') ?: 'ha-socket-io-us-east-1.minds.com:3030',
"thirdpartynetworks" => Minds\Core\Di\Di::_()->get('ThirdPartyNetworks\Manager')->availableNetworks(),
"categories" => Minds\Core\Config::_()->get('categories') ?: [],
"stripe_key" => Minds\Core\Config::_()->get('payments')['stripe']['public_key'],
"recaptchaKey" => Minds\Core\Config::_()->get('google')['recaptcha']['site_key'],
"max_video_length" => (Core\Session::getLoggedInUser() && Core\Session::getLoggedInUser()->isPlus())
? Minds\Core\Config::_()->get('max_video_length_plus')
: Minds\Core\Config::_()->get('max_video_length'),
"max_video_file_size" => Minds\Core\Config::_()->get('max_video_file_size') ?: 0,
"features" => (object) (Minds\Core\Config::_()->get('features') ?: []),
"blockchain" => (object) Minds\Core\Di\Di::_()->get('Blockchain\Manager')->getPublicSettings(),
"plus" => Minds\Core\Config::_()->get('plus'),
"report_reasons" => Minds\Core\Config::_()->get('report_reasons'),
"last_tos_update" => (Minds\Core\Config::_()->get('last_tos_update') ?: time()),
'handlers' => [
'plus' => Minds\Core\Di\Di::_()->get('Config')->get('plus')['handler'] ?? null,
'pro' => Minds\Core\Di\Di::_()->get('Config')->get('pro')['handler'] ?? null,
],
'upgrades' => Minds\Core\Di\Di::_()->get('Config')->get('upgrades'),
'contribution_values' => ContributionValues::export(),
];
return Factory::response($minds);
return Factory::response(
Core\Di\Di::_()->get('Config\Exported')
->export()
);
}
/**
......
......@@ -39,9 +39,14 @@ class keys implements Interfaces\Api
// $priv = helpers\openssl::temporaryPrivateKey($priv, $unlock_password, $unlock_password);
// \elgg_set_plugin_user_setting('privatekey', $priv, elgg_get_logged_in_user_guid(), 'gatherings');
//}
$keystore->unlockPrivateKey($unlock_password, null);
$tmp = $keystore->getUnlockedPrivateKey();
try {
$keystore->unlockPrivateKey($unlock_password, null);
$tmp = $keystore->getUnlockedPrivateKey();
} catch (\Exception $e) {
$response['status'] = 'error';
$response['message'] = $e->getMessage();
return Factory::response($response);
}
if (!$tmp || !$unlock_password) {
$response['status'] = 'error';
......
......@@ -30,7 +30,7 @@ class channel implements Interfaces\Api
{
$currentUser = Session::getLoggedinUser();
$channel = new User($pages[0]);
$channel = new User(strtolower($pages[0]));
$channel->fullExport = true; //get counts
$channel->exportCounts = true;
......
......@@ -34,7 +34,7 @@ class settings implements Interfaces\Api
]);
}
$user = new User($pages[0]);
$user = new User(strtolower($pages[0]));
}
/** @var Manager $manager */
......@@ -66,7 +66,7 @@ class settings implements Interfaces\Api
]);
}
$user = new User($pages[0]);
$user = new User(strtolower($pages[0]));
}
/** @var Manager $manager */
......
......@@ -53,7 +53,7 @@ class assets implements Interfaces\Api
]);
}
$user = new User($pages[1]);
$user = new User(strtolower($pages[1]));
}
// Check uploaded file
......
......@@ -34,7 +34,7 @@ class domain implements Interfaces\Api
]);
}
$user = new User($pages[0]);
$user = new User(strtolower($pages[0]));
}
/** @var ProDomain $proDomain */
......
......@@ -10,7 +10,7 @@ namespace Minds\Controllers\fs\v1;
use Minds\Core;
use Minds\Entities;
use Minds\Interfaces;
use Minds\Api\Factory;
use Minds\Helpers\File;
class avatars implements Interfaces\FS
{
......@@ -59,10 +59,8 @@ class avatars implements Interfaces\FS
$contents = file_get_contents($filepath);
}
if ($filepath) {
$finfo = finfo_open(FILEINFO_MIME);
$mimetype = finfo_file($finfo, $filepath);
finfo_close($finfo);
if (!empty($contents)) {
$mimetype = File::getMime($contents);
} else {
$mimetype = 'image/jpeg';
}
......
......@@ -10,7 +10,7 @@ namespace Minds\Controllers\fs\v1;
use Minds\Core;
use Minds\Entities;
use Minds\Interfaces;
use Minds\Api\Factory;
use Minds\Helpers\File;
class banners implements Interfaces\FS
{
......@@ -102,9 +102,7 @@ class banners implements Interfaces\FS
}
}
$finfo = finfo_open(FILEINFO_MIME);
$mimetype = finfo_buffer($finfo, $content);
finfo_close($finfo);
$mimetype = File::getMime($content);
header('Content-Type: '.$mimetype);
header('Expires: ' . date('r', time() + 864000));
......
......@@ -10,7 +10,7 @@ namespace Minds\Controllers\fs\v1;
use Minds\Core;
use Minds\Entities;
use Minds\Interfaces;
use Minds\Api\Factory;
use Minds\Helpers\File;
class paywall implements Interfaces\FS
{
......@@ -31,9 +31,7 @@ class paywall implements Interfaces\FS
$contents = file_get_contents(Core\Di\Di::_()->get('Config')->get('path') . 'engine/Assets/photos/andromeda-galaxy.jpg');
}
$finfo = finfo_open(FILEINFO_MIME);
$mimetype = finfo_file($finfo, $filepath);
finfo_close($finfo);
$mimetype = File::getMime($contents);
header('Content-Type: '.$mimetype);
header('Expires: ' . date('r', time() + 864000));
header("Pragma: public");
......
......@@ -4,11 +4,14 @@
*/
namespace Minds\Controllers\fs\v1;
use Minds\Api\Factory;
use Minds\Common;
use Minds\Core;
use Minds\Core\Di\Di;
use Minds\Core\Features\Manager as FeaturesManager;
use Minds\Entities;
use Minds\Interfaces;
use Minds\Core\Features\Manager as FeaturesManager;
use Minds\Helpers\File;
class thumbnail extends Core\page implements Interfaces\page
{
......@@ -18,9 +21,30 @@ class thumbnail extends Core\page implements Interfaces\page
exit;
}
Core\Security\ACL::$ignore = true;
$guid = $pages[0] ?? null;
if (!$guid) {
return Factory::response([
'status' => 'error',
'message' => 'guid must be provided'
]);
}
$size = isset($pages[1]) ? $pages[1] : null;
$entity = Entities\Factory::build($guid);
if (!$entity) {
return Factory::response([
'status' => 'error',
'message' => 'Entity not found'
]);
}
$featuresManager = new FeaturesManager;
if ($featuresManager->has('cdn-jwt')) {
if ($entity->access_id !== Common\Access::PUBLIC && $featuresManager->has('cdn-jwt')) {
$signedUri = new Core\Security\SignedUri();
$uri = (string) \Zend\Diactoros\ServerRequestFactory::fromGlobals()->getUri();
if (!$signedUri->confirm($uri)) {
......@@ -31,9 +55,8 @@ class thumbnail extends Core\page implements Interfaces\page
/** @var Core\Media\Thumbnails $mediaThumbnails */
$mediaThumbnails = Di::_()->get('Media\Thumbnails');
Core\Security\ACL::$ignore = true;
$size = isset($pages[1]) ? $pages[1] : null;
$thumbnail = $mediaThumbnails->get($pages[0], $size);
$thumbnail = $mediaThumbnails->get($entity, $size);
if ($thumbnail instanceof \ElggFile) {
$thumbnail->open('read');
......@@ -47,8 +70,7 @@ class thumbnail extends Core\page implements Interfaces\page
}
try {
$finfo = new \finfo(FILEINFO_MIME);
$contentType = $finfo->buffer($contents) ?: 'image/jpeg';
$contentType = File::getMime($contents);
} catch (\Exception $e) {
error_log($e);
$contentType = 'image/jpeg';
......
......@@ -14,7 +14,7 @@ class ReferralsEarningsMetric extends AbstractEarningsMetric
protected $id = 'earnings_referrals';
/** @var string */
protected $label = 'Referrals USD';
protected $label = 'Referrals';
/** @var string */
protected $description = "Total earnings for your active referrals. You earn $0.10 for every active referral. A referral must log in at least 3 of 7 days after registration to be credited.";
......
......@@ -14,7 +14,7 @@ class SalesEarningsMetric extends AbstractEarningsMetric
protected $id = 'earnings_sales';
/** @var string */
protected $label = 'Sales USD';
protected $label = 'Sales';
/** @var string */
protected $description = "Total earnings for the sales you have referred. You earn a 25% commission when your referrals purchase Plus, Pro or Minds Tokens.";
......
......@@ -14,7 +14,7 @@ class ViewsEarningsMetric extends AbstractEarningsMetric
protected $id = 'earnings_views';
/** @var string */
protected $label = 'Pageviews USD';
protected $label = 'Pageviews';
/** @var string */
protected $description = "Total earnings for the pageviews on your channel's assets. You earn $1 for every 1,000 pageviews.";
......
......@@ -14,7 +14,7 @@ class SubscribersMetric extends AbstractEngagementMetric
protected $id = 'subscribers';
/** @var string */
protected $label = 'Subscribes';
protected $label = 'Subscribers';
/** @var string */
protected $description = "Number of subscribers your channel has gained";
......
......@@ -17,5 +17,9 @@ class ConfigProvider extends Provider
$this->di->bind('Config', function ($di) {
return new Config();
}, ['useFactory'=>true]);
$this->di->bind('Config\Exported', function ($di) {
return new Exported();
}, ['useFactory' => true]);
}
}
<?php
/**
* Exported
* @author edgebal
*/
namespace Minds\Core\Config;
use Minds\Core\Blockchain\Manager as BlockchainManager;
use Minds\Core\Di\Di;
use Minds\Core\I18n\I18n;
use Minds\Core\Navigation\Manager as NavigationManager;
use Minds\Core\Rewards\Contributions\ContributionValues;
use Minds\Core\Session;
use Minds\Core\ThirdPartyNetworks\Manager as ThirdPartyNetworksManager;
use Minds\Entities\User;
use Minds\Helpers\Counters;
class Exported
{
/** @var Config */
protected $config;
/** @var ThirdPartyNetworksManager */
protected $thirdPartyNetworks;
/** @var I18n */
protected $i18n;
/**
* Exported constructor.
* @param Config $config
* @param ThirdPartyNetworksManager $thirdPartyNetworks
* @param I18n $i18n
* @param BlockchainManager $blockchain
*/
public function __construct(
$config = null,
$thirdPartyNetworks = null,
$i18n = null,
$blockchain = null
) {
$this->config = $config ?: Di::_()->get('Config');
$this->thirdPartyNetworks = $thirdPartyNetworks ?: Di::_()->get('ThirdPartyNetworks\Manager');
$this->i18n = $i18n ?: Di::_()->get('I18n');
$this->blockchain = $blockchain ?: Di::_()->get('Blockchain\Manager');
}
/**
* @return array
*/
public function export(): array
{
$context = defined('__MINDS_CONTEXT__') ? __MINDS_CONTEXT__ : 'app';
$exported = [
'MindsContext' => $context,
'LoggedIn' => Session::isLoggedIn() ? true : false,
'Admin' => Session::isAdmin() ? true : false,
'cdn_url' => $this->config->get('cdn_url'),
'cdn_assets_url' => $this->config->get('cdn_assets_url'),
'site_url' => $this->config->get('site_url'),
'cinemr_url' => $this->config->get('cinemr_url'),
'socket_server' => $this->config->get('sockets-server-uri') ?: 'ha-socket-io-us-east-1.minds.com:3030',
'navigation' => NavigationManager::export(),
'thirdpartynetworks' => $this->thirdPartyNetworks->availableNetworks(),
'language' => $this->i18n->getLanguage(),
'languages' => $this->i18n->getLanguages(),
'categories' => $this->config->get('categories') ?: [],
'stripe_key' => $this->config->get('payments')['stripe']['public_key'],
'recaptchaKey' => $this->config->get('google')['recaptcha']['site_key'],
'max_video_length' => $this->config->get('max_video_length'),
'max_video_file_size' => $this->config->get('max_video_file_size'),
'features' => (object) ($this->config->get('features') ?: []),
'blockchain' => (object) $this->blockchain->getPublicSettings(),
'sale' => $this->config->get('blockchain')['sale'],
'last_tos_update' => $this->config->get('last_tos_update') ?: time(),
'tags' => $this->config->get('tags') ?: [],
'plus' => $this->config->get('plus'),
'report_reasons' => $this->config->get('report_reasons'),
'handlers' => [
'plus' => $this->config->get('plus')['handler'] ?? null,
'pro' => $this->config->get('pro')['handler'] ?? null,
],
'upgrades' => $this->config->get('upgrades'),
'contribution_values' => ContributionValues::export(),
'environment' => getenv('MINDS_ENV') ?: 'development',
];
if (Session::isLoggedIn()) {
/** @var User $user */
$user = Session::getLoggedinUser();
$exported['user'] = $user->export();
$exported['user']['rewards'] = (bool) $user->getPhoneNumberHash();
$exported['wallet'] = [
'balance' => Counters::get($user->guid, 'points', false),
];
if ($user->isPlus()) {
$exported['max_video_length'] = $this->config->get('max_video_length_plus');
}
}
if ($context === 'embed') {
$exported['MindsEmbed'] = $embedded_entity ?? null;
}
return $exported;
}
}
<?php
/**
* Index
* @author edgebal
*/
namespace Minds\Core\Front;
use Minds\Core\Config\Exported;
use Minds\Core\Di\Di;
use Minds\Core\Pro\Domain as ProDomain;
use Minds\Core\Pro\Settings;
use Minds\Core\SEO\Manager;
class Index
{
/** @var Exported */
protected $configExported;
/** @var ProDomain */
protected $proDomain;
/** @var string[] */
protected $meta = [];
/** @var string[] */
protected $head = [];
/** @var string[] */
protected $tail = [];
/** @var string */
protected $context = 'app';
/** @var string */
protected $title = '';
/**
* Index constructor.
* @param Exported $configExported
* @param ProDomain $proDomain
*/
public function __construct(
$configExported = null,
$proDomain = null
) {
$this->configExported = $configExported ?: Di::_()->get('Config\Exported');
$this->proDomain = $proDomain ?: Di::_()->get('Pro\Domain');
$this->build();
}
public function build(): void
{
$this->meta = [];
$this->head = [];
$this->tail = [];
//
/** @var Settings|null $pro */
$pro = $this->proDomain->lookup($_SERVER['HTTP_HOST'] ?? null);
// Config variable
$minds = $this->configExported->export();
if ($pro) {
$minds['pro'] = $pro;
}
// Title
$this->title = 'Minds';
if ($pro) {
$this->title = $pro->getTitle() ?: $pro->getDomain();
}
// Favicons
$icons = [
[
'type' => 'image/svg',
'href' => "{$minds['cdn_assets_url']}assets/logos/bulb.svg",
],
[
'rel' => 'apple-touch-icon',
'type' => 'image/png',
'href' => "{$minds['cdn_assets_url']}assets/logos/bulb-apple-touch-icon.png",
'sizes' => '180x180',
],
[
'type' => 'image/png',
'href' => "{$minds['cdn_assets_url']}assets/logos/bulb-32x32.png",
'sizes' => '32x32',
],
[
'type' => 'image/png',
'href' => "{$minds['cdn_assets_url']}assets/logos/bulb-16x16.png",
'sizes' => '16x16',
],
];
if ($pro) {
$icons = [
[
'type' => 'image/jpeg',
'href' => $this->proDomain->getIcon($pro),
],
];
}
foreach ($icons as $icon) {
$attrs = [];
foreach (array_merge(['rel' => 'icon'], $icon) as $key => $value) {
$attrs[] = sprintf("%s=%s", $key, htmlspecialchars($value));
}
$this->meta[] = sprintf("<link %s />", implode(' ', $attrs));
}
// SEO Meta + Title Override
$meta = Manager::get();
foreach ($meta as $name => $content) {
$name = htmlspecialchars($name);
$content = htmlspecialchars($content);
if ($name === 'title') {
$this->title = $content;
continue;
}
$nameAttr = 'name';
if (
strpos($name, ":") !== false &&
strpos($name, "smartbanner") === false
) {
// Attributes with a colon that are not smartbanner
// should use property="<name>"
$nameAttr = 'property';
}
$this->meta[] = sprintf(
"<meta %s=\"%s\" content=\"%s\" />",
$nameAttr,
$name,
$content
);
}
// Head
if ($pro) {
$this->head[] = sprintf(
"<!-- Minds Pro: %s -->\n%s\n<!-- End -->",
$pro->getUserGuid(),
$pro->getCustomHead() ?: '<!-- (no custom head) -->'
);
}
// Tail
$this->tail[] = sprintf("<script>window.Minds = %s;</script>", json_encode($minds));
}
/**
* @return string
*/
public function getMetaHtml(): string
{
return PHP_EOL . implode(PHP_EOL, $this->meta) . PHP_EOL;
}
/**
* @return string
*/
public function getHeadHtml(): string
{
return PHP_EOL . implode(PHP_EOL, $this->head) . PHP_EOL;
}
/**
* @return string
*/
public function getTailHtml(): string
{
return PHP_EOL . implode(PHP_EOL, $this->tail) . PHP_EOL;
}
/**
* @return string
*/
public function getContext(): string
{
return $this->context;
}
/**
* @return string
*/
public function getTitle(): string
{
return $this->title;
}
}
<?php
/**
* Module
* @author edgebal
*/
namespace Minds\Core\Front;
use Minds\Interfaces\ModuleInterface;
class Module implements ModuleInterface
{
/**
* Executed onInit
* @return void
*/
public function onInit(): void
{
(new Provider())->register();
}
}
<?php
/**
* Provider
* @author edgebal
*/
namespace Minds\Core\Front;
use Minds\Core\Di\Provider as DiProvider;
class Provider extends DiProvider
{
public function register()
{
$this->di->bind('Front\Index', function () {
return new Index();
}, [ 'useFactory' => true ]);
}
}
......@@ -20,7 +20,7 @@ class Image implements AssetsInterface
public function upload(array $media, array $data)
{
$filename = "/image/{$this->entity->batch_guid}/{$this->entity->guid}/master.jpg";
$filename = "image/{$this->entity->batch_guid}/{$this->entity->guid}/master.jpg";
// @note: legacy file handling
$file = new \ElggFile();
......
......@@ -64,7 +64,10 @@ class Manager
}
$uri = $this->config->get('cdn_url') . 'fs/v1/thumbnail/' . $asset_guid . '/' . $size;
$uri = $this->signUri($uri);
if ($entity->access_id !== ACCESS_PUBLIC) {
$uri = $this->signUri($uri);
}
return $uri;
}
......
......@@ -9,6 +9,7 @@
namespace Minds\Core\Media\Proxy;
use Minds\Core\Di\Di;
use Minds\Helpers\File;
use Minds\Core\Http\Curl\Client;
use Minds\Traits\MagicAttributes;
......@@ -99,8 +100,7 @@ class Download
throw new \Exception('Invalid image');
}
$finfo = new \finfo(FILEINFO_MIME);
$mime = $finfo->buffer($content);
$mime = File::getMime($content);
if (!$mime) {
throw new \Exception('Cannot read image MIME');
......
......@@ -8,16 +8,27 @@ use Minds\Entities;
class Thumbnails
{
/** @var Core\Config */
protected $config;
/** @var Core\EntitiesBuilder */
protected $entitiesBuilder;
public function __construct($config = null)
public function __construct($config = null, $entitiesBuilder = null)
{
$this->config = $config ?: Di::_()->get('Config');
$this->entitiesBuilder = $entitiesBuilder ?: Di::_()->get('EntitiesBuilder');
}
public function get($guid, $size)
/**
* @param $entity Entities\Entity|string
* @param $size
* @return bool|\ElggFile|mixed|string
*/
public function get($entity, $size)
{
$entity = Entities\Factory::build($guid);
if (is_string($entity)) {
$entity = $this->entitiesBuilder->build($entity);
}
if (!$entity || !Core\Security\ACL::_()->read($entity)) {
return false;
}
......
......@@ -4,15 +4,13 @@
*/
namespace Minds\Core\Media\Video;
use Aws\S3\S3Client;
use Minds\Common;
use Minds\Core\Config;
use Minds\Core\Di\Di;
use Minds\Core\Session;
use Minds\Entities\Entity;
use Minds\Entities\Activity;
use Minds\Entities\Image;
use Minds\Entities\Entity;
use Minds\Entities\Video;
use Minds\Core\Comments\Comment;
use Aws\S3\S3Client;
class Manager
{
......@@ -64,7 +62,12 @@ class Manager
if (!$cmd) {
return null;
}
if ($entity->access_id !== Common\Access::PUBLIC) {
$url = (string)$this->s3->createPresignedRequest($cmd, '+48 hours')->getUri();
} else {
$url = $this->config->get('cinemr_url') . $entity->cinemr_guid . '/' . $size;
}
return (string) $this->s3->createPresignedRequest($cmd, '+48 hours')->getUri();
return $url;
}
}
......@@ -110,7 +110,7 @@ class OpenSSL implements EncryptionInterface
{
$private_key = openssl_get_privatekey($private_key, $password);
if (!$private_key) {
throw new \Exception('Could not decrypt private key');
throw new \Exception('Failed to unlock private key.');
}
openssl_pkey_export($private_key, $pkeyout, $newpass);
return $pkeyout;
......
......@@ -27,6 +27,7 @@ class Minds extends base
Referrals\Module::class,
Reports\Module::class,
VideoChat\Module::class,
Front\Module::class,
];
/**
......
......@@ -5,9 +5,11 @@ namespace Minds\Core\Storage\Services;
use Aws\S3\S3Client;
use Minds\Core\Config;
use Minds\Core\Di\Di;
use Minds\Helpers\File;
class S3 implements ServiceInterface
{
/** @var S3Client */
public $s3;
public $filepath;
public $mode;
......@@ -61,10 +63,7 @@ class S3 implements ServiceInterface
public function write($data)
{
//TODO: check mime performance here
$finfo = new \finfo(FILEINFO_MIME_TYPE);
$mimeType = $finfo->buffer($data);
$mimeType = File::getMimeType($data);
$write = $this->s3->putObject([
// 'ACL' => 'public-read',
......@@ -72,16 +71,9 @@ class S3 implements ServiceInterface
'Key' => $this->filepath,
'ContentType' => $mimeType,
'ContentLength' => strlen($data),
//'ContentLength' => filesize($file),
'Body' => $data,
]);
//also write to disk until full migration
/*$disk = new Disk();
$disk->open($this->filepath, 'write');
$disk->write($data);
$disk->close();*/
return true;
}
......@@ -104,18 +96,7 @@ class S3 implements ServiceInterface
break;
case "redirect":
default:
//for now, check if the file exists, and fallback to disk if not!
/*if (!$this->s3->doesObjectExist(Config::_()->aws['bucket'], $this->filepath)) {
$disk = new Disk();
$disk->open($this->filepath, 'read');
$content = $disk->read();
$disk->close();
return $content;
}*/
$url = $this->s3->getObjectUrl(Config::_()->aws['bucket'], $this->filepath, "+15 minutes");
//$this->filepath = str_replace('//', '/', $this->filepath);
//$url = Config::_()->aws['cloudfront'] . $this->filepath;
header("Location: $url");
exit;
}
......
<?php
namespace Minds\Helpers;
class File
{
const HEADER_LENGTH = 16;
public static function getMimeType(&$data): string
{
return self::getType($data, FILEINFO_MIME_TYPE);
}
public static function getMime(&$data): string
{
return self::getType($data, FILEINFO_MIME);
}
protected static function getType(&$data, int $type): string
{
$header = substr($data, 0, self::HEADER_LENGTH);
$finfo = new \finfo($type);
$type = $finfo->buffer($header);
unset($finfo);
return $type;
}
}
......@@ -33,6 +33,7 @@ class ManagerSpec extends ObjectBehavior
{
$activity = new Activity();
$activity->set('entity_guid', 123);
$activity->set('access_id', ACCESS_PRIVATE);
$this->config->get('cdn_url')
->willReturn('https://minds.dev/');
$uri = 'https://minds.dev/fs/v1/thumbnail/123/xlarge';
......@@ -42,10 +43,22 @@ class ManagerSpec extends ObjectBehavior
->shouldBe('signed url will be here');
}
public function it_should_return_unsigned_public_asset_uri()
{
$activity = new Activity();
$activity->set('entity_guid', 123);
$activity->set('access_id', ACCESS_PUBLIC);
$this->config->get('cdn_url')
->willReturn('https://minds.dev/');
$this->getPublicAssetUri($activity)
->shouldBe('https://minds.dev/fs/v1/thumbnail/123/xlarge');
}
public function it_should_return_public_asset_uri_for_image()
{
$entity = new Image();
$entity->set('guid', 123);
$entity->set('access_id', ACCESS_PRIVATE);
$this->config->get('cdn_url')
->willReturn('https://minds.dev/');
$uri = 'https://minds.dev/fs/v1/thumbnail/123/xlarge';
......@@ -55,10 +68,22 @@ class ManagerSpec extends ObjectBehavior
->shouldBe('signed url will be here');
}
public function it_should_return_an_unsigned_url_for_an_image()
{
$entity = new Image();
$entity->set('guid', 123);
$entity->set('access_id', ACCESS_PUBLIC);
$this->config->get('cdn_url')
->willReturn('https://minds.dev/');
$this->getPublicAssetUri($entity)
->shouldBe('https://minds.dev/fs/v1/thumbnail/123/xlarge');
}
public function it_should_return_public_asset_uri_for_video()
{
$entity = new Video();
$entity->set('guid', 123);
$entity->set('access_id', ACCESS_PRIVATE);
$this->config->get('cdn_url')
->willReturn('https://minds.dev/');
$uri = 'https://minds.dev/fs/v1/thumbnail/123/xlarge';
......@@ -68,6 +93,19 @@ class ManagerSpec extends ObjectBehavior
->shouldBe('signed url will be here');
}
public function it_should_return_unsigned_public_asset_uri_for_video()
{
$entity = new Video();
$entity->set('guid', 123);
$entity->set('access_id', ACCESS_PUBLIC);
$this->config->get('cdn_url')
->willReturn('https://minds.dev/');
$uri = 'https://minds.dev/fs/v1/thumbnail/123/xlarge';
$this->getPublicAssetUri($entity)
->shouldBe('https://minds.dev/fs/v1/thumbnail/123/xlarge');
}
public function it_should_return_public_asset_uri_for_comment()
{
$entity = new Comment();
......@@ -80,4 +118,15 @@ class ManagerSpec extends ObjectBehavior
$this->getPublicAssetUri($entity)
->shouldBe('signed url will be here');
}
public function it_should_return_unsigned_public_asset_uri_for_comment()
{
$entity = new Comment();
$entity->setAttachment('attachment_guid', '123');
$entity->access_id = ACCESS_PUBLIC;
$this->config->get('cdn_url')
->willReturn('https://minds.dev/');
$this->getPublicAssetUri($entity)
->shouldBe('https://minds.dev/fs/v1/thumbnail/123/xlarge');
}
}
......@@ -27,7 +27,7 @@ class ManagerSpec extends ObjectBehavior
$this->shouldHaveType(Manager::class);
}
public function it_should_get_a_720p_video(RequestInterface $request, \Aws\CommandInterface $cmd)
public function it_should_get_a_signed_720p_video_url(RequestInterface $request, \Aws\CommandInterface $cmd)
{
$this->config->get('transcoder')
->willReturn([
......@@ -39,22 +39,60 @@ class ManagerSpec extends ObjectBehavior
'useRoles' => true,
]);
$this->config->get('cinemr_url')
->willReturn('https://url.com/cinemr');
$this->s3->getCommand('GetObject', [
'Bucket' => 'cinemr',
'Key' => 'dir/123/720.mp4'
])
->shouldBeCalled()
->willReturn($cmd);
$request->getUri()
->willReturn('s3-signed-url-here');
$this->s3->createPresignedRequest(Argument::any(), Argument::any())
->willReturn($request);
$video = new Video();
$video->set('cinemr_guid', 123);
$video->set('access_id', ACCESS_PRIVATE);
$this->getPublicAssetUri($video, '720.mp4')
->shouldBe('s3-signed-url-here');
}
public function it_should_get_an_unsigned_720p_video_url(RequestInterface $request, \Aws\CommandInterface $cmd)
{
$this->config->get('transcoder')
->willReturn([
'dir' => 'dir',
]);
$this->config->get('aws')
->willReturn([
'region' => 'us-east-1',
'useRoles' => true,
]);
$this->config->get('cinemr_url')
->willReturn('https://url.com/cinemr');
$this->s3->getCommand('GetObject', [
'Bucket' => 'cinemr',
'Key' => 'dir/123/720.mp4'
])
->shouldBeCalled()
->willReturn($cmd);
$request->getUri()
->willReturn('s3-signed-url-here');
$this->s3->createPresignedRequest(Argument::any(), Argument::any())
->willReturn($request);
$video = new Video();
$video->set('cinemr_guid', 123);
$this->getPublicAssetUri($video, '720.mp4')
->shouldBe('https://url.com/cinemr123/720.mp4');
}
}
......@@ -22,8 +22,7 @@ class SpamSpec extends ObjectBehavior
public function it_should_detect_spam_in_a_blog(
Blog $blog,
ProhibitedDomains $prohibitedDomains
)
{
) {
$prohibitedDomains->get()
->shouldBeCalled()
->willReturn(['bit.ly']);
......@@ -41,8 +40,7 @@ class SpamSpec extends ObjectBehavior
public function it_should_detect_spam_in_a_comment(
Comment $comment,
ProhibitedDomains $prohibitedDomains
)
{
) {
$prohibitedDomains->get()
->shouldBeCalled()
->willReturn(['bit.ly']);
......@@ -60,8 +58,7 @@ class SpamSpec extends ObjectBehavior
public function it_should_detect_spam_in_a_user(
User $user,
ProhibitedDomains $prohibitedDomains
)
{
) {
$prohibitedDomains->get()
->shouldBeCalled()
->willReturn(['bit.ly']);
......@@ -79,8 +76,7 @@ class SpamSpec extends ObjectBehavior
public function it_should_detect_spam_in_a_group(
Group $group,
ProhibitedDomains $prohibitedDomains
)
{
) {
$prohibitedDomains->get()
->shouldBeCalled()
->willReturn(['bit.ly']);
......@@ -98,8 +94,7 @@ class SpamSpec extends ObjectBehavior
public function it_should_detect_NO_spam_in_a_blog(
Blog $blog,
ProhibitedDomains $prohibitedDomains
)
{
) {
$prohibitedDomains->get()
->shouldBeCalled()
->willReturn(['bit.ly']);
......@@ -116,8 +111,7 @@ class SpamSpec extends ObjectBehavior
public function it_should_detect_NO_spam_in_a_comment(
Comment $comment,
ProhibitedDomains $prohibitedDomains
)
{
) {
$prohibitedDomains->get()
->shouldBeCalled()
->willReturn(['bit.ly']);
......@@ -134,8 +128,7 @@ class SpamSpec extends ObjectBehavior
public function it_should_detect_NO_spam_in_a_user(
User $user,
ProhibitedDomains $prohibitedDomains
)
{
) {
$prohibitedDomains->get()
->shouldBeCalled()
->willReturn(['bit.ly']);
......@@ -150,10 +143,9 @@ class SpamSpec extends ObjectBehavior
}
public function it_should_detect_NO_spam_in_a_group(
Group $group,
Group $group,
ProhibitedDomains $prohibitedDomains
)
{
) {
$prohibitedDomains->get()
->shouldBeCalled()
->willReturn(['bit.ly']);
......
......@@ -121,49 +121,6 @@ class ElggFile extends ElggObject {
return $this->mimetype = $mimetype;
}
/**
* Detects mime types based on filename or actual file.
*
* @param mixed $file The full path of the file to check. For uploaded files, use tmp_name.
* @param mixed $default A default. Useful to pass what the browser thinks it is.
* @since 1.7.12
*
* @note If $file is provided, this may be called statically
*
* @return mixed Detected type on success, false on failure.
*/
public function detectMimeType($file = null, $default = null) {
if (!$file) {
if (isset($this) && $this->filename) {
$file = $this->filename;
} else {
return false;
}
}
$mime = false;
// for PHP5 folks.
if (function_exists('finfo_file') && defined('FILEINFO_MIME_TYPE')) {
$resource = finfo_open(FILEINFO_MIME_TYPE);
if ($resource) {
$mime = finfo_file($resource, $file);
}
}
// for everyone else.
if (!$mime && function_exists('mime_content_type')) {
$mime = mime_content_type($file);
}
// default
if (!$mime) {
return $default;
}
return $mime;
}
/**
* Set the optional file description.
*
......@@ -363,4 +320,11 @@ class ElggFile extends ElggObject {
return $this->filestore;
}
/**
* Executed prior to object serialization
*/
public function __sleep()
{
unset($this->handle);
}
}