mushy 0.21.2 → 0.24.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,262 +1,254 @@
1
1
  require 'ferrum'
2
2
 
3
- module Mushy
4
-
5
- class Browser < Flux
6
-
7
- def self.details
8
- {
9
- name: 'Browser',
10
- title: 'Use a browser',
11
- fluxGroup: { name: 'Web' },
12
- description: 'Visit a page in a browser.',
13
- config: {
14
- url: {
15
- description: 'The URL to visit.',
16
- type: 'text',
17
- value: 'https://www.google.com',
18
- },
19
- headless: {
20
- description: 'Run this browser headless.',
21
- type: 'boolean',
22
- shrink: true,
23
- value: '',
24
- },
25
- timeout: {
26
- description: 'The default timeout (in seconds) before closing the browser. Default is 5 seconds.',
27
- type: 'integer',
28
- shrink: true,
29
- value: '',
30
- },
31
- execute: {
32
- description: 'Javascript to run after the page is loaded.',
33
- type: 'textarea',
34
- shrink: true,
35
- value: '',
36
- },
37
- cookies: {
38
- description: 'Cookies for the web request. These can be received from a previous browser event with {{cookies}}, or can be typed manually.',
39
- type: 'editgrid',
40
- shrink: true,
41
- value: [],
42
- editors: [
43
- { id: 'name', target: 'name', field: { type: 'text', value: '', default: '' } },
44
- { id: 'value', target: 'value', field: { type: 'text', value: '', default: '' } },
45
- { id: 'domain', target: 'domain', field: { type: 'text', value: '', default: '' } },
46
- { id: 'path', target: 'path', field: { type: 'text', value: '', default: '' } },
47
- { id: 'expires', target: 'expires', field: { type: 'text', value: '', default: '' } },
48
- { id: 'size', target: 'size', field: { type: 'integer', value: 0, default: 0 } },
49
- { id: 'httpOnly', target: 'httpOnly', field: { type: 'boolean', value: false, default: false } },
50
- { id: 'secure', target: 'secure', field: { type: 'boolean', value: true, default: true } },
51
- { id: 'sameSite', target: 'sameSite', field: { type: 'text', value: 'None', default: 'None' } },
52
- { id: 'priority', target: 'priority', field: { type: 'text', value: 'Medium', default: 'Medium' } },
53
- ],
54
- },
55
- carry_cookies_from: {
56
- description: 'Carry the cookies from this path in the event. Defaults to "cookies".',
57
- type: 'text',
58
- shrink: true,
59
- value: '',
60
- },
61
- headers: {
62
- description: 'Headers for the web request. These can be received from a previous browser event with {{headers}}, or can be typed manually.',
63
- type: 'keyvalue',
64
- shrink: true,
65
- value: {},
66
- },
67
- carry_headers_from: {
68
- description: 'Carry the headers from this path in the event. Defaults to "headers".',
69
- type: 'text',
70
- shrink: true,
71
- value: '',
72
- },
73
- wait_before_closing: {
74
- description: 'Wait this many seconds before closing the browser.',
75
- type: 'integer',
76
- shrink: true,
77
- value: '',
78
- },
3
+ class Mushy::Browser < Mushy::Flux
4
+ def self.details
5
+ {
6
+ name: 'Browser',
7
+ title: 'Use a browser',
8
+ fluxGroup: { name: 'Web' },
9
+ description: 'Visit a page in a browser.',
10
+ config: {
11
+ url: {
12
+ description: 'The URL to visit.',
13
+ type: 'text',
14
+ value: 'https://www.google.com'
15
+ },
16
+ headless: {
17
+ description: 'Run this browser headless.',
18
+ type: 'boolean',
19
+ shrink: true,
20
+ value: ''
21
+ },
22
+ timeout: {
23
+ description: 'The default timeout (in seconds) before closing the browser. Default is 5 seconds.',
24
+ type: 'integer',
25
+ shrink: true,
26
+ value: ''
27
+ },
28
+ execute: {
29
+ description: 'Javascript to run after the page is loaded.',
30
+ type: 'textarea',
31
+ shrink: true,
32
+ value: ''
33
+ },
34
+ cookies: {
35
+ description: 'Cookies for the web request. These can be received from a previous browser event with {{cookies}}, or can be typed manually.',
36
+ type: 'editgrid',
37
+ shrink: true,
38
+ value: [],
39
+ editors: [
40
+ { id: 'name', target: 'name', field: { type: 'text', value: '', default: '' } },
41
+ { id: 'value', target: 'value', field: { type: 'text', value: '', default: '' } },
42
+ { id: 'domain', target: 'domain', field: { type: 'text', value: '', default: '' } },
43
+ { id: 'path', target: 'path', field: { type: 'text', value: '', default: '' } },
44
+ { id: 'expires', target: 'expires', field: { type: 'text', value: '', default: '' } },
45
+ { id: 'size', target: 'size', field: { type: 'integer', value: 0, default: 0 } },
46
+ { id: 'httpOnly', target: 'httpOnly', field: { type: 'boolean', value: false, default: false } },
47
+ { id: 'secure', target: 'secure', field: { type: 'boolean', value: true, default: true } },
48
+ { id: 'sameSite', target: 'sameSite', field: { type: 'text', value: 'None', default: 'None' } },
49
+ { id: 'priority', target: 'priority', field: { type: 'text', value: 'Medium', default: 'Medium' } },
50
+ ]
51
+ },
52
+ carry_cookies_from: {
53
+ description: 'Carry the cookies from this path in the event. Defaults to "cookies".',
54
+ type: 'text',
55
+ shrink: true,
56
+ value: ''
57
+ },
58
+ headers: {
59
+ description: 'Headers for the web request. These can be received from a previous browser event with {{headers}}, or can be typed manually.',
60
+ type: 'keyvalue',
61
+ shrink: true,
62
+ value: {}
63
+ },
64
+ carry_headers_from: {
65
+ description: 'Carry the headers from this path in the event. Defaults to "headers".',
66
+ type: 'text',
67
+ shrink: true,
68
+ value: ''
69
+ },
70
+ wait_before_closing: {
71
+ description: 'Wait this many seconds before closing the browser.',
72
+ type: 'integer',
73
+ shrink: true,
74
+ value: ''
75
+ }
76
+ },
77
+ examples: {
78
+ 'Successful Call' => {
79
+ description: 'This will open https://www.google.com and return the result.',
80
+ config: { url: "https://www.google.com" },
81
+ result: {
82
+ url: 'https://www.google.com/',
83
+ status: 200,
84
+ title: 'Google',
85
+ cookies: [
86
+ {
87
+ name: '1P_JAR',
88
+ value: '2021-10-06-12',
89
+ domain: '.google.com',
90
+ path: '/',
91
+ expires: 1636117150.583117,
92
+ size: 19,
93
+ httpOnly: false,
94
+ secure: true,
95
+ session: false,
96
+ sameSite: 'None',
97
+ priority: 'Medium'
98
+ }
99
+ ],
100
+ headers: {},
101
+ time: 1.486214604,
102
+ body: '<html itemscope="" itemtype="http://schema.org/WebPage" lang="en">...</html>'
103
+ }
79
104
  },
80
- examples: {
81
- "Successful Call" => {
82
- description: 'This will open https://www.google.com and return the result.',
83
- config: {
84
- url: "https://www.google.com",
85
- },
86
- result: {
87
- "url": "https://www.google.com/",
88
- "status": 200,
89
- "title": "Google",
90
- "cookies": [
91
- {
92
- "name": "1P_JAR",
93
- "value": "2021-10-06-12",
94
- "domain": ".google.com",
95
- "path": "/",
96
- "expires": 1636117150.583117,
97
- "size": 19,
98
- "httpOnly": false,
99
- "secure": true,
100
- "session": false,
101
- "sameSite": "None",
102
- "priority": "Medium"
103
- },
104
- ],
105
- "headers": {},
106
- "time": 1.486214604,
107
- "body": "<html itemscope=\"\" itemtype=\"http://schema.org/WebPage\" lang=\"en\">...</html>"
108
- }
109
- },
110
- "Login To a Site" => {
111
- description: 'This will open https://www.yoursitepleasethankyou.com, login using javascript, and then return the state of the browser after logging in.',
112
- input: {
113
- url: "https://www.yoursitepleasethankyou.com",
114
- username: "MYUSERNAME",
115
- password: "MYPASSWORD",
116
- },
117
- config: {
118
- url: "{{url}}",
119
- timeout: 10,
120
- execute: "$('#username').val('{{username}}');
105
+ 'Login To a Site' => {
106
+ description: 'This will open https://www.yoursitepleasethankyou.com, login using javascript, and then return the state of the browser after logging in.',
107
+ input: {
108
+ url: 'https://www.yoursitepleasethankyou.com',
109
+ username: 'MYUSERNAME',
110
+ password: 'MYPASSWORD'
111
+ },
112
+ config: {
113
+ url: '{{url}}',
114
+ timeout: 10,
115
+ execute: "$('#username').val('{{username}}');
121
116
  $('#next').click();
122
117
  $('#password').val('{{password}}');
123
118
  $('#login').click();"
124
- },
125
- result: {
126
- "url": "https://yoursitepleasethankyou/",
127
- "status": 200,
128
- "title": "",
129
- "cookies": [
130
- {
131
- "name": "session_id",
132
- "value": "1jfujsx5xbnuxmsjmgjhzfpi",
133
- "domain": ".yoursitepleasethankyou",
134
- "path": "/",
135
- "expires": -1,
136
- "size": 41,
137
- "httpOnly": true,
138
- "secure": true,
139
- "session": true,
140
- "sameSite": "Lax",
141
- "priority": "Medium"
142
- }
143
- ],
144
- "headers": {},
145
- "time": 4.633920809,
146
- "body": "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head></head>...</html>"
147
- }
148
- },
149
- "Access a Page After Logging In" => {
150
- description: 'This will open a page using cookies from the previous request. Note that the cookies came from another browser flux event.',
151
- input: {
152
- "url": "https://yoursitepleasethankyou/",
153
- "cookies": [
154
- {
155
- "name": "session_id",
156
- "value": "1jfujsx5xbnuxmsjmgjhzfpi",
157
- "domain": ".yoursitepleasethankyou",
158
- "path": "/",
159
- "expires": -1,
160
- "size": 41,
161
- "httpOnly": true,
162
- "secure": true,
163
- "session": true,
164
- "sameSite": "Lax",
165
- "priority": "Medium"
166
- }
167
- ],
168
- },
169
- config: {
170
- url: "https://www.yoursitepleasethankyou.com/myaccount",
171
- carry_cookies_from: "{{cookies}}"
172
- },
173
- result: {
174
- "url": "https://yoursitepleasethankyou/",
175
- "status": 200,
176
- "title": "",
177
- "cookies": [
178
- {
179
- "name": "session_id",
180
- "value": "1jfujsx5xbnuxmsjmgjhzfpi",
181
- "domain": ".yoursitepleasethankyou",
182
- "path": "/",
183
- "expires": -1,
184
- "size": 41,
185
- "httpOnly": true,
186
- "secure": true,
187
- "session": true,
188
- "sameSite": "Lax",
189
- "priority": "Medium"
190
- }
191
- ],
192
- "headers": {},
193
- "time": 4.633920809,
194
- "body": "<html><head></head>Your name is John Doe...</html>"
195
- }
196
- }
197
- }
119
+ },
120
+ result: {
121
+ url: 'https://yoursitepleasethankyou/',
122
+ status: 200,
123
+ title: '',
124
+ cookies: [
125
+ {
126
+ name: 'session_id',
127
+ value: '1jfujsx5xbnuxmsjmgjhzfpi',
128
+ domain: '.yoursitepleasethankyou',
129
+ path: '/',
130
+ expires: -1,
131
+ size: 41,
132
+ httpOnly: true,
133
+ secure: true,
134
+ session: true,
135
+ sameSite: 'Lax',
136
+ priority: 'Medium'
137
+ }
138
+ ],
139
+ headers: {},
140
+ time: 4.633920809,
141
+ body: '<html xmlns="http://www.w3.org/1999/xhtml"><head></head>...</html>'
142
+ }
143
+ },
144
+ 'Access a Page After Logging In' => {
145
+ description: 'This will open a page using cookies from the previous request. Note that the cookies came from another browser flux event.',
146
+ input: {
147
+ url: 'https://yoursitepleasethankyou/',
148
+ cookies: [
149
+ {
150
+ name: 'session_id',
151
+ value: '1jfujsx5xbnuxmsjmgjhzfpi',
152
+ domain: '.yoursitepleasethankyou',
153
+ path: '/',
154
+ expires: -1,
155
+ size: 41,
156
+ httpOnly: true,
157
+ secure: true,
158
+ session: true,
159
+ sameSite: 'Lax',
160
+ priority: 'Medium'
161
+ }
162
+ ]
163
+ },
164
+ config: {
165
+ url: 'https://www.yoursitepleasethankyou.com/myaccount',
166
+ carry_cookies_from: '{{cookies}}'
167
+ },
168
+ result: {
169
+ url: 'https://yoursitepleasethankyou/',
170
+ status: 200,
171
+ title: '',
172
+ cookies: [
173
+ {
174
+ name: 'session_id',
175
+ value: '1jfujsx5xbnuxmsjmgjhzfpi',
176
+ domain: '.yoursitepleasethankyou',
177
+ path: '/',
178
+ expires: -1,
179
+ size: 41,
180
+ httpOnly: true,
181
+ secure: true,
182
+ session: true,
183
+ sameSite: 'Lax',
184
+ priority: 'Medium'
185
+ }
186
+ ],
187
+ headers: {},
188
+ time: 4.633920809,
189
+ body: '<html><head></head>Your name is John Doe...</html>'
190
+ }
191
+ }
198
192
  }
199
- end
200
-
201
- def process event, config
202
-
203
- timeout = config[:timeout] ? config[:timeout].to_i : 5
193
+ }
194
+ end
204
195
 
205
- browser = Ferrum::Browser.new(
206
- headless: (config[:headless].to_s != 'false'),
207
- timeout: timeout)
196
+ def process event, config
197
+ timeout = config[:timeout] ? config[:timeout].to_i : 5
208
198
 
209
- get_the_cookies_from(event, config).each { |c| browser.cookies.set(c) }
199
+ browser = Ferrum::Browser.new(
200
+ headless: (config[:headless].to_s != 'false'),
201
+ timeout: timeout
202
+ )
210
203
 
211
- browser.headers.add get_the_headers_from(event, config)
204
+ get_the_cookies_from(event, config).each { |c| browser.cookies.set(c) }
212
205
 
213
- the_start = Time.now
214
- browser.goto config[:url]
215
- time = Time.now - the_start
206
+ browser.headers.add get_the_headers_from(event, config)
216
207
 
217
- browser.execute(config[:execute]) if config[:execute]
208
+ the_start = Time.now.utc
209
+ browser.goto config[:url]
210
+ time = Time.now.utc - the_start
218
211
 
219
- sleep(config[:wait_before_closing].to_i) if config[:wait_before_closing] && config[:wait_before_closing].to_i > 0
212
+ browser.execute(config[:execute]) if config[:execute]
220
213
 
221
- result = {
222
- url: browser.url,
223
- status: browser.network.status,
224
- title: browser.frames[0].title,
225
- cookies: browser.cookies.all.map { |k, v| v.instance_variable_get('@attributes') },
226
- headers: browser.headers.get,
227
- time: time,
228
- body: browser.body
229
- }
214
+ sleep(config[:wait_before_closing].to_i) if config[:wait_before_closing]&.to_i&.positive?
230
215
 
231
- result = adjust( { browser: browser, result: result, config: config } )
216
+ result = {
217
+ url: browser.url,
218
+ status: browser.network.status,
219
+ title: browser.frames[0].title,
220
+ cookies: browser.cookies.all.map { |_, v| v.instance_variable_get('@attributes') },
221
+ headers: browser.headers.get,
222
+ time: time,
223
+ body: browser.body
224
+ }
232
225
 
233
- browser.quit
226
+ result = adjust({ browser: browser, result: result, config: config })
234
227
 
235
- result
236
- end
228
+ browser.quit
237
229
 
238
- def adjust input
239
- input[:result]
240
- end
241
-
242
- def get_the_cookies_from event, config
243
- carry_cookies_from = config[:carry_cookies_from].to_s == '' ? 'cookies' : config[:carry_cookies_from]
244
- cookies = event[carry_cookies_from.to_sym]
245
- cookies = [] unless cookies.is_a?(Array)
246
- config[:cookies] = [] unless config[:cookies].is_a?(Array)
247
- config[:cookies].each { |x| cookies << x }
248
- cookies
249
- end
230
+ result
231
+ end
250
232
 
251
- def get_the_headers_from event, config
252
- carry_headers_from = config[:carry_headers_from].to_s == '' ? 'headers' : config[:carry_headers_from]
253
- headers = event[carry_headers_from.to_sym]
254
- headers = {} unless headers.is_a?(Hash)
255
- config[:headers] = {} unless config[:headers].is_a?(Hash)
256
- config[:headers].each { |k, v| headers[k] = v }
257
- headers
258
- end
233
+ def adjust(input)
234
+ input[:result]
235
+ end
259
236
 
237
+ def get_the_cookies_from(event, config)
238
+ carry_cookies_from = config[:carry_cookies_from].to_s == '' ? 'cookies' : config[:carry_cookies_from]
239
+ cookies = event[carry_cookies_from.to_sym]
240
+ cookies = [] unless cookies.is_a?(Array)
241
+ config[:cookies] = [] unless config[:cookies].is_a?(Array)
242
+ config[:cookies].each { |x| cookies << x }
243
+ cookies
260
244
  end
261
245
 
262
- end
246
+ def get_the_headers_from(event, config)
247
+ carry_headers_from = config[:carry_headers_from].to_s == '' ? 'headers' : config[:carry_headers_from]
248
+ headers = event[carry_headers_from.to_sym]
249
+ headers = {} unless headers.is_a?(Hash)
250
+ config[:headers] = {} unless config[:headers].is_a?(Hash)
251
+ config[:headers].each { |k, v| headers[k] = v }
252
+ headers
253
+ end
254
+ end
@@ -1,76 +1,68 @@
1
1
  require 'csv'
2
2
 
3
- module Mushy
4
-
5
- class BuildCsv < Flux
6
-
7
- def self.details
8
- {
9
- name: 'BuildCsv',
10
- title: "Build CSV",
11
- description: 'Build a CSV.',
12
- fluxGroup: { name: 'CSV' },
13
- config: {
14
- input_path: {
15
- description: 'The path to the set of records to include in the CSV.',
16
- type: 'text',
17
- value: 'records',
18
- },
19
- output_path: {
20
- description: 'The path to the CSV content in the outgoing event.',
21
- type: 'text',
22
- value: 'records',
23
- },
24
- headers: {
25
- description: 'The values to include in the CSV, as well as the header values.',
26
- type: 'keyvalue',
27
- value: {},
28
- },
29
- header_row: {
30
- description: 'Include a header row?',
31
- type: 'boolean',
32
- value: true,
33
- },
3
+ class Mushy::BuildCsv < Mushy::Flux
4
+ def self.details
5
+ {
6
+ name: 'BuildCsv',
7
+ title: 'Build CSV',
8
+ description: 'Build a CSV.',
9
+ fluxGroup: { name: 'CSV' },
10
+ config: {
11
+ input_path: {
12
+ description: 'The path to the set of records to include in the CSV.',
13
+ type: 'text',
14
+ value: 'records'
15
+ },
16
+ output_path: {
17
+ description: 'The path to the CSV content in the outgoing event.',
18
+ type: 'text',
19
+ value: 'records'
20
+ },
21
+ headers: {
22
+ description: 'The values to include in the CSV, as well as the header values.',
23
+ type: 'keyvalue',
24
+ value: {}
25
+ },
26
+ header_row: {
27
+ description: 'Include a header row?',
28
+ type: 'boolean',
29
+ value: true
30
+ }
31
+ },
32
+ examples: {
33
+ 'Build a Simple CSV' => {
34
+ description: 'Converts a set of records to a CSV.',
35
+ input: {
36
+ things: [
37
+ { name: 'Apple', color: 'Red' },
38
+ { name: 'Banana', color: 'Yellow' },
39
+ { name: 'Pear', color: 'Green' }
40
+ ]
41
+ },
42
+ config: {
43
+ input_path: 'things',
44
+ output_path: 'records',
45
+ headers: { name: 'Name', color: 'Color' },
46
+ header_row: true
47
+ },
48
+ result: {
49
+ records: 'Name,Color\nApple,Red\nBanana,Yellow\nPear,Green\n'
50
+ }
34
51
  },
35
- examples: {
36
- "Build a Simple CSV" => {
37
- description: 'Converts a set of records to a CSV.',
38
- input: {
39
- things: [
40
- { name: "Apple", color:"Red" },
41
- { name: "Banana", color: "Yellow" },
42
- { name: "Pear", color: "Green" }
43
- ]
44
- },
45
- config: {
46
- input_path: "things",
47
- output_path: "records",
48
- headers: { name: "Name", color: "Color" },
49
- header_row: true
50
- },
51
- result: {
52
- records: "Name,Color\nApple,Red\nBanana,Yellow\nPear,Green\n"
53
- }
54
- },
55
- }
56
52
  }
57
- end
58
-
59
- def process event, config
60
- records = event[config[:input_path].to_sym] || event[config[:input_path].to_s]
53
+ }
54
+ end
61
55
 
62
- headers = config[:headers]
56
+ def process(event, config)
57
+ records = event[config[:input_path].to_sym] || event[config[:input_path].to_s]
63
58
 
64
- {
65
- config[:output_path] => CSV.generate do |c|
66
- if config[:header_row].to_s == 'true'
67
- c << headers.map { |h| h[1] }
68
- end
69
- records.each { |x| c << headers.map { |h| x[h[0].to_sym] || x[h[0].to_s] } }
70
- end
71
- }
72
- end
59
+ headers = config[:headers]
73
60
 
61
+ {
62
+ config[:output_path] => CSV.generate do |c|
63
+ c << headers.map { |h| h[1] } if config[:header_row].to_s == 'true'
64
+ records.each { |x| c << headers.map { |h| x[h[0].to_sym] || x[h[0].to_s] } }
65
+ end
66
+ }
74
67
  end
75
-
76
- end
68
+ end