Skip to content

Commit 6b0b86a

Browse files
committed
Emit only valid N-Quads from toRdf.
- Check for valid language format. - Check for valid subject, predicate, object, and datatype IRIs. - Drop invalid N-Quads.
1 parent 874b3a1 commit 6b0b86a

File tree

3 files changed

+36
-8
lines changed

3 files changed

+36
-8
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
- Use rdf-canonize to compare n-quads test results.
55
- Multiple graph tests.
66
- Sort `@type` when looking for scoped contexts.
7+
- Emit only valid N-Quads from toRdf.
8+
- **Note**: This could have a performance impact.
79

810
### Changed
911
- Use JSON-LD WG tests.

lib/toRdf.js

+34
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ const {
3232
isAbsolute: _isAbsoluteIri
3333
} = require('./url');
3434

35+
const _HEX = '[0-9A-Fa-f]';
36+
const _UCHAR = '\\u' + _HEX + '{4}|\\U' + _HEX + '{8}';
37+
const IRIREF_RE = new RegExp('^([^\\x00-\\x20<>"{}|^`\\\\]|' + _UCHAR + ')*$');
38+
const LANG_RE = /^[a-zA-Z]+(-[a-zA-Z0-9]+)*$/;
39+
3540
const api = {};
3641
module.exports = api;
3742

@@ -56,6 +61,11 @@ api.toRDF = (input, options) => {
5661
if(graphName === '@default') {
5762
graphTerm = {termType: 'DefaultGraph', value: ''};
5863
} else if(_isAbsoluteIri(graphName)) {
64+
// invalid graph IRI
65+
if(!IRIREF_RE.test(graphName)) {
66+
continue;
67+
}
68+
5969
if(graphName.startsWith('_:')) {
6070
graphTerm = {termType: 'BlankNode'};
6171
} else {
@@ -109,6 +119,11 @@ function _graphToRDF(dataset, graph, graphTerm, issuer, options) {
109119
continue;
110120
}
111121

122+
// invalid subject IRI
123+
if(!IRIREF_RE.test(id)) {
124+
continue;
125+
}
126+
112127
// RDF predicate
113128
const predicate = {
114129
termType: property.startsWith('_:') ? 'BlankNode' : 'NamedNode',
@@ -120,6 +135,11 @@ function _graphToRDF(dataset, graph, graphTerm, issuer, options) {
120135
continue;
121136
}
122137

138+
// invalid predicate IRI
139+
if(!IRIREF_RE.test(property)) {
140+
continue;
141+
}
142+
123143
// skip blank node predicates unless producing generalized RDF
124144
if(predicate.termType === 'BlankNode' &&
125145
!options.produceGeneralizedRdf) {
@@ -219,6 +239,11 @@ function _objectToRDF(item) {
219239
let value = item['@value'];
220240
const datatype = item['@type'] || null;
221241

242+
// invalid datatype IRI
243+
if(datatype && !IRIREF_RE.test(datatype)) {
244+
return null;
245+
}
246+
222247
// convert to XSD datatypes as appropriate
223248
if(types.isBoolean(value)) {
224249
object.value = value.toString();
@@ -234,6 +259,9 @@ function _objectToRDF(item) {
234259
object.value = value.toFixed(0);
235260
object.datatype.value = datatype || XSD_INTEGER;
236261
} else if('@language' in item) {
262+
if(!LANG_RE.test(item['@language'])) {
263+
return null;
264+
}
237265
object.value = value;
238266
object.datatype.value = datatype || RDF_LANGSTRING;
239267
object.language = item['@language'];
@@ -244,6 +272,12 @@ function _objectToRDF(item) {
244272
} else {
245273
// convert string/node object to RDF
246274
const id = types.isObject(item) ? item['@id'] : item;
275+
276+
// invalid object IRI
277+
if(!IRIREF_RE.test(id)) {
278+
return null;
279+
}
280+
247281
object.termType = id.startsWith('_:') ? 'BlankNode' : 'NamedNode';
248282
object.value = id;
249283
}

tests/test-common.js

-8
Original file line numberDiff line numberDiff line change
@@ -216,14 +216,6 @@ const TEST_TYPES = {
216216
/^#tli02/,
217217
// blank node properties
218218
/^#t0118/,
219-
// well formed
220-
/^#twf01/,
221-
/^#twf02/,
222-
/^#twf03/,
223-
/^#twf04/,
224-
/^#twf05/,
225-
/^#twf06/,
226-
/^#twf07/,
227219
// html
228220
/^#th001/,
229221
/^#th002/,

0 commit comments

Comments
 (0)