param : function.getQueryString().entrySet()) {
203 | if (Parameter.isParameter(param.getValue())) {
204 | String paramName = Parameter.parameterDecode(param.getValue());
205 | sb.append(param.getKey() + "=\" + " + paramName + " + \"&");
206 | } else {
207 | sb.append(param.getKey() + "=" + param.getValue() + "&");
208 | }
209 | }
210 |
211 | if (sb.length() > 0) {
212 | sb.deleteCharAt(sb.length() - 1);
213 | }
214 |
215 | return sb.toString();
216 | }
217 | }
218 |
--------------------------------------------------------------------------------
/templates/triviacrack.gtf:
--------------------------------------------------------------------------------
1 | {
2 | "garglSchemaVersion": "1.0",
3 | "moduleVersion": "1.0",
4 | "moduleName": "TriviaCrack",
5 | "moduleDescription": "Integrate into the Trivia Crack game (https://apps.facebook.com/triviacrack/)",
6 | "functions": [
7 | {
8 | "request": {
9 | "method": "GET",
10 | "url": "https://api.preguntados.com/api/users/@UserID@",
11 | "httpVersion": "HTTP/1.1",
12 | "headers": [
13 | {
14 | "description": "",
15 | "name": "Eter-Agent",
16 | "value": "1|Web-FB|Chrome 39.0.2171.65|0|Windows|0|1.1||en||1"
17 | },
18 | {
19 | "description": "",
20 | "name": "Origin",
21 | "value": "https://preguntados.com"
22 | },
23 | {
24 | "description": "",
25 | "name": "Accept-Encoding",
26 | "value": "gzip, deflate, sdch"
27 | },
28 | {
29 | "description": "",
30 | "name": "etergames-referer",
31 | "value": "true"
32 | },
33 | {
34 | "description": "",
35 | "name": "Host",
36 | "value": "api.preguntados.com"
37 | },
38 | {
39 | "description": "",
40 | "name": "Accept-Language",
41 | "value": "en-US,en;q=0.8"
42 | },
43 | {
44 | "description": "",
45 | "name": "User-Agent",
46 | "value": "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36"
47 | },
48 | {
49 | "description": "",
50 | "name": "Content-Type",
51 | "value": "application/json; charset=utf-8"
52 | },
53 | {
54 | "description": "",
55 | "name": "Accept",
56 | "value": "application/json, text/javascript, */*; q=0.01"
57 | },
58 | {
59 | "description": "",
60 | "name": "Referer",
61 | "value": "https://preguntados.com/game/"
62 | },
63 | {
64 | "description": "",
65 | "name": "Connection",
66 | "value": "keep-alive"
67 | },
68 | {
69 | "description": "",
70 | "name": "Eter-Session",
71 | "value": "ap_session=undefined"
72 | }
73 | ],
74 | "queryString": [
75 | {
76 | "description": "Integer value representing the number of milliseconds since 1 January 1970 00:00:00 UTC (Unix Epoch).",
77 | "name": "_",
78 | "value": "@TimestampInMilliseconds@"
79 | }
80 | ]
81 | },
82 | "response": {
83 | "headers": [
84 | {
85 | "name": "Date"
86 | },
87 | {
88 | "name": "Server"
89 | },
90 | {
91 | "name": "Vary"
92 | },
93 | {
94 | "name": "Access-Control-Allow-Methods"
95 | },
96 | {
97 | "name": "Content-Type"
98 | },
99 | {
100 | "name": "Access-Control-Allow-Origin"
101 | },
102 | {
103 | "name": "Access-Control-Allow-Credentials"
104 | },
105 | {
106 | "name": "Connection"
107 | },
108 | {
109 | "name": "Accept-Ranges"
110 | },
111 | {
112 | "name": "Access-Control-Allow-Headers"
113 | },
114 | {
115 | "name": "Content-Length"
116 | }
117 | ],
118 | "fields": []
119 | },
120 | "connection": "745790",
121 | "functionName": "GetUserData",
122 | "functionDescription": "Get data about a trivia crack user"
123 | },
124 | {
125 | "request": {
126 | "method": "GET",
127 | "url": "https://api.preguntados.com/api/products",
128 | "httpVersion": "HTTP/1.1",
129 | "headers": [
130 | {
131 | "description": "",
132 | "name": "Eter-Agent",
133 | "value": "1|Web-FB|Chrome 39.0.2171.65|0|Windows|0|1.1|en|en||1"
134 | },
135 | {
136 | "description": "",
137 | "name": "Origin",
138 | "value": "https://preguntados.com"
139 | },
140 | {
141 | "description": "",
142 | "name": "Accept-Encoding",
143 | "value": "gzip, deflate, sdch"
144 | },
145 | {
146 | "description": "",
147 | "name": "etergames-referer",
148 | "value": "true"
149 | },
150 | {
151 | "description": "",
152 | "name": "Host",
153 | "value": "api.preguntados.com"
154 | },
155 | {
156 | "description": "",
157 | "name": "Accept-Language",
158 | "value": "en-US,en;q=0.8"
159 | },
160 | {
161 | "description": "",
162 | "name": "User-Agent",
163 | "value": "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36"
164 | },
165 | {
166 | "description": "",
167 | "name": "Content-Type",
168 | "value": "application/json; charset=utf-8"
169 | },
170 | {
171 | "description": "",
172 | "name": "Accept",
173 | "value": "application/json, text/javascript, */*; q=0.01"
174 | },
175 | {
176 | "description": "",
177 | "name": "Referer",
178 | "value": "https://preguntados.com/game/"
179 | },
180 | {
181 | "description": "",
182 | "name": "Connection",
183 | "value": "keep-alive"
184 | },
185 | {
186 | "description": "",
187 | "name": "Eter-Session",
188 | "value": "ap_session=undefined"
189 | }
190 | ],
191 | "queryString": [
192 | {
193 | "description": "",
194 | "name": "market_type",
195 | "value": "FACEBOOK"
196 | },
197 | {
198 | "description": "Integer value representing the number of milliseconds since 1 January 1970 00:00:00 UTC (Unix Epoch).",
199 | "name": "_",
200 | "value": "@TimestampInMilliseconds@"
201 | }
202 | ]
203 | },
204 | "response": {
205 | "headers": [
206 | {
207 | "name": "Date"
208 | },
209 | {
210 | "name": "Server"
211 | },
212 | {
213 | "name": "Vary"
214 | },
215 | {
216 | "name": "Access-Control-Allow-Methods"
217 | },
218 | {
219 | "name": "Content-Type"
220 | },
221 | {
222 | "name": "Access-Control-Allow-Origin"
223 | },
224 | {
225 | "name": "Access-Control-Allow-Credentials"
226 | },
227 | {
228 | "name": "Connection"
229 | },
230 | {
231 | "name": "Accept-Ranges"
232 | },
233 | {
234 | "name": "Access-Control-Allow-Headers"
235 | },
236 | {
237 | "name": "Content-Length"
238 | }
239 | ],
240 | "fields": []
241 | },
242 | "connection": "745790",
243 | "functionName": "GetProducts",
244 | "functionDescription": "Get Trivia Crack products"
245 | },
246 | {
247 | "request": {
248 | "method": "GET",
249 | "url": "https://api.preguntados.com/api/users/@UserID@/dashboard",
250 | "httpVersion": "HTTP/1.1",
251 | "headers": [
252 | {
253 | "description": "",
254 | "name": "Eter-Agent",
255 | "value": "1|Web-FB|Chrome 39.0.2171.65|0|Windows|0|1.1|en|en||1"
256 | },
257 | {
258 | "description": "",
259 | "name": "Origin",
260 | "value": "https://preguntados.com"
261 | },
262 | {
263 | "description": "",
264 | "name": "Accept-Encoding",
265 | "value": "gzip, deflate, sdch"
266 | },
267 | {
268 | "description": "",
269 | "name": "etergames-referer",
270 | "value": "true"
271 | },
272 | {
273 | "description": "",
274 | "name": "Host",
275 | "value": "api.preguntados.com"
276 | },
277 | {
278 | "description": "",
279 | "name": "Accept-Language",
280 | "value": "en-US,en;q=0.8"
281 | },
282 | {
283 | "description": "",
284 | "name": "User-Agent",
285 | "value": "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36"
286 | },
287 | {
288 | "description": "",
289 | "name": "Content-Type",
290 | "value": "application/json; charset=utf-8"
291 | },
292 | {
293 | "description": "",
294 | "name": "Accept",
295 | "value": "application/json, text/javascript, */*; q=0.01"
296 | },
297 | {
298 | "description": "",
299 | "name": "Referer",
300 | "value": "https://preguntados.com/game/"
301 | },
302 | {
303 | "description": "",
304 | "name": "Connection",
305 | "value": "keep-alive"
306 | },
307 | {
308 | "description": "",
309 | "name": "Eter-Session",
310 | "value": "ap_session=undefined"
311 | }
312 | ],
313 | "queryString": [
314 | {
315 | "description": "",
316 | "name": "app_config_version",
317 | "value": "1418500689"
318 | },
319 | {
320 | "description": "Integer value representing the number of milliseconds since 1 January 1970 00:00:00 UTC (Unix Epoch).",
321 | "name": "_",
322 | "value": "@TimestampInMilliseconds@"
323 | }
324 | ]
325 | },
326 | "response": {
327 | "headers": [
328 | {
329 | "name": "Date"
330 | },
331 | {
332 | "name": "Server"
333 | },
334 | {
335 | "name": "transfer-encoding"
336 | },
337 | {
338 | "name": "Vary"
339 | },
340 | {
341 | "name": "Access-Control-Allow-Methods"
342 | },
343 | {
344 | "name": "Content-Type"
345 | },
346 | {
347 | "name": "Access-Control-Allow-Origin"
348 | },
349 | {
350 | "name": "Access-Control-Allow-Credentials"
351 | },
352 | {
353 | "name": "Connection"
354 | },
355 | {
356 | "name": "Accept-Ranges"
357 | },
358 | {
359 | "name": "Access-Control-Allow-Headers"
360 | }
361 | ],
362 | "fields": []
363 | },
364 | "connection": "745790",
365 | "functionName": "GetDashboard",
366 | "functionDescription": "Get Trivia Crack Dashboard"
367 | },
368 | {
369 | "request": {
370 | "method": "GET",
371 | "url": "https://api.preguntados.com/api/users/@UserID@/games/@GameID@",
372 | "httpVersion": "HTTP/1.1",
373 | "headers": [
374 | {
375 | "description": "",
376 | "name": "Eter-Agent",
377 | "value": "1|Web-FB|Chrome 39.0.2171.65|0|Windows|0|1.1|en|en||1"
378 | },
379 | {
380 | "description": "",
381 | "name": "Origin",
382 | "value": "https://preguntados.com"
383 | },
384 | {
385 | "description": "",
386 | "name": "Accept-Encoding",
387 | "value": "gzip, deflate, sdch"
388 | },
389 | {
390 | "description": "",
391 | "name": "etergames-referer",
392 | "value": "true"
393 | },
394 | {
395 | "description": "",
396 | "name": "Host",
397 | "value": "api.preguntados.com"
398 | },
399 | {
400 | "description": "",
401 | "name": "Accept-Language",
402 | "value": "en-US,en;q=0.8"
403 | },
404 | {
405 | "description": "",
406 | "name": "User-Agent",
407 | "value": "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36"
408 | },
409 | {
410 | "description": "",
411 | "name": "Content-Type",
412 | "value": "application/json; charset=utf-8"
413 | },
414 | {
415 | "description": "",
416 | "name": "Accept",
417 | "value": "application/json, text/javascript, */*; q=0.01"
418 | },
419 | {
420 | "description": "",
421 | "name": "Referer",
422 | "value": "https://preguntados.com/game/"
423 | },
424 | {
425 | "description": "",
426 | "name": "Connection",
427 | "value": "keep-alive"
428 | },
429 | {
430 | "description": "",
431 | "name": "Eter-Session",
432 | "value": "ap_session=undefined"
433 | }
434 | ],
435 | "queryString": [
436 | {
437 | "description": "Integer value representing the number of milliseconds since 1 January 1970 00:00:00 UTC (Unix Epoch).",
438 | "name": "_",
439 | "value": "@TimestampInMilliseconds@"
440 | }
441 | ]
442 | },
443 | "response": {
444 | "headers": [
445 | {
446 | "name": "Date"
447 | },
448 | {
449 | "name": "Server"
450 | },
451 | {
452 | "name": "Vary"
453 | },
454 | {
455 | "name": "Access-Control-Allow-Methods"
456 | },
457 | {
458 | "name": "Content-Type"
459 | },
460 | {
461 | "name": "Access-Control-Allow-Origin"
462 | },
463 | {
464 | "name": "Access-Control-Allow-Credentials"
465 | },
466 | {
467 | "name": "Connection"
468 | },
469 | {
470 | "name": "Accept-Ranges"
471 | },
472 | {
473 | "name": "Access-Control-Allow-Headers"
474 | },
475 | {
476 | "name": "Content-Length"
477 | }
478 | ],
479 | "fields": []
480 | },
481 | "connection": "747627",
482 | "functionName": "GetGameData",
483 | "functionDescription": "Get Trivia Crack game data"
484 | }
485 | ]
486 | }
--------------------------------------------------------------------------------
/recorders/chrome/Panel/gargl.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var shouldRecord = false;
3 | var garglItems = [];
4 | var nextId = 0;
5 |
6 | const maxUrlLength = 90;
7 | const garglSchemaVersion = "1.0";
8 |
9 | const removeButtonHtml = " 0) string += (alternateSeperatorBetweenKeyAndValue || "=") + param.value;
90 | }
91 |
92 | return string;
93 | }
94 |
95 | function addRowToGarglItemsTable(idNumber, garglItem) {
96 | var removeButtonId = "removeButton" + idNumber;
97 | var editButtonId = "editButton" + idNumber;
98 | var detailsButtonId = "detailsButton" + idNumber;
99 |
100 | var funcNameInputId = "funcNameInput" + idNumber;
101 | var funcUrlId = "funcUrlId" + idNumber;
102 | var funcMethodId = "funcMethodId" + idNumber;
103 |
104 | var url = garglItem.request.url;
105 | var method = garglItem.request.method;
106 |
107 | if(url.length > maxUrlLength) url = url.substr(0,maxUrlLength) + "..."
108 |
109 | var tr = document.createElement("tr");
110 | tr.setAttribute("class","garglTableEntry");
111 | tr.innerHTML = "| " + functionNameInputHtml + " id='" + funcNameInputId + "' value='" + (garglItem.functionName || "") + "' /> | ";
112 | tr.innerHTML += "" + url + " | ";
113 | tr.innerHTML += "" + method + " | ";
114 | tr.innerHTML += "" + detailsButtonHtml + " id='" + detailsButtonId + "' /> | ";
115 | tr.innerHTML += "" + editButtonHtml + " id='" + editButtonId + "' /> | ";
116 | tr.innerHTML += "" + removeButtonHtml + " id='" + removeButtonId + "' /> | ";
117 |
118 | document.querySelector(garglTableSelector).appendChild(tr);
119 |
120 | var removeButton = document.querySelector("#" + removeButtonId);
121 | removeButton.addEventListener('click', function() {
122 | removeGarglItem(idNumber, removeButton);
123 | });
124 |
125 | var editButton = document.querySelector("#" + editButtonId);
126 | editButton.addEventListener('click', function() {
127 | showEditForm(idNumber);
128 | });
129 |
130 | var detailsButton = document.querySelector("#" + detailsButtonId);
131 | detailsButton.addEventListener('click', function() {
132 | showDetails(idNumber);
133 | });
134 | }
135 |
136 | function updateRowInGarglItemsTable(idNumber, garglItem) {
137 | var funcNameInputId = "funcNameInput" + idNumber;
138 | var funcUrlId = "funcUrlId" + idNumber;
139 | var funcMethodId = "funcMethodId" + idNumber;
140 |
141 | var url = garglItem.request.url;
142 | if(url.length > maxUrlLength) url = url.substr(0,maxUrlLength) + "..."
143 |
144 | document.querySelector("#"+funcNameInputId).value = garglItem.functionName;
145 | document.querySelector("#"+funcUrlId).innerHTML = url;
146 | document.querySelector("#"+funcMethodId).innerHTML = garglItem.request.method;
147 | }
148 |
149 | function showEditForm(idNumber) {
150 | var garglItem = garglItems[idNumber];
151 | garglItem.functionName = getFunctionName(idNumber);
152 |
153 | document.querySelector(garglEditFormFunctionIdNumberSelector).value = idNumber;
154 | document.querySelector(garglEditFormFunctionNameSelector).value = garglItem.functionName;
155 | document.querySelector(garglEditFormFunctionDescriptionSelector).value = garglItem.functionDescription || "";
156 | document.querySelector(garglEditFormFunctionRequestURLSelector).value = garglItem.request.url;
157 | document.querySelector(garglEditFormFunctionRequestMethodSelector).value = garglItem.request.method;
158 |
159 | createRequestFieldForm(garglEditFormFunctionRequestHeadersSelector, garglItem.request.headers);
160 | createRequestFieldForm(garglEditFormFunctionRequestQueryStringSelector, garglItem.request.queryString);
161 |
162 | if(garglItem.request.postData) {
163 | createRequestFieldForm(garglEditFormFunctionRequestPostDataSelector, garglItem.request.postData);
164 | }
165 | else createRequestFieldForm(garglEditFormFunctionRequestPostDataSelector, null);
166 |
167 | if(garglItem.response.fields) {
168 | garglItem.response.fields.forEach(function(field) {
169 | addResponseField(null, field.name, field.cssSelector);
170 | })
171 | };
172 |
173 | document.querySelector(garglRecordAreaSelector).style.display = "none";
174 | document.querySelector(garglStartFormSelector).style.display = "none";
175 | document.querySelector(garglOpenFormSelector).style.display = "none";
176 | document.querySelector(garglEditFormSelector).style.display = "block";
177 | }
178 |
179 | function createRequestFieldForm(formAreaSelector, requestFieldArray) {
180 | var formAreaElement = document.querySelector(formAreaSelector);
181 |
182 | if(!requestFieldArray || requestFieldArray.length == 0) formAreaElement.style.display = "none";
183 | else {
184 | var lastRequestFieldElement = null;
185 | formAreaElement.style.display = "block";
186 |
187 | requestFieldArray.forEach(function(requestField) {
188 | var requestFieldId = "requestField" + requestField.name;
189 |
190 | var span = document.createElement("span");
191 | span.setAttribute("class", garglRequestFieldElementClass);
192 |
193 | span.innerHTML = "
";
194 | span.innerHTML += "";
195 |
196 | formAreaElement.appendChild(span);
197 | lastRequestFieldElement = span;
198 | });
199 |
200 | var br1 = document.createElement("br");
201 | var br2 = document.createElement("br");
202 | lastRequestFieldElement.appendChild(br1);
203 | lastRequestFieldElement.appendChild(br2);
204 | }
205 | }
206 |
207 | function grabRequestFieldFormData(formAreaSelector) {
208 | var fieldData = [];
209 | var formAreaElement = document.querySelector(formAreaSelector);
210 |
211 | if(formAreaElement.style.display != "none") {
212 |
213 | var fieldElements = formAreaElement.querySelectorAll("." + garglRequestFieldElementClass);
214 |
215 | for(var i = 0; i < fieldElements.length; i ++) {
216 | var field = {
217 | description: "",
218 | name: fieldElements[i].querySelector("label").innerHTML.replace(": ",""),
219 | value: fieldElements[i].querySelector("input").value,
220 | };
221 |
222 | fieldData.push(field);
223 | }
224 | }
225 |
226 | return fieldData;
227 | }
228 |
229 | function cancelEditGarglItem() {
230 | var requestFieldElements = document.querySelectorAll("." + garglRequestFieldElementClass);
231 | var responseFieldElements = document.querySelectorAll("." + garglResponseFieldElementClass);
232 |
233 | if(requestFieldElements) {
234 | for(var i = 0; i < requestFieldElements.length; i ++) {
235 | requestFieldElements[i].parentNode.removeChild(requestFieldElements[i]);
236 | };
237 | }
238 |
239 | if(responseFieldElements) {
240 | for(var i = 0; i < responseFieldElements.length; i ++) {
241 | responseFieldElements[i].parentNode.removeChild(responseFieldElements[i]);
242 | };
243 | }
244 |
245 | startGargl();
246 | }
247 |
248 | function saveEditGarglItem() {
249 | var idNumber = document.querySelector(garglEditFormFunctionIdNumberSelector).value;
250 |
251 | var garglItem = garglItems[idNumber];
252 |
253 | garglItem.functionName = document.querySelector(garglEditFormFunctionNameSelector).value;
254 | garglItem.functionDescription = document.querySelector(garglEditFormFunctionDescriptionSelector).value;
255 | garglItem.request.url = document.querySelector(garglEditFormFunctionRequestURLSelector).value;
256 | garglItem.request.method = document.querySelector(garglEditFormFunctionRequestMethodSelector).value;
257 |
258 | garglItem.request.headers = grabRequestFieldFormData(garglEditFormFunctionRequestHeadersSelector);
259 | garglItem.request.queryString = grabRequestFieldFormData(garglEditFormFunctionRequestQueryStringSelector);
260 |
261 | if(garglItem.request.postData) {
262 | garglItem.request.postData = grabRequestFieldFormData(garglEditFormFunctionRequestPostDataSelector);
263 | }
264 |
265 | garglItem.response.fields = grabResponseFieldFormData();
266 |
267 | updateRowInGarglItemsTable(idNumber, garglItem);
268 | cancelEditGarglItem();
269 | }
270 |
271 | function removeGarglItem(idNumber, removeButton) {
272 | garglItems[idNumber] = null;
273 |
274 | var tr = removeButton.parentNode.parentNode;
275 | tr.parentNode.removeChild(tr);
276 | }
277 |
278 | function showDetails(idNumber) {
279 | var garglItem = garglItems[idNumber];
280 | var garglRequest = garglItem.request
281 |
282 | garglItem.functionName = getFunctionName(idNumber);
283 |
284 | var detailsString = "Function Name: " + garglItem.functionName || "";
285 | detailsString += "\nFunction Description: " + garglItem.functionDescription || "";
286 |
287 | detailsString += "\n\nFunction Request URL: " + garglRequest.url;
288 | detailsString += "\nFunction Request Method: " + garglRequest.method;
289 |
290 | if(garglRequest.queryString && garglRequest.queryString.length > 0) {
291 | detailsString += "\n\nFunction Request Query String:\n" + convertRequestFieldArrayToString(garglRequest.queryString, "\n", ": ");
292 | }
293 |
294 | if(garglRequest.postData && garglRequest.postData.length > 0) {
295 | detailsString += "\n\nFunction Request Post Data:\n" + convertRequestFieldArrayToString(garglRequest.postData, "\n", ": ");
296 | }
297 |
298 | alert(detailsString);
299 | }
300 |
301 | function getFunctionName(id) {
302 | return document.querySelector("#funcNameInput" + id).value.replace(/ /g, "-");
303 | }
304 |
305 | function trackRequest(request) {
306 | var urlWithoutQueryString = removeQueryStringFromUrl(request.request.url);
307 | var domain = getDomainOfUrl(urlWithoutQueryString);
308 |
309 | if(shouldRecord && !urlWithoutQueryString.match(/.gif$|.jpeg$|.jpg$|.png$|.js$|.css$|.swf$/)) {
310 | var domainMustContain = document.querySelector(garglDomainSearchSelector).value;
311 | if(domainMustContain.length > 0 && domain.indexOf(domainMustContain) === -1) return;
312 |
313 | addGarglMetadataToItem(request);
314 | removeUnneededMetadataFromItem(request);
315 |
316 | garglItems.push(request);
317 |
318 | addRowToGarglItemsTable(nextId, request);
319 | nextId ++;
320 | }
321 | }
322 |
323 | function cleanUpDownloadLink(a) {
324 | a.textContent = 'Downloaded';
325 | a.dataset.disabled = true;
326 |
327 | // Need a small delay for the revokeObjectURL to work properly.
328 | setTimeout(function() {
329 | window.URL.revokeObjectURL(a.href);
330 | a.parentNode.removeChild(a);
331 | }, 1500);
332 | }
333 |
334 | function createDownloadLink() {
335 | window.URL = window.webkitURL || window.URL;
336 | var prevLink = document.querySelector('a');
337 | var moduleName = document.querySelector(garglModuleNameSelector).value.replace(/ /g, "-");
338 | var moduleDescription = document.querySelector(garglModuleDescriptionSelector).value;
339 |
340 | if (prevLink) window.URL.revokeObjectURL(prevLink.href);
341 |
342 | var garglItemsWithoutEmptys = [];
343 | garglItems.forEach(function(item, itemIndex) {
344 | if(item) {
345 | item.functionName = getFunctionName(itemIndex);
346 | garglItemsWithoutEmptys.push(item);
347 | }
348 | });
349 |
350 | var garglFormattedItems = {
351 | garglSchemaVersion: garglSchemaVersion,
352 | moduleVersion: "1.0",
353 | moduleName: moduleName,
354 | moduleDescription: moduleDescription,
355 | functions: garglItemsWithoutEmptys
356 | };
357 |
358 | var fileContents = JSON.stringify(garglFormattedItems, null, "\t");
359 | var bb = new Blob([fileContents], {type: 'text/plain'});
360 |
361 | var a = prevLink || document.createElement('a');
362 | a.download = ((moduleName.length > 0 ? moduleName.toLowerCase() : "gargl") + ".gtf");
363 | a.href = window.URL.createObjectURL(bb);
364 | a.textContent = 'Click to download';
365 |
366 | a.dataset.downloadurl = ['text/plain', a.download, a.href].join(':');
367 |
368 | document.querySelector(garglSaveHolderSelector).appendChild(a);
369 |
370 | a.onclick = function(e) {
371 | if ('disabled' in this.dataset) return false;
372 | cleanUpDownloadLink(this);
373 | };
374 | }
375 |
376 | function removeUnneededMetadataFromItem(item) {
377 | delete(item.startedDateTime);
378 | delete(item.time);
379 | delete(item.cache);
380 | delete(item.timings);
381 | delete(item.pageref);
382 |
383 | delete(item.request.headersSize);
384 | delete(item.request.bodySize);
385 | delete(item.request.cookies);
386 |
387 | if(item.request) {
388 | if(item.request.postData && item.request.postData.params) {
389 | item.request.postData = item.request.postData.params;
390 | }
391 | item.request.headers = removeUnneededHeaders(item.request.headers, /Cookie|Content-Length/i, false);
392 | }
393 |
394 | if(item.response) {
395 | var responseFields = item.response.fields || [];
396 | item.response = {
397 | headers: removeUnneededHeaders(item.response.headers, null, true),
398 | fields: responseFields
399 | };
400 | }
401 | }
402 |
403 | function addGarglMetadataToItem(item) {
404 | if(item.request) {
405 | item.request.url = removeQueryStringFromUrl(item.request.url);
406 |
407 | if(item.request.queryString) {
408 | item.request.queryString.forEach(function(queryArg) {
409 | queryArg.description = "";
410 | queryArg.name = decodeURIComponent(queryArg.name);
411 | queryArg.value = decodeURIComponent(queryArg.value);
412 | });
413 | }
414 |
415 | if(item.request.postData) {
416 | var postData = item.request.postData;
417 | var params = postData.params || postData;
418 | params.forEach(function(postArg) {
419 | postArg.description = "";
420 | postArg.name = decodeURIComponent(postArg.name);
421 | postArg.value = decodeURIComponent(postArg.value);
422 | });
423 | }
424 | }
425 | }
426 |
427 | function removeUnneededHeaders(headersArray, regexForUnneeded, removeHeaderValuesFromAll) {
428 | var headersToKeep = [];
429 | headersArray.forEach(function (header) {
430 | if(removeHeaderValuesFromAll) delete(header.value);
431 |
432 | if(!header.name.match(regexForUnneeded)) headersToKeep.push(header)
433 | });
434 |
435 | return headersToKeep;
436 | }
437 |
438 | function startGargl() {
439 | document.querySelector(garglRecordAreaSelector).style.display = "block";
440 | document.querySelector(garglStartFormSelector).style.display = "none";
441 | document.querySelector(garglOpenFormSelector).style.display = "none";
442 | document.querySelector(garglEditFormSelector).style.display = "none";
443 | }
444 |
445 | function showOpenForm() {
446 | document.querySelector(garglRecordAreaSelector).style.display = "none";
447 | document.querySelector(garglStartFormSelector).style.display = "none";
448 | document.querySelector(garglOpenFormSelector).style.display = "block";
449 | document.querySelector(garglEditFormSelector).style.display = "none";
450 | }
451 |
452 | function processFile() {
453 | var file = document.querySelector(garglOpenSelector).files[0];
454 |
455 | var extensionIndex = file.name.indexOf(".gtf");
456 | if(extensionIndex == -1 || extensionIndex != (file.name.length - 4)) {
457 | alert("File must be a gargle template file (.gtf)");
458 | }
459 | else {
460 | var reader = new FileReader();
461 |
462 | reader.addEventListener("load", function(event) {
463 | var text = event.target.result;
464 | var garglModule = JSON.parse(text);
465 |
466 | document.querySelector(garglModuleNameSelector).value = garglModule.moduleName;
467 | document.querySelector(garglModuleDescriptionSelector).value = garglModule.moduleDescription;
468 |
469 | shouldRecord = true;
470 | garglModule.functions.forEach(function(item) { trackRequest(item); });
471 | shouldRecord = false;
472 |
473 | startGargl();
474 | });
475 |
476 | reader.readAsText(file);
477 | }
478 | }
479 |
480 | function addResponseField(clickEvent, responseName, responseSelector) {
481 | responseName = responseName || "";
482 | responseSelector = responseSelector || "";
483 |
484 | var responseFieldsArea = document.querySelector(editFormFunctionResponseFieldsSelector);
485 |
486 | var nextResponseId = responseFieldsArea.querySelectorAll("."+garglResponseFieldElementClass).length;
487 | var fieldNameId = "editFormFunctionResponseFieldName" + nextResponseId;
488 | var fieldSelectorId = "editFormFunctionResponseFieldSelector" + nextResponseId;
489 | var fieldSelectorTestId = "editFormFunctionResponseFieldTest" + nextResponseId;
490 |
491 | var span = document.createElement("span");
492 | span.setAttribute("class", garglResponseFieldElementClass);
493 |
494 | span.innerHTML = '';
495 | span.innerHTML += '';
496 | span.innerHTML += '
';
497 | span.innerHTML += '';
498 | span.innerHTML += '';
499 | span.innerHTML += ''
500 | span.innerHTML += '
';
501 |
502 | responseFieldsArea.appendChild(span);
503 |
504 | document.querySelector("#"+fieldSelectorTestId).onclick = function() {
505 | var idNumber = document.querySelector(garglEditFormFunctionIdNumberSelector).value;
506 | var selectorString = document.querySelector("#"+fieldSelectorId).value;
507 |
508 | var garglItem = garglItems[idNumber];
509 |
510 | if(garglItem.getContent) {
511 | garglItem.getContent(function(content, encoding) {
512 | try {
513 | content = content.replace(/\n|\t/g,"")
514 |
515 | var holder = document.createElement("span");
516 | holder.innerHTML = content;
517 |
518 | var matches = holder.querySelectorAll(selectorString);
519 |
520 | if(matches.length > 0) {
521 | var matchString = "Inner contents of matching elements:\n\n"
522 |
523 | for(var i = 0; i < matches.length; i ++) {
524 | var contents = null;
525 |
526 | if(matches[i].nodeName.match(/input|textarea/i)) {
527 | contents = matches[i].value;
528 | }
529 | else contents = matches[i].innerHTML;
530 |
531 | matchString += (contents + "\n\n");
532 | }
533 |
534 | alert(matchString);
535 | }
536 | else alert("No matching elements found");
537 | }
538 | catch(e) {
539 | alert(e);
540 | }
541 | });
542 | }
543 | else {
544 | alert(garglFileGetResponseError);
545 | }
546 | };
547 |
548 | document.querySelector("#"+fieldNameId).focus();
549 | }
550 |
551 | function viewResponse() {
552 | var idNumber = document.querySelector(garglEditFormFunctionIdNumberSelector).value;
553 | var garglItem = garglItems[idNumber];
554 |
555 | if(garglItem.getContent) {
556 | garglItem.getContent(function(content, encoding) {
557 | window.URL = window.webkitURL || window.URL;
558 |
559 | var responseTextarea = document.getElementById("responseTextarea");
560 | var prevLink = document.querySelector('a');
561 | if (prevLink) window.URL.revokeObjectURL(prevLink.href);
562 |
563 | var fileContents = content;
564 | var bb = new Blob([fileContents], {type: 'text/plain'});
565 |
566 |
567 | if (responseTextarea) { //if we already added a textare, just change value of it
568 | responseTextarea.value = fileContents;
569 | } else { //if we didn't added a textarea yet, add one
570 | responseTextarea = document.createElement('input');
571 | responseTextarea.type = "textarea";
572 | responseTextarea.id = "responseTextarea";
573 | responseTextarea.value = fileContents;
574 | responseTextarea.style.position = "fixed";
575 | responseTextarea.style.zIndex = "-1";
576 | responseTextarea.style.top = "-1000px";
577 |
578 | var garglCopyResponseBtn = document.createElement('input');
579 | garglCopyResponseBtn.type = "button"
580 | garglCopyResponseBtn.id = "garglCopyResponseBtn";
581 | garglCopyResponseBtn.value = "Copy Response";
582 |
583 | document.querySelector(garglViewResponseHolderSelector).appendChild(garglCopyResponseBtn);
584 | document.querySelector(garglViewResponseHolderSelector).appendChild(responseTextarea);
585 |
586 | garglCopyResponseBtn.addEventListener('click', function(e) {
587 | responseTextarea.select();
588 |
589 | try {
590 | var successful = document.execCommand('copy');
591 | if(!successful)
592 | alert('Unable to copy!');
593 | } catch (err) {
594 | alert('Unsupported Browser!');
595 | }
596 | });
597 | }
598 |
599 | var a = prevLink || document.createElement('a');
600 | a.download = "response.txt";
601 | a.href = window.URL.createObjectURL(bb);
602 | a.textContent = 'Click to download';
603 |
604 | a.dataset.downloadurl = ['text/plain', a.download, a.href].join(':');
605 |
606 | document.querySelector(garglViewResponseHolderSelector).appendChild(a);
607 |
608 | a.onclick = function(e) {
609 | if ('disabled' in this.dataset) return false;
610 | cleanUpDownloadLink(this);
611 | };
612 | });
613 | }
614 | else {
615 | alert(garglFileGetResponseError);
616 | }
617 | }
618 |
619 | function grabResponseFieldFormData() {
620 | var fieldData = [];
621 | var fieldElements = document.querySelectorAll("." + garglResponseFieldElementClass);
622 |
623 | for(var i = 0; i < fieldElements.length; i ++) {
624 | var fieldInputs = fieldElements[i].querySelectorAll("input");
625 |
626 | var field = {
627 | name: fieldInputs[0].value.replace(/ /g,"-"),
628 | cssSelector: fieldInputs[1].value
629 | };
630 |
631 | if(field.name.length > 0 && field.cssSelector.length > 0) fieldData.push(field);
632 | }
633 |
634 | return fieldData;
635 | }
636 |
637 | window.addEventListener('load', function() {
638 | document.querySelector(garglRecordSelector).onclick = toggleRecord;
639 | document.querySelector(garglClearSelector).onclick = clearGarglItemsTable;
640 | document.querySelector(garglSaveSelector).onclick = createDownloadLink;
641 | document.querySelector(garglNewSelector).onclick = startGargl;
642 | document.querySelector(garglExistingSelector).onclick = showOpenForm;
643 | document.querySelector(garglEditSaveSelector).onclick = saveEditGarglItem;
644 | document.querySelector(garglEditCancelSelector).onclick = cancelEditGarglItem;
645 | document.querySelector(garglNewResponseFieldSelector).onclick = addResponseField;
646 | document.querySelector(garglViewResponseSelector).onclick = viewResponse;
647 |
648 | document.querySelector(garglOpenSelector).onchange = processFile;
649 |
650 | document.querySelector(garglRecordAreaSelector).style.display = "none";
651 | document.querySelector(garglOpenFormSelector).style.display = "none";
652 | document.querySelector(garglEditFormSelector).style.display = "none";
653 | });
654 |
655 | chrome.devtools.network.onRequestFinished.addListener(trackRequest);
656 | })();
657 |
--------------------------------------------------------------------------------