mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Create MetadataParser that detects JSON with Context link and throws an error
* feat: add PlainJsonLdFilter to reject JSON with context link * refactor: abstract parseLinkHeader into HeaderUtils * docs: typo in comment field Co-authored-by: Ruben Verborgh <ruben@verborgh.org> * refactor: Replace BadRequestHttpError with NotImplementedError Co-authored-by: Ruben Verborgh <ruben@verborgh.org> * refactor: incorporate requested changes * refactor: requested changes incorporated * refactor: remove obsolete code lines Co-authored-by: Ruben Verborgh <ruben@verborgh.org>
This commit is contained in:
@@ -2,7 +2,7 @@ import type { NamedNode } from '@rdfjs/types';
|
||||
import { DataFactory } from 'n3';
|
||||
import { getLoggerFor } from '../../../logging/LogUtil';
|
||||
import type { HttpRequest } from '../../../server/HttpRequest';
|
||||
import { parseParameters, splitAndClean, transformQuotedStrings } from '../../../util/HeaderUtil';
|
||||
import { parseLinkHeader } from '../../../util/HeaderUtil';
|
||||
import type { RepresentationMetadata } from '../../representation/RepresentationMetadata';
|
||||
import { MetadataParser } from './MetadataParser';
|
||||
import namedNode = DataFactory.namedNode;
|
||||
@@ -23,25 +23,9 @@ export class LinkRelParser extends MetadataParser {
|
||||
}
|
||||
|
||||
public async handle(input: { request: HttpRequest; metadata: RepresentationMetadata }): Promise<void> {
|
||||
const link = input.request.headers.link ?? [];
|
||||
const entries: string[] = Array.isArray(link) ? link : [ link ];
|
||||
for (const entry of entries) {
|
||||
this.parseLink(entry, input.metadata);
|
||||
}
|
||||
}
|
||||
|
||||
protected parseLink(linkEntry: string, metadata: RepresentationMetadata): void {
|
||||
const { result, replacements } = transformQuotedStrings(linkEntry);
|
||||
for (const part of splitAndClean(result)) {
|
||||
const [ link, ...parameters ] = part.split(/\s*;\s*/u);
|
||||
if (/^[^<]|[^>]$/u.test(link)) {
|
||||
this.logger.warn(`Invalid link header ${part}.`);
|
||||
continue;
|
||||
}
|
||||
for (const { name, value } of parseParameters(parameters, replacements)) {
|
||||
if (name === 'rel' && this.linkRelMap[value]) {
|
||||
metadata.add(this.linkRelMap[value], namedNode(link.slice(1, -1)));
|
||||
}
|
||||
for (const { target, parameters } of parseLinkHeader(input.request.headers.link)) {
|
||||
if (this.linkRelMap[parameters.rel]) {
|
||||
input.metadata.add(this.linkRelMap[parameters.rel], namedNode(target));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
45
src/http/input/metadata/PlainJsonLdFilter.ts
Normal file
45
src/http/input/metadata/PlainJsonLdFilter.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { getLoggerFor } from '../../../logging/LogUtil';
|
||||
import type { HttpRequest } from '../../../server/HttpRequest';
|
||||
import { NotImplementedHttpError } from '../../../util/errors/NotImplementedHttpError';
|
||||
import { parseContentType, parseLinkHeader } from '../../../util/HeaderUtil';
|
||||
import { JSON_LD } from '../../../util/Vocabularies';
|
||||
import type { RepresentationMetadata } from '../../representation/RepresentationMetadata';
|
||||
import { MetadataParser } from './MetadataParser';
|
||||
|
||||
/**
|
||||
* Filter that errors on JSON-LD with a plain application/json content-type.
|
||||
* This will not store metadata, only throw errors if necessary.
|
||||
*/
|
||||
export class PlainJsonLdFilter extends MetadataParser {
|
||||
protected readonly logger = getLoggerFor(this);
|
||||
|
||||
public constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public async handle(input: {
|
||||
request: HttpRequest;
|
||||
metadata: RepresentationMetadata;
|
||||
}): Promise<void> {
|
||||
const contentTypeHeader = input.request.headers['content-type'];
|
||||
if (!contentTypeHeader) {
|
||||
return;
|
||||
}
|
||||
const { value: contentType } = parseContentType(contentTypeHeader);
|
||||
// Throw error on content-type application/json AND a link header that refers to a JSON-LD context.
|
||||
if (
|
||||
contentType === 'application/json' &&
|
||||
this.linkHasContextRelation(input.request.headers.link)
|
||||
) {
|
||||
throw new NotImplementedHttpError(
|
||||
'JSON-LD is only supported with the application/ld+json content type.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private linkHasContextRelation(link: string | string[] = []): boolean {
|
||||
return parseLinkHeader(link).some(
|
||||
({ parameters }): boolean => parameters.rel === JSON_LD.context,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user