Closed smoogly closed 10 years ago
Да не, вроде все правильно. Энтити резолвятся сразу в момент компиляции во всех строковых литералах. Т.е. ты по факту написал так:
match / {
unescapes('<h1><img src=x onerror=alert(1)></h1>')
}
После чего ты обманул компилятор, сказав, что вернул заэскейпленный текст, а на деле ничего такого не сделал. Ну и получил, что хотел.
Наверное, тебе нужно было написать так:
match / {
unescapes('<h1>&lt;img src=x onerror=alert(1)&gt;</h1>')
}
Если передавать в рантайме значения, то то же самое происходит.
module 'main'
external xml unescapes(scalar)
external xml format (scalar, scalar)
match / {
unescapes(format(.format, .substitute))
}
var yr = require('yate/lib/runtime.js');
require('./template.yate.compiled.js');
yr.externals['unescapes'] = function(arg) {
return arg;
};
yr.externals['format'] = function(format, substitute) {
return require('util').format(format, substitute);
};
var result = yr.run('main', {
format: '<h1>%s</h1>',
substitute: '<img src=x onerror=alert(1)>'
});
console.log(result);
Результат: <h1><img src=x onerror=alert(1)></h1>
,
Ожидаю: <h1><img src=x onerror=alert(1)></h1>
При этом
module 'main'
external xml format (scalar, scalar)
match / {
format(.format, .substitute)
}
var yr = require('yate/lib/runtime.js');
require('./template.yate.compiled.js');
yr.externals['format'] = function(format, substitute) {
return require('util').format(format, substitute);
};
var result = yr.run('main', {
format: '<h1>%s</h1>',
substitute: '<img src=x onerror=alert(1)>'
});
console.log(result);
Даёт правильную строку <h1><img src=x onerror=alert(1)></h1>
Значит проблема при конвертации между scalar и xml в экстернале.
Еще раз повторю. Энтити внутри строк: т.е. вот такие: "blabla ©"
— это ровно тоже самое, что и соответствующий символ. По сути, энтити нужны только для всяких символов типа
— которые невидимы.
Энтити, которые ты берешь из входящего дерева — никак специально не обрабатываются. Это просто символы в строке, без какого-либо специального значения.
А конвертации как раз никакой нет. Ты просто принудительно меняешь тип строки. Она была скаляр — если бы ты ее вывел, то в ней все бы заэскейпилось. А ты сказал, что там xml — т.е. ты по сути сказал, что ее эскейпить не нужно, ты сам про все позаботился.
Вообще, я не очень понимаю, чего ты добиваешься, но вот так будет то, что тебе нужно безо всяких функций:
match / {
<h1>
"<img src=x onerror=alert(1)>"
</h1>
}
Если передавать в рантайме значения, то то же самое происходит.
Мне кажется, тут дело в сигнатурах. Попробуй вот так:
external xml unescapes(xml)
external xml format (scalar, scalar)
(Ну или просто unescapes
не используй, у тебя уже и так format
xml
отдает)
Потому что у тебя unescapes(format(...))
— формат отдает xml
, а unescapes
принимает scalar
. По идее тут должно случиться автоматическое преобразование xml -> scalar
.
И да, можно скомпилированный код посмотреть:
r0 += (yr.externals['unescapes'])(xml2scalar( (yr.externals['format'])(simpleScalar('format', c0), simpleScalar('substitute', c0)) ));
Но почему xml2scalar преобразует entities?
Не понимаю, почему <
— то же самое, что <
.
Преобразование безобидное для случаев типа ©
, но не для <
и >
по очевидным причинам.
Ок, может быть я использую ять неправильно. Естественно, в примере я старался локализовать проблему и всё по-максимуму упростить.
Код выглядит вот так:
bold = (
<em class="{pageId}-delete-popup-content-title">
'%s'
</em>
)
i18n-xml(meta.language, 'app.delete.confirm', format(bold, .title))
Определены вот так:
external xml i18n-xml(scalar, scalar)
external xml format(xml)
yr.externals['i18n-xml'] = function(lang, locKey) {
/* jshint unused:false */
var i18n = require('putils').i18n;
return i18n.apply(i18n, arguments);
};
yr.externals['format'] = function(format, values) {
/* jshint unused:false */
var args = Array.prototype.slice.call(arguments, 1);
var util = require('util');
return util.format.apply(util, [format].concat(args.map(function(arg) {
return require('lodash').escape(arg);
})));
};
Какой true yate way, чтобы оно работало?
Но почему xml2scalar преобразует entities?
Потому что это обратное преобразование к scalar2xml. Посмотри в runtime.js что они делают.
Какой true yate way, чтобы оно работало?
Я не могу все это у себя воспроизвести, слишком много каких-то левых зависимостей.
Могу предположить, что надо таки указать явно тип третьего аргумента в i18-xml
:
external xml i18n-xml(scalar, scalar, xml)
Понял, спасибо за объяснения.
Есть ли способ указать тип для всех остальных аргументов, или сказать яти "не конвертировать тип, пришедший в аргумент экстернала"?
Компилирую шаблон
и запускаю через
Получаю
<h1><img src=x onerror=alert(1)></h1>
, ожидаю увидеть<h1><img src=x onerror=alert(1)></h1>
Версия яти: 0.0.72