Skip to content

Commit 179a6ad

Browse files
committed
Disable remote context lookups by default
The old behaviour can be restored by setting `remoteContextLookups` to true in the `ComponentsManagerBuilder`. Closes #119
1 parent 5ee7843 commit 179a6ad

11 files changed

+108
-3
lines changed

lib/loading/ComponentRegistry.ts

+4
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@ export class ComponentRegistry {
1919
private readonly logger: Logger;
2020
private readonly componentResources: Record<string, Resource>;
2121
private readonly skipContextValidation: boolean;
22+
private readonly remoteContextLookups: boolean;
2223

2324
public constructor(options: IComponentLoaderRegistryOptions) {
2425
this.moduleState = options.moduleState;
2526
this.objectLoader = options.objectLoader;
2627
this.logger = options.logger;
2728
this.componentResources = options.componentResources;
2829
this.skipContextValidation = options.skipContextValidation;
30+
this.remoteContextLookups = options.remoteContextLookups;
2931
}
3032

3133
/**
@@ -51,6 +53,7 @@ export class ComponentRegistry {
5153
importPaths: this.moduleState.importPaths,
5254
logger: this.logger,
5355
skipContextValidation: this.skipContextValidation,
56+
remoteContextLookups: this.remoteContextLookups,
5457
}));
5558
}
5659

@@ -119,4 +122,5 @@ export interface IComponentLoaderRegistryOptions {
119122
logger: Logger;
120123
componentResources: Record<string, Resource>;
121124
skipContextValidation: boolean;
125+
remoteContextLookups: boolean;
122126
}

lib/loading/ComponentsManagerBuilder.ts

+13
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export class ComponentsManagerBuilder<Instance = any> {
3131
private readonly moduleState?: IModuleState;
3232
private readonly skipContextValidation: boolean;
3333
private readonly typeChecking: boolean;
34+
private readonly remoteContextLookups: boolean;
3435

3536
public constructor(options: IComponentsManagerBuilderOptions<Instance>) {
3637
this.mainModulePath = options.mainModulePath;
@@ -48,6 +49,9 @@ export class ComponentsManagerBuilder<Instance = any> {
4849
this.typeChecking = options.typeChecking === undefined ?
4950
true :
5051
Boolean(options.typeChecking);
52+
this.remoteContextLookups = options.remoteContextLookups === undefined ?
53+
false :
54+
Boolean(options.typeChecking);
5155
}
5256

5357
public static createLogger(logLevel: LogLevel = 'warn'): Logger {
@@ -100,6 +104,7 @@ export class ComponentsManagerBuilder<Instance = any> {
100104
logger: this.logger,
101105
componentResources,
102106
skipContextValidation: this.skipContextValidation,
107+
remoteContextLookups: this.remoteContextLookups,
103108
});
104109
await this.componentLoader(componentRegistry);
105110
const componentFinalizer = new ComponentRegistryFinalizer({
@@ -116,6 +121,7 @@ export class ComponentsManagerBuilder<Instance = any> {
116121
objectLoader,
117122
logger: this.logger,
118123
skipContextValidation: this.skipContextValidation,
124+
remoteContextLookups: this.remoteContextLookups,
119125
});
120126
await this.configLoader(configRegistry);
121127
this.logger.info(`Loaded configs`);
@@ -213,4 +219,11 @@ export interface IComponentsManagerBuilderOptions<Instance> {
213219
* Defaults to `true`.
214220
*/
215221
typeChecking?: boolean;
222+
/**
223+
* If remote context lookups are allowed.
224+
* If not allowed, an error is thrown if a remote lookup occurs.
225+
* If allowed, only a warning is emitted.
226+
* Defaults to `false`.
227+
*/
228+
remoteContextLookups?: boolean;
216229
}

lib/loading/ConfigRegistry.ts

+4
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ export class ConfigRegistry {
1414
private readonly objectLoader: RdfObjectLoader;
1515
private readonly logger: Logger;
1616
private readonly skipContextValidation: boolean;
17+
private readonly remoteContextLookups: boolean;
1718

1819
public constructor(options: IConfigLoaderRegistryOptions) {
1920
this.moduleState = options.moduleState;
2021
this.objectLoader = options.objectLoader;
2122
this.logger = options.logger;
2223
this.skipContextValidation = options.skipContextValidation;
24+
this.remoteContextLookups = options.remoteContextLookups;
2325
}
2426

2527
/**
@@ -35,6 +37,7 @@ export class ConfigRegistry {
3537
ignoreImports: false,
3638
logger: this.logger,
3739
skipContextValidation: this.skipContextValidation,
40+
remoteContextLookups: this.remoteContextLookups,
3841
}));
3942
}
4043

@@ -81,4 +84,5 @@ export interface IConfigLoaderRegistryOptions {
8184
objectLoader: RdfObjectLoader;
8285
logger: Logger;
8386
skipContextValidation: boolean;
87+
remoteContextLookups: boolean;
8488
}

lib/rdf/PrefetchedDocumentLoader.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@ export class PrefetchedDocumentLoader extends FetchDocumentLoader {
2525
private readonly contexts: Record<string, any>;
2626
private readonly path?: string;
2727
private readonly logger?: Logger;
28+
private readonly remoteContextLookups?: boolean;
2829

2930
public constructor(options: IPrefetchedDocumentLoaderOptions) {
3031
super();
3132
this.contexts = { ...options.contexts, ...PrefetchedDocumentLoader.DEFAULT_CONTEXTS };
3233
this.logger = options.logger;
3334
this.path = options.path;
35+
this.remoteContextLookups = options.remoteContextLookups;
3436
}
3537

3638
public async load(url: string): Promise<IJsonLdContext> {
@@ -47,8 +49,12 @@ export class PrefetchedDocumentLoader extends FetchDocumentLoader {
4749
}
4850

4951
// Warn before doing a remote context lookup
52+
const errorMessage = `Detected remote context lookup for '${url}'${this.path ? ` in ${this.path}` : ''}. This may indicate a missing or invalid dependency, incorrect version number, or an invalid context URL.`;
53+
if (!this.remoteContextLookups) {
54+
throw new Error(errorMessage);
55+
}
5056
if (this.logger) {
51-
this.logger.warn(`Detected remote context lookup for '${url}'${this.path ? ` in ${this.path}` : ''}. This may indicate a missing or invalid dependency, incorrect version number, or an invalid context URL.`);
57+
this.logger.warn(errorMessage);
5258
}
5359
return super.load(url);
5460
}
@@ -58,4 +64,5 @@ export interface IPrefetchedDocumentLoaderOptions {
5864
contexts: Record<string, any>;
5965
logger?: Logger;
6066
path?: string;
67+
remoteContextLookups?: boolean;
6168
}

lib/rdf/RdfParser.ts

+7
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ export class RdfParser {
5050
contexts: options.contexts || {},
5151
logger: options.logger,
5252
path: options.path,
53+
remoteContextLookups: options.remoteContextLookups,
5354
}),
5455
// Enable strict parsing of JSON-LD to error on potential user config errors
5556
strictValues: true,
@@ -124,4 +125,10 @@ export type RdfParserOptions = ParseOptions & {
124125
* If JSON-LD context validation should be skipped.
125126
*/
126127
skipContextValidation?: boolean;
128+
/**
129+
* If remote context lookups are allowed.
130+
* If not allowed, an error is thrown if a remote lookup occurs.
131+
* If allowed, only a warning is emitted.
132+
*/
133+
remoteContextLookups?: boolean;
127134
};

test/unit/loading/ComponentRegistry-test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ describe('ComponentRegistry', () => {
3131
logger,
3232
componentResources,
3333
skipContextValidation: false,
34+
remoteContextLookups: false,
3435
});
3536
});
3637

test/unit/loading/ComponentRegistryFinalizer-test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ describe('ComponentRegistryFinalizer', () => {
3333
logger,
3434
componentResources,
3535
skipContextValidation: false,
36+
remoteContextLookups: false,
3637
});
3738
finalizer = new ComponentRegistryFinalizer({
3839
objectLoader,

test/unit/loading/ComponentsManager-test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ describe('ComponentsManager', () => {
5656
objectLoader,
5757
logger,
5858
skipContextValidation: false,
59+
remoteContextLookups: false,
5960
});
6061
dumpErrorState = false;
6162
configConstructorPool = <any> {

test/unit/loading/ComponentsManagerBuilder-test.ts

+27
Original file line numberDiff line numberDiff line change
@@ -342,4 +342,31 @@ describe('ComponentsManagerBuilder', () => {
342342
transports: expect.anything(),
343343
});
344344
});
345+
346+
it('should build with true remoteContextLookups', async() => {
347+
const componentsManagerBuilder = new ComponentsManagerBuilder({
348+
mainModulePath,
349+
remoteContextLookups: true,
350+
});
351+
const mgr = await componentsManagerBuilder.build();
352+
353+
expect(mgr).toBeTruthy();
354+
expect(mgr.moduleState).toBe(dummyModuleState);
355+
expect(mgr.objectLoader).toBeInstanceOf(RdfObjectLoader);
356+
expect(Object.keys(mgr.componentResources).length).toBe(2);
357+
expect(mgr.configRegistry).toBeInstanceOf(ConfigRegistry);
358+
expect(mgr.dumpErrorState).toBe(true);
359+
expect(mgr.configConstructorPool).toBeInstanceOf(ConfigConstructorPool);
360+
expect((<any> mgr.configConstructorPool).constructionStrategy).toBeInstanceOf(ConstructionStrategyCommonJs);
361+
expect((<any> mgr.configConstructorPool).configPreprocessors.length).toBe(3);
362+
expect((<any> mgr.configConstructorPool).configPreprocessors[0]).toBeInstanceOf(ConfigPreprocessorOverride);
363+
expect((<any> mgr.configConstructorPool).configPreprocessors[1]).toBeInstanceOf(ConfigPreprocessorComponentMapped);
364+
expect((<any> mgr.configConstructorPool).configPreprocessors[2]).toBeInstanceOf(ConfigPreprocessorComponent);
365+
expect(mgr.logger).toBeTruthy();
366+
expect(createLogger).toBeCalledTimes(1);
367+
expect(createLogger).toHaveBeenCalledWith({
368+
level: 'warn',
369+
transports: expect.anything(),
370+
});
371+
});
345372
});

test/unit/loading/ConfigRegistry-test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ describe('ConfigRegistry', () => {
2727
objectLoader,
2828
logger,
2929
skipContextValidation: false,
30+
remoteContextLookups: false,
3031
});
3132
});
3233

test/unit/rdf/PrefetchedDocumentLoader-test.ts

+41-2
Original file line numberDiff line numberDiff line change
@@ -77,31 +77,70 @@ describe('PrefetchedDocumentLoader', () => {
7777
});
7878

7979
it('for a non-prefetched context', async() => {
80+
await expect(loader.load('http://remote.org/context')).rejects
81+
.toThrow(`Detected remote context lookup for 'http://remote.org/context' in PATH. This may indicate a missing or invalid dependency, incorrect version number, or an invalid context URL.`);
82+
});
83+
84+
it('for a non-prefetched context with a logger', async() => {
85+
const logger: any = {
86+
warn: jest.fn(),
87+
};
88+
loader = new PrefetchedDocumentLoader({
89+
contexts: {},
90+
logger,
91+
path: 'PATH',
92+
});
93+
await expect(loader.load('http://remote.org/context')).rejects
94+
.toThrow(`Detected remote context lookup for 'http://remote.org/context' in PATH. This may indicate a missing or invalid dependency, incorrect version number, or an invalid context URL.`);
95+
});
96+
97+
it('for a non-prefetched context with a logger without path', async() => {
98+
const logger: any = {
99+
warn: jest.fn(),
100+
};
101+
loader = new PrefetchedDocumentLoader({
102+
contexts: {},
103+
logger,
104+
});
105+
await expect(loader.load('http://remote.org/context')).rejects
106+
.toThrow(`Detected remote context lookup for 'http://remote.org/context'. This may indicate a missing or invalid dependency, incorrect version number, or an invalid context URL.`);
107+
});
108+
109+
it('for a non-prefetched context with remoteContextLookups: true', async() => {
110+
loader = new PrefetchedDocumentLoader({
111+
contexts: {
112+
'http://example.org/context': { a: 'b' },
113+
},
114+
path: 'PATH',
115+
remoteContextLookups: true,
116+
});
80117
expect(await loader.load('http://remote.org/context'))
81118
.toEqual({ x: 'y' });
82119
});
83120

84-
it('for a non-prefetched context with a logger', async() => {
121+
it('for a non-prefetched context with a logger with remoteContextLookups: true', async() => {
85122
const logger: any = {
86123
warn: jest.fn(),
87124
};
88125
loader = new PrefetchedDocumentLoader({
89126
contexts: {},
90127
logger,
91128
path: 'PATH',
129+
remoteContextLookups: true,
92130
});
93131
expect(await loader.load('http://remote.org/context'))
94132
.toEqual({ x: 'y' });
95133
expect(logger.warn).toHaveBeenCalledWith(`Detected remote context lookup for 'http://remote.org/context' in PATH. This may indicate a missing or invalid dependency, incorrect version number, or an invalid context URL.`);
96134
});
97135

98-
it('for a non-prefetched context with a logger without path', async() => {
136+
it('for a non-prefetched context with a logger without path with remoteContextLookups: true', async() => {
99137
const logger: any = {
100138
warn: jest.fn(),
101139
};
102140
loader = new PrefetchedDocumentLoader({
103141
contexts: {},
104142
logger,
143+
remoteContextLookups: true,
105144
});
106145
expect(await loader.load('http://remote.org/context'))
107146
.toEqual({ x: 'y' });

0 commit comments

Comments
 (0)