diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4d26bf1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +doc +pkg +tmp/* +.DS_Store +.yardoc +*.db +*.log +*.swp +*~ diff --git a/COPYING.txt b/COPYING.txt new file mode 100644 index 0000000..d511905 --- /dev/null +++ b/COPYING.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/History.txt b/History.txt new file mode 100644 index 0000000..f273103 --- /dev/null +++ b/History.txt @@ -0,0 +1,4 @@ +=== 1.0.0 / 2009-11-25 + +* Initial release. + diff --git a/Manifest.txt b/Manifest.txt new file mode 100644 index 0000000..2ff264f --- /dev/null +++ b/Manifest.txt @@ -0,0 +1,21 @@ +COPYING.txt +History.txt +Manifest.txt +README.txt +Rakefile +lib/shodan.rb +lib/shodan/extensions.rb +lib/shodan/extensions/uri.rb +lib/shodan/extensions/uri/query_params.rb +lib/shodan/extensions/uri/http.rb +lib/shodan/host.rb +lib/shodan/page.rb +lib/shodan/has_pages.rb +lib/shodan/query.rb +lib/shodan/shodan.rb +lib/shodan/version.rb +tasks/spec.rb +spec/spec_helper.rb +spec/has_pages_examples.rb +spec/query_spec.rb +spec/shodan_spec.rb diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..25594da --- /dev/null +++ b/README.txt @@ -0,0 +1,45 @@ += shodanrb + +* http://github.com/postmodern/shodanrb + +== DESCRIPTION: + +A Ruby interface to SHODAN, a computer search engine. + +== FEATURES/PROBLEMS: + +* Supports basic queries. +* Supports +country+ search operator. +* Supports +hostname+ search operator. +* Supports +net+ search operator. +* Supports +port+ search operator. + +== EXAMPLES: + +== REQUIREMENTS: + +* {nokogiri}[http://nokogiri.rubyforge.org] >= 1.4.0 + +== INSTALL: + + $ sudo gem install shodanrb + +== LICENSE: + +shodanrb - A Ruby interface to SHODAN, a computer search engine. + +Copyright (c) 2009 Hal Brodigan (postmodern.mod3 at gmail.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..cf6702d --- /dev/null +++ b/Rakefile @@ -0,0 +1,20 @@ +# -*- ruby -*- + +require 'rubygems' +require 'hoe' +require 'hoe/signing' +require './tasks/spec.rb' + +Hoe.spec('shodanrb') do + self.developer('Postmodern', 'postmodern.mod3@gmail.com') + + self.extra_deps = [ + ['nokogiri', '>=1.4.0'] + ] + + self.extra_dev_deps = [ + ['rspec', '>=1.2.8'] + ] +end + +# vim: syntax=ruby diff --git a/lib/shodan.rb b/lib/shodan.rb new file mode 100644 index 0000000..3d08d01 --- /dev/null +++ b/lib/shodan.rb @@ -0,0 +1,23 @@ +# +# shodanrb - A Ruby interface to SHODAN, a computer search engine. +# +# Copyright (c) 2009 Hal Brodigan (postmodern.mod3 at gmail.com) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +require 'shodan/query' +require 'shodan/shodan' +require 'shodan/version' diff --git a/lib/shodan/countries.rb b/lib/shodan/countries.rb new file mode 100644 index 0000000..3c9cbb4 --- /dev/null +++ b/lib/shodan/countries.rb @@ -0,0 +1,274 @@ +# +# shodanrb - A Ruby interface to SHODAN, a computer search engine. +# +# Copyright (c) 2009 Hal Brodigan (postmodern.mod3 at gmail.com) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +module Shodan + # Country Code List: ISO 3166-1993 (E) + module Countries + Mexico = 'MX' + GuineaBissau = 'GW' + Afghanistan = 'AF' + Ethiopia = 'ET' + SyrianArabRepublic = 'SY' + SvalbardJanMayenIslands = 'SJ' + Tonga = 'TO' + Pakistan = 'PK' + Unknownorunspecifiedcountry = 'ZZ' + BritishVirginIslands = 'VG' + Somalia = 'SO' + Bolivia = 'BO' + NorthernMarianaIslands = 'MP' + Nicaragua = 'NI' + Dominica = 'DM' + Sweden = 'SE' + Greece = 'GR' + Micronesia = 'FM' + Guadeloupe = 'GP' + UnitedArabEmirates = 'AE' + Cambodia = 'KH' + Ireland = 'IE' + Vanuatu = 'VU' + FrenchGuiana = 'GF' + Denmark = 'DK' + Czechoslovakia = 'CS' + Norway = 'NO' + Gabon = 'GA' + Malawi = 'MW' + Djibouti = 'DJ' + Namibia = 'NA' + Samoa = 'WS' + WallisFutunaIslands = 'WF' + Switzerland = 'CH' + Chad = 'TD' + UnitedStatesVirginIslands = 'VI' + Bhutan = 'BT' + PuertoRico = 'PR' + Haiti = 'HT' + Tajikistan = 'TJ' + Guyana = 'GY' + Turkmenistan = 'TM' + Kuwait = 'KW' + Canada = 'CA' + France = 'FR' + DominicanRepublic = 'DO' + Venezuela = 'VE' + Belize = 'BZ' + Italy = 'IT' + Congo = 'CG' + Tokelau = 'TK' + Mayotte = 'YT' + Algeria = 'DZ' + Lebanon = 'LB' + Azerbaijan = 'AZ' + CocosIslands = 'CC' + FrenchSouthernTerritories = 'TF' + Israel = 'IL' + Nigeria = 'NG' + Austria = 'AT' + Hungary = 'HU' + SolomonIslands = 'SB' + China = 'CN' + SaudiArabia = 'SA' + Angola = 'AO' + Kazakhstan = 'KZ' + Guam = 'GU' + Peru = 'PE' + HongKong = 'HK' + Latvia = 'LV' + Bangladesh = 'BD' + GreatBritain = 'GB' + ChristmasIsland = 'CX' + CookIislands = 'CK' + Luxembourg = 'LU' + Bahrain = 'BH' + Malta = 'MT' + Colombia = 'CO' + Panama = 'PA' + Oman = 'OM' + Netherlands = 'NL' + Philippines = 'PH' + Burundi = 'BI' + StPierreMiquelon = 'PM' + Antarctica = 'AQ' + Germany = 'DE' + Macau = 'MO' + Armenia = 'AM' + Nepal = 'NP' + Pitcairn = 'PN' + Mauritius = 'MU' + BruneiDarussalam = 'BN' + Bulgaria = 'BG' + Indonesia = 'ID' + Tanzania,UnitedRepublicof = 'TZ' + MarshallIslands = 'MH' + AmericanSamoa = 'AS' + Lesotho = 'LS' + Slovakia = 'SK' + SouthGeorgiaandtheSouthSandwichIslands = 'GS' + PapuaNewGuinea = 'PG' + Jordan = 'JO' + Cyprus = 'CY' + NeutralZone = 'NT' + Burma = 'BU' + SierraLeone = 'SL' + Yemen = 'YE' + Ukraine = 'UA' + WesternSahara = 'EH' + Bermuda = 'BM' + Croatia = 'HR' + Aruba = 'AW' + Belgium = 'BE' + Liberia = 'LR' + Grenada = 'GD' + Monserrat = 'MS' + Thailand = 'TH' + FranceMetropolitan = 'FX' + Botswana = 'BW' + Cuba = 'CU' + Andorra = 'AD' + VaticanCityState = 'VA' + Estonia = 'EE' + EastTimor = 'TP' + BouvetIsland = 'BV' + EquatorialGuinea = 'GQ' + Tunisia = 'TN' + Togo = 'TG' + Sudan = 'SD' + NetherlandsAntilles = 'AN' + FaroeIslands = 'FO' + TurksCaicosIslands = 'TC' + Barbados = 'BB' + AntiguaBarbuda = 'AG' + Mauritania = 'MR' + Fiji = 'FJ' + BosniaandHerzegovina = 'BA' + Taiwan,ProvinceofChina = 'TW' + StKittsandNevis = 'KN' + Comoros = 'KM' + BurkinaFaso = 'BF' + BritishIndianOceanTerritory = 'IO' + ElSalvador = 'SV' + Maldives = 'MV' + SaintLucia = 'LC' + Niue = 'NU' + Georgia = 'GE' + Zimbabwe = 'ZW' + Spain = 'ES' + Lao = 'LA' + Monaco = 'MC' + Martinique = 'MQ' + Uzbekistan = 'UZ' + CaymanIslands = 'KY' + Bahama = 'BS' + IslamicRepublicofIran = 'IR' + Zambia = 'ZM' + Uganda = 'UG' + Finland = 'FI' + Mongolia = 'MN' + Eritrea = 'ER' + Gibraltar = 'GI' + Portugal = 'PT' + Kiribati = 'KI' + Iraq = 'IQ' + Morocco = 'MA' + Argentina = 'AR' + Malaysia = 'MY' + India = 'IN' + Greenland = 'GL' + StVincentGrenadines = 'VC' + Egypt = 'EG' + Reunion = 'RE' + Australia = 'AU' + CzechRepublic = 'CZ' + Zaire = 'ZR' + VietNam = 'VN' + Suriname = 'SR' + NewZealand = 'NZ' + Honduras = 'HN' + NorfolkIsland = 'NF' + Guinea = 'GN' + Nauru = 'NR' + Belarus = 'BY' + Korea = 'KR' + UnitedStatesMinorOutlyingIslands = 'UM' + SanMarino = 'SM' + Yugoslavia = 'YU' + IvoryCoast = 'CI' + Swaziland = 'SZ' + Niger = 'NE' + Albania = 'AL' + StHelena = 'SH' + Mali = 'ML' + Slovenia = 'SI' + Poland = 'PL' + LibyanArabJamahiriya = 'LY' + Myanmar = 'MM' + Mozambique = 'MZ' + Japan = 'JP' + Kyrgyzstan = 'KG' + CapeVerde = 'CV' + SouthAfrica = 'ZA' + HeardMcDonaldIslands = 'HM' + Malvinas = 'FK' + Liechtenstein = 'LI' + Romania = 'RO' + Kenya = 'KE' + FrenchPolynesia = 'PF' + TrinidadTobago = 'TT' + NewCaledonia = 'NC' + Singapore = 'SG' + Tuvalu = 'TV' + Benin = 'BJ' + Ghana = 'GH' + Cameroon = 'CM' + Guatemala = 'GT' + Qatar = 'QA' + SriLanka = 'LK' + Madagascar = 'MG' + Turkey = 'TR' + Palau = 'PW' + Senegal = 'SN' + Chile = 'CL' + Gambia = 'GM' + Iceland = 'IS' + Uruguay = 'UY' + UnitedStatesofAmerica = 'US' + Ecuador = 'EC' + Brazil = 'BR' + SaoTome = 'ST' + Rwanda = 'RW' + RussianFederation = 'RU' + Jamaica = 'JM' + Anguilla = 'AI' + Paraguay = 'PY' + CostaRica = 'CR' + Seychelles = 'SC' + Lithuania = 'LT' + Moldova = 'MD' + CentralAfricanRepublic = 'CF' + + def Countries.each(&block) + self.constants.each do |name| + block.call(self.constant_get(name)) if block + end + + return self + end + end +end diff --git a/lib/shodan/extensions.rb b/lib/shodan/extensions.rb new file mode 100644 index 0000000..8f4745e --- /dev/null +++ b/lib/shodan/extensions.rb @@ -0,0 +1,21 @@ +# +# shodanrb - A Ruby interface to SHODAN, a computer search engine. +# +# Copyright (c) 2009 Hal Brodigan (postmodern.mod3 at gmail.com) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +require 'shodan/extensions/uri' diff --git a/lib/shodan/extensions/uri.rb b/lib/shodan/extensions/uri.rb new file mode 100644 index 0000000..e24b02b --- /dev/null +++ b/lib/shodan/extensions/uri.rb @@ -0,0 +1,22 @@ +# +# shodanrb - A Ruby interface to SHODAN, a computer search engine. +# +# Copyright (c) 2009 Hal Brodigan (postmodern.mod3 at gmail.com) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +require 'shodan/extensions/uri/query_params' +require 'shodan/extensions/uri/http' diff --git a/lib/shodan/extensions/uri/http.rb b/lib/shodan/extensions/uri/http.rb new file mode 100644 index 0000000..965b77b --- /dev/null +++ b/lib/shodan/extensions/uri/http.rb @@ -0,0 +1,31 @@ +# +# shodanrb - A Ruby interface to SHODAN, a computer search engine. +# +# Copyright (c) 2009 Hal Brodigan (postmodern.mod3 at gmail.com) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +require 'shodan/extensions/uri/query_params' + +require 'uri/http' + +module URI + class HTTP < Generic + + include QueryParams + + end +end diff --git a/lib/shodan/extensions/uri/query_params.rb b/lib/shodan/extensions/uri/query_params.rb new file mode 100644 index 0000000..88a157f --- /dev/null +++ b/lib/shodan/extensions/uri/query_params.rb @@ -0,0 +1,96 @@ +# +# shodanrb - A Ruby interface to SHODAN, a computer search engine. +# +# Copyright (c) 2009 Hal Brodigan (postmodern.mod3 at gmail.com) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +require 'cgi' + +module URI + module QueryParams + # Query parameters + attr_reader :query_params + + # + # Creates a new URI::HTTP object and initializes query_params as a + # new Hash. + # + def initialize(*args) + @query_params = {} + + super(*args) + + parse_query_params + end + + # + # Sets the query data and updates query_params. + # + def query=(query_str) + new_query = super(query_str) + parse_query_params + return new_query + end + + protected + + # + # Parses the query parameters from the query data, populating + # query_params with the parsed parameters. + # + def parse_query_params + @query_params.clear + + if @query + @query.split('&').each do |param| + name, value = param.split('=') + + if value + @query_params[name] = URI.decode(value) + else + @query_params[name] = nil + end + end + end + end + + private + + # :nodoc + def path_query + str = @path + + unless @query_params.empty? + str += '?' + @query_params.to_a.map { |name,value| + if value==true + "#{name}=active" + elsif value + if value.kind_of?(Array) + "#{name}=#{CGI.escape(value.join(' '))}" + else + "#{name}=#{CGI.escape(value.to_s)}" + end + else + "#{name}=" + end + }.join('&') + end + + return str + end + end +end diff --git a/lib/shodan/has_pages.rb b/lib/shodan/has_pages.rb new file mode 100644 index 0000000..0189d6e --- /dev/null +++ b/lib/shodan/has_pages.rb @@ -0,0 +1,129 @@ +# +# shodanrb - A Ruby interface to SHODAN, a computer search engine. +# +# Copyright (c) 2009 Hal Brodigan (postmodern.mod3 at gmail.com) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +module Shodan + module HasPages + include Enumerable + + # + # Returns the first page. + # + def first_page + page_cache[1] + end + + # + # Returns the page at the specified _index_. + # + def [](index) + page_cache[index] + end + + # + # Returns the pages with the specified _indices_. + # + def pages(indices) + indices.map { |index| page_cache[index] } + end + + # + # Iterates over the pages with the specified _indices_, passing each + # to the specified _block_. + # + def each_page(indices,&block) + indices.map { |index| block.call(page_cache[index]) } + end + + # + # Iterates over all the pages of the query, passing each to the + # specified _block_. + # + def each(&block) + index = 1 + + until ((next_page = page_cache[index]).empty?) do + block.call(next_page) + index = index + 1 + end + + return self + end + + # + # Iterates over the elements on the page with the specified _index_, + # passing each element to the specified _block_. + # + def each_on_page(index,&block) + page_cache[index].each(&block) + end + + # + # Iterates over each element on the pages with the specified _indices_, + # passing each element to the specified _block_. + # + def each_on_pages(indices,&block) + each_page(indices) { |page| page.each(&block) } + end + + # + # Returns the first Result on the first_page. + # + def top_result + first_page.first + end + + # + # Returns the Result at the specified _index_. + # + def result_at(index) + page(page_index_of(index))[result_index_of(index)] + end + + protected + + # + # Returns the page index for the specified result _rank_. + # + def page_index_of(rank) + (((rank.to_i - 1) / results_per_page.to_i) + 1) + end + + # + # Returns the rank offset for the specified _page_index_. + # + def result_offset_of(page_index) + ((page_index.to_i - 1) * results_per_page.to_i) + end + + # + # Returns the in-page index of the specified result _rank_. + # + def result_index_of(rank) + ((rank.to_i - 1) % results_per_page.to_i) + end + + # + # The cache of previously requested pages. + # + def page_cache + @page_cache ||= Hash.new { |hash,key| hash[key] = page(key.to_i) } + end + end +end diff --git a/lib/shodan/host.rb b/lib/shodan/host.rb new file mode 100644 index 0000000..c74756a --- /dev/null +++ b/lib/shodan/host.rb @@ -0,0 +1,116 @@ +# +# shodanrb - A Ruby interface to SHODAN, a computer search engine. +# +# Copyright (c) 2009 Hal Brodigan (postmodern.mod3 at gmail.com) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +module Shodan + class Host + + # The IP of the host + attr_reader :ip + + # The date the host was added + attr_reader :date + + # The host-name of the host + attr_reader :hostname + + # The response returned by the host + attr_reader :response + + # The HTTP version supported by the host + attr_reader :http_version + + # The HTTP status code in the response + attr_reader :code + + # The HTTP status string in the response + attr_reader :status + + # The HTTP headers included in the response + attr_reader :headers + + # + # Creates a new host with the given _ip_, _data_, _response_ and _hostname_. + # + def initialize(ip,date,response,hostname=nil) + @ip = ip + @date = date + @response = response + @hostname = hostname + + @http_version = nil + @code = nil + @status = nil + @headers = {} + + if response =~ /^HTTP\/?/ + lines = response.split("\r") + match = lines.first.split(/\s+/,3) + + if match[0].include?('/') + @http_version = match[0].split('/').last + end + + if match[2] + @code = match[2].to_i + end + + @status = match[3] + + lines[1..-1].each do |line| + name, value = line.chomp.split(/:\s+/,2) + + @headers[name] = value + end + end + end + + # + # Returns the Server software name. + # + def server_name + if (server = @headers['Server']) + return server.split('/',2).first + end + end + + # + # Returns the Server software version. + # + def server_version + if (server = @headers['Server']) + return server.split('/',2).last + end + end + + # + # Provides transparent access to the values in +headers+. + # + def method_missing(sym,*args,&block) + if (args.empty? && block.nil?) + name = sym.id2name.sub('_','-').capitalize + + return @headers[name] if @headers.key?(name) + end + + return super(sym,*args,&block) + end + + end +end diff --git a/lib/shodan/page.rb b/lib/shodan/page.rb new file mode 100644 index 0000000..7da7be9 --- /dev/null +++ b/lib/shodan/page.rb @@ -0,0 +1,148 @@ +# +# shodanrb - A Ruby interface to SHODAN, a computer search engine. +# +# Copyright (c) 2009 Hal Brodigan (postmodern.mod3 at gmail.com) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +require 'shodan/host' + +module Shodan + class Page < Array + + # + # Creates a new Page object with the given _hosts_. If a _block_ + # is given, it will be passed the newly created Page object. + # + def initialize(hosts=[],&block) + super(hosts) + + block.call(self) if block + end + + # + # Returns a mapped Array of the hosts within the Page using the + # given _block_. If the _block_ is not given, the page will be + # returned. + # + # page.map + # # => # + # + # page.map { |host| host.ip } + # # => [...] + # + def map(&block) + return self unless block + + mapped = [] + + each { |element| mapped << block.call(element) } + return mapped + end + + # + # Selects the hosts within the Page which match the given _block_. + # + # page.select { |host| host.headers['Server'] =~ /IIS/ } + # + def select(&block) + self.class.new(super(&block)) + end + + alias hosts_with select + + def each_ip(&block) + each do |host| + block.call(host.ip) if block + end + end + + def hosts_with_ip(ip,&block) + hosts_with do |host| + if host.ip.match(ip) + block.call(host) if block + + true + end + end + end + + def ips + Enumerator.new(self,:each_ip).to_a + end + + def each_hostname(&block) + each do |host| + block.call(host.name) if (block && host.name) + end + end + + def hosts_with_name(name,&block) + hosts_with do |host| + if (host.name && host.name.match(name)) + block.call(host) if block + + true + end + end + end + + def names + Enumerator.new(self,:each_hostname) + end + + def each_date(&block) + each do |host| + block.call(host.date) if block + end + end + + def dates + Enumerator.new(self,:each_date).to_a + end + + def each_response(&block) + each do |host| + block.call(host.response) if block + end + end + + def responses_with(pattern,&block) + hosts_with do |host| + if host.response.match(pattern) + block.call(host) if block + + true + end + end + end + + def responses(&block) + Enumerator.new(self,:each_response).to_a + end + + def each_headers(&block) + each do |host| + block.call(host.headers) if block + end + end + + def headers + Enumerator.new(self,:each_headers).to_a + end + + end +end diff --git a/lib/shodan/query.rb b/lib/shodan/query.rb new file mode 100644 index 0000000..c947fdd --- /dev/null +++ b/lib/shodan/query.rb @@ -0,0 +1,163 @@ +# +# shodanrb - A Ruby interface to SHODAN, a computer search engine. +# +# Copyright (c) 2009 Hal Brodigan (postmodern.mod3 at gmail.com) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +require 'shodan/extensions/uri' +require 'shodan/countries' +require 'shodan/has_pages' +require 'shodan/page' +require 'shodan/shodan' + +require 'net/http' +require 'nokogiri' + +module Shodan + class Query + + include HasPages + + # Search URL + SEARCH_URL = 'http://shodan.surtri.com/' + + # Results per page + RESULTS_PER_PAGE = 20 + + # Search query + attr_accessor :query + + # Countries to search within + attr_reader :countries + + # Hostnames to search for + attr_reader :hostnames + + # CIDR Network blocks to search within + attr_reader :networks + + # Ports to search for + attr_reader :ports + + def initialize(options={},&block) + @agent = Shodan.web_agent + @query = options[:query] + + @countries = [] + + if options[:countries] + @countries += options[:countries] + elsif options[:country] + @countries << option[:country] + end + + @hostnames = [] + + if options[:hostnames] + @hostnames += options[:hostnames] + elsif options[:hostname] + @hostnames << options[:hostname] + end + + @networks = [] + + if options[:networks] + @networks += options[:networks] + elsif options[:network] + @networks << options[:network] + end + + @ports = [] + + if options[:ports] + @ports += options[:ports] + elsif options[:port] + @ports << options[:port] + end + + block.call(self) if block + end + + def self.from_url(url) + url = URI(url.to_s) + + return self.new( + :query => url.query_params['q'].gsub('+',' ') + ) + end + + def results_per_page + RESULTS_PER_PAGE + end + + def expression + expr = [] + + expr << @query if @query + + expr += @countries.map { |code| "country:#{code}" } + expr += @hostnames.map { |host| "host:#{host}" } + expr += @networks.map { |net| "net:#{net}" } + expr += @ports.map { |port| "port:#{port}" } + + return expr.join(' ') + end + + def search_url + url = URI(SEARCH_URL) + + url.query_params['q'] = expression + return url + end + + def page_url(index) + url = search_url + + unless index == 1 + url.query_params['page'] = index + end + + return url + end + + def page(index) + Page.new do |new_page| + doc = @agent.get(page_url(index)) + + doc.search('#search/div.result').each do |result| + div = result.at('div') + + ip = if (a = div.at('a')) + a.inner_text + else + div.children.first.inner_text + end + + hostname = if (host_node = result.at('div/a:last')) + host_node.inner_text + end + + date = result.at('div/span').inner_text.split(' ').last + response = result.at('p').inner_text.strip + + new_page << Host.new(ip,date,response,hostname) + end + end + end + + end +end diff --git a/lib/shodan/shodan.rb b/lib/shodan/shodan.rb new file mode 100644 index 0000000..bf9358b --- /dev/null +++ b/lib/shodan/shodan.rb @@ -0,0 +1,128 @@ +# +# shodanrb - A Ruby interface to SHODAN, a computer search engine. +# +# Copyright (c) 2009 Hal Brodigan (postmodern.mod3 at gmail.com) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +require 'shodan/query' + +require 'mechanize' + +module Shodan + # Common proxy port. + COMMON_PROXY_PORT = 8080 + + # + # Returns the +Hash+ of proxy information. + # + def Shodan.proxy + @@shodan_proxy ||= {:host => nil, :port => COMMON_PROXY_PORT, :user => nil, :password => nil} + end + + # + # Creates a HTTP URI based from the given _proxy_info_ hash. The + # _proxy_info_ hash defaults to Web.proxy, if not given. + # + # _proxy_info_ may contain the following keys: + # :host:: The proxy host. + # :port:: The proxy port. Defaults to COMMON_PROXY_PORT, + # if not specified. + # :user:: The user-name to login as. + # :password:: The password to login with. + # + def Shodan.proxy_uri(proxy_info=Shodan.proxy) + if Shodan.proxy[:host] + return URI::HTTP.build( + :host => Shodan.proxy[:host], + :port => Shodan.proxy[:port], + :userinfo => "#{Shodan.proxy[:user]}:#{Shodan.proxy[:password]}", + :path => '/' + ) + end + end + + # + # Returns the supported Shodan User-Agent Aliases. + # + def Shodan.user_agent_aliases + WWW::Mechanize::AGENT_ALIASES + end + + # + # Returns the Shodan User-Agent + # + def Shodan.user_agent + @@shodan_user_agent ||= Shodan.user_agent_aliases['Windows IE 6'] + end + + # + # Sets the Shodan User-Agent to the specified _agent_. + # + def Shodan.user_agent=(agent) + @@shodan_user_agent = agent + end + + # + # Sets the Shodan User-Agent using the specified user-agent alias + # _name_. + # + def Shodan.user_agent_alias=(name) + @@shodan_user_agent = Shodan.user_agent_aliases[name.to_s] + end + + # + # Creates a new WWW::Mechanize agent with the given _options_. + # + # _options_ may contain the following keys: + # :user_agent_alias:: The User-Agent Alias to use. + # :user_agent:: The User-Agent string to use. + # :proxy:: A +Hash+ of proxy information which may + # contain the following keys: + # :host:: The proxy host. + # :port:: The proxy port. + # :user:: The user-name to login as. + # :password:: The password to login with. + # + # Shodan.web_agent + # + # Shodan.web_agent(:user_agent_alias => 'Linux Mozilla') + # Shodan.web_agent(:user_agent => 'Google Bot') + # + def Shodan.web_agent(options={},&block) + agent = WWW::Mechanize.new + + if options[:user_agent_alias] + agent.user_agent_alias = options[:user_agent_alias] + elsif options[:user_agent] + agent.user_agent = options[:user_agent] + elsif Shodan.user_agent + agent.user_agent = Shodan.user_agent + end + + proxy = (options[:proxy] || Shodan.proxy) + if proxy[:host] + agent.set_proxy(proxy[:host],proxy[:port],proxy[:user],proxy[:password]) + end + + block.call(agent) if block + return agent + end + + def Shodan.query(options={},&block) + Query.new(options,&block) + end +end diff --git a/lib/shodan/version.rb b/lib/shodan/version.rb new file mode 100644 index 0000000..ce583b2 --- /dev/null +++ b/lib/shodan/version.rb @@ -0,0 +1,24 @@ +# +# shodanrb - A Ruby interface to SHODAN, a computer search engine. +# +# Copyright (c) 2009 Hal Brodigan (postmodern.mod3 at gmail.com) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +module Shodan + # shodanrb version + VERSION = '0.1.0' +end diff --git a/spec/has_pages_examples.rb b/spec/has_pages_examples.rb new file mode 100644 index 0000000..00fc234 --- /dev/null +++ b/spec/has_pages_examples.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +shared_examples_for "has Pages" do + it "should have a first page" do + @query.first_page.should_not be_nil + end + + it "should allow indexed access" do + @query[1].should_not be_nil + end + + it "should allow accessing multiple pages" do + pages = @query.pages(1..2) + pages.should_not be_nil + pages.length.should == 2 + end +end diff --git a/spec/query_spec.rb b/spec/query_spec.rb new file mode 100644 index 0000000..2fb2ebd --- /dev/null +++ b/spec/query_spec.rb @@ -0,0 +1,93 @@ +require 'shodan/query' + +require 'spec_helper' +require 'has_pages_examples' + +describe Query do + before(:all) do + @query = Query.new(:query => 'ssh') + @page = @query.first_page + end + + it_should_behave_like "has Pages" + + describe "query expression" do + it "should support basic queries" do + q = Query.new(:query => 'ssh') + + q.expression.should == 'ssh' + end + + it "should support the country search operator" do + q = Query.new( + :query => 'ssh', :countries => [ + Countries::Mexico, + Countries::Nicaragua + ] + ) + + q.expression.should == 'ssh country:MX country:NI' + end + + it "should support host search operator" do + q = Query.new( + :query => 'http', + :hostnames => ['www.wired.com'] + ) + + q.expression.should == 'http host:www.wired.com' + end + + it "should support the net search operator" do + q = Query.new( + :query => 'ssh', + :networks => ['112.0.0.0/8'] + ) + + q.expression.should == 'ssh net:112.0.0.0/8' + end + + it "should support the port search operator" do + q = Query.new( + :query => 'login', + :ports => [21, 23] + ) + + q.expression.should == 'login port:21 port:23' + end + end + + describe "search URL" do + before(:all) do + @uri = @query.search_url + end + + it "should be a valid HTTP URI" do + @uri.class.should == URI::HTTP + end + + it "should have a 'q' query-param" do + @uri.query_params['q'].should == @query.query + end + end + + describe "page specific URLs" do + before(:all) do + @uri = @query.page_url(2) + end + + it "should have a 'page' query-param" do + @uri.query_params['page'].should == 2 + end + end + + describe "queries from search URLs" do + before(:all) do + @query = Query.from_url("http://shodan.surtri.com/?q=login+port%3A21+port%3A23") + end + + it "should have a query" do + @query.query.should == 'login port:21 port:23' + end + end +end diff --git a/spec/shodan_spec.rb b/spec/shodan_spec.rb new file mode 100644 index 0000000..783f64b --- /dev/null +++ b/spec/shodan_spec.rb @@ -0,0 +1,33 @@ +require 'shodan/shodan' + +require 'spec_helper' + +describe "Shodan" do + it "should have a VERSION constant" do + Shodan.constant_defined?('VERSION').should == true + end + + describe "User-Agent support" do + it "should have a default User-Agent string" do + Shodan.user_agent.should_not be_nil + end + end + + describe "Proxy support" do + it "should provide a :host key" do + Shodan.proxy.has_key?(:host).should == true + end + + it "should provide a :port key" do + Shodan.proxy.has_key?(:port).should == true + end + + it "should provide a :user key" do + Shodan.proxy.has_key?(:user).should == true + end + + it "should provide a :password key" do + Shodan.proxy.has_key?(:password).should == true + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..8fadc61 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,7 @@ +require 'rubygems' +gem 'rspec', '>=1.2.8' +require 'spec' + +require 'shodan/version' + +include Shodan diff --git a/tasks/spec.rb b/tasks/spec.rb new file mode 100644 index 0000000..41d6645 --- /dev/null +++ b/tasks/spec.rb @@ -0,0 +1,10 @@ +require 'spec/rake/spectask' + +desc "Run all specifications" +Spec::Rake::SpecTask.new(:spec) do |t| + t.libs += ['lib', 'spec'] + t.spec_opts = ['--colour', '--format', 'specdoc'] +end + +task :test => :spec +task :default => :spec