diff --git a/packages/backend/src/routers/hosting/puter-site.js b/packages/backend/src/routers/hosting/puter-site.js index 2e94d85b..fbf9ce5f 100644 --- a/packages/backend/src/routers/hosting/puter-site.js +++ b/packages/backend/src/routers/hosting/puter-site.js @@ -27,10 +27,13 @@ const { LLRead } = require("../../filesystem/ll_operations/ll_read"); const { Actor, UserActorType, SiteActorType } = require("../../services/auth/Actor"); const APIError = require("../../api/APIError"); +const AT_DIRECTORY_NAMESPACE = '4aa6dc52-34c1-4b8a-b63c-a62b27f727cf'; + class PuterSiteMiddleware extends AdvancedBase { static MODULES = { path: require('path'), mime: require('mime-types'), + uuidv5: require('uuid').v5, } install (app) { app.use(this.run.bind(this)); @@ -66,9 +69,39 @@ class PuterSiteMiddleware extends AdvancedBase { const context = Context.get(); const services = context.get('services'); + + const get_username_site = (async () => { + if ( ! subdomain.endsWith('.at') ) return; + const parts = subdomain.split('.'); + if ( parts.length !== 2 ) return; + const username = parts[0]; + if ( ! username.match(config.username_regex) ) { + return; + } + const svc_fs = services.get('filesystem'); + const index_node = await svc_fs.node(new NodePathSelector( + `/${username}/Public/index.html` + )); + const node = await svc_fs.node(new NodePathSelector( + `/${username}/Public` + )); + if ( ! await index_node.exists() ) return; + + return { + name: username + '.at', + uuid: this.modules.uuidv5(username, AT_DIRECTORY_NAMESPACE), + root_dir_id: await node.get('mysql-id'), + }; + }) + + const site = + await get_username_site() || + await (async () => { + const svc_puterSite = services.get('puter-site'); + const site = await svc_puterSite.get_subdomain(subdomain); + return site; + })(); - const svc_puterSite = services.get('puter-site'); - const site = await svc_puterSite.get_subdomain(subdomain); if ( site === null ) { return res.status(404).send('Subdomain not found'); } diff --git a/packages/backend/src/services/PuterHomepageService.js b/packages/backend/src/services/PuterHomepageService.js index 32d32e52..cdb86a81 100644 --- a/packages/backend/src/services/PuterHomepageService.js +++ b/packages/backend/src/services/PuterHomepageService.js @@ -75,6 +75,8 @@ class PuterHomepageService extends BaseService { app_name_regex: config.app_name_regex, app_name_max_length: config.app_name_max_length, app_title_max_length: config.app_title_max_length, + hosting_domain: config.static_hosting_domain + + (config.pub_port !== 80 && config.pub_port !== 443 ? ':' + config.pub_port : ''), subdomain_regex: config.subdomain_regex, subdomain_max_length: config.subdomain_max_length, domain: config.domain, diff --git a/packages/backend/src/services/WebServerService.js b/packages/backend/src/services/WebServerService.js index 03848d7a..cfcd5794 100644 --- a/packages/backend/src/services/WebServerService.js +++ b/packages/backend/src/services/WebServerService.js @@ -314,7 +314,11 @@ class WebServerService extends BaseService { // Validate host header against allowed domains to prevent host header injection // https://www.owasp.org/index.php/Host_Header_Injection app.use((req, res, next)=>{ - const allowedDomains = [config.domain.toLowerCase(), config.static_hosting_domain.toLowerCase()]; + const allowedDomains = [ + config.domain.toLowerCase(), + config.static_hosting_domain.toLowerCase(), + 'at.' + config.static_hosting_domain.toLowerCase(), + ]; // Retrieve the Host header and ensure it's in a valid format const hostHeader = req.headers.host; diff --git a/src/UI/UIWindow.js b/src/UI/UIWindow.js index 90167c7b..9061a0bc 100644 --- a/src/UI/UIWindow.js +++ b/src/UI/UIWindow.js @@ -337,6 +337,32 @@ async function UIWindow(options) { if(options.is_dir){ // Detail layout header h += window.explore_table_headers(); + + // Maybe render iframe for users public directory + (() => { + if ( options.is_saveFileDialog || options.is_openFileDialog || options.is_directoryPicker ) { + return false; + } + + if ( ! options.path || ! options.path.startsWith('/') ) { // sus + return false; + } + + const components = options.path.slice(1).split('/'); + + console.log('components???', components); + if ( components.length === 2 && components[1] === 'Public' ) { + const username = components[0]; + h += ` + `; + } + })(); // Add 'This folder is empty' message by default h += `
`;