$value ) { if ( 'extension' === $property && ! empty( $value ) ) { $this->extension = new Extension_Model( $value ); continue; } if ( property_exists( $this, $property ) ) { $this->$property = $value; } } } /** * Get the ID value of the threat based on its related extension and vulnerabilities. * * @since 0.5.0 * * @param Extension_Model $extension The extension to get the ID from. * * @return string */ private static function get_id_from_vulnerable_extension( Extension_Model $extension ) { return "$extension->type-$extension->slug-$extension->version"; } /** * Get the title from a vulnerable extension. * * @since 0.5.0 * * @param Extension_Model $extension The extension to get the title from. * * @return string|null */ private static function get_title_from_vulnerable_extension( Extension_Model $extension ) { $titles = array( 'plugins' => sprintf( /* translators: placeholders are the theme name and version number. Example: "Vulnerable theme: Jetpack (version 1.2.3)" */ __( 'Vulnerable plugin: %1$s (version %2$s)', 'jetpack-protect-models' ), $extension->name, $extension->version ), 'themes' => sprintf( /* translators: placeholders are the theme name and version number. Example: "Vulnerable theme: Jetpack (version 1.2.3)" */ __( 'Vulnerable theme: %1$s (version %2$s)', 'jetpack-protect-models' ), $extension->name, $extension->version ), 'core' => sprintf( /* translators: placeholder is the version number. Example: "Vulnerable WordPress (version 1.2.3)" */ __( 'Vulnerable WordPress (version %s)', 'jetpack-protect-models' ), $extension->version ), ); return $titles[ $extension->type ] ?? null; } /** * Get the description from a vulnerable extension. * * @since 0.5.0 * * @param Extension_Model $extension The extension to get the description from. * @param array $vulnerabilities The vulnerabilities to get the description from. * * @return string */ private static function get_description_from_vulnerable_extension( Extension_Model $extension, array $vulnerabilities ) { return sprintf( /* translators: placeholders are the theme name and version number. Example: "The installed version of Jetpack (1.2.3) has a known security vulnerability." */ _n( 'The installed version of %1$s (%2$s) has a known security vulnerability.', 'The installed version of %1$s (%2$s) has known security vulnerabilities.', count( $vulnerabilities ), 'jetpack-protect-models' ), $extension->name, $extension->version ); } /** * Get the latest fixed_in version from a list of vulnerabilities. * * @since 0.5.0 * * @param array $vulnerabilities The vulnerabilities to get the fixed_in version from. * * @return string|bool|null The latest fixed_in version, or false if any of the vulnerabilities are not fixed. */ private static function get_fixed_in_from_vulnerabilities( array $vulnerabilities ) { $fixed_in = null; foreach ( $vulnerabilities as $vulnerability ) { // If any of the vulnerabilities are not fixed, the threat is not fixed. if ( ! $vulnerability->fixed_in ) { break; } // Use the latest available fixed_in version. if ( ! $fixed_in || ( $fixed_in && version_compare( $vulnerability->fixed_in, $fixed_in, '>' ) ) ) { $fixed_in = $vulnerability->fixed_in; } } return $fixed_in; } /** * Generate a threat from extension vulnerabilities. * * @since 0.5.0 * * @param Extension_Model $extension The extension to generate the threat for. * @param Vulnerability_Model[] $vulnerabilities The vulnerabilities to generate the threat from. * * @return Threat_Model */ public static function generate_from_extension_vulnerabilities( Extension_Model $extension, array $vulnerabilities ) { return new Threat_Model( array( 'id' => self::get_id_from_vulnerable_extension( $extension ), 'title' => self::get_title_from_vulnerable_extension( $extension ), 'description' => self::get_description_from_vulnerable_extension( $extension, $vulnerabilities ), 'fixed_in' => self::get_fixed_in_from_vulnerabilities( $vulnerabilities ), 'vulnerabilities' => $vulnerabilities, ) ); } }