@reality.eth/reality-eth-lib 3.1.14 → 3.1.15
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.
- package/formatters/question.js +62 -9
- package/package.json +4 -2
- package/test/formatters.js +14 -1
package/formatters/question.js
CHANGED
|
@@ -5,6 +5,8 @@ const BigNumber = require('bignumber.js');
|
|
|
5
5
|
const ethereumjs_abi = require('ethereumjs-abi')
|
|
6
6
|
const vsprintf = require("sprintf-js").vsprintf
|
|
7
7
|
const QUESTION_MAX_OUTCOMES = 128;
|
|
8
|
+
const marked = require('marked');
|
|
9
|
+
const DOMPurify = require('isomorphic-dompurify');
|
|
8
10
|
|
|
9
11
|
exports.delimiter = function() {
|
|
10
12
|
return '\u241f'; // Thought about '\u0000' but it seems to break something;
|
|
@@ -176,7 +178,7 @@ exports.parseQuestionJSON = function(data, errors_to_title) {
|
|
|
176
178
|
// Strip unicode null-terminated-string control characters if there are any.
|
|
177
179
|
// These seem to be stripped already if we got data via The Graph, and only passed to us on RPC.
|
|
178
180
|
data = data.replace(/\u0000/g, "");
|
|
179
|
-
|
|
181
|
+
|
|
180
182
|
var question_json;
|
|
181
183
|
try {
|
|
182
184
|
question_json = JSON.parse(data);
|
|
@@ -187,28 +189,79 @@ exports.parseQuestionJSON = function(data, errors_to_title) {
|
|
|
187
189
|
'errors': {"json_parse_failed": true}
|
|
188
190
|
};
|
|
189
191
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
+
|
|
193
|
+
if (question_json['outcomes'] && question_json['outcomes'].length > QUESTION_MAX_OUTCOMES)
|
|
194
|
+
if(question_json['errors'])
|
|
195
|
+
question_json['errors']['too_many_outcomes'] = true
|
|
196
|
+
else
|
|
197
|
+
question_json['errors'] = {'too_many_outcomes': true};
|
|
198
|
+
if ('type' in question_json && question_json['type'] == 'datetime' && 'precision' in question_json)
|
|
199
|
+
if (!(['Y', 'm', 'd', 'H', 'i', 's'].includes(question_json['precision'])))
|
|
200
|
+
if(question_json['errors'])
|
|
201
|
+
question_json['errors']['invalid_precision'] = true
|
|
202
|
+
else
|
|
203
|
+
question_json['errors'] = {'invalid_precision': true};
|
|
204
|
+
// If errors_to_title is specified, we add any error message to the title to make sure we don't lose it
|
|
205
|
+
if (errors_to_title) {
|
|
206
|
+
if ('errors' in question_json) {
|
|
207
|
+
const prependers = {
|
|
208
|
+
'invalid_precision': 'Invalid date format',
|
|
209
|
+
'too_many_outcomes': 'Too many outcomes'
|
|
210
|
+
}
|
|
211
|
+
for (const e in question_json['errors']) {
|
|
212
|
+
if (e in prependers) {
|
|
213
|
+
question_json['title'] = '['+prependers[e]+'] ' + question_json['title'];
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
192
217
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
218
|
+
|
|
219
|
+
try{
|
|
220
|
+
switch(question_json['format']){
|
|
221
|
+
case 'text/markdown':{
|
|
222
|
+
const safeMarkdown = DOMPurify.sanitize(question_json['title'], { USE_PROFILES: {html: false}});
|
|
223
|
+
if (safeMarkdown !== question_json['title'])
|
|
224
|
+
if(question_json['errors'])
|
|
225
|
+
question_json['errors']['unsafe_markdown'] = true;
|
|
226
|
+
else
|
|
227
|
+
question_json['errors'] = {'unsafe_markdown': true};
|
|
228
|
+
else
|
|
229
|
+
question_json['title-markdown-html'] = marked.parse(safeMarkdown).replace(/<img.*src=\"(.*?)\".*alt=\"(.*?)\".*\/?>/, '<a href="$1">$2</a>');
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
case 'text/plain': {
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
case undefined:{
|
|
236
|
+
question_json['format'] = 'text/plain';
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
default:{
|
|
240
|
+
question_json['errors'] = {'invalid_format': true};
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
196
243
|
}
|
|
244
|
+
} catch(e){
|
|
245
|
+
if(question_json && question_json['errors'])
|
|
246
|
+
question_json['errors']['markdown_parse_failed'] = true
|
|
197
247
|
}
|
|
248
|
+
|
|
198
249
|
// If errors_to_title is specified, we add any error message to the title to make sure we don't lose it
|
|
199
250
|
if (errors_to_title) {
|
|
200
251
|
if ('errors' in question_json) {
|
|
201
252
|
const prependers = {
|
|
202
|
-
'
|
|
203
|
-
'
|
|
253
|
+
'invalid_format': 'Invalid format',
|
|
254
|
+
'unsafe_markdown': 'Unsafe markdown',
|
|
255
|
+
'markdown_parse_failed': 'Bad markdown parse'
|
|
204
256
|
}
|
|
205
|
-
for (
|
|
257
|
+
for (const e in question_json['errors']) {
|
|
206
258
|
if (e in prependers) {
|
|
207
259
|
question_json['title'] = '['+prependers[e]+'] ' + question_json['title'];
|
|
208
260
|
}
|
|
209
261
|
}
|
|
210
262
|
}
|
|
211
263
|
}
|
|
264
|
+
|
|
212
265
|
return question_json;
|
|
213
266
|
|
|
214
267
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reality.eth/reality-eth-lib",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.15",
|
|
4
4
|
"description": "Tools for handling questions in the reality.eth fact verification platform",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "env TZ='Asia/Kabul' mocha ./test"
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
"bignumber.js": "^7.2.1",
|
|
21
21
|
"bn.js": "^5.2.1",
|
|
22
22
|
"ethereumjs-abi": "^0.6.5",
|
|
23
|
+
"isomorphic-dompurify": "^0.23.0",
|
|
24
|
+
"marked": "^4.1.1",
|
|
23
25
|
"sprintf-js": "^1.1.1"
|
|
24
26
|
},
|
|
25
27
|
"devDependencies": {
|
|
@@ -36,5 +38,5 @@
|
|
|
36
38
|
"url": "https://github.com/RealityETH/monorepo/issues"
|
|
37
39
|
},
|
|
38
40
|
"homepage": "https://reality.eth.link",
|
|
39
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "5b0b4dd179e68567d2a0086fc10a6d0f9967af47"
|
|
40
42
|
}
|
package/test/formatters.js
CHANGED
|
@@ -200,7 +200,6 @@ describe('Answer strings', function() {
|
|
|
200
200
|
var qtext = rc_question.encodeText('multiple-select', 'oink', outcomes, 'my-category');
|
|
201
201
|
var q1 = rc_question.populatedJSONForTemplate(rc_template.defaultTemplateForType('multiple-select'), qtext);
|
|
202
202
|
expect(q1.errors.too_many_outcomes).to.equal(true);
|
|
203
|
-
console.log(q1.title);
|
|
204
203
|
expect(q1.title).to.equal('oink');
|
|
205
204
|
var q2 = rc_question.populatedJSONForTemplate(rc_template.defaultTemplateForType('multiple-select'), qtext, true);
|
|
206
205
|
expect(q2.errors.too_many_outcomes).to.equal(true);
|
|
@@ -241,6 +240,20 @@ describe('Broken questions', function() {
|
|
|
241
240
|
});
|
|
242
241
|
});
|
|
243
242
|
|
|
243
|
+
describe('Unsafe markdown questions', function() {
|
|
244
|
+
it('Sets an error if a question includes unsafe html in markdown', function() {
|
|
245
|
+
const qUnsafeMarkdown = "{\"title\": \"# Title <p>abc<iframe\/\/src=jAva	script:alert(3)>def<\/p>\", \"type\": \"bool\", \"category\": \"art\", \"lang\": \"en_US\", \"format\": \"text/markdown\"}";
|
|
246
|
+
const q = rc_question.parseQuestionJSON(qUnsafeMarkdown, true);
|
|
247
|
+
expect(q.errors.unsafe_markdown).to.equal(true);
|
|
248
|
+
});
|
|
249
|
+
it('Sets no error if a question includes valid markdown without html', function() {
|
|
250
|
+
const qUnsafeMarkdown = "{\"title\": \"# Title\", \"type\": \"bool\", \"category\": \"art\", \"lang\": \"en_US\", \"format\": \"text/markdown\"}";
|
|
251
|
+
const q = rc_question.parseQuestionJSON(qUnsafeMarkdown, true);
|
|
252
|
+
expect(q.errors).to.equal(undefined);
|
|
253
|
+
expect(q.format).to.equal('text/markdown');
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
|
|
244
257
|
describe('Commitment ID tests', function() {
|
|
245
258
|
// Using rinkeby question:
|
|
246
259
|
// 0xa09ce5e7943f281a782a0dc021c4029f9088bec4-0x0ade9a55d4dfca644062792d8e66cec9fbd5579761d760a6e0ae9856e81086a4
|