From 83fdb9e1af16bfdb00504e885698c8189d565fb0 Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Wed, 18 Jun 2025 11:59:06 +1000 Subject: [PATCH] feat: Get multipage sites working with link modifications --- .../ipfs.act/index.html | 2 +- example_sites/ipfs.freeconcept/index.html | 28 +++++++ example_sites/ipfs.freeconcept/test.html | 28 +++++++ public/index.html | 1 + server.js | 77 +++++++++++++++++-- 5 files changed, 127 insertions(+), 9 deletions(-) rename public/demo.html => example_sites/ipfs.act/index.html (99%) create mode 100644 example_sites/ipfs.freeconcept/index.html create mode 100644 example_sites/ipfs.freeconcept/test.html diff --git a/public/demo.html b/example_sites/ipfs.act/index.html similarity index 99% rename from public/demo.html rename to example_sites/ipfs.act/index.html index 654e2b7..1a65179 100644 --- a/public/demo.html +++ b/example_sites/ipfs.act/index.html @@ -24,4 +24,4 @@ © Nathan.Woodburn/ - \ No newline at end of file + diff --git a/example_sites/ipfs.freeconcept/index.html b/example_sites/ipfs.freeconcept/index.html new file mode 100644 index 0000000..accb7fc --- /dev/null +++ b/example_sites/ipfs.freeconcept/index.html @@ -0,0 +1,28 @@ + + + + + + IPFS.freeconcept + + + + + + + + + + +

IPFS.freeconcept

+

This is a demo website with multiple pages running on IPFS.

+

It is designed to showcase the capabilities of IPFS and Handshake domains.

+

Have a look at this other page test.html

+ + Fire Portal + +
+ © Nathan.Woodburn/ +
+ + diff --git a/example_sites/ipfs.freeconcept/test.html b/example_sites/ipfs.freeconcept/test.html new file mode 100644 index 0000000..6471610 --- /dev/null +++ b/example_sites/ipfs.freeconcept/test.html @@ -0,0 +1,28 @@ + + + + + + IPFS.freeconcept + + + + + + + + + + +

IPFS.freeconcept

+

This is a demo subpage running on IPFS.

+

It is designed to showcase the capabilities of IPFS and Handshake domains.

+

This demonstrates how a folder can be used to store multipage websites

+ + Fire Portal + +
+ © Nathan.Woodburn/ +
+ + diff --git a/public/index.html b/public/index.html index 272e7a3..6dd362d 100644 --- a/public/index.html +++ b/public/index.html @@ -123,6 +123,7 @@

Examples:

diff --git a/server.js b/server.js index 84d3be4..a7891a2 100644 --- a/server.js +++ b/server.js @@ -53,6 +53,51 @@ function injectTrackingScript(content, mimeType) { return content; } +// Helper function to make links absolute in HTML content +function makeLinksAbsolute(content, mimeType, domain, subPath = '') { + if (!mimeType || !mimeType.includes('text/html')) { + return content; + } + + let htmlContent = content.toString(); + const baseUrl = `/${domain}`; + + // Create base directory for proper path resolution + let basePath = '/'; + if (subPath) { + // Remove file part if present + const pathParts = subPath.split('/'); + if (pathParts.length > 1 && !subPath.endsWith('/')) { + pathParts.pop(); + } + basePath = `/${pathParts.join('/')}/`; + } + + // Function to resolve paths + const resolvePath = (href) => { + if (href.startsWith('/')) { + // Absolute path within the site - make it absolute to our gateway + return `${baseUrl}${href}`; + } else if (!href.match(/^(https?:|mailto:|tel:|#|javascript:|data:)/)) { + // Relative path - resolve it against current directory + return `${baseUrl}${basePath}${href}`; + } + return href; // Already absolute or special protocol + }; + + // Replace href attributes (like ) + htmlContent = htmlContent.replace(/href=["'](.*?)["']/g, (match, href) => { + return `href="${resolvePath(href)}"`; + }); + + // Replace src attributes (like ) + htmlContent = htmlContent.replace(/src=["'](.*?)["']/g, (match, src) => { + return `src="${resolvePath(src)}"`; + }); + + return htmlContent; +} + // Status endpoint app.get('/api/status', (req, res) => { res.json({ status: 'online', version: '1.0.0' }); @@ -98,8 +143,12 @@ app.get('/:domain', async (req, res, next) => { res.setHeader('Content-Type', content.mimeType); } - // Inject tracking script if content is HTML - const processedContent = injectTrackingScript(content.data, content.mimeType); + // Process HTML content: make links absolute and inject tracking script + let processedContent = content.data; + if (content.mimeType && content.mimeType.includes('text/html')) { + processedContent = makeLinksAbsolute(processedContent, content.mimeType, domain, ''); + processedContent = injectTrackingScript(processedContent, content.mimeType); + } // Return the content res.send(processedContent); @@ -155,8 +204,12 @@ app.get('/:domain/*', async (req, res, next) => { res.setHeader('Content-Type', content.mimeType); } - // Inject tracking script if content is HTML - const processedContent = injectTrackingScript(content.data, content.mimeType); + // Process HTML content: make links absolute and inject tracking script + let processedContent = content.data; + if (content.mimeType && content.mimeType.includes('text/html')) { + processedContent = makeLinksAbsolute(processedContent, content.mimeType, domain, subPath); + processedContent = injectTrackingScript(processedContent, content.mimeType); + } // Return the content res.send(processedContent); @@ -206,8 +259,12 @@ app.get('/hns/:domain/*', async (req, res) => { res.setHeader('Content-Type', content.mimeType); } - // Inject tracking script if content is HTML - const processedContent = injectTrackingScript(content.data, content.mimeType); + // Process HTML content: make links absolute and inject tracking script + let processedContent = content.data; + if (content.mimeType && content.mimeType.includes('text/html')) { + processedContent = makeLinksAbsolute(processedContent, content.mimeType, domain, subPath); + processedContent = injectTrackingScript(processedContent, content.mimeType); + } // Return the content res.send(processedContent); @@ -255,8 +312,12 @@ app.get('/hns/:domain', async (req, res) => { res.setHeader('Content-Type', content.mimeType); } - // Inject tracking script if content is HTML - const processedContent = injectTrackingScript(content.data, content.mimeType); + // Process HTML content: make links absolute and inject tracking script + let processedContent = content.data; + if (content.mimeType && content.mimeType.includes('text/html')) { + processedContent = makeLinksAbsolute(processedContent, content.mimeType, domain, ''); + processedContent = injectTrackingScript(processedContent, content.mimeType); + } // Return the content res.send(processedContent);