@mablhq/mabl-cli 1.50.4 → 1.51.6

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.
@@ -16,6 +16,9 @@ class MablStep extends MablAction_1.MablAction {
16
16
  canContinueOnFailure() {
17
17
  return false;
18
18
  }
19
+ canFailAtEnd() {
20
+ return false;
21
+ }
19
22
  getStepName() {
20
23
  return 'UnimplementedStep';
21
24
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AssertStep = exports.fieldToAssertionStep = exports.assertionStepToField = void 0;
3
+ exports.AssertStep = exports.fieldToAssertionStep = exports.assertionStepToField = exports.OnFailure = void 0;
4
4
  const ConditionAction_1 = require("../actions/ConditionAction");
5
5
  const FindAction_1 = require("../actions/FindAction");
6
6
  const MablStep_1 = require("../MablStep");
@@ -12,6 +12,12 @@ const GetCurrentLocationDescriptor_1 = require("../types/GetCurrentLocationDescr
12
12
  const GetVariableValue_1 = require("../actions/GetVariableValue");
13
13
  const GetVariableDescriptor_1 = require("../types/GetVariableDescriptor");
14
14
  const CountAction_1 = require("../actions/CountAction");
15
+ var OnFailure;
16
+ (function (OnFailure) {
17
+ OnFailure["ContinueWithWarning"] = "continue";
18
+ OnFailure["FailImmediately"] = "terminate";
19
+ OnFailure["FailTestAtEnd"] = "failAtEnd";
20
+ })(OnFailure = exports.OnFailure || (exports.OnFailure = {}));
15
21
  exports.assertionStepToField = {
16
22
  AssertEquals: 'equals',
17
23
  AssertPresent: 'present',
@@ -67,9 +73,17 @@ class AssertStep extends MablStep_1.MablStep {
67
73
  args[0] && typeof args[0] === 'object'
68
74
  ? args[0]
69
75
  : undefined;
70
- this.continueOnFailure = ((_a = this.assertArguments) === null || _a === void 0 ? void 0 : _a.onFailure) === 'continue';
76
+ this.onFailure =
77
+ ((_a = this.assertArguments) === null || _a === void 0 ? void 0 : _a.onFailure) ||
78
+ OnFailure.FailImmediately;
71
79
  this.observationScope = (_b = this.assertArguments) === null || _b === void 0 ? void 0 : _b.observationScope;
72
80
  }
81
+ canContinueOnFailure() {
82
+ return this.onFailure !== OnFailure.FailImmediately;
83
+ }
84
+ canFailAtEnd() {
85
+ return this.onFailure === OnFailure.FailTestAtEnd;
86
+ }
73
87
  validate() {
74
88
  if (!(this.actions.length === 2 || this.actions.length === 3) &&
75
89
  !(this.actions[0] instanceof FindAction_1.FindAction) &&
@@ -110,7 +124,7 @@ class AssertStep extends MablStep_1.MablStep {
110
124
  extractDescriptor: (_a = this.extractAction) === null || _a === void 0 ? void 0 : _a.extractDescriptor,
111
125
  conditionDescriptor: this.conditionAction.conditionDescriptor,
112
126
  countDescriptor: (_b = this.countAction) === null || _b === void 0 ? void 0 : _b.countDescriptor,
113
- continueOnFailure: this.continueOnFailure,
127
+ onFailure: this.onFailure,
114
128
  observationScope: this.observationScope,
115
129
  descriptorToActionMap,
116
130
  };
@@ -199,16 +213,21 @@ class AssertStep extends MablStep_1.MablStep {
199
213
  }
200
214
  return new AssertStep('assert', [
201
215
  {
202
- onFailure: stepArgs.continueOnFailure ? 'continue' : undefined,
216
+ onFailure: stepArgs.onFailure,
203
217
  observationScope: stepArgs.observationScope,
204
218
  },
205
219
  ], actions);
206
220
  }
207
221
  toMablscript() {
208
- var _a, _b;
222
+ var _a, _b, _c, _d;
209
223
  const assertAction = `.assert(${!!(((_a = this.assertArguments) === null || _a === void 0 ? void 0 : _a.onFailure) ||
210
224
  ((_b = this.assertArguments) === null || _b === void 0 ? void 0 : _b.observationScope))
211
- ? (0, MablAction_1.convertObjectToMablscriptArgs)(this.assertArguments)
225
+ ? (0, MablAction_1.convertObjectToMablscriptArgs)({
226
+ ...this.assertArguments,
227
+ onFailure: ((_c = this.assertArguments) === null || _c === void 0 ? void 0 : _c.onFailure) === OnFailure.FailImmediately
228
+ ? undefined
229
+ : (_d = this.assertArguments) === null || _d === void 0 ? void 0 : _d.onFailure,
230
+ })
212
231
  : ''})`;
213
232
  if (this.countAction) {
214
233
  return `${this.primaryAction.toMablscript()}.${this.countAction.toMablscript()}.${this.conditionAction.toMablscript()}${assertAction}`;
@@ -36,11 +36,11 @@ class AssertStepOld extends MablStep_1.MablStep {
36
36
  this.primaryAction = actions[0];
37
37
  this.extractAction = actions[1];
38
38
  if (args.length === 1) {
39
- this.continueOnFailure = args[0].onFailure === 'continue';
39
+ this.onFailure = args[0].onFailure;
40
40
  this.observationScope = args[0].observationScope;
41
41
  }
42
42
  else if (args.length === 2) {
43
- this.continueOnFailure = args[1].onFailure === 'continue';
43
+ this.onFailure = args[1].onFailure;
44
44
  this.observationScope = args[1].observationScope;
45
45
  }
46
46
  }
@@ -97,7 +97,7 @@ class AssertStepOld extends MablStep_1.MablStep {
97
97
  throw new Error(`Error generating step descriptor for ${this.getStepName()}: Unexpected find type ${find.findType}`);
98
98
  }
99
99
  }
100
- formatted.continueOnFailure = this.continueOnFailure;
100
+ formatted.onFailure = this.onFailure;
101
101
  formatted.observationScope = this.observationScope;
102
102
  return formatted;
103
103
  }
@@ -42,7 +42,7 @@ class IfConditionStep extends MablStep_1.MablStep {
42
42
  find,
43
43
  extractDescriptor: (_b = this.extractAction) === null || _b === void 0 ? void 0 : _b.extractDescriptor,
44
44
  conditionDescriptor,
45
- continueOnFailure: false,
45
+ onFailure: AssertStep_1.OnFailure.FailImmediately,
46
46
  descriptorToActionMap: new Map().set(find, this.primaryAction),
47
47
  };
48
48
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mablhq/mabl-cli",
3
- "version": "1.50.4",
3
+ "version": "1.51.6",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "description": "The official mabl command line interface tool",
6
6
  "main": "index.js",
@@ -48,13 +48,69 @@ mablEmbeddedPdfDetector = () => {
48
48
  }
49
49
  }
50
50
 
51
+ /**
52
+ * Returns the URL string of the element which should in some way be embedding a PDF.
53
+ * @param {HTMLElement} originalPdfElement The element embedding the PDF, should have embed tag, object tag,
54
+ * @returns {(string|undefined)} The URL which should host the PDF, or undefined if none was found
55
+ */
56
+ function getPdfUrlFromElement(originalPdfElement) {
57
+ return (
58
+ originalPdfElement.src ||
59
+ originalPdfElement.data || // embed has @src, object has @data
60
+ undefined
61
+ );
62
+ }
63
+
64
+ /**
65
+ * Checks that the URL embedding the PDF leads to a valid location and/or
66
+ * has a valid protocol
67
+ * @param {HTMLElement} element The element on the page whose URL to check
68
+ * @returns {boolean} Whether or not the element is valid
69
+ */
70
+ function checkUrlProtocol(element) {
71
+ if (element.src === 'about:blank') {
72
+ // this is likely the chrome viewer for a POST
73
+ // don't do anything, we might get a manual update later
74
+ // if the trainer finds a PDF
75
+ return false;
76
+ }
77
+ // Validate that the URL is an allowed protocol to prevent XSS, see IST-561
78
+ const pdfUrlString = getPdfUrlFromElement(element);
79
+ try {
80
+ const pdfUrl = new URL(pdfUrlString);
81
+ // data: is allowed to support embedding the PDF inline using a data URI scheme
82
+ const allowedProtocols = ['http:', 'https:', 'data:'];
83
+ if (!allowedProtocols.includes(pdfUrl?.protocol)) {
84
+ console.warn(
85
+ `PDF Handler ignoring element with URL ${pdfUrlString} because protocol ${pdfUrl?.protocol} does not match one of the allowed protocols ${allowedProtocols}`,
86
+ );
87
+ return false;
88
+ } else if (
89
+ pdfUrl?.protocol === 'data:' &&
90
+ !/^data:application\/pdf[,;]/.test(pdfUrl?.href ?? '') // starts with data:application/pdf and either , or ; separator
91
+ ) {
92
+ console.warn(
93
+ `PDF Handler ignoring element with URL ${pdfUrlString} because it does not use application/pdf MIME type`,
94
+ );
95
+ return false;
96
+ }
97
+ } catch (e) {
98
+ console.warn(
99
+ `PDF Handler ignoring element with URL ${pdfUrlString}; error ${e} was thrown while converting to URL`,
100
+ );
101
+ return false;
102
+ }
103
+ return true;
104
+ }
105
+
51
106
  async function handle(event) {
52
107
  const element = event.target;
53
108
  if (
54
109
  checkAnimationEvent(event) &&
55
110
  checkElement(element) &&
56
111
  checkMimeType(element) &&
57
- !isMablMarked(element)
112
+ !isMablMarked(element) &&
113
+ checkUrlProtocol(element)
58
114
  ) {
59
115
  const baseUri = document.baseURI;
60
116
  const pdfElement = element;
@@ -100,7 +156,7 @@ mablEmbeddedPdfDetector = () => {
100
156
 
101
157
  function checkMimeType(element) {
102
158
  const mimeType = element.type;
103
- const path = element.src || element.data; // src for embed, data for object
159
+ const path = getPdfUrlFromElement(element);
104
160
  const isAPdf =
105
161
  (mimeType && mimeType.toLowerCase() === 'application/pdf') || // mime type is PDF
106
162
  (!mimeType && path && /\.pdf($|[?#])/i.test(path)) || // or if we don't have a mime type test the path up to query or hash
@@ -130,6 +186,7 @@ const MABL_DEFAULT_PDF_NAME = 'mablPdf';
130
186
  function documentHasDocType() {
131
187
  return document.doctype && document.doctype.name;
132
188
  }
189
+
133
190
  function runEmbeddedPdfDetector() {
134
191
  if (documentHasDocType()) {
135
192
  mablEmbeddedPdfDetector();