Blocked claims (#81)

* handle blocked claims
* fix chainquery endpoint
* channel-level blocking
* don't show blocked claims in the result grid
* optimisation: break out of foreach loop if match found
* add caching for api request
* rename cache key
This commit is contained in:
Akinwale Ariwodola 2020-01-07 23:13:38 +01:00 committed by GitHub
parent 02551e98d7
commit 31d515e992
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 713 additions and 453 deletions

1055
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -222,7 +222,7 @@ return [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => 'chainquery.lbry.io',
'host' => 'chainquery.lbry.com',
/**
* CakePHP will use the default DB port based on the driver selected
* MySQL on MAMP uses port 8889, MAMP users will want to uncomment
@ -257,9 +257,9 @@ return [
*/
//'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'],
'url' => env('DATABASE_URL', 'chainquery.lbry.io:3600'),
'url' => env('DATABASE_URL', 'chainquery.lbry.com:3600'),
],
'localdb' => [ // Local db for price history
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',

View file

@ -7,6 +7,7 @@ use Mdanter\Ecc\Crypto\Signature\Signer;
use Mdanter\Ecc\Serializer\PublicKey\PemPublicKeySerializer;
use Mdanter\Ecc\Serializer\PublicKey\DerPublicKeySerializer;
use Mdanter\Ecc\Serializer\Signature\DerSignatureSerializer;
use Cake\Cache\Cache;
use Cake\Core\Configure;
use Cake\Datasource\ConnectionManager;
use Cake\Log\Log;
@ -30,6 +31,8 @@ class MainController extends AppController {
const tagReceiptAddress = 'bLockNgmfvnnnZw7bM6SPz6hk5BVzhevEp';
const blockedListUrl = 'https://api.lbry.com/file/list_blocked';
protected $redis;
public function initialize() {
@ -154,8 +157,10 @@ class MainController extends AppController {
$endLimitId = $maxClaimId;
}
$blockedList = json_decode($this->_getBlockedList());
$claims = $this->Claims->find()->select($this->Claims)->
select(['publisher' => 'C.name'])->leftJoin(['C' => 'claim'], ['C.claim_id = Claims.publisher_id'])->
select(['publisher' => 'C.name', 'publisher_transaction_hash_id' => 'C.transaction_hash_id', 'publisher_vout' => 'C.vout'])->
leftJoin(['C' => 'claim'], ['C.claim_id = Claims.publisher_id'])->
where(['Claims.id >' => $startLimitId, 'Claims.id <=' => $endLimitId])->
order(['Claims.id' => 'DESC'])->toArray();
@ -173,6 +178,17 @@ class MainController extends AppController {
$claims[$i]->LicenseUrl = $json->metadata->licenseUrl;
}
}
$claimChannel = null;
if ($claims[$i]->publisher_transaction_hash_id) {
$claimChannel = new \stdClass();
$claimChannel->transaction_hash_id = $claims[$i]->publisher_transaction_hash_id;
$claimChannel->vout = $claims[$i]->publisher_vout;
}
$blocked = $this->_isClaimBlocked($claims[$i], $claimChannel, $blockedList);
$claims[$i]->isBlocked = $blocked;
$claims[$i]->thumbnail_url = $blocked ? null : $claims[$i]->thumbnail_url; // don't show the thumbnails too
}
$this->set('pageLimit', $pageLimit);
@ -220,8 +236,15 @@ class MainController extends AppController {
}
}
}
// fetch blocked list
$blockedList = json_decode($this->_getBlockedList());
$claimChannel = $this->Claims->find()->select(['transaction_hash_id', 'vout'])->where(['claim_id' => $claim->publisher_id])->first();
$claimIsBlocked = $this->_isClaimBlocked($claim, $claimChannel, $blockedList);
$this->set('claim', $claim);
$this->set('moreClaims', $moreClaims);
$this->set('claimIsBlocked', $claimIsBlocked);
$this->set('moreClaims', $claimIsBlocked ? [] : $moreClaims);
}
}
@ -957,4 +980,44 @@ class MainController extends AppController {
// Close any open file handle
return $response;
}
private function _isClaimBlocked($claim, $claimChannel, $blockedList) {
if (!$blockedList || !isset($blockedList->data)) {
// invalid blockedList response
return false;
}
$blockedOutpoints = $blockedList->data->outpoints;
$claimIsBlocked = false;
foreach ($blockedOutpoints as $outpoint) {
// $parts[0] = txid
// $parts[1] = vout
$parts = explode(':', $outpoint);
if ($claim->transaction_hash_id == $parts[0] && $claim->vout == $parts[1]) {
$claimIsBlocked = true;
break;
}
// check if the publisher (channel) is blocked
// block the channel if that's the case
if ($claimChannel && $claimChannel->transaction_hash_id == $parts[0] && $claimChannel->vout == $parts[1]) {
$claimIsBlocked = true;
break;
}
}
return $claimIsBlocked;
}
private function _getBlockedList() {
$cachedList = Cache::read('list_blocked', 'api_requests');
if ($cachedList !== false) {
return $cachedList;
}
// get the result from the api
$response = self::curl_get(self::blockedListUrl);
Cache::write('list_blocked', $response, 'api_requests');
return $response;
}
}

View file

@ -35,6 +35,14 @@ $ctTag = $claim->getContentTag();
<?php endif; ?>
</div>
<?php if ($claim->isBlocked): ?>
<div class="blocked-info">
In response to a complaint we received under the US Digital Millennium Copyright Act, we have blocked access to this content from our applications. For more information, please refer to <a href="https://lbry.com/faq/dmca" target="_blank">DMCA takedown requests</a>
</div>
<?php else: ?>
<div class="metadata">
<div class="title" title="<?php echo $claim->claim_type == 1 ? $claim->name : ((strlen(trim($claim->title)) > 0) ? $claim->title : '') ?>"><?php echo $claim->claim_type == 1 ? $claim->name : ((strlen(trim($claim->title)) > 0) ? $claim->title : '<em>No Title</em>') ?></div>
<div class="link" title="<?php echo $claim->getLbryLink() ?>"><a href="<?php echo $claim->getLbryLink() ?>" rel="nofollow"><?php echo $claim->getLbryLink() ?></a></div>
@ -61,10 +69,10 @@ $ctTag = $claim->getContentTag();
<!--<div class="label half-width">Author</div>
<div class="label half-width">License</div>-->
<!--<div class="value half-width" title="<?php echo strlen(trim($claim->author)) > 0 ? $claim->author : '<em>Unspecified</em>' ?>"><?php echo strlen(trim($claim->author)) > 0 ? $claim->author : '<em>Unspecified</em>' ?></div>
<div class="value half-width" title="<?php echo strlen(trim($claim->license)) > 0 ? $claim->license : '' ?>">
<?php if (strlen(trim($claim->LicenseUrl)) > 0): ?><a href="<?php echo $claim->LicenseUrl ?>" rel="nofollow" target="_blank"><?php endif; ?>
<?php echo strlen(trim($claim->License)) > 0 ? $claim->License : '<em>Unspecified</em>' ?>
@ -73,4 +81,5 @@ $ctTag = $claim->getContentTag();
-->
<?php endif; ?>
</div>
<?php endif; ?>
</div>

View file

@ -65,6 +65,15 @@ if (strlen(trim($desc)) == 0) {
</div>
<div class="claims-body">
<?php if ($claimIsBlocked): ?>
<div class="blocked-claim-info">
<div class="content">
In response to a complaint we received under the US Digital Millennium Copyright Act, we have blocked access to this content from our applications. For more information, please refer to <a href="https://lbry.com/faq/dmca" target="_blank">DMCA takedown requests</a>.
</div>
</div>
<?php else: ?>
<div class="claim-info">
<div data-autothumb="<?php echo $autoThumbText ?>" class="thumbnail <?php echo $a[mt_rand(0, count($a) - 1)] ?>">
<?php if (!$claim->is_nsfw && strlen(trim($claim->thumbnail_url)) > 0): ?>
@ -140,6 +149,7 @@ if (strlen(trim($desc)) == 0) {
<div class="clear"></div>
<?php endif; ?>
<?php if (count($moreClaims) > 0): ?>
@ -155,7 +165,7 @@ if (strlen(trim($desc)) == 0) {
$row++;
}
echo $this->element('claimbox', array('claim' => $claim, 'idx' => $idx, 'last_row' => $last_row));
$idx++;
$idx++;
endforeach; ?>
<div class="clear"></div>
</div>

View file

@ -83,6 +83,7 @@ border-radius: 0 8px 8px 0 }
.claims-grid .claim-grid-item .tags .nsfw { background: #e53935; text-align: center; color: #fff; position: relative; left: 1px }
.claims-grid .claim-grid-item .tags .bid-state { background: #551CA1; text-align: center; color: #fff; }
.claims-grid .claim-grid-item .tags .content-type { background: #880e4f; text-align: center; color: #fff; }
.claims-grid .claim-grid-item .blocked-info { padding: 24px; font-size: 90%; }
.claims-grid .claim-grid-item .metadata { padding: 24px; font-size: 90% }
.claims-grid .claim-grid-item .title { font-size: 120%; height: 25px; line-height: 25px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
.claims-grid .claim-grid-item .desc { font-size: 90%; font-weight: 300; height: 72px; overflow: hidden; text-overflow: ellipsis; margin: 8px 0 20px 0; line-height: 24px }
@ -95,6 +96,8 @@ border-radius: 0 8px 8px 0 }
.claims-grid .claim-grid-item .spacer { height: 16px }
.claims-body { width: 1200px; margin: 0 auto 0 auto; cursor: default }
.claims-body .blocked-claim-info { border: 1px solid rgba(0,0,0,.15); cursor: default }
.claims-body .blocked-claim-info .content { padding: 48px }
.claims-body .claim-info { width: 400px; float: left; /*box-shadow: 0 2px 4px rgba(0,0,0,.175);*/ border: 1px solid rgba(0,0,0,.15); cursor: default }
.claims-body .claim-info .thumbnail { width: 100%; height: 220px; background: #f0f0f0; display: block; position: relative; overflow: hidden }
.claims-body .claim-info .thumbnail img { width: 100% }

View file

@ -38,7 +38,7 @@ function buildChartData(claimsData) {
}
function loadChartData() {
var api_url = "https://chainquery.lbry.io/api/sql?query=";
var api_url = "https://chainquery.lbry.com/api/sql?query=";
var query = "SELECT c1.claim_type, c1.bid_state, c1.effective_amount, c1.transaction_time, o.transaction_time AS 'spent_time' FROM claim c1 LEFT JOIN (SELECT output.claim_id, tx.transaction_time FROM output INNER JOIN input ON input.prevout_hash = output.transaction_hash AND input.prevout_n = output.vout INNER JOIN transaction tx ON tx.id = input.transaction_id) o ON o.claim_id=c1.claim_id AND c1.bid_state='Spent' ORDER BY c1.transaction_time ASC";
var url = api_url + query;
var loadProgress = $('.bids-chart-container .load-progress');
@ -167,4 +167,4 @@ divId: 'chart-export'
}
});
loadChartData();
});
});

View file

@ -97,7 +97,7 @@ function buildChartData(blockData) {
}
function loadChartData() {
var api_url = "https://chainquery.lbry.io/api/sql?query=";
var api_url = "https://chainquery.lbry.com/api/sql?query=";
var query = "SELECT height, block_time FROM block WHERE confirmations > 0 ORDER BY height";
var url = api_url + query;
var loadProgress = $('.mining-inflation-chart-container .load-progress');
@ -261,4 +261,4 @@ divId: 'chart-export'
}
});
loadChartData();
});
});