parent = $parent;
$this->page = 'wpscan';
add_action( 'admin_menu', array( $this, 'menu' ) );
}
/**
* Admin menu
*
* @since 1.0.0
* @access public
* @return void
*/
public function menu() {
$title = __( 'Report', 'wpscan' );
add_submenu_page(
'wpscan',
$title,
$title,
$this->parent->WPSCAN_ROLE,
$this->page,
array( $this, 'page' )
);
}
/**
* Render report page
*
* @since 1.0.0
* @access public
* @return string
*/
public function page() {
include $this->parent->plugin_dir . '/views/report.php';
}
/**
* Get vulnerability status based on fixed_in
*
* @since 1.15.2
* @access public
* @return string
*/
public function status( $vulnerability ) {
return empty( $vulnerability->fixed_in )
? __( 'We are not aware of a fix for this vulnerability.', 'wpscan' )
: sprintf( __( 'This vulnerability was fixed in version %s. We recommend that you update as soon as possible.', 'wpscan' ), esc_html( $vulnerability->fixed_in ) );
}
/**
* HTML markup for the vulnerability details
*
* @since 1.15.2
* @access public
* @return string
*/
public function vulnerability_output( $vulnerability ) {
$html = '
';
$html .= '
' . esc_html( $vulnerability->title ) . '
';
$html .= '
' . $this->status( $vulnerability ) . '
';
$html .= $this->vulnerability_severity( $vulnerability );
$html .= '
Click here for further details
';
$html .= '
';
return $html;
}
/**
* List vulnerabilities on screen
*
* @since 1.0.0
*
* @param string $type - Type of report: WordPress, plugins, themes.
* @param string $name - key name of the element.
*
* @access public
* @return array
*/
public function list_api_vulnerabilities( $type, $name ) {
$report = $this->parent->get_report();
$ignored = $this->parent->get_ignored_vulnerabilities();
$null_text = __( 'No known vulnerabilities found to affect this version', 'wpscan' );
$not_checked_text = __( 'Not checked yet. Click the Run All button to run a scan', 'wpscan' );
if ( empty( $report ) || ! isset( $report[ $type ] ) ) {
return null;
}
$report = $report[ $type ];
if ( array_key_exists( $name, $report ) ) {
$report = $report[ $name ];
} else {
echo esc_html( $not_checked_text );
return;
}
if ( isset( $report['vulnerabilities'] ) ) {
$list = array();
usort( $report['vulnerabilities'], array( 'self', 'sort_vulnerabilities' ) );
foreach ( $report['vulnerabilities'] as $vulnerability ) {
$id = 'security-checks' === $type ? $vulnerability['id'] : $vulnerability->id;
if ( in_array( $id, $ignored, true ) ) {
continue;
}
$list[] = $this->vulnerability_output( $vulnerability );
}
echo empty( $list ) ? $null_text : join( '
', $list );
} else {
echo esc_html( $null_text );
}
}
/**
* List security check vulnerabilities in the report.
* This should be merged with the list_api_vulnerabilities() function,
* in the future, if anyone can figure out how...
*
* @param object $check - The check instance.
*
* @access public
* @return string
* @since 1.0.0
*
*/
public function list_security_check_vulnerabilities( $instance ) {
$vulnerabilities = $instance->get_vulnerabilities();
$count = $instance->get_vulnerabilities_count();
$ignored = $this->parent->get_ignored_vulnerabilities();
$not_checked_text = __( 'Not checked yet. Click the Run button to run a scan', 'wpscan' );
if ( ! isset( $vulnerabilities ) ) {
echo esc_html( $not_checked_text );
} elseif ( empty( $vulnerabilities ) || 0 === $count ) {
echo esc_html( $instance->success_message() );
} else {
$list = array();
foreach ( $vulnerabilities as $vulnerability ) {
if ( in_array( $vulnerability['id'], $ignored, true ) ) {
continue;
}
$html = "";
$html .= "
" . wp_kses( $vulnerability['title'], array( 'a' => array( 'href' => array() ) ) ) . '
';
$html .= "
";
$html .= "" . esc_html( $vulnerability['severity'] ) ." Severity";
$html .= '
';
$html .= "
Click here for further details
";
$html .= '
';
$list[] = $html;
}
echo join( '
', $list );
}
}
/**
* Sort vulnerabilities by severity
*
* @since 1.0.0
* @access public
* @return int
*/
public function sort_vulnerabilities( $a, $b ) {
$a = isset( $a->cvss->score ) ? intval( $a->cvss->score ) : 0;
$b = isset( $b->cvss->score ) ? intval( $b->cvss->score ) : 0;
return $b > $a ? 1 : -1;
}
/**
* Vulnerability severity
*
* @since 1.0.0
* @access public
* @return string
*/
public function vulnerability_severity( $vulnerability ) {
$plan = $this->parent->classes['account']->get_account_status()['plan'];
if ( 'enterprise' !== $plan ) {
return;
}
$html = "";
if ( isset( $vulnerability->cvss->severity ) ) {
$severity = $vulnerability->cvss->severity;
$html .= "" . esc_html( $severity ) . ' Severity';
}
$html .= '
';
return $html;
}
/**
* Is the plugin/theme is closed
*
* @since 1.0.0
* @access public
* @return boolean
*/
public function is_item_closed( $type, $name ) {
$report = $this->parent->get_report();
if ( empty( $report ) || ! isset( $report[ $type ] ) ) {
return null;
}
$report = $report[ $type ];
if ( array_key_exists( $name, $report ) ) {
$report = $report[ $name ];
}
return isset( $report['closed'] ) ? $report['closed'] : false;
}
/**
* Get all vulnerabilities
*
* @since 1.0.0
* @access public
* @return array
*/
public function get_all_vulnerabilities() {
$ret = array();
$report = $this->parent->get_report();
$ignored = $this->parent->get_ignored_vulnerabilities();
$types = array( 'wordpress', 'plugins', 'themes', 'security-checks' );
foreach ( $types as $type ) {
if ( isset( $report[ $type ] ) ) {
foreach ( $report[ $type ] as $item ) {
if ( isset( $item['vulnerabilities'] ) ) {
foreach ( $item['vulnerabilities'] as $vuln ) {
$id = 'security-checks' === $type ? $vuln['id'] : $vuln->id;
$title = 'security-checks' === $type ? $vuln['title'] : $this->parent->get_sanitized_vulnerability_title( $vuln );
if ( in_array( $id, $ignored, true ) ) {
continue;
}
$ret[] = $title;
}
}
}
}
}
return $ret;
}
/**
* Get item non-ignored vulnerabilities count
*
* @since 1.0.0
*
* @param string $type - Type of report: WordPress, plugins, themes.
* @param string $name - key name of the element.
*
* @access public
* @return int|null
*/
public function get_item_vulnerabilities_count( $type, $name ) {
$report = $this->parent->get_report();
$ignored = $this->parent->get_ignored_vulnerabilities();
if ( empty( $report ) ) {
return null;
}
if ( isset( $report[ $type ] ) && array_key_exists( $name, $report[ $type ] ) ) {
$report = $report[ $type ][ $name ];
}
foreach ( $report['vulnerabilities'] as $key => &$item ) {
$id = 'security-checks' === $type ? $item['id'] : $item->id;
if ( in_array( $id, $ignored, true ) ) {
unset( $report['vulnerabilities'][ $key ] );
}
}
return count( $report['vulnerabilities'] );
}
/**
* Show status icons: checked, attention and error
*
* @since 1.0.0
*
* @param string $type - Type of report: WordPress, plugins, themes.
* @param string $name - key name of the element.
*
* @access public
* @return string
*/
public function get_status( $type, $name ) {
$report = $this->parent->get_report();
$ignored = $this->parent->get_ignored_vulnerabilities();
if ( empty( $report ) ) {
return null;
}
if ( isset( $report[ $type ] ) && array_key_exists( $name, $report[ $type ] ) ) {
$report = $report[ $type ][ $name ];
}
if ( array_key_exists( 'not_found', $report ) ) {
$icon = 'dashicons-yes is-green';
} elseif ( ! isset( $report['vulnerabilities'] ) ) {
$icon = 'dashicons-no-alt is-gray';
} elseif ( empty( $report['vulnerabilities'] ) ) {
$icon = 'dashicons-yes is-green';
} else {
$count = $this->get_item_vulnerabilities_count( $type, $name );
$icon = 0 === $count ? 'dashicons-yes is-green' : 'dashicons-warning is-red';
}
return " ";
}
}