watobo 0.9.8.677

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. data/bin/watobo_gui.rb +39 -0
  2. data/certificates/cert.pem +19 -0
  3. data/certificates/privkey.pem +15 -0
  4. data/certificates/watobo_dh.key +5 -0
  5. data/config/datastore.yml +5 -0
  6. data/config/forwarding_proxy.yml +12 -0
  7. data/config/general.yml +4 -0
  8. data/config/gui.yml +23 -0
  9. data/config/interceptor.yml +16 -0
  10. data/config/scan_policy.yml +13 -0
  11. data/config/scanner.yml +34 -0
  12. data/icons/Add.ico +0 -0
  13. data/icons/Add_24x24.ico +0 -0
  14. data/icons/Bandwidth.ico +0 -0
  15. data/icons/Bandwidth_24x24.ico +0 -0
  16. data/icons/Mr. Bomb.ico +0 -0
  17. data/icons/Mr. Bomb_16x16.ico +0 -0
  18. data/icons/Mr. Bomb_24x24.ico +0 -0
  19. data/icons/Orange Ball.ico +0 -0
  20. data/icons/Orange Ball_16x16.ico +0 -0
  21. data/icons/Orange Ball_24x24.ico +0 -0
  22. data/icons/Pause.ico +0 -0
  23. data/icons/Play.ico +0 -0
  24. data/icons/Play_24x24.ico +0 -0
  25. data/icons/Red Ball.ico +0 -0
  26. data/icons/Red Ball_16x16.ico +0 -0
  27. data/icons/Red Ball_24x24.ico +0 -0
  28. data/icons/Run.ico +0 -0
  29. data/icons/Stop.ico +0 -0
  30. data/icons/Stop_24x24.ico +0 -0
  31. data/icons/Terminal.ico +0 -0
  32. data/icons/Transfer.ico +0 -0
  33. data/icons/Transfer_16x16.ico +0 -0
  34. data/icons/User.ico +0 -0
  35. data/icons/User_16x16.ico +0 -0
  36. data/icons/User_24x24.ico +0 -0
  37. data/icons/Web Browser.ico +0 -0
  38. data/icons/Web Browser_16x16.ico +0 -0
  39. data/icons/Write Document.ico +0 -0
  40. data/icons/Yellow Ball.ico +0 -0
  41. data/icons/Yellow Ball_16x16.ico +0 -0
  42. data/icons/Yellow Ball_24x24.ico +0 -0
  43. data/icons/advanced.ico +0 -0
  44. data/icons/advanced_16x16.ico +0 -0
  45. data/icons/advanced_24x24.ico +0 -0
  46. data/icons/applications.ico +0 -0
  47. data/icons/applications_16x16.ico +0 -0
  48. data/icons/applications_24x24.ico +0 -0
  49. data/icons/browser_16x16.ico +0 -0
  50. data/icons/browser_24x24.ico +0 -0
  51. data/icons/burn.ico +0 -0
  52. data/icons/burn_16x16.ico +0 -0
  53. data/icons/burn_24x24.ico +0 -0
  54. data/icons/calculator.ico +0 -0
  55. data/icons/calculator_24x24.ico +0 -0
  56. data/icons/cb_checked.ico +0 -0
  57. data/icons/cb_checked_orange.ico +0 -0
  58. data/icons/cb_unchecked.ico +0 -0
  59. data/icons/coin_24x24.ico +0 -0
  60. data/icons/conversation.ico +0 -0
  61. data/icons/conversation_24x24.ico +0 -0
  62. data/icons/engine.ico +0 -0
  63. data/icons/filter.ico +0 -0
  64. data/icons/folder.ico +0 -0
  65. data/icons/folder_16x16.ico +0 -0
  66. data/icons/fuzzer_16x16.ico +0 -0
  67. data/icons/fuzzer_24x24.ico +0 -0
  68. data/icons/go-down_16x16.png +0 -0
  69. data/icons/go-up_16x16.png +0 -0
  70. data/icons/help.ico +0 -0
  71. data/icons/help_16x16.ico +0 -0
  72. data/icons/help_24x24.ico +0 -0
  73. data/icons/iChat.ico +0 -0
  74. data/icons/iChat_16x16.ico +0 -0
  75. data/icons/iChat_24x24.ico +0 -0
  76. data/icons/icons.txt +3 -0
  77. data/icons/info.ico +0 -0
  78. data/icons/info_16x16.ico +0 -0
  79. data/icons/info_24x24.ico +0 -0
  80. data/icons/interceptor_24x24.ico +0 -0
  81. data/icons/lock.ico +0 -0
  82. data/icons/lock_12x12.ico +0 -0
  83. data/icons/lock_16x16.ico +0 -0
  84. data/icons/monitor.ico +0 -0
  85. data/icons/plugin.ico +0 -0
  86. data/icons/plugin_24x24.ico +0 -0
  87. data/icons/scan_16x16.png +0 -0
  88. data/icons/send.ico +0 -0
  89. data/icons/server.ico +0 -0
  90. data/icons/server_16x16.ico +0 -0
  91. data/icons/siberas_logo_x24.gif +0 -0
  92. data/icons/tag_blue_32x32.ico +0 -0
  93. data/icons/watobo-48x48.png +0 -0
  94. data/icons/watobo-logo.png +0 -0
  95. data/icons/watobo.ico +0 -0
  96. data/lib/watobo/adapters/data_store.rb +38 -0
  97. data/lib/watobo/adapters/file/file_store.rb +211 -0
  98. data/lib/watobo/adapters/session_store.rb +27 -0
  99. data/lib/watobo/adapters.rb +26 -0
  100. data/lib/watobo/config.rb +143 -0
  101. data/lib/watobo/constants.rb +92 -0
  102. data/lib/watobo/core/active_check.rb +404 -0
  103. data/lib/watobo/core/cookie.rb +69 -0
  104. data/lib/watobo/core/fuzz_gen.rb +160 -0
  105. data/lib/watobo/core/http_socket.rb +142 -0
  106. data/lib/watobo/core/interceptor.rb +729 -0
  107. data/lib/watobo/core/passive_check.rb +141 -0
  108. data/lib/watobo/core/project.rb +1058 -0
  109. data/lib/watobo/core/scanner.rb +396 -0
  110. data/lib/watobo/core/session.rb +1320 -0
  111. data/lib/watobo/core/simple_ca.rb +393 -0
  112. data/lib/watobo/core.rb +34 -0
  113. data/lib/watobo/defaults.rb +40 -0
  114. data/lib/watobo/external/diff/lcs/array.rb +42 -0
  115. data/lib/watobo/external/diff/lcs/block.rb +72 -0
  116. data/lib/watobo/external/diff/lcs/callbacks.rb +343 -0
  117. data/lib/watobo/external/diff/lcs/change.rb +190 -0
  118. data/lib/watobo/external/diff/lcs/hunk.rb +279 -0
  119. data/lib/watobo/external/diff/lcs/ldiff.rb +247 -0
  120. data/lib/watobo/external/diff/lcs/string.rb +40 -0
  121. data/lib/watobo/external/diff/lcs.rb +1124 -0
  122. data/lib/watobo/external/ntlm/ntlm.rb +797 -0
  123. data/lib/watobo/externals.rb +28 -0
  124. data/lib/watobo/framework/create_project.rb +55 -0
  125. data/lib/watobo/framework/init.rb +149 -0
  126. data/lib/watobo/framework/init_modules.rb +116 -0
  127. data/lib/watobo/framework/license_text.rb +50 -0
  128. data/lib/watobo/framework.rb +26 -0
  129. data/lib/watobo/gui/about_watobo.rb +68 -0
  130. data/lib/watobo/gui/browser_preview.rb +460 -0
  131. data/lib/watobo/gui/certificate_dialog.rb +132 -0
  132. data/lib/watobo/gui/chat_diff.rb +415 -0
  133. data/lib/watobo/gui/chatviewer_frame.rb +427 -0
  134. data/lib/watobo/gui/checkboxtree.rb +221 -0
  135. data/lib/watobo/gui/checks_policy_frame.rb +123 -0
  136. data/lib/watobo/gui/client_cert_dialog.rb +227 -0
  137. data/lib/watobo/gui/confirm_scan_dialog.rb +67 -0
  138. data/lib/watobo/gui/conversation_table.rb +386 -0
  139. data/lib/watobo/gui/conversation_table_ctrl.rb +175 -0
  140. data/lib/watobo/gui/csrf_token_dialog.rb +446 -0
  141. data/lib/watobo/gui/dashboard.rb +341 -0
  142. data/lib/watobo/gui/define_scope_frame.rb +380 -0
  143. data/lib/watobo/gui/edit_comment.rb +70 -0
  144. data/lib/watobo/gui/edit_scope_dialog.rb +69 -0
  145. data/lib/watobo/gui/finding_info.rb +212 -0
  146. data/lib/watobo/gui/findings_tree.rb +459 -0
  147. data/lib/watobo/gui/full_scan_dialog.rb +269 -0
  148. data/lib/watobo/gui/fuzzer_gui.rb +1522 -0
  149. data/lib/watobo/gui/hex_viewer.rb +106 -0
  150. data/lib/watobo/gui/interceptor_gui.rb +994 -0
  151. data/lib/watobo/gui/interceptor_settings_dialog.rb +201 -0
  152. data/lib/watobo/gui/log_viewer.rb +97 -0
  153. data/lib/watobo/gui/login_wizzard.rb +301 -0
  154. data/lib/watobo/gui/main_window.rb +1815 -0
  155. data/lib/watobo/gui/manual_request_editor.rb +1105 -0
  156. data/lib/watobo/gui/master_pw_dialog.rb +142 -0
  157. data/lib/watobo/gui/password_policy_dialog.rb +98 -0
  158. data/lib/watobo/gui/plugin/base.rb +82 -0
  159. data/lib/watobo/gui/plugin_board.rb +95 -0
  160. data/lib/watobo/gui/preferences_dialog.rb +116 -0
  161. data/lib/watobo/gui/progress_window.rb +102 -0
  162. data/lib/watobo/gui/project_wizzard.rb +369 -0
  163. data/lib/watobo/gui/proxy_dialog.rb +550 -0
  164. data/lib/watobo/gui/quick_scan_dialog.rb +242 -0
  165. data/lib/watobo/gui/request_editor.rb +480 -0
  166. data/lib/watobo/gui/save_chat_dialog.rb +158 -0
  167. data/lib/watobo/gui/scanner_settings_dialog.rb +360 -0
  168. data/lib/watobo/gui/select_chat_dialog.rb +169 -0
  169. data/lib/watobo/gui/session_management_dialog.rb +688 -0
  170. data/lib/watobo/gui/sites_tree.rb +347 -0
  171. data/lib/watobo/gui/status_bar.rb +88 -0
  172. data/lib/watobo/gui/table_editor.rb +445 -0
  173. data/lib/watobo/gui/tagless_viewer.rb +62 -0
  174. data/lib/watobo/gui/templates/plugin.rb +80 -0
  175. data/lib/watobo/gui/templates/plugin2.rb +103 -0
  176. data/lib/watobo/gui/text_viewer.rb +247 -0
  177. data/lib/watobo/gui/transcoder_window.rb +215 -0
  178. data/lib/watobo/gui/utils/gui_utils.rb +129 -0
  179. data/lib/watobo/gui/utils/init_icons.rb +106 -0
  180. data/lib/watobo/gui/utils/load_icons.rb +54 -0
  181. data/lib/watobo/gui/utils/load_plugins.rb +94 -0
  182. data/lib/watobo/gui/utils/master_password.rb +90 -0
  183. data/lib/watobo/gui/utils/save_default_settings.rb +99 -0
  184. data/lib/watobo/gui/utils/save_project_settings.rb +21 -0
  185. data/lib/watobo/gui/utils/save_proxy_settings.rb +45 -0
  186. data/lib/watobo/gui/utils/save_session_settings.rb +21 -0
  187. data/lib/watobo/gui/utils/session_history.rb +134 -0
  188. data/lib/watobo/gui/workspace_dialog.rb +89 -0
  189. data/lib/watobo/gui/www_auth_dialog.rb +348 -0
  190. data/lib/watobo/gui/xml_viewer_frame.rb +114 -0
  191. data/lib/watobo/gui.rb +139 -0
  192. data/lib/watobo/mixins/httpparser.rb +664 -0
  193. data/lib/watobo/mixins/request_parser.rb +210 -0
  194. data/lib/watobo/mixins/shapers.rb +345 -0
  195. data/lib/watobo/mixins/transcoders.rb +88 -0
  196. data/lib/watobo/mixins.rb +32 -0
  197. data/lib/watobo/utils/check_regex.rb +36 -0
  198. data/lib/watobo/utils/copy_object.rb +29 -0
  199. data/lib/watobo/utils/crypto.rb +74 -0
  200. data/lib/watobo/utils/expand_range.rb +45 -0
  201. data/lib/watobo/utils/file_management.rb +73 -0
  202. data/lib/watobo/utils/load_chat.rb +219 -0
  203. data/lib/watobo/utils/load_icon.rb +47 -0
  204. data/lib/watobo/utils/print_debug.rb +34 -0
  205. data/lib/watobo/utils/response_hash.rb +143 -0
  206. data/lib/watobo/utils/secure_eval.rb +57 -0
  207. data/lib/watobo/utils/text2request.rb +96 -0
  208. data/lib/watobo/utils.rb +32 -0
  209. data/lib/watobo.rb +76 -0
  210. data/modules/active/Apache/mod_status.rb +123 -0
  211. data/modules/active/Flash/crossdomain.rb +102 -0
  212. data/modules/active/directories/dirwalker.rb +89 -0
  213. data/modules/active/discovery/fileextensions.rb +151 -0
  214. data/modules/active/discovery/http_methods.rb +135 -0
  215. data/modules/active/domino/domino_db.lst +164 -0
  216. data/modules/active/domino/domino_db.rb +128 -0
  217. data/modules/active/fileinclusion/lfi_simple.rb +134 -0
  218. data/modules/active/jboss/jboss_basic.rb +119 -0
  219. data/modules/active/sap/business_objects.rb +73 -0
  220. data/modules/active/sap/its_commands.rb +101 -0
  221. data/modules/active/sap/its_service_parameter.rb +105 -0
  222. data/modules/active/sap/its_services.rb +103 -0
  223. data/modules/active/sap/its_xss.rb +98 -0
  224. data/modules/active/sqlinjection/sql_boolean.rb +262 -0
  225. data/modules/active/sqlinjection/sqli_simple.rb +205 -0
  226. data/modules/active/xss/xss_simple.rb +179 -0
  227. data/modules/passive/cookie_options.rb +97 -0
  228. data/modules/passive/cookie_xss.rb +85 -0
  229. data/modules/passive/detect_code.rb +89 -0
  230. data/modules/passive/detect_fileupload.rb +80 -0
  231. data/modules/passive/detect_infrastructure.rb +98 -0
  232. data/modules/passive/detect_one_time_tokens.rb +86 -0
  233. data/modules/passive/dirindexing.rb +81 -0
  234. data/modules/passive/disclosure_emails.rb +82 -0
  235. data/modules/passive/disclosure_ipaddr.rb +87 -0
  236. data/modules/passive/filename_as_parameter.rb +85 -0
  237. data/modules/passive/form_spotter.rb +75 -0
  238. data/modules/passive/hotspots.rb +86 -0
  239. data/modules/passive/in_script_parameter.rb +92 -0
  240. data/modules/passive/multiple_server_headers.rb +98 -0
  241. data/modules/passive/possible_login.rb +134 -0
  242. data/modules/passive/redirect_url.rb +88 -0
  243. data/modules/passive/redirectionz.rb +96 -0
  244. data/modules/passive/xss_dom.rb +91 -0
  245. data/plugins/catalog/catalog.ico +0 -0
  246. data/plugins/catalog/catalog.rb +726 -0
  247. data/plugins/catalog/db_tests +6483 -0
  248. data/plugins/catalog/db_variables +29 -0
  249. data/plugins/filefinder/dbs/hbci.db +12 -0
  250. data/plugins/filefinder/filefinder.rb +602 -0
  251. data/plugins/sslchecker/cli/sslchecker_cli.rb +21 -0
  252. data/plugins/sslchecker/gui/cipher_table.rb +260 -0
  253. data/plugins/sslchecker/gui/gui.rb +245 -0
  254. data/plugins/sslchecker/gui/sslchecker.rb +26 -0
  255. data/plugins/sslchecker/icons/green_16x16.ico +0 -0
  256. data/plugins/sslchecker/icons/grey_16x16.ico +0 -0
  257. data/plugins/sslchecker/icons/red_16x16.ico +0 -0
  258. data/plugins/sslchecker/icons/sslchecker.ico +0 -0
  259. data/plugins/sslchecker/lib/check.rb +117 -0
  260. metadata +317 -0
@@ -0,0 +1,994 @@
1
+ # .
2
+ # interceptor_gui.rb
3
+ #
4
+ # Copyright 2012 by siberas, http://www.siberas.de
5
+ #
6
+ # This file is part of WATOBO (Web Application Tool Box)
7
+ # http://watobo.sourceforge.com
8
+ #
9
+ # WATOBO is free software; you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation version 2 of the License.
12
+ #
13
+ # WATOBO is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with WATOBO; if not, write to the Free Software
20
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
+ # .
22
+ module Watobo
23
+ module Gui
24
+ class InterceptEditor < FXVerticalFrame
25
+
26
+ include Watobo::Constants
27
+ include Watobo::Gui::Utils
28
+
29
+ def initialize(owner, opts)
30
+
31
+ super(owner, opts)
32
+
33
+ @lock = Mutex.new
34
+ @text = nil
35
+
36
+ @event_dispatcher_listeners = Hash.new
37
+
38
+ text_view_header = FXHorizontalFrame.new(self, :opts => LAYOUT_FILL_X|LAYOUT_SIDE_BOTTOM|LAYOUT_FIX_HEIGHT, :height => 24, :padding => 0)
39
+
40
+ #@auto_apply_cbtn.connect(SEL_COMMAND, method(:onInterceptChanged))
41
+
42
+ @pmatch_btn = FXButton.new(text_view_header, "<", nil, nil, 0, FRAME_RAISED|LAYOUT_FILL_Y)
43
+ @pmatch_btn.disable
44
+
45
+ @pmatch_btn.connect(SEL_COMMAND) {
46
+ if @textbox.numMatches > 0
47
+ @match_pos_label.textColor = 'black'
48
+ pos = @textbox.showPrevMatch() + 1
49
+ @match_pos_label.text = "#{pos}/#{@textbox.numMatches}"
50
+ else
51
+ @match_pos_label.textColor = 'grey'
52
+ end
53
+ }
54
+
55
+ @match_pos_label = FXLabel.new(text_view_header, "0/0", :opts => LAYOUT_FILL_Y)
56
+ @match_pos_label.textColor = 'grey'
57
+
58
+ @nmatch_btn = FXButton.new(text_view_header, ">", nil, nil, 0, FRAME_RAISED|LAYOUT_FILL_Y)
59
+ @nmatch_btn.disable
60
+
61
+ @nmatch_btn.connect(SEL_COMMAND) {
62
+
63
+ @textbox.showNextMatch()
64
+ if @textbox.numMatches > 0
65
+ @match_pos_label.textColor = 'black'
66
+ pos = @textbox.showNextMatch() + 1
67
+ @match_pos_label.text = "#{pos}/#{@textbox.numMatches}"
68
+ else
69
+ @match_pos_label.textColor = 'grey'
70
+ end
71
+ }
72
+
73
+ @filter_dt = FXDataTarget.new('')
74
+ # @filter_text = FXTextField.new(text_view_header, 10,
75
+ # :target => @filter_dt, :selector => FXDataTarget::ID_VALUE,
76
+ # :opts => FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y)
77
+
78
+ @filter_text = FXComboBox.new(text_view_header, 20, @filter_dt, 0, FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_TOP|LAYOUT_FILL_X)
79
+ @filter_text.connect(SEL_COMMAND){
80
+ applyFilter()
81
+ addFilterHistory()
82
+ }
83
+
84
+ @filter_text.connect(SEL_CHANGED) {
85
+ applyFilter()
86
+ }
87
+ inputFieldHotkeyHandler(@filter_text)
88
+
89
+ @auto_select_cbtn = FXCheckButton.new(text_view_header, "auto-select", nil, 0, ICON_BEFORE_TEXT|LAYOUT_SIDE_TOP|LAYOUT_RIGHT|LAYOUT_FILL_Y)
90
+ #@mode_btn = FXButton.new(text_view_header, "Highlight", :opts=> MENUBUTTON_DOWN|FRAME_RAISED|FRAME_THICK|ICON_AFTER_TEXT|LAYOUT_RIGHT|LAYOUT_FILL_Y)
91
+
92
+ reset_button = FXButton.new(text_view_header, "&Reset", nil, nil, 0, FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_Y)
93
+ reset_button.connect(SEL_COMMAND){ resetTextbox() }
94
+
95
+ #-----------------------
96
+ text_frame = FXVerticalFrame.new(self, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_SUNKEN|FRAME_THICK, :padding=>0)
97
+
98
+ @textbox_dt = FXDataTarget.new('')
99
+
100
+ @textbox = Watobo::Gui::TextView2.new(text_frame, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y)
101
+ # @textbox = Watobo::Gui::TextView2.new(text_frame, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y)
102
+ # @textbox = FXText.new(text_frame, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y)
103
+ # @textbox = FXText.new(text_frame, :target => @textbox_dt, :selector => FXDataTarget::ID_VALUE, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y)
104
+ @textbox.textStyle -= TEXT_WORDWRAP
105
+ @textbox.extend Watobo::Mixins::RequestParser
106
+
107
+ @textbox.editable = true
108
+
109
+ @markers = []
110
+
111
+ @record_input = false # EXPERIMENTAL !!!
112
+
113
+ @last_cursor_pos = 0
114
+ @start_selection_pos = 0
115
+
116
+ @input_start = 0
117
+ @input_len = 0
118
+
119
+ @textbox.connect(SEL_RIGHTBUTTONRELEASE) do |sender, sel, event|
120
+ unless event.moved?
121
+ FXMenuPane.new(self) do |menu_pane|
122
+ addStringInfo(menu_pane, sender)
123
+ addDecoder(menu_pane, sender)
124
+ addEncoder(menu_pane, sender)
125
+ FXMenuSeparator.new(menu_pane)
126
+ target = FXMenuCheck.new(menu_pane, "word wrap" )
127
+ target.check = ( @textbox.textStyle & TEXT_WORDWRAP > 0 ) ? true : false
128
+ target.connect(SEL_COMMAND) { |tsender, tsel, titem|
129
+ if tsender.checked?
130
+ @textbox.textStyle |= TEXT_WORDWRAP
131
+ else
132
+ @textbox.textStyle ^= TEXT_WORDWRAP
133
+ end
134
+ }
135
+
136
+ menu_pane.create
137
+ menu_pane.popup(nil, event.root_x, event.root_y)
138
+ app.runModalWhileShown(menu_pane)
139
+ end
140
+
141
+ end
142
+ end
143
+
144
+ # KEY_Return
145
+ # KEY_Control_L
146
+ # KEY_Control_R
147
+ # KEY_s
148
+ @ctrl_pressed = false
149
+
150
+ @textbox.connect(SEL_KEYPRESS, method(:initEditKeys))
151
+
152
+ @textbox.connect(SEL_KEYRELEASE) do |sender, sel, event|
153
+ @ctrl_pressed = false if event.code == KEY_Control_L or event.code == KEY_Control_R
154
+ false
155
+ end
156
+
157
+ end
158
+
159
+ def subscribe(event, &callback)
160
+ (@event_dispatcher_listeners[event] ||= []) << callback
161
+ end
162
+
163
+ def clearEvents(event)
164
+ @event_dispatcher_listener[event].clear
165
+ end
166
+
167
+ def empty?
168
+ @textbox.to_s.empty?
169
+ end
170
+
171
+ def clear
172
+ @textbox.setText('')
173
+ end
174
+
175
+ def setText(text=nil)
176
+ return false if text.nil?
177
+ if text.is_a? Array
178
+ new_text = text.join
179
+ else
180
+ new_text = "#{text}"
181
+ end
182
+
183
+ @lock.synchronize do
184
+ @text = new_text.strip.gsub(/\r/,'')
185
+
186
+ unless @text.empty?
187
+ @textbox.setText @text
188
+ end
189
+ end
190
+ # @textbox.handle(self, FXSEL(SEL_UPDATE, 0), nil)
191
+ #@textbox.update
192
+
193
+ end
194
+
195
+ def parseRequest(prefs={})
196
+ begin
197
+ return @textbox.to_request(prefs)
198
+ rescue SyntaxError, LocalJumpError, NameError
199
+ notify(:error, "#{$!}")
200
+ rescue => bang
201
+ puts bang
202
+ notify(:error, "Could not parse request: #{$!}")
203
+ end
204
+
205
+ return nil
206
+ end
207
+
208
+ private
209
+
210
+ def recordedText
211
+ @textbox.extractText(@input_start, @input_len)
212
+ end
213
+
214
+ def applyFilter
215
+ pattern = @filter_text.text
216
+ @textbox.reset_text
217
+ @match_pos_label.textColor = 'grey'
218
+ @match_pos_label.text = "0/0"
219
+ return true if pattern == ''
220
+
221
+ @textbox.applyFilter(pattern)
222
+ if @textbox.numMatches > 0
223
+
224
+ @match_pos_label.text = "1/#{@textbox.numMatches}"
225
+ #@match_pos_label.enable
226
+ @match_pos_label.textColor = 'black'
227
+ @textbox.showMatch(0, :select_match => @auto_select_cbtn.checked? )
228
+ @nmatch_btn.enable
229
+ @pmatch_btn.enable
230
+ else
231
+ @nmatch_btn.disable
232
+ @pmatch_btn.disable
233
+ end
234
+ # puts "got #{matches.length} matches for pattern #{Regexp.quote(pattern)}"
235
+ end
236
+
237
+ def inputFieldHotkeyHandler(widget)
238
+ @ctrl_pressed = false
239
+
240
+ widget.connect(SEL_KEYPRESS) { |sender, sel, event|
241
+ # puts event.code
242
+ @ctrl_pressed = true if event.code == KEY_Control_L or event.code == KEY_Control_R
243
+ # @shift_pressed = true if @ctrl_pressed and ( event.code == KEY_Shift_L or event.code == KEY_Shift_R )
244
+ if event.code == KEY_Return
245
+ applyFilter()
246
+ @textbox.setFocus()
247
+ @textbox.setDefault()
248
+ @textbox.showMatch(0, :select_match => @auto_select_cbtn.checked? )
249
+ true # special handling of KEY_Return, because we don't want a linebreak in textbox.
250
+ end
251
+
252
+ if @ctrl_pressed
253
+ case event.code
254
+ when KEY_w
255
+ @textbox.textStyle ^= TEXT_WORDWRAP
256
+ when KEY_n
257
+ @textbox.showNextMatch()
258
+ addFilterHistory()
259
+ when KEY_N
260
+ @textbox.showPrevMatch()
261
+ addFilterHistory()
262
+ when KEY_r
263
+ @textbox.reset_filter()
264
+ end
265
+ end
266
+
267
+ if event.code == KEY_F1
268
+
269
+ unless event.moved?
270
+ FXMenuPane.new(self) do |menu_pane|
271
+ FXMenuCaption.new(menu_pane, "Hotkeys:")
272
+ FXMenuSeparator.new(menu_pane)
273
+ [ "<ctrl-r> - Reset Filter",
274
+ "<ctrl-n> - Goto Next",
275
+ "<ctrl-shift-n> - Goto Prev",
276
+ "<ctrl-w> - Switch Wordwrap"
277
+ ].each do |hk|
278
+ FXMenuCaption.new(menu_pane, hk).backColor = 'yellow'
279
+ end
280
+
281
+ menu_pane.create
282
+
283
+ menu_pane.popup(nil, event.root_x, event.root_y)
284
+ app.runModalWhileShown(menu_pane)
285
+ end
286
+
287
+ end
288
+ true
289
+ else
290
+ false
291
+ end
292
+ }
293
+
294
+ widget.connect(SEL_KEYRELEASE) { |sender, sel, event|
295
+ @ctrl_pressed = false if event.code == KEY_Control_L or event.code == KEY_Control_R
296
+ false
297
+ }
298
+ end
299
+
300
+ def initEditKeys(sender, sel, event)
301
+ # @shift_pressed = true if @ctrl_pressed and ( event.code == KEY_Shift_L or event.code == KEY_Shift_R )
302
+ if event.code == KEY_F1
303
+
304
+ unless event.moved?
305
+ FXMenuPane.new(self) do |menu_pane|
306
+ FXMenuCaption.new(menu_pane, "Hotkeys:")
307
+ FXMenuSeparator.new(menu_pane)
308
+ [ "<ctrl-r> - Reset Filter",
309
+ "<ctrl-n> - Goto Next",
310
+ "<ctrl-shift-n> - Goto Prev",
311
+ "<ctrl-w> - Switch Wordwrap",
312
+ "<ctrl-b> - Encode Base64",
313
+ "<ctrl-shift-b> - Decode Base64",
314
+ "<ctrl-u> - Encode URL",
315
+ "<ctrl-shift-u> - Decode URL",
316
+ ].each do |hk|
317
+ FXMenuCaption.new(menu_pane, hk).backColor = 'yellow'
318
+ end
319
+
320
+ menu_pane.create
321
+
322
+ menu_pane.popup(nil, event.root_x, event.root_y)
323
+ app.runModalWhileShown(menu_pane)
324
+ end
325
+
326
+ end
327
+ end
328
+
329
+ if @ctrl_pressed
330
+ return true if event.code == KEY_Control_L or event.code == KEY_Control_R
331
+ if event.code == KEY_Return
332
+ notify(:hotkey_ctrl_enter)
333
+ true # special handling of KEY_Return, because we don't want a linebreak in textbox.
334
+ else
335
+
336
+ case event.code
337
+ when KEY_w
338
+ @textbox.textStyle ^= TEXT_WORDWRAP
339
+ when KEY_n
340
+ @textbox.showNextMatch()
341
+ addFilterHistory()
342
+ when KEY_N
343
+ @textbox.showPrevMatch()
344
+ addFilterHistory()
345
+ when KEY_r
346
+ resetTextbox()
347
+ end
348
+
349
+ pos = @textbox.selStartPos
350
+ len = @textbox.selEndPos - pos
351
+
352
+ if len == 0 then
353
+ pos = @input_start
354
+ len = @input_len
355
+ end
356
+
357
+ unless len==0
358
+ text = @textbox.extractText(pos,len)
359
+ rptxt = case event.code
360
+ when KEY_u
361
+ CGI::escape(text).strip
362
+ when KEY_b
363
+ Base64.encode64(text).strip
364
+ when KEY_U
365
+ CGI::unescape(text).strip
366
+ when KEY_B
367
+ Base64.decode64(text).strip
368
+ else
369
+ text
370
+ end
371
+ @textbox.replaceText(pos, len, rptxt,false)
372
+ @textbox.setSelection(pos,rptxt.length)
373
+ end
374
+ false
375
+ end
376
+ else
377
+ @ctrl_pressed = true if event.code == KEY_Control_L or event.code == KEY_Control_R
378
+ false
379
+ end
380
+ end
381
+
382
+ def addFilterHistory()
383
+ text = @filter_text.text
384
+ return true if text == ''
385
+ has_item = false
386
+ @filter_text.each do |item, data|
387
+ has_item = true if data == text
388
+ end
389
+ @filter_text.appendItem(text, text) unless has_item == true
390
+ @filter_text.numVisible = @filter_text.numItems
391
+ end
392
+
393
+ def resetTextbox()
394
+ @textbox.setPrintable(@text)
395
+ @textbox.reset_filter
396
+ @match_pos_label.text = "0/0"
397
+ @match_pos_label.textColor = 'grey'
398
+ end
399
+
400
+ def notify(event, *args)
401
+ if @event_dispatcher_listeners[event]
402
+ @event_dispatcher_listeners[event].each do |m|
403
+ m.call(*args) if m.respond_to? :call
404
+ end
405
+ end
406
+ end
407
+
408
+ end
409
+
410
+ class InterceptorUI < FXTopWindow
411
+
412
+ include Responder
413
+ include Watobo
414
+ include Watobo::Gui::Icons
415
+ def execute
416
+ create
417
+ show(PLACEMENT_SCREEN)
418
+ # getApp().runModalFor(self)
419
+ end
420
+
421
+ # this method is obsolet! Use addRequest() instead
422
+ def modifyRequest(request, thread)
423
+ addRequest(request, thread)
424
+ end
425
+
426
+ # this method is obsolet! Use addResponse() instead
427
+ def modifyResponse(request, thread)
428
+ addResponse(request, thread)
429
+ end
430
+
431
+ def addRequest(request, thread)
432
+ puts "* [Interceptor] addRequest"
433
+
434
+ new_request = {
435
+ :request => request,
436
+ :thread => thread
437
+ }
438
+
439
+ @request_lock.synchronize do
440
+ # enable_buttons()
441
+ @request_queue << new_request
442
+
443
+ end
444
+
445
+ # enable_buttons()
446
+
447
+ end
448
+
449
+ def addResponse(response, thread)
450
+ response.extend Watobo::Mixin::Parser::Web10
451
+ response.extend Watobo::Mixin::Shaper::Web10
452
+
453
+ response.fixupContentLength()
454
+
455
+ # puts response
456
+
457
+ new_response = {
458
+ :response => response,
459
+ :thread => thread
460
+ }
461
+
462
+ @response_lock.synchronize do
463
+ @response_queue.push new_response
464
+
465
+ end
466
+ end
467
+
468
+ def initialize(owner, interceptor, opts)
469
+ # Invoke base class initialize function first
470
+
471
+ super( owner, 'Interceptor', nil, nil, DECOR_ALL|DECOR_TITLE|DECOR_BORDER|DECOR_RESIZE, 0, 0, 600, 400, 0, 0, 0, 0, 0, 0)
472
+ self.connect(SEL_CLOSE, method(:onClose))
473
+ self.icon = ICON_INTERCEPTOR
474
+ @interceptor = interceptor
475
+
476
+ @request_list = []
477
+ @response_list = []
478
+
479
+ @request_queue = []
480
+ @response_queue = []
481
+
482
+ @request_lock = Mutex.new
483
+ @response_lock = Mutex.new
484
+
485
+ # initial frame setup
486
+ mr_splitter = FXSplitter.new(self, LAYOUT_FILL_X|LAYOUT_FILL_Y|SPLITTER_VERTICAL|SPLITTER_REVERSED|SPLITTER_TRACKING)
487
+
488
+ top_frame = FXVerticalFrame.new(mr_splitter, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y||LAYOUT_FIX_HEIGHT|LAYOUT_BOTTOM,:height => 500)
489
+ top_splitter = FXSplitter.new(top_frame, LAYOUT_FILL_X|SPLITTER_HORIZONTAL|LAYOUT_FILL_Y|SPLITTER_TRACKING)
490
+
491
+ #log_frame = FXVerticalFrame.new(mr_splitter, :opts => LAYOUT_FILL_X|LAYOUT_SIDE_BOTTOM,:height => 100)
492
+
493
+ filter_frame = FXVerticalFrame.new(top_splitter, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y||LAYOUT_FIX_HEIGHT|LAYOUT_BOTTOM)
494
+ FXLabel.new(filter_frame, "Intercept:" )
495
+ @intercept_request = FXCheckButton.new(filter_frame, "Requests", nil, 0,
496
+ ICON_BEFORE_TEXT|LAYOUT_SIDE_TOP)
497
+ @intercept_request.connect(SEL_COMMAND, method(:onInterceptChanged))
498
+
499
+ @intercept_response = FXCheckButton.new(filter_frame, "Response", nil, 0,
500
+ ICON_BEFORE_TEXT|LAYOUT_SIDE_TOP)
501
+ @intercept_response.connect(SEL_COMMAND, method(:onInterceptChanged))
502
+
503
+ @filter_options_btn = FXButton.new(filter_frame, "Filter Options", nil, nil, 0, FRAME_RAISED|FRAME_THICK|LAYOUT_LEFT)
504
+ @filter_options_btn.connect(SEL_COMMAND, method(:onBtnFilterOptions))
505
+ #@intercept_request.checkState = false
506
+ #@intercept_response.checkState = false
507
+ unless @interceptor.nil?
508
+
509
+ @intercept_request.checkState = @interceptor.mode & INTERCEPT_REQUEST > 0
510
+ @intercept_response.checkState = @interceptor.mode & INTERCEPT_RESPONSE > 0
511
+ end
512
+
513
+ view_frame = FXVerticalFrame.new(top_splitter, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y||LAYOUT_FIX_HEIGHT|LAYOUT_BOTTOM)
514
+
515
+ @tabBook = FXTabBook.new(view_frame, nil, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_RIGHT)
516
+
517
+ button_frame = FXHorizontalFrame.new(view_frame, LAYOUT_FILL_X)
518
+ @tabBook.connect(SEL_COMMAND) { |sender, sel, item|
519
+ case item
520
+ when 0
521
+ enable_buttons if @request_list.length > 0
522
+ when 1
523
+ enable_buttons if @response_list.length > 0
524
+ end
525
+
526
+ }
527
+ @request_tab = FXTabItem.new(@tabBook, "Request (0)", nil)
528
+ request_frame_outer = FXVerticalFrame.new(@tabBook, LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_RAISED)
529
+ # request_frame = FXVerticalFrame.new(request_frame_outer, LAYOUT_FILL_X|LAYOUT_FILL_Y)
530
+
531
+ @requestbox = Watobo::Gui::InterceptEditor.new(request_frame_outer, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y)
532
+
533
+ @response_tab = FXTabItem.new(@tabBook, "Response (0)", nil)
534
+ response_frame_outer = FXVerticalFrame.new(@tabBook, LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_RAISED)
535
+ #response_frame = FXVerticalFrame.new(response_frame_outer, LAYOUT_FILL_X|LAYOUT_FILL_Y, :padding=>0)
536
+ # @responsebox = Watobo::Gui::RequestEditor.new(response_frame, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y )
537
+ @responsebox = Watobo::Gui::InterceptEditor.new(response_frame_outer, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y)
538
+ # @responsebox.editable = true
539
+
540
+ @accept_button = FXButton.new(button_frame, "Accept", nil, nil, 0, FRAME_RAISED|FRAME_THICK|LAYOUT_LEFT)
541
+ @accept_button.connect(SEL_COMMAND, method(:onAcceptChanges))
542
+
543
+ @discard_button = FXButton.new(button_frame, "Discard", nil, nil, 0, FRAME_RAISED|FRAME_THICK|LAYOUT_LEFT)
544
+ @discard_button.connect(SEL_COMMAND, method(:onDiscard))
545
+
546
+ @drop_button = FXButton.new(button_frame, "Drop", nil, nil, 0, FRAME_RAISED|FRAME_THICK|LAYOUT_LEFT)
547
+ @drop_button.connect(SEL_COMMAND, method(:onDrop))
548
+
549
+ # log_text_frame = FXVerticalFrame.new(log_frame, LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_SUNKEN|FRAME_THICK, :padding=>0)
550
+ # @log_viewer = FXText.new(log_text_frame, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y)
551
+
552
+ disable_buttons()
553
+
554
+ # start an update timer
555
+ @update_timer = FXApp.instance.addTimeout( 50, :repeat => true) {
556
+ @request_lock.synchronize do
557
+ unless @request_queue.empty?
558
+ @request_list.concat @request_queue
559
+ @request_queue.clear
560
+ @request_tab.text = "Request (#{@request_list.length})"
561
+ end
562
+
563
+ if @request_list.length > 0 and @requestbox.empty?
564
+ @requestbox.setText @request_list.first[:request]
565
+ end
566
+
567
+ end
568
+ @response_lock.synchronize do
569
+ unless @response_queue.empty?
570
+ @response_list.concat @response_queue
571
+ @response_queue.clear
572
+ @response_tab.text = "Response (#{@response_list.length})"
573
+ end
574
+
575
+ if @response_list.length > 0 and @responsebox.empty?
576
+ @responsebox.setText @response_list.first[:response]
577
+ end
578
+
579
+ end
580
+ update_buttons
581
+ }
582
+
583
+ end
584
+
585
+ def releaseAll()
586
+ # puts "* closing interceptor"
587
+ # puts "* disable all interceptions"
588
+ #@project.intercept_request = false
589
+ #@project.intercept_response = false
590
+ # puts "* release all interceptions ..."
591
+ @request_list.each do |ir|
592
+ ir[:thread].run
593
+ end
594
+ @response_list.each do |ir|
595
+ ir[:thread].run
596
+ end
597
+
598
+ end
599
+
600
+ private
601
+
602
+ def onAcceptChanges(sender, sel, ptr)
603
+ if @tabBook.current == 0 then
604
+
605
+ begin
606
+ @request_lock.synchronize do
607
+ request = @request_list.first
608
+ if not request.nil?
609
+ request[:request].clear
610
+ request[:request].concat @requestbox.parseRequest
611
+ @requestbox.clear
612
+ Watobo.print_debug( self.class.to_s, "release thread #{request[:thread]}")
613
+ request[:thread].run
614
+ @request_list.shift
615
+ @request_tab.text = "Request (#{@request_list.length})"
616
+ #getNextRequest()
617
+ else
618
+ puts "* [INTERCEPTOR] NOTHING TO RELEASE"
619
+ end
620
+ end
621
+ rescue => bang
622
+ puts "!!! Error"
623
+ puts bang
624
+ end
625
+ else
626
+ begin
627
+ @response_lock.synchronize do
628
+ response = @response_list.first
629
+ if not response.nil?
630
+ response[:response].clear
631
+ new_response = @responsebox.parseRequest(:update_content_length => true)
632
+ response[:response].concat new_response
633
+ response[:thread].run
634
+ @responsebox.clear
635
+ @response_list.shift
636
+ @response_tab.text = "Response (#{@response_list.length})"
637
+ # getNextResponse()
638
+ end
639
+ end
640
+ rescue => bang
641
+ puts "!!! Error"
642
+ puts bang
643
+ end
644
+ end
645
+
646
+ end
647
+
648
+ def onDrop(sender, sel, ptr)
649
+ if @tabBook.current == 0 then
650
+ @request_lock.synchronize do
651
+ request = @request_list.first
652
+ if request
653
+ request[:request].clear
654
+ request[:thread].kill
655
+ @request_list.shift
656
+ @requestbox.clear
657
+ end
658
+ @request_tab.text = "Request (#{@request_list.length})"
659
+ end
660
+ #getNextRequest()
661
+ else
662
+ @response_lock.synchronize do
663
+ response = @response_list.first
664
+ if response
665
+ response[:response].clear
666
+ response[:thread].kill
667
+ @response_list.shift
668
+ @responsebox.clear
669
+ end
670
+ @response_tab.text = "Response (#{@response_list.length})"
671
+ # getNextResponse()
672
+ end
673
+ end
674
+ end
675
+
676
+ def onDiscard(sender, sel, ptr)
677
+ if @tabBook.current == 0 then
678
+ @request_lock.synchronize do
679
+ request = @request_list.first
680
+ request[:thread].run if request
681
+ @request_list.shift
682
+ @requestbox.clear
683
+ @request_tab.text = "Request (#{@request_list.length})"
684
+
685
+ end
686
+ #getNextRequest()
687
+ else
688
+ @response_lock.synchronize do
689
+ response = @response_list.first
690
+ response[:thread].run if response
691
+ @response_list.shift
692
+ @responsebox.clear
693
+ @response_tab.text = "Response (#{@response_list.length})"
694
+ #getNextResponse()
695
+ end
696
+ end
697
+ end
698
+
699
+ def onDiscardAll(sender, sel, ptr)
700
+
701
+ end
702
+
703
+ # def onHide
704
+ # # puts "* hiding interceptor"
705
+ # @interceptor.mode = INTERCEPT_NONE
706
+ # @mutex.synchronize {
707
+ # @cv.signal
708
+ # }
709
+ # end
710
+
711
+ def onClose(sender, sel, ptr)
712
+ puts "* closing Interceptor UI"
713
+ puts "+ stop intercepting"
714
+ @interceptor.mode = INTERCEPT_NONE
715
+ puts "+ release all interceptions"
716
+ releaseAll()
717
+ #getApp().stopModal(self, 1)
718
+ puts "_"
719
+
720
+ self.hide()
721
+ end
722
+
723
+ def enable_buttons
724
+ @accept_button.enabled = true
725
+ @discard_button.enabled = true
726
+ @drop_button.enabled = true
727
+ end
728
+
729
+ def disable_buttons
730
+ @accept_button.enabled = false
731
+ @discard_button.enabled = false
732
+ @drop_button.enabled = false
733
+ end
734
+
735
+ def update_buttons
736
+ if @tabBook.current == 0 then
737
+ @request_lock.synchronize do
738
+ if @request_list.length > 0
739
+ enable_buttons
740
+ else
741
+ disable_buttons
742
+ end
743
+ end
744
+
745
+ else
746
+ @response_lock.synchronize do
747
+ if @response_list.length > 0
748
+ enable_buttons
749
+ else
750
+ disable_buttons
751
+ end
752
+ end
753
+ end
754
+ end
755
+
756
+ def onBtnFilterOptions(sender, sel, ptr)
757
+
758
+ dlg = Watobo::Gui::InterceptorFilterSettingsDialog.new( self,
759
+ :request_filter_settings => @interceptor.getRequestFilter(),
760
+ :response_filter_settings => @interceptor.getResponseFilter()
761
+ )
762
+ if dlg.execute != 0 then
763
+ # TODO: Apply interceptor settings
764
+ @interceptor.setRequestFilter(dlg.getRequestFilter)
765
+ @interceptor.setResponseFilter(dlg.getResponseFilter)
766
+ end
767
+
768
+ end
769
+
770
+ def onInterceptChanged(sender, sel, ptr)
771
+ begin
772
+ unless @interceptor.nil? then
773
+ @interceptor.mode = @intercept_response.checked? ? INTERCEPT_RESPONSE : 0
774
+ @interceptor.mode |= @intercept_request.checked? ? INTERCEPT_REQUEST : 0
775
+ #puts @interceptor.mode
776
+ end
777
+ rescue => bang
778
+ puts bang
779
+ puts bang.backtrace if $DEBUG
780
+ end
781
+ end
782
+
783
+ end
784
+
785
+ class InterceptorFilterSettingsDialog < FXDialogBox
786
+
787
+ include Responder
788
+ def getRequestFilter()
789
+ @request_filter
790
+ end
791
+
792
+ def getResponseFilter()
793
+ @response_filter
794
+ end
795
+
796
+ def initialize(owner, settings = {} )
797
+ super(owner, "Interceptor Settings", DECOR_ALL, :width => 300, :height => 425)
798
+
799
+ @request_filter = { }
800
+
801
+ @response_filter = { }
802
+
803
+ @request_filter.update settings[:request_filter_settings]
804
+ @response_filter.update settings[:response_filter_settings]
805
+
806
+ FXMAPFUNC(SEL_COMMAND, ID_ACCEPT, :onAccept)
807
+
808
+ base_frame = FXVerticalFrame.new(self, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y, :padding => 0)
809
+ @tabbook = FXTabBook.new(base_frame, nil, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_RIGHT)
810
+ buttons_frame = FXHorizontalFrame.new(base_frame, :opts => LAYOUT_FILL_X)
811
+ @req_opt_tab = FXTabItem.new(@tabbook, "Request Options", nil)
812
+ frame = FXVerticalFrame.new(@tabbook, :opts => FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|LAYOUT_FILL_Y)
813
+ scroll_window = FXScrollWindow.new(frame, SCROLLERS_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_Y)
814
+ @req_opt_frame = FXVerticalFrame.new(scroll_window, :opts => FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|LAYOUT_FILL_Y)
815
+
816
+ @resp_opt_tab = FXTabItem.new(@tabbook, "Response Options", nil)
817
+ frame= FXVerticalFrame.new(@tabbook, :opts => FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|LAYOUT_FILL_Y)
818
+ scroll_window = FXScrollWindow.new(frame, SCROLLERS_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_Y)
819
+ @resp_opt_frame = FXVerticalFrame.new(scroll_window, :opts => FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|LAYOUT_FILL_Y)
820
+
821
+ initRequestFilterFrame()
822
+ updateRequestFilterFrame()
823
+
824
+ initResponseFilterFrame()
825
+ updateResponseFilterFrame()
826
+
827
+ @finishButton = FXButton.new(buttons_frame, "Accept" , nil, nil, :opts => BUTTON_NORMAL|LAYOUT_RIGHT)
828
+ @finishButton.enable
829
+ @finishButton.connect(SEL_COMMAND) do |sender, sel, item|
830
+ #self.handle(self, FXSEL(SEL_COMMAND, ID_CANCEL), nil)
831
+ self.handle(self, FXSEL(SEL_COMMAND, ID_ACCEPT), nil)
832
+ end
833
+
834
+ @cancelButton = FXButton.new(buttons_frame, "Cancel" ,
835
+ :target => self, :selector => FXDialogBox::ID_CANCEL,
836
+ :opts => BUTTON_NORMAL|LAYOUT_RIGHT)
837
+ end
838
+
839
+ private
840
+
841
+ def onAccept(sender, sel, event)
842
+ #TODO: Check if regex is valid
843
+ @request_filter[:method_filter] = @method_filter_dt.value
844
+ @request_filter[:negate_method_filter] = @neg_method_filter_cb.checked?
845
+ @request_filter[:negate_url_filter] = @neg_url_filter_cb.checked?
846
+ @request_filter[:url_filter] = @url_filter_dt.value
847
+ @request_filter[:file_type_filter] = @ftype_filter_dt.value
848
+ @request_filter[:negate_file_type_filter] = @neg_ftype_filter_cb.checked?
849
+
850
+ @request_filter[:parms_filter] = @parms_filter_dt.value
851
+ @request_filter[:negate_parms_filter] = @neg_parms_filter_cb.checked?
852
+
853
+ @response_filter[:content_type_filter] = @content_type_filter_dt.value
854
+ @response_filter[:negate_content_type_filter] = @neg_ctype_filter_cb.checked?
855
+
856
+ @response_filter[:response_code_filter] = @rcode_filter_dt.value
857
+ @response_filter[:negate_response_code_filter] = @neg_rcode_filter_cb.checked?
858
+
859
+ getApp().stopModal(self, 1)
860
+ self.hide()
861
+ return 1
862
+ end
863
+
864
+ def updateRequestFilterFrame()
865
+ @parms_filter.handle(self, FXSEL(SEL_UPDATE, 0), nil)
866
+ @url_filter.handle(self, FXSEL(SEL_UPDATE, 0), nil)
867
+ @ftype_filter.handle(self, FXSEL(SEL_UPDATE, 0), nil)
868
+ @method_filter.handle(self, FXSEL(SEL_UPDATE, 0), nil)
869
+ end
870
+
871
+ def updateResponseFilterFrame()
872
+ @content_type_filter.handle(self, FXSEL(SEL_UPDATE, 0), nil)
873
+ @rcode_filter.handle(self, FXSEL(SEL_UPDATE, 0), nil)
874
+ # @neg_rcode_filter_cb.handle(self, FXSEL(SEL_UPDATE, 0), nil)
875
+ # @neg_ctype_filter_cb.handle(self, FXSEL(SEL_UPDATE, 0), nil)
876
+ end
877
+
878
+ def initResponseFilterFrame()
879
+
880
+ gbframe = FXGroupBox.new(@resp_opt_frame, "Content Type", LAYOUT_SIDE_RIGHT|FRAME_GROOVE|LAYOUT_FILL_X, 0, 0, 0, 0)
881
+ frame = FXVerticalFrame.new(gbframe, :opts => LAYOUT_FILL_X, :padding => 0)
882
+ fxtext = FXText.new(frame, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y|TEXT_WORDWRAP)
883
+ fxtext.backColor = fxtext.parent.backColor
884
+ fxtext.disable
885
+ text = "Regular expression for HTTP Content-Type. E.g., '(text|script)'"
886
+ fxtext.setText(text)
887
+ @content_type_filter_dt = FXDataTarget.new('')
888
+ @content_type_filter_dt.value = @response_filter[:content_type_filter]
889
+ @content_type_filter = FXTextField.new(frame, 20, :target => @content_type_filter_dt, :selector => FXDataTarget::ID_VALUE, :opts => TEXTFIELD_NORMAL|LAYOUT_SIDE_LEFT|LAYOUT_FILL_X)
890
+ @neg_ctype_filter_cb = FXCheckButton.new(frame, "Negate Filter", nil, 0, JUSTIFY_LEFT|JUSTIFY_TOP|ICON_BEFORE_TEXT|LAYOUT_SIDE_TOP)
891
+ #@neg_method_filter_cb.checkState = false
892
+ @neg_ctype_filter_cb.checkState = @response_filter[:negate_content_type_filter]
893
+
894
+ gbframe = FXGroupBox.new(@resp_opt_frame, "Response Code", LAYOUT_SIDE_RIGHT|FRAME_GROOVE|LAYOUT_FILL_X, 0, 0, 0, 0)
895
+ frame = FXVerticalFrame.new(gbframe, :opts => LAYOUT_FILL_X, :padding => 0)
896
+ fxtext = FXText.new(frame, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y|TEXT_WORDWRAP)
897
+ fxtext.backColor = fxtext.parent.backColor
898
+ fxtext.disable
899
+ text = "Regular expression for HTTP Content-Type. E.g., '200'"
900
+ fxtext.setText(text)
901
+ @rcode_filter_dt = FXDataTarget.new('')
902
+ @rcode_filter_dt.value = @response_filter[:response_code_filter]
903
+
904
+ @rcode_filter = FXTextField.new(frame, 20, :target => @rcode_filter_dt, :selector => FXDataTarget::ID_VALUE, :opts => TEXTFIELD_NORMAL|LAYOUT_SIDE_LEFT|LAYOUT_FILL_X)
905
+ @neg_rcode_filter_cb = FXCheckButton.new(frame, "Negate Filter", nil, 0, JUSTIFY_LEFT|JUSTIFY_TOP|ICON_BEFORE_TEXT|LAYOUT_SIDE_TOP)
906
+ #@neg_method_filter_cb.checkState = false
907
+ @neg_rcode_filter_cb.checkState = @response_filter[:negate_response_code_filter]
908
+
909
+ end
910
+
911
+ def initRequestFilterFrame()
912
+ gbframe = FXGroupBox.new(@req_opt_frame, "URL Filter", LAYOUT_SIDE_RIGHT|FRAME_GROOVE|LAYOUT_FILL_X, 0, 0, 0, 0)
913
+ frame = FXVerticalFrame.new(gbframe, :opts => LAYOUT_FILL_X, :padding => 0)
914
+ fxtext = FXText.new(frame, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y|TEXT_WORDWRAP)
915
+ fxtext.backColor = fxtext.parent.backColor
916
+ fxtext.disable
917
+ text = "Regular Expression Filter For URL. E.g., '.*www.mysite.com.*login.php'"
918
+ fxtext.setText(text)
919
+
920
+ @url_filter_dt = FXDataTarget.new('')
921
+ @url_filter_dt.value = @request_filter[:url_filter]
922
+ @url_filter = FXTextField.new(frame, 20, :target => @url_filter_dt, :selector => FXDataTarget::ID_VALUE, :opts => TEXTFIELD_NORMAL|LAYOUT_SIDE_LEFT|LAYOUT_FILL_X)
923
+ @neg_url_filter_cb = FXCheckButton.new(frame, "Negate Filter", nil, 0, JUSTIFY_LEFT|JUSTIFY_TOP|ICON_BEFORE_TEXT|LAYOUT_SIDE_TOP)
924
+ #@neg_url_filter_cb.checkState = false
925
+ @neg_url_filter_cb.checkState = @request_filter[:negate_url_filter]
926
+
927
+ gbframe = FXGroupBox.new(@req_opt_frame, "Method Filter", LAYOUT_SIDE_RIGHT|FRAME_GROOVE|LAYOUT_FILL_X, 0, 0, 0, 0)
928
+ frame = FXVerticalFrame.new(gbframe, :opts => LAYOUT_FILL_X, :padding => 0)
929
+ fxtext = FXText.new(frame, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y|TEXT_WORDWRAP)
930
+ fxtext.backColor = fxtext.parent.backColor
931
+ fxtext.disable
932
+ text = "Regular expression for HTTP method. E.g., '(get|PoSt)'"
933
+ fxtext.setText(text)
934
+ @method_filter_dt = FXDataTarget.new('')
935
+ @method_filter_dt.value = @request_filter[:method_filter]
936
+ @method_filter = FXTextField.new(frame, 20, :target => @method_filter_dt, :selector => FXDataTarget::ID_VALUE, :opts => TEXTFIELD_NORMAL|LAYOUT_SIDE_LEFT|LAYOUT_FILL_X)
937
+ @neg_method_filter_cb = FXCheckButton.new(frame, "Negate Filter", nil, 0, JUSTIFY_LEFT|JUSTIFY_TOP|ICON_BEFORE_TEXT|LAYOUT_SIDE_TOP)
938
+ #@neg_method_filter_cb.checkState = false
939
+ @neg_method_filter_cb.checkState = @request_filter[:negate_method_filter]
940
+
941
+ gbframe = FXGroupBox.new(@req_opt_frame, "Parm Filter", LAYOUT_SIDE_RIGHT|FRAME_GROOVE|LAYOUT_FILL_X, 0, 0, 0, 0)
942
+ frame = FXVerticalFrame.new(gbframe, :opts => LAYOUT_FILL_X, :padding => 0)
943
+ fxtext = FXText.new(frame, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y|TEXT_WORDWRAP)
944
+ fxtext.backColor = fxtext.parent.backColor
945
+ fxtext.disable
946
+ text = "Regular Expression Filter For Parameter Names. E.g., for intercepting requests containing parameters beginning with 'act' use the regex pattern '^act.*' (without single quotes)"
947
+ fxtext.setText(text)
948
+ @parms_filter_dt = FXDataTarget.new('')
949
+ @parms_filter_dt.value = @request_filter[:parms_filter]
950
+ @parms_filter = FXTextField.new(frame, 20, :target => @parms_filter_dt, :selector => FXDataTarget::ID_VALUE, :opts => TEXTFIELD_NORMAL|LAYOUT_SIDE_LEFT|LAYOUT_FILL_X)
951
+ @neg_parms_filter_cb = FXCheckButton.new(frame, "Negate Filter", nil, 0, JUSTIFY_LEFT|JUSTIFY_TOP|ICON_BEFORE_TEXT|LAYOUT_SIDE_TOP)
952
+ #@neg_parm_filter_cb.checkState = false
953
+ @neg_parms_filter_cb.checkState = @request_filter[:negate_parms_filter]
954
+
955
+ gbframe = FXGroupBox.new(@req_opt_frame, "File Type Filter", LAYOUT_SIDE_RIGHT|FRAME_GROOVE|LAYOUT_FILL_X, 0, 0, 0, 0)
956
+ frame = FXVerticalFrame.new(gbframe, :opts => LAYOUT_FILL_X, :padding => 0)
957
+ fxtext = FXText.new(frame, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y|TEXT_WORDWRAP)
958
+ fxtext.backColor = fxtext.parent.backColor
959
+ fxtext.disable
960
+ text = "Regular expression for file types by its extension. E.g., for intercepting requests where file type is PHP use '^php$' (without single quotes)"
961
+ fxtext.setText(text)
962
+ @ftype_filter_dt = FXDataTarget.new('')
963
+ @ftype_filter_dt.value = @request_filter[:file_type_filter]
964
+ @ftype_filter = FXTextField.new(frame, 20, :target => @ftype_filter_dt, :selector => FXDataTarget::ID_VALUE, :opts => TEXTFIELD_NORMAL|LAYOUT_SIDE_LEFT|LAYOUT_FILL_X)
965
+ @neg_ftype_filter_cb = FXCheckButton.new(frame, "Negate Filter", nil, 0, JUSTIFY_LEFT|JUSTIFY_TOP|ICON_BEFORE_TEXT|LAYOUT_SIDE_TOP)
966
+ #@neg_parm_filter_cb.checkState = false
967
+ @neg_ftype_filter_cb.checkState = @request_filter[:negate_file_type_filter]
968
+ end
969
+ end
970
+ #
971
+ end
972
+ end
973
+
974
+ if __FILE__ == $0
975
+ class TestGui < FXMainWindow
976
+ def initialize(app)
977
+ # Call base class initializer first
978
+ super(app, "Test Application", :width => 800, :height => 600)
979
+ frame = FXVerticalFrame.new(self, LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_GROOVE)
980
+ Watobo::Gui::InterceptorUI.new(frame, nil, nil)
981
+ end
982
+
983
+ # Create and show the main window
984
+ def create
985
+ super # Create the windows
986
+ show(PLACEMENT_SCREEN) # Make the main window appear
987
+
988
+ end
989
+ end
990
+ # application = FXApp.new('LayoutTester', 'FoxTest')
991
+ TestGui.new($application)
992
+ $application.create
993
+ $application.run
994
+ end