mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00

* Solution works but tests don't * refactor(FetchUtil): use arrayifyStream * refactor(FetchUtil): split fetchDataset into 2 separate functions * style(FetchUtil): onelining instead of declaring new local var * test: trying to mock rdfDereferencer * refactor: promise can't have async function as arg * test(FetchUtil): pass Quad array to mockDereference instead * test: all tests should pass now and coverage is back to 100% * style: comment typo * chore: make package.json and package-lock.json compatible with main * chore: fix package.json double entries * chore: updated package.json to be alfabetical again * refactor(AgentGroupAccessChecker): Remove converter from contructor and config * refactor(TokenOwnerShipValidator): Remove converter from constructor and config * refactor(FetchUtil): Return BadRequestHttpError instead of generic Error * test(FetchUtil): return Response object instead of mocking fetch * style: typos and newlines
94 lines
3.9 KiB
TypeScript
94 lines
3.9 KiB
TypeScript
import { Readable } from 'stream';
|
|
import { DataFactory } from 'n3';
|
|
import type { Quad } from 'n3';
|
|
import rdfDereferencer from 'rdf-dereference';
|
|
import { v4 } from 'uuid';
|
|
import { TokenOwnershipValidator } from '../../../../src/identity/ownership/TokenOwnershipValidator';
|
|
import type { ExpiringStorage } from '../../../../src/storage/keyvalue/ExpiringStorage';
|
|
import { SOLID } from '../../../../src/util/Vocabularies';
|
|
const { literal, namedNode, quad } = DataFactory;
|
|
|
|
jest.mock('uuid');
|
|
jest.mock('rdf-dereference', (): any => ({
|
|
dereference: jest.fn(),
|
|
}));
|
|
|
|
function quadToString(qq: Quad): string {
|
|
const subPred = `<${qq.subject.value}> <${qq.predicate.value}>`;
|
|
if (qq.object.termType === 'Literal') {
|
|
return `${subPred} "${qq.object.value}"`;
|
|
}
|
|
return `${subPred} <${qq.object.value}>`;
|
|
}
|
|
|
|
describe('A TokenOwnershipValidator', (): void => {
|
|
const rdfDereferenceMock: jest.Mocked<typeof rdfDereferencer> = rdfDereferencer as any;
|
|
const webId = 'http://alice.test.com/#me';
|
|
const token = 'randomlyGeneratedToken';
|
|
const tokenTriple = quad(namedNode(webId), SOLID.terms.oidcIssuerRegistrationToken, literal(token));
|
|
const tokenString = `${quadToString(tokenTriple)}.`;
|
|
let storage: ExpiringStorage<string, string>;
|
|
let validator: TokenOwnershipValidator;
|
|
|
|
function mockDereference(qq?: Quad): any {
|
|
rdfDereferenceMock.dereference.mockImplementation((uri: string): any => ({
|
|
uri,
|
|
quads: Readable.from(qq ? [ qq ] : []),
|
|
exists: true,
|
|
}));
|
|
}
|
|
|
|
beforeEach(async(): Promise<void> => {
|
|
const now = Date.now();
|
|
jest.spyOn(Date, 'now').mockReturnValue(now);
|
|
(v4 as jest.Mock).mockReturnValue(token);
|
|
|
|
const map = new Map<string, any>();
|
|
storage = {
|
|
get: jest.fn().mockImplementation((key: string): any => map.get(key)),
|
|
set: jest.fn().mockImplementation((key: string, value: any): any => map.set(key, value)),
|
|
delete: jest.fn().mockImplementation((key: string): any => map.delete(key)),
|
|
} as any;
|
|
|
|
mockDereference();
|
|
|
|
validator = new TokenOwnershipValidator(storage);
|
|
});
|
|
|
|
it('errors if no token is stored in the storage.', async(): Promise<void> => {
|
|
// Even if the token is in the WebId, it will error since it's not in the storage
|
|
mockDereference(tokenTriple);
|
|
await expect(validator.handle({ webId })).rejects.toThrow(expect.objectContaining({
|
|
message: expect.stringContaining(tokenString),
|
|
details: { quad: tokenString },
|
|
}));
|
|
expect(rdfDereferenceMock.dereference).toHaveBeenCalledTimes(0);
|
|
});
|
|
|
|
it('errors if the expected triple is missing.', async(): Promise<void> => {
|
|
// First call will add the token to the storage
|
|
await expect(validator.handle({ webId })).rejects.toThrow(tokenString);
|
|
expect(rdfDereferenceMock.dereference).toHaveBeenCalledTimes(0);
|
|
// Second call will fetch the WebId
|
|
await expect(validator.handle({ webId })).rejects.toThrow(tokenString);
|
|
expect(rdfDereferenceMock.dereference).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('resolves if the WebId contains the verification triple.', async(): Promise<void> => {
|
|
mockDereference(tokenTriple);
|
|
// First call will add the token to the storage
|
|
await expect(validator.handle({ webId })).rejects.toThrow(tokenString);
|
|
// Second call will succeed since it has the verification triple
|
|
await expect(validator.handle({ webId })).resolves.toBeUndefined();
|
|
});
|
|
|
|
it('fails if the WebId contains the wrong verification triple.', async(): Promise<void> => {
|
|
const wrongQuad = quad(namedNode(webId), SOLID.terms.oidcIssuerRegistrationToken, literal('wrongToken'));
|
|
mockDereference(wrongQuad);
|
|
// First call will add the token to the storage
|
|
await expect(validator.handle({ webId })).rejects.toThrow(tokenString);
|
|
// Second call will fail since it has the wrong verification triple
|
|
await expect(validator.handle({ webId })).rejects.toThrow(tokenString);
|
|
});
|
|
});
|