Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions src/hooks.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as Sentry from '@sentry/sveltekit';
import type { Handle } from '@sveltejs/kit';
import redirects from './redirects.json';
import { sequence } from '@sveltejs/kit/hooks';
import { getMarkdownContent, processMarkdownWithPartials } from '$lib/server/markdown';
import { getMarkdownContent } from '$lib/server/markdown';
import { type GithubUser } from '$routes/(init)/init/(utils)/auth';
import { createInitSessionClient } from '$routes/(init)/init/(utils)/appwrite';
import type { AppwriteUser } from '$lib/utils/console';
Expand All @@ -24,9 +24,7 @@ const markdownHandler: Handle = async ({ event, resolve }) => {
return new Response('Not found', { status: 404 });
}

const processedContent = await processMarkdownWithPartials(content);

return new Response(processedContent, {
return new Response(content, {
status: 200,
headers: {
'Content-Type': 'text/markdown; charset=utf-8'
Expand Down
47 changes: 0 additions & 47 deletions src/lib/server/markdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,6 @@ import { readFile } from 'fs/promises';
import { join, normalize, resolve } from 'path';
import { generateDynamicMarkdown, hasDynamicMarkdownGenerator } from './markdown-generators';

const partialsCache = new Map<string, string>();

export async function processMarkdownWithPartials(content: string): Promise<string> {
const partialsDir = join(process.cwd(), 'src', 'partials');
const resolvedPartialsDir = resolve(partialsDir);
const partialRegex = /\{%\s*partial\s+file="([^"]+)"\s*\/%\}/g;

const matches = [...content.matchAll(partialRegex)];
if (matches.length === 0) return content;

let result = content;
for (const match of matches) {
const partialFile = match[1];
const fullMatch = match[0];

if (!partialsCache.has(partialFile)) {
try {
const normalizedPartialFile = normalize(partialFile).replace(
/^(\.\.(\/|\\|$))+/,
''
);
const partialPath = resolve(partialsDir, normalizedPartialFile);

if (
!partialPath.startsWith(resolvedPartialsDir + '/') &&
partialPath !== resolvedPartialsDir
) {
console.warn(`Partial path traversal attempt detected: ${partialFile}`);
partialsCache.set(partialFile, '');
continue;
}

const partialContent = await readFile(partialPath, 'utf-8');
partialsCache.set(partialFile, partialContent);
} catch {
console.warn(`Partial not found: ${partialFile}`);
partialsCache.set(partialFile, '');
}
}

const partialContent = partialsCache.get(partialFile) || '';
result = result.replaceAll(fullMatch, partialContent);
}

return result;
}

/**
* Gets markdown content for a route.
* - For dynamic routes with registered generators, generates markdown from data sources
Expand Down