Skip to content

Commit c880534

Browse files
davidlehngkellogg
authored andcommitted
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 6891936 commit c880534

File tree

2 files changed

+36
-0
lines changed

2 files changed

+36
-0
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@
205205
- Use rdf-canonize to compare n-quads test results.
206206
- Maintain multiple graphs.
207207
- Sort `@type` when looking for scoped contexts.
208+
- Emit only valid N-Quads from toRdf.
209+
- **Note**: This could have a performance impact.
208210

209211
### Changed
210212
- Use JSON-LD WG tests.

lib/toRdf.js

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

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

@@ -58,6 +63,11 @@ api.toRDF = (input, options) => {
5863
if(graphName === '@default') {
5964
graphTerm = {termType: 'DefaultGraph', value: ''};
6065
} else if(_isAbsoluteIri(graphName)) {
66+
// invalid graph IRI
67+
if(!IRIREF_RE.test(graphName)) {
68+
continue;
69+
}
70+
6171
if(graphName.startsWith('_:')) {
6272
graphTerm = {termType: 'BlankNode'};
6373
} else {
@@ -110,6 +120,11 @@ function _graphToRDF(dataset, graph, graphTerm, issuer, options) {
110120
continue;
111121
}
112122

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

139+
// invalid predicate IRI
140+
if(!IRIREF_RE.test(property)) {
141+
continue;
142+
}
143+
124144
// skip blank node predicates unless producing generalized RDF
125145
if(predicate.termType === 'BlankNode' &&
126146
!options.produceGeneralizedRdf) {
@@ -226,6 +246,11 @@ function _objectToRDF(item, issuer, dataset, graphTerm) {
226246
let value = item['@value'];
227247
const datatype = item['@type'] || null;
228248

249+
// invalid datatype IRI
250+
if(datatype && !IRIREF_RE.test(datatype)) {
251+
return null;
252+
}
253+
229254
// convert to XSD/JSON datatypes as appropriate
230255
if(datatype === '@json') {
231256
object.value = jsonCanonicalize(value);
@@ -244,6 +269,9 @@ function _objectToRDF(item, issuer, dataset, graphTerm) {
244269
object.value = value.toFixed(0);
245270
object.datatype.value = datatype || XSD_INTEGER;
246271
} else if('@language' in item) {
272+
if(!LANG_RE.test(item['@language'])) {
273+
return null;
274+
}
247275
object.value = value;
248276
object.datatype.value = datatype || RDF_LANGSTRING;
249277
object.language = item['@language'];
@@ -258,6 +286,12 @@ function _objectToRDF(item, issuer, dataset, graphTerm) {
258286
} else {
259287
// convert string/node object to RDF
260288
const id = types.isObject(item) ? item['@id'] : item;
289+
290+
// invalid object IRI
291+
if(!IRIREF_RE.test(id)) {
292+
return null;
293+
}
294+
261295
object.termType = id.startsWith('_:') ? 'BlankNode' : 'NamedNode';
262296
object.value = id;
263297
}

0 commit comments

Comments
 (0)