RSpec.describe Pluginscan::VulnerabilityScanner do describe "#scan" do subject(:scanner) { Pluginscan::VulnerabilityScanner.new } it "raises an error if the result didn't include the plugin slug" do stub_vuln_api_success('another_plugin' => { 'vulnerabilities' => [] }) expect{ scanner.scan('my_plugin') } .to raise_error(Pluginscan::WPVulnDB::UnexpectedJSONError) end it "raises an error if a list of vulnerabilities couldn't be found" do stub_vuln_api_success('my_plugin' => {}) expect{ scanner.scan('my_plugin') } .to raise_error(Pluginscan::WPVulnDB::UnexpectedJSONError) end it "returns an empty array if the response was 'not found'" do stub_vuln_api_response_not_found expect(scanner.scan('my_plugin')).to eq [] end it "raises an error if we got blocked" do stub_vuln_api_response_blocked expect{ scanner.scan('my_plugin') } .to raise_error(Pluginscan::WPVulnDB::AccessDeniedError) end it "raises an error if the code wasn't 200" do stub_vuln_api_response(status: 503, body: 'Something went wrong') expect{ scanner.scan('my_plugin') } .to raise_error(Pluginscan::WPVulnDB::APIError) end it "raises an error if the connection failed with a socket error" do allow(HTTParty).to receive(:get).and_raise(SocketError, "Failed to open TCP connection to wpvulndb.com:443 (getaddrinfo: nodename nor servname provided, or not known)") expect{ scanner.scan('my_plugin') } .to raise_error(Pluginscan::AdvisoriesAPI::ConnectionError) end it "raises an error if the connection failed with a timeout" do allow(HTTParty).to receive(:get).and_raise(Net::OpenTimeout, "execution expired (Net::OpenTimeout)") expect{ scanner.scan('my_plugin') } .to raise_error(Pluginscan::AdvisoriesAPI::ConnectionError) end it "returns an array of hashes if results were found" do vulnerabilities = [ { 'id' => 6425, 'title' => "Relevanssi 3.2 - Unspecified SQL Injection", 'created_at' => "2014-08-01T10:58:47.000Z", 'fixed_in' => "3.3", }, { 'id' => 6426, 'title' => "Relevanssi 2.7.2 - Stored XSS Vulnerability", 'created_at' => "2014-08-23T10:58:47.000Z", 'fixed_in' => "2.7.3", }, ] stub_vuln_api_success('my_plugin' => { 'vulnerabilities' => vulnerabilities }) results = scanner.scan('my_plugin') expect(results.count).to eq 2 expect(results.first.title).to eq "Relevanssi 3.2 - Unspecified SQL Injection" expect(results.first.date).to eq Date.new(2014, 8, 1) expect(results.first.fixed_in).to eq "3.3" expect(results.first.url).to eq "https://wpvulndb.com/vulnerabilities/6425" expect(results.last.title).to eq "Relevanssi 2.7.2 - Stored XSS Vulnerability" expect(results.last.date).to eq Date.new(2014, 8, 23) expect(results.last.fixed_in).to eq "2.7.3" expect(results.last.url).to eq "https://wpvulndb.com/vulnerabilities/6426" end def stub_vuln_api_success(body) json_header = { 'Content-Type' => 'application/json; charset=utf-8' } stub_vuln_api_response(status: 200, body: body.to_json, headers: json_header) end def stub_vuln_api_response_not_found stub_vuln_api_response(status: 404, body: "The page you were looking for doesn't exist (404).") end def stub_vuln_api_response_blocked blocked_page = "\n\n\n \n Access denied\n \n\n\n\n
\n

Access denied

\n

Your IP was blocked because of suspicious acitivity.

\n

If you think your IP should not be blocked, please contact us at team [at] wpvulndb [.] com

\n
\n\n\n" stub_vuln_api_response(status: 403, body: blocked_page) end def stub_vuln_api_response(status: 200, body: '', headers: {}) stub_request(:get, 'https://wpvulndb.com/api/v2/plugins/my_plugin') .with(headers: { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent' => 'Ruby' }) .to_return(status: status, body: body, headers: headers) end end end