Skip to content

Commit d9d27bf

Browse files
committed
Fixes getodk/central#1470: decode html entities in form version + fix _versionSplicer
1 parent 32deca2 commit d9d27bf

File tree

4 files changed

+50
-13
lines changed

4 files changed

+50
-13
lines changed

lib/data/schema.js

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -538,22 +538,15 @@ const injectPublicKey = (xml, keystr) => new Promise((pass, fail) => {
538538
const _versionSplicer = (replace) => (xml, insert) => new Promise((pass, fail) => {
539539
const stack = [];
540540
const parser = new hparser.Parser({
541-
onattribute: (name, value) => {
541+
onattribute: (name) => {
542542
if ((stripNamespacesFromPath(name) === 'version') && (stack.length) === 4 &&
543543
(stack[0] === 'html') && (stack[1] === 'head') && (stack[2] === 'model') &&
544544
(stack[3] === 'instance')) {
545-
// okay, we have found the thing we are looking for.
546-
// idx points at the position of the closing "
547-
//
548-
// TODO: we cheat here and reference the hp2 internal tokenizer index to find
549-
// out where the attribute actually is. the parser startIndex and endIndex point
550-
// at the whitespace preceding the tag until the tag is closed. obviously this is
551-
// pretty bad but i don't see a more robust solution right now.
552-
const idx = parser.tokenizer.index;
545+
const result = replace
546+
? `${xml.slice(0, parser.startIndex)}version="${insert}"${xml.slice(parser.endIndex)}`
547+
: `${xml.slice(0, parser.endIndex-1)}${insert}"${xml.slice(parser.endIndex)}`;
553548
parser.reset();
554-
return replace
555-
? pass(`${xml.slice(0, idx - value.length)}${insert}${xml.slice(idx)}`)
556-
: pass(`${xml.slice(0, idx)}${insert}${xml.slice(idx)}`);
549+
return pass(result);
557550
}
558551
},
559552
// n.b. opentag happens AFTER all the attributes for that tag have been emitted!

lib/model/frames/form.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ class Form extends Frame.define(
122122
const xmlFormId = idText.map(blankStringToNull)
123123
.orThrow(Problem.user.missingParameter({ field: 'formId' }));
124124

125-
const version = versionText.orElse('');
125+
const version = versionText.map(decodeXML).orElse('');
126126
const name = nameText.map(decodeXML).orNull();
127127
const key = pubKey.map((k) => new Key({ public: k }));
128128
return new Form.Partial({ xmlFormId, name }, { def: new Form.Def({ version, name }), key });

test/integration/api/forms/forms.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,19 @@ describe('api: /projects/:id/forms (create, read, update)', () => {
9292
body.hash.should.equal('07ed8a51cc3f6472b7dfdc14c2005861');
9393
}))));
9494

95+
it('should decode html entities in the value of form version - getodk/central#1470', testService((service) =>
96+
service.login('alice', (asAlice) =>
97+
asAlice.post('/v1/projects/1/forms')
98+
.send(testData.forms.simple2.replace('2.1', '<{}>'))
99+
.set('Content-Type', 'application/xml')
100+
.expect(200)
101+
.then(({ body }) => {
102+
body.should.be.a.Form();
103+
body.name.should.equal('Simple 2');
104+
body.version.should.equal('<{}>');
105+
body.hash.should.equal('232ffd287a8eaef0103ad2386dafa44e');
106+
}))));
107+
95108
it('should reject if form id ends in .xml', testService((service) =>
96109
service.login('alice', (asAlice) =>
97110
asAlice.post('/v1/projects/1/forms')

test/unit/data/schema.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2146,6 +2146,37 @@ describe('form schema', () => {
21462146
<bind nodeset="/data/age" type="int"/>
21472147
</model>
21482148
2149+
</h:head>
2150+
<h:body>
2151+
<input ref="/data/name">
2152+
<label>What is your name?</label>
2153+
</input>
2154+
<input ref="/data/age">
2155+
<label>What is your age?</label>
2156+
</input>
2157+
</h:body>
2158+
</h:html>`)));
2159+
2160+
it('should set the version even when existing version has special characters - getodk/central#1470', () =>
2161+
setVersion(testData.forms.simple2.replace('2.1', '&lt;{}&gt;'), '9').then((result) => result.should.equal(`<h:html xmlns="http://www.w3.org/2002/xforms" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:jr="http://openrosa.org/javarosa">
2162+
<h:head>
2163+
<h:title>Simple 2</h:title>
2164+
<model>
2165+
<instance>
2166+
<data id="simple2" version="9">
2167+
<meta>
2168+
<instanceID/>
2169+
</meta>
2170+
<name/>
2171+
<age/>
2172+
</data>
2173+
</instance>
2174+
2175+
<bind nodeset="/data/meta/instanceID" type="string" readonly="true()" calculate="concat('uuid:', uuid())"/>
2176+
<bind nodeset="/data/name" type="string"/>
2177+
<bind nodeset="/data/age" type="int"/>
2178+
</model>
2179+
21492180
</h:head>
21502181
<h:body>
21512182
<input ref="/data/name">

0 commit comments

Comments
 (0)