fix: Redis expire guard, transferOwnership prev-owner, SVG regex
- Redis get() rejects legacy expire=0 entries and cleans them up - transferOwnership invalidates previous owner in addition to new - SVG regex uses non-greedy match and handles self-closing <svg /> - SVG fallback returns empty string instead of HTML wrapper - Memory channel comment: FIFO eviction, not timestamp-based
This commit is contained in:
4 files changed
+17
-3
No files matched your search
@@ -86,8 +86,8 @@ export const sanitizeSvg = (svgText: string) => {
|
||||
// linkedom's DOMParser omits html/body for fragment-only SVG; DOMPurify needs a body root.
|
||||
const wrapped = `<html><body>${svgText}</body></html>`;
|
||||
const sanitized = purify.sanitize(wrapped, svgSanitizeOptions);
|
||||
const svgMatch = sanitized.match(/<svg[\s\S]*<\/svg>/i);
|
||||
return svgMatch ? svgMatch[0] : sanitized;
|
||||
const svgMatch = sanitized.match(/<svg[\s\S]*?(?:<\/svg>|\/>)/i);
|
||||
return svgMatch ? svgMatch[0] : "";
|
||||
};
|
||||
|
||||
export { svgSanitizeOptions, purify };
|
||||
@@ -327,13 +327,22 @@ export const groupRouter = createTRPCRouter({
|
||||
await throwIfGroupNotFoundAsync(ctx.db, input.groupId);
|
||||
await throwIfGroupNameIsReservedAsync(ctx.db, input.groupId);
|
||||
|
||||
const group = await ctx.db.query.groups.findFirst({
|
||||
columns: { ownerId: true },
|
||||
where: eq(groups.id, input.groupId),
|
||||
});
|
||||
|
||||
await ctx.db
|
||||
.update(groups)
|
||||
.set({
|
||||
ownerId: input.userId,
|
||||
})
|
||||
.where(eq(groups.id, input.groupId));
|
||||
|
||||
invalidateUserCache(input.userId);
|
||||
if (group?.ownerId && group.ownerId !== input.userId) {
|
||||
invalidateUserCache(group.ownerId);
|
||||
}
|
||||
}),
|
||||
deleteGroup: permissionRequiredProcedure
|
||||
.requiresPermission("admin")
|
||||
|
||||
@@ -56,6 +56,11 @@ export class RedisCacheHandler implements CacheHandler {
|
||||
body: number[];
|
||||
};
|
||||
|
||||
if (parsed.expire <= 0) {
|
||||
await this.redis.del(this.entryKey(cacheKey)).catch(() => {});
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const allTags = [...parsed.tags, ...softTags];
|
||||
const expiration = await this.getExpiration(allTags);
|
||||
if (expiration !== 0 && expiration > parsed.timestamp) {
|
||||
|
||||
@@ -12,7 +12,7 @@ export const memoryPublish = (channel: string, data: unknown) => {
|
||||
const serialized = superjson.stringify(data);
|
||||
lastData.set(channel, { data: serialized, timestamp: Date.now() });
|
||||
|
||||
// Bounded: evict oldest if over limit
|
||||
// ponytail: FIFO eviction by Map insertion order, not timestamp.
|
||||
if (lastData.size > MAX_ENTRIES) {
|
||||
const oldest = lastData.keys().next().value;
|
||||
if (oldest) lastData.delete(oldest);
|
||||
|
||||
Reference in new issue
Block a user