From 513d9e0a164072a4cc1ab567051fe1e02aa97550 Mon Sep 17 00:00:00 2001 From: Innei Date: Sun, 8 May 2022 21:01:06 +0800 Subject: [PATCH] fix: snippet private data leak --- src/modules/snippet/snippet.controller.ts | 23 +++++++++++++++++++++-- src/modules/snippet/snippet.service.ts | 22 +++++++++++++++++----- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/modules/snippet/snippet.controller.ts b/src/modules/snippet/snippet.controller.ts index 839b834c..36187eb7 100644 --- a/src/modules/snippet/snippet.controller.ts +++ b/src/modules/snippet/snippet.controller.ts @@ -107,9 +107,28 @@ export class SnippetController { if (typeof reference !== 'string') { throw new ForbiddenException('reference should be string') } - const cached = await this.snippetService.getCachedSnippet(reference, name) + let cached: string | null = null + if (isMaster) { + cached = + ( + await Promise.all( + (['public', 'private'] as const).map((type) => { + return this.snippetService.getCachedSnippet(reference, name, type) + }), + ) + ).find(Boolean) || null + } else { + cached = await this.snippetService.getCachedSnippet( + reference, + name, + 'public', + ) + } + if (cached) { - return cached + const json = JSON.safeParse(cached) + + return json ? json : cached } const snippet = await this.snippetService.getSnippetByName(name, reference) diff --git a/src/modules/snippet/snippet.service.ts b/src/modules/snippet/snippet.service.ts index fa1ff9d5..78b97b04 100644 --- a/src/modules/snippet/snippet.service.ts +++ b/src/modules/snippet/snippet.service.ts @@ -154,7 +154,7 @@ export class SnippetService { async cacheSnippet(model: SnippetModel, value: any) { const { reference, name } = model - const key = `${reference}:${name}` + const key = `${reference}:${name}:${model.private ? 'private' : ''}` const client = this.cacheService.getClient() await client.hset( getRedisKey(RedisKeys.SnippetCache), @@ -162,16 +162,28 @@ export class SnippetService { typeof value !== 'string' ? JSON.stringify(value) : value, ) } - async getCachedSnippet(reference: string, name: string) { - const key = `${reference}:${name}` + async getCachedSnippet( + reference: string, + name: string, + accessType: 'public' | 'private', + ) { + const key = `${reference}:${name}:${ + accessType === 'private' ? 'private' : '' + }` const client = this.cacheService.getClient() const value = await client.hget(getRedisKey(RedisKeys.SnippetCache), key) return value } async deleteCachedSnippet(reference: string, name: string) { - const key = `${reference}:${name}` + const keyBase = `${reference}:${name}` + const key1 = `${keyBase}:` + const key2 = `${keyBase}:private` const client = this.cacheService.getClient() - await client.hdel(getRedisKey(RedisKeys.SnippetCache), key) + await Promise.all( + [key1, key2].map((key) => { + return client.hdel(getRedisKey(RedisKeys.SnippetCache), key) + }), + ) } }