Skip to content

Commit

Permalink
Ticket #4603 - Antispam: Integrate Lasso Moderation API.
Browse files Browse the repository at this point in the history
  • Loading branch information
AntonLV committed Jan 10, 2024
1 parent 4342c9a commit b6404e7
Show file tree
Hide file tree
Showing 9 changed files with 354 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public function response($oAlert)
BxDolService::call('bx_antispam', 'check_form_for_toxicity', array(&$oAlert->aExtras['object']));
break;
case 'form_submitted':
BxDolService::call('bx_antispam', 'on_form_submitted', array($oAlert->aExtras['module'], $oAlert->aExtras['entry_id']));
BxDolService::call('bx_antispam', 'on_form_submitted', array($oAlert->aExtras['module'], $oAlert->aExtras['entry_id'], $oAlert->aExtras['action'], &$oAlert->aExtras['form_object']));
break;
}
} elseif ('comment' == $oAlert->sUnit && BxDolService::call('bx_antispam', 'is_last_form_submitted_toxic', array())) {
Expand Down
9 changes: 9 additions & 0 deletions modules/boonex/antispam/classes/BxAntispamConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ class BxAntispamConfig extends BxDolModuleConfig
'toxicity_enable' => 'bx_antispam_toxicity_filter_enable',
'toxicity_action' => 'bx_antispam_toxicity_filter_action',
'toxicity_report' => 'bx_antispam_toxicity_filter_report',
'lm_enable' => 'bx_antispam_lasso_moderation_enable',
'lm_api_key' => 'bx_antispam_lasso_moderation_api_key',
'lm_webhook_secret' => 'lasso_moderation_webhook_secret',
'lm_action' => 'bx_antispam_lasso_moderation_action',
'lm_report' => 'bx_antispam_lasso_moderation_report',
);
/**
* default local options, it is filled in with real system options in class contructor, @see restoreAntispamOptions
Expand All @@ -44,6 +49,10 @@ class BxAntispamConfig extends BxDolModuleConfig
'toxicity_enable' => '',
'toxicity_action' => '',
'toxicity_report' => '',
'lm_enable' => '',
'lm_api_key' => '',
'lm_action' => '',
'lm_report' => ''
);

public function __construct($aModule)
Expand Down
162 changes: 162 additions & 0 deletions modules/boonex/antispam/classes/BxAntispamLassoModeration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
<?php defined('BX_DOL') or die('hack attempt');
/**
* Copyright (c) UNA, Inc - https://una.io
* MIT License - https://opensource.org/licenses/MIT
*
* @defgroup Antispam Antispam
* @ingroup UnaModules
*
* @{
*/

class BxAntispamLassoModeration extends BxDol
{
protected $_sModule;
protected $_oModule;

protected $_sApiKey;
protected $_sWebhookSecret;
protected $_sEndpoint;

public function __construct()
{
parent::__construct();

$this->_sModule = 'bx_antispam';
$this->_oModule = BxDolModule::getInstance($this->_sModule);

$this->_sApiKey = $this->_oModule->_oConfig->getAntispamOption('lm_api_key');
$this->_sWebhookSecret = $this->_oModule->_oConfig->getAntispamOption('lm_webhook_secret');

$this->_sEndpoint = 'https://api.lassomoderation.com/api/v1';
}

public function processEvent()
{
$sInput = @file_get_contents("php://input");

$sInputHmac = hash_hmac('sha256', $sInput, $this->_sWebhookSecret, true);
$sInputHmac = 'sha256=' . base64_encode($sInputHmac);

if($sInputHmac !== '')
return 404;

$aEvent = json_decode($sInput, true);
if(empty($aEvent) || !is_array($aEvent))
return 404;

//TODO: Do something here.

//$this->_onHarmfulContentFound();

return 200;
}

public function addContent($sModule, $iId, $aData = [])
{
$aModule = BxDolModuleQuery::getInstance()->getModuleByName($sModule);
if(empty($aModule) || !is_array($aModule))
return false;

$iAuthorId = !empty($aData['author_id']) ? $aData['author_id'] : bx_srv($sModule, 'get_author', [$iId]);
$sAuthorName = !empty($aData['author_name']) ? $aData['author_name'] : BxDolProfile::getInstanceMagic($iAuthorId)->getDisplayName();

$iDataAdded = !empty($aData['date_added']) ? $aData['date_added'] : bx_srv($sModule, 'get_date_added', [$iId]);

$sText = !empty($aData['text']) ? $aData['text'] : bx_srv($sModule, 'get_text', [$iId]);

$aParams = [
'project' => [
'id' => md5(BX_DOL_URL_ROOT),
'name' => getParam('site_title'),
],
'topic' => [
'id' => 'mod_' . $aModule['id'],
'name' => $aModule['title'],
],
'user' => [
'id' => 'prof_' . $iAuthorId,
'name' => $sAuthorName
],
'content_id' => $sModule . '_' . $iId,
'created_at' => bx_time_utc($iDataAdded ? $iDataAdded : time()),
'text' => $sText,
'image_urls' => isset($aData['images']) ? $aData['images'] : [],
'video_urls' => isset($aData['videos']) ? $aData['videos'] : []
];

return $this->_call('/content', $aParams);
}

public function log($mixedContents, $sTitle = '')
{
$this->_oModule->log($mixedContents, 'Lasso Moderation', $sTitle);
}

/**
* Internal methods.
*/
protected function _call($sRequest, $aParams, $sMethod = 'post-json', $aHeaders = [])
{
$aHeaders[] = 'Authorization: Bearer ' . $this->_sApiKey;

$sResult = bx_file_get_contents($this->_sEndpoint . $sRequest, $aParams, $sMethod, $aHeaders);
if(empty($sResult)) {
$this->log($sResult, 'Call (' . $sRequest . '): ');
$this->log($aParams);
return false;
}

$aResult = json_decode($sResult, true);
if(empty($aResult) || !is_array($aResult) || !isset($aResult['success'])) {
$this->log($sResult, 'Call (' . $sRequest . '): ');
$this->log($aParams);
return false;
}

return true;
}

protected function _onHarmfulContentFound($sModule, $iContentId)
{
if(!$sModule || $this->_oConfig->getAntispamOption('lm_report') != 'on')
return;

$oModule = BxDolModule::getInstance($sModule);
$CNF = &$oModule->_oConfig->CNF;
$sContentUrl = isset($CNF['URI_VIEW_ENTRY']) ? bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $iContentId)) : false;
$sManageContentUrl = isset($CNF['URL_MANAGE_ADMINISTRATION']) ? bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URL_MANAGE_ADMINISTRATION'])) : false;

$oProfile = BxDolProfile::getInstance();
if(!$oProfile)
return;

$aPlus = array(
'AuthorUrl' => $oProfile->getUrl(),
'AuthorNickName' => $oProfile->getDisplayName(),
'Page' => htmlspecialchars_adv($_SERVER['PHP_SELF']),
'bx_if:content_url' => [
'condition' => boolval($sContentUrl),
'content' => ['c_url' => $sContentUrl],
],
'bx_if:manage_content_url' => [
'condition' => boolval($sManageContentUrl),
'content' => ['m_url' => $sManageContentUrl],
],
);

$aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate('bx_antispam_lasso_moderation_report', $aPlus);
if(!$aTemplate)
trigger_error('Email template or translation missing: bx_antispam_lasso_moderation_report', E_USER_ERROR);

sendMail(getParam('site_email'), $aTemplate['Subject'], $aTemplate['Body']);

bx_alert('bx_antispam', 'harmful_content_posted', $iContentId, bx_get_logged_profile_id(), [
'module' => $sModule,
'entry_id' => $iContentId,
'entry_url' => $sContentUrl,
]);
}
}

/** @} */
86 changes: 85 additions & 1 deletion modules/boonex/antispam/classes/BxAntispamModule.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ public function __construct(&$aModule)
$this->_bLastSubmittedFormWasToxic = false;
}

public function actionContentChecked()
{
$iResult = 404;

if($this->_oConfig->getAntispamOption('lm_enable') == 'on') {
$oLassoModeration = bx_instance('BxAntispamLassoModeration', [], $this->getName());
$iResult = $oLassoModeration->processEvent();
}

http_response_code($iResult);
}

public function serviceUpdateDisposableDomainsLists ()
{
$o = bx_instance('BxAntispamDisposableEmailDomains', array(), 'bx_antispam');
Expand Down Expand Up @@ -261,10 +273,56 @@ public function serviceSetCommentAsPending($iCmtId) {
return $this->_oDb->setCommentStatus($iCmtId, BX_CMT_STATUS_PENDING);
}

public function serviceOnFormSubmitted($sModule, $iEntry) {
public function serviceOnFormSubmitted($sModule, $iEntry, $sAction, &$oForm)
{
if ($this->_bLastSubmittedFormWasToxic) {
$this->serviceOnToxicContentPosted($sModule, $iEntry);
}

if($this->_oConfig->getAntispamOption('lm_enable') == 'on') {
$oModule = BxDolModule::getInstance($sModule);

$CNF = &$oModule->_oConfig->CNF;

$iAuthorId = bx_get_logged_profile_id();
$iAuthorName = BxDolProfile::getInstance()->getDisplayName();

$iDataAdded = time();

$sText = '';
if(isset($CNF['FIELD_TEXT'], $oForm->aInputs[$CNF['FIELD_TEXT']]))
$sText = $oForm->getCleanValue($CNF['FIELD_TEXT']);
if(empty($sText) && isset($oForm->aInputs['text']))
$sText = $oForm->getCleanValue('text');

$aMedias = [
'images' => ['fields' => ['FIELD_PHOTO', 'FIELD_PICTURE', 'FIELD_COVER'], 'data' => []],
'videos' => ['fields' => ['FIELD_VIDEO'], 'data' => []]
];
foreach($aMedias as $sName => $aMedia)
foreach($aMedia['fields'] as $sField) {
if(!isset($CNF[$sField], $oForm->aInputs[$CNF[$sField]]))
continue;

$oStorage = BxDolStorage::getObjectInstance($oForm->aInputs[$CNF[$sField]]['storage_object']);
if(!$oStorage)
continue;

$aGhosts = $oStorage->getGhosts($iAuthorId, $sAction == 'insert' ? 0 : $iEntry);
foreach($aGhosts as $aGhost)
$aMedias[$sName]['data'][] = $oStorage->getFileUrlById($aGhost['id']);
}

$oLassoModeration = bx_instance('BxAntispamLassoModeration', [], $this->getName());
$oLassoModeration->addContent($sModule, $iEntry, [
'author_id' => $iAuthorId,
'author_name' => $iAuthorName,
'date_added' => $iDataAdded,
'text' => $sText,
'images' => $aMedias['images']['data'],
'videos' => $aMedias['videos']['data']
]);
}
}

public function serviceOnToxicContentFound(&$sText) {
Expand Down Expand Up @@ -525,6 +583,32 @@ public function serviceGetToxicityFilterActions ()
];
}

/**
* @return array with avaliable Lasso Moderation actions
*/
public function serviceGetLassoModerationActions ()
{
return [
'none' => _t('_bx_antispam_option_lasso_moderation_action_none'),
'disapprove' => _t('_bx_antispam_option_lasso_moderation_action_disapprove'),
];
}

public function log($mixedContents, $sSection = '', $sTitle = '')
{
if(is_array($mixedContents))
$mixedContents = var_export($mixedContents, true);
else if(is_object($mixedContents))
$mixedContents = json_encode($mixedContents);

if(empty($sSection))
$sSection = "Core";

$sTitle .= "\n";

bx_log('bx_antispam', ":\n[" . $sSection . "] " . $sTitle . $mixedContents);
}

protected function getErrorMessageIpBlocked ()
{
bx_import('BxDolLanguages');
Expand Down
20 changes: 20 additions & 0 deletions modules/boonex/antispam/classes/BxAntispamStudioOptions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php defined('BX_DOL') or die('hack attempt');
/**
* Copyright (c) UNA, Inc - https://una.io
* MIT License - https://opensource.org/licenses/MIT
*
* @defgroup Antispam Antispam
* @ingroup UnaModules
*
* @{
*/

class BxAntispamStudioOptions extends BxTemplStudioOptions
{
protected function getCustomValueLassoModerationWebhookUrl($aItem, $mixedValue)
{
return bx_replace_markers($mixedValue, [
'site_url' => BX_DOL_URL_ROOT
]);
}
}
15 changes: 14 additions & 1 deletion modules/boonex/antispam/classes/BxAntispamStudioPage.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
* @{
*/

require_once ('BxAntispamStudioOptions.php');

class BxAntispamStudioPage extends BxTemplStudioModule
{
protected $oModule;
Expand All @@ -28,7 +30,18 @@ function __construct($sModule, $mixedPageName, $sPage = "")
);
}

function getHelp ()
protected function getSettings()
{
$oOptions = new BxAntispamStudioOptions($this->sModule);

$this->aPageCss = array_merge($this->aPageCss, $oOptions->getCss());
$this->aPageJs = array_merge($this->aPageJs, $oOptions->getJs());
return BxDolStudioTemplate::getInstance()->parseHtmlByName('module.html', [
'content' => $oOptions->getCode(),
]);
}

protected function getHelp ()
{
return _t('_bx_antispam_help_text');
}
Expand Down
25 changes: 24 additions & 1 deletion modules/boonex/antispam/install/langs/en.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
<li><b>Akismet</b> - automatic spam content blocking using <a target="_blank" href="http://akismet.com">Akismet service</a></li>
<li><b>StopForumSpam</b> - automatic spam content blocking using <a target="_blank" href="http://www.stopforumspam.com">StopForumSpam service</a></li>
<li><b>Profanity filter</b> - profanity filter, based on a predefined list of words with the ability to add to words this list</a></li>
<li><b>Toxicity filter</b> - toxicity filter, based on a <a target="_blank" href="https://www.perspectiveapi.com/">Perspective API</a> provided by Google</a></li>
<li><b>Toxicity filter</b> - toxicity filter, based on a <a target="_blank" href="https://www.perspectiveapi.com/">Perspective API</a> provided by Google</li>
<li><b>Harmful filter</b> - harmfulness filter, based on a <a target="_blank" href="https://www.lassomoderation.com/">Lasso Moderation API</a></li>
</ul>
]]></string>
<string name="_bx_antispam_help_dnsbl"><![CDATA[
Expand Down Expand Up @@ -203,5 +204,27 @@ This antispam method scan submitted content for the URLs and check them if any o
<bx_if:manage_content_url>
<b>Manage:</b> <a href="{m_url}">{m_url}</a><br /><br />
</bx_if:manage_content_url>
{email_footer}]]></string>

<string name="_bx_antispam_adm_stg_cpt_category_lasso_moderation"><![CDATA[Lasso Moderation]]></string>
<string name="_bx_antispam_option_lasso_moderation_enable"><![CDATA[Enable]]></string>
<string name="_bx_antispam_option_lasso_moderation_api_key"><![CDATA[API key]]></string>
<string name="_bx_antispam_option_lasso_moderation_webhook_secret"><![CDATA[Webhook Secret]]></string>
<string name="_bx_antispam_option_lasso_moderation_webhook_url"><![CDATA[Webhook URL]]></string>
<string name="_bx_antispam_option_lasso_moderation_action"><![CDATA[Action]]></string>
<string name="_bx_antispam_option_lasso_moderation_action_none"><![CDATA[None]]></string>
<string name="_bx_antispam_option_lasso_moderation_action_disapprove"><![CDATA[Disapprove]]></string>
<string name="_bx_antispam_option_lasso_moderation_report"><![CDATA[Send report to admin if harmful content discovered]]></string>
<string name="_bx_antispam_et_lasso_moderation_report_name"><![CDATA[Harmful content posted report message]]></string>
<string name="_bx_antispam_et_lasso_moderation_report_subject"><![CDATA[Harmful content has been posted]]></string>
<string name="_bx_antispam_et_lasso_moderation_report_body"><![CDATA[{email_header}
<b>Profile:</b> <a href="{AuthorUrl}">{AuthorNickName}</a><br />
<b>Page:</b> {Page}<br /><br />
<bx_if:content_url>
<b>Content:</b> <a href="{c_url}">{c_url}</a><br /><br />
</bx_if:content_url>
<bx_if:manage_content_url>
<b>Manage:</b> <a href="{m_url}">{m_url}</a><br /><br />
</bx_if:manage_content_url>
{email_footer}]]></string>
</resources>
Loading

0 comments on commit b6404e7

Please sign in to comment.