mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat!: remove caching from AgentGroupAccessChecker
This commit is contained in:
parent
4d1bd93e94
commit
3c43d046ef
@ -4,23 +4,7 @@
|
||||
{
|
||||
"comment": "Checks if the agent belongs to a group that has access.",
|
||||
"@id": "urn:solid-server:default:AgentGroupAccessChecker",
|
||||
"@type": "AgentGroupAccessChecker",
|
||||
"cache": {
|
||||
"@id": "urn:solid-server:default:ExpiringAclCache",
|
||||
"@type": "WrappedExpiringStorage",
|
||||
"source": { "@type": "MemoryMapStorage" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "Makes sure the expiring storage cleanup timer is stopped when the application needs to stop.",
|
||||
"@id": "urn:solid-server:default:Finalizer",
|
||||
"@type": "ParallelHandler",
|
||||
"handlers": [
|
||||
{
|
||||
"@type": "FinalizableHandler",
|
||||
"finalizable": { "@id": "urn:solid-server:default:ExpiringAclCache" }
|
||||
}
|
||||
]
|
||||
"@type": "AgentGroupAccessChecker"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import type { Store, Term } from 'n3';
|
||||
import type { ResourceIdentifier } from '../../http/representation/ResourceIdentifier';
|
||||
import type { ExpiringStorage } from '../../storage/keyvalue/ExpiringStorage';
|
||||
import { fetchDataset } from '../../util/FetchUtil';
|
||||
import { promiseSome } from '../../util/PromiseUtil';
|
||||
import { readableToQuads } from '../../util/StreamUtil';
|
||||
@ -11,20 +10,10 @@ import { AccessChecker } from './AccessChecker';
|
||||
/**
|
||||
* Checks if the given WebID belongs to a group that has access.
|
||||
* Implements the behaviour of groups from the WAC specification.
|
||||
*
|
||||
* Fetched results will be stored in an ExpiringStorage.
|
||||
*
|
||||
* Requires a storage that can store JS objects.
|
||||
* `expiration` parameter is how long entries in the cache should be stored in seconds, defaults to 3600.
|
||||
*/
|
||||
export class AgentGroupAccessChecker extends AccessChecker {
|
||||
private readonly cache: ExpiringStorage<string, Promise<Store>>;
|
||||
private readonly expiration: number;
|
||||
|
||||
public constructor(cache: ExpiringStorage<string, Promise<Store>>, expiration = 3600) {
|
||||
public constructor() {
|
||||
super();
|
||||
this.cache = cache;
|
||||
this.expiration = expiration * 1000;
|
||||
}
|
||||
|
||||
public async handle({ acl, rule, credential }: AccessCheckerArgs): Promise<boolean> {
|
||||
@ -49,24 +38,18 @@ export class AgentGroupAccessChecker extends AccessChecker {
|
||||
const groupDocument: ResourceIdentifier = { path: /^[^#]*/u.exec(group.value)![0] };
|
||||
|
||||
// Fetch the required vCard group file
|
||||
const quads = await this.fetchCachedQuads(groupDocument.path);
|
||||
const quads = await this.fetchQuads(groupDocument.path);
|
||||
return quads.countQuads(group, VCARD.terms.hasMember, webId, null) !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches quads from the given URL.
|
||||
* Will cache the values for later re-use.
|
||||
*/
|
||||
private async fetchCachedQuads(url: string): Promise<Store> {
|
||||
let result = await this.cache.get(url);
|
||||
if (!result) {
|
||||
private async fetchQuads(url: string): Promise<Store> {
|
||||
const prom = (async(): Promise<Store> => {
|
||||
const representation = await fetchDataset(url);
|
||||
return readableToQuads(representation.data);
|
||||
})();
|
||||
await this.cache.set(url, prom, this.expiration);
|
||||
result = await prom;
|
||||
}
|
||||
return result;
|
||||
return await prom;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ import type { AccessCheckerArgs } from '../../../../src/authorization/access/Acc
|
||||
import { AgentGroupAccessChecker } from '../../../../src/authorization/access/AgentGroupAccessChecker';
|
||||
import { BasicRepresentation } from '../../../../src/http/representation/BasicRepresentation';
|
||||
import type { Representation } from '../../../../src/http/representation/Representation';
|
||||
import type { ExpiringStorage } from '../../../../src/storage/keyvalue/ExpiringStorage';
|
||||
import { INTERNAL_QUADS } from '../../../../src/util/ContentTypes';
|
||||
import * as fetchUtil from '../../../../src/util/FetchUtil';
|
||||
import { ACL, VCARD } from '../../../../src/util/Vocabularies';
|
||||
@ -17,7 +16,6 @@ describe('An AgentGroupAccessChecker', (): void => {
|
||||
acl.addQuad(namedNode('noMatch'), ACL.terms.agentGroup, namedNode('badGroup'));
|
||||
let fetchMock: jest.SpyInstance;
|
||||
let representation: Representation;
|
||||
let cache: ExpiringStorage<string, Promise<Store>>;
|
||||
let checker: AgentGroupAccessChecker;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
@ -27,9 +25,7 @@ describe('An AgentGroupAccessChecker', (): void => {
|
||||
fetchMock.mockResolvedValue(representation);
|
||||
fetchMock.mockClear();
|
||||
|
||||
cache = new Map() as any;
|
||||
|
||||
checker = new AgentGroupAccessChecker(cache);
|
||||
checker = new AgentGroupAccessChecker();
|
||||
});
|
||||
|
||||
it('can handle all requests.', async(): Promise<void> => {
|
||||
@ -50,11 +46,4 @@ describe('An AgentGroupAccessChecker', (): void => {
|
||||
const input: AccessCheckerArgs = { acl, rule: namedNode('groupMatch'), credential: {}};
|
||||
await expect(checker.handle(input)).resolves.toBe(false);
|
||||
});
|
||||
|
||||
it('caches fetched results.', async(): Promise<void> => {
|
||||
const input: AccessCheckerArgs = { acl, rule: namedNode('groupMatch'), credential: { webId }};
|
||||
await expect(checker.handle(input)).resolves.toBe(true);
|
||||
await expect(checker.handle(input)).resolves.toBe(true);
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user