Merge pull request #405 from HeyPuter/eric/path-builder

Add path builder
This commit is contained in:
Eric Dubé 2024-05-16 19:08:56 -04:00 committed by GitHub
commit 297db58e68
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 69 additions and 2 deletions

View File

@ -26,6 +26,7 @@ const auth = require('../middleware/auth.js');
const { generate_puter_page_html } = require('../temp/puter_page_loader'); const { generate_puter_page_html } = require('../temp/puter_page_loader');
const { Context } = require('../util/context'); const { Context } = require('../util/context');
const { DB_READ } = require('../services/database/consts'); const { DB_READ } = require('../services/database/consts');
const { PathBuilder } = require('../util/pathutil.js');
let auth_user; let auth_user;
@ -246,6 +247,7 @@ router.all('*', async function(req, res, next) {
// /assets/ // /assets/
// ------------------------ // ------------------------
else if (path.startsWith('/assets/')) { else if (path.startsWith('/assets/')) {
path = PathBuilder.resolve(path);
return res.sendFile(path, { root: __dirname + '../../public' }, function (err) { return res.sendFile(path, { root: __dirname + '../../public' }, function (err) {
if (err && err.statusCode) { if (err && err.statusCode) {
return res.status(err.statusCode).send('Error /public/') return res.status(err.statusCode).send('Error /public/')
@ -338,7 +340,7 @@ router.all('*', async function(req, res, next) {
// /dist/... // /dist/...
else if(path.startsWith('/dist/') || path.startsWith('/src/')){ else if(path.startsWith('/dist/') || path.startsWith('/src/')){
path = _path.resolve(path); path = PathBuilder.resolve(path);
return res.sendFile(path, {root: config.assets.gui}, function(err){ return res.sendFile(path, {root: config.assets.gui}, function(err){
if(err && err.statusCode){ if(err && err.statusCode){
return res.status(err.statusCode).send('Error /gui/dist/') return res.status(err.statusCode).send('Error /gui/dist/')
@ -348,6 +350,7 @@ router.all('*', async function(req, res, next) {
// All other paths // All other paths
else{ else{
path = PathBuilder.resolve(path);
return res.sendFile(path, {root: _path.join(config.assets.gui, 'src')}, function(err){ return res.sendFile(path, {root: _path.join(config.assets.gui, 'src')}, function(err){
if(err && err.statusCode){ if(err && err.statusCode){
return res.status(err.statusCode).send('Error /gui/') return res.status(err.statusCode).send('Error /gui/')
@ -364,7 +367,11 @@ router.all('*', async function(req, res, next) {
subdomain === 'draw' || subdomain === 'camera' || subdomain === 'recorder' || subdomain === 'draw' || subdomain === 'camera' || subdomain === 'recorder' ||
subdomain === 'dev-center' || subdomain === 'terminal'){ subdomain === 'dev-center' || subdomain === 'terminal'){
let root = _path.join(__dirname, config.defaultjs_asset_path, 'apps', subdomain); let root = PathBuilder
.add(__dirname)
.add(config.defaultjs_asset_path, { allow_traversal: true })
.add('apps').add(subdomain)
.build();
if ( subdomain === 'docs' ) root += '/dist'; if ( subdomain === 'docs' ) root += '/dist';
root = _path.normalize(root); root = _path.normalize(root);

View File

@ -0,0 +1,60 @@
const { AdvancedBase } = require("@heyputer/puter-js-common");
/**
* PathBuilder implements the builder pattern for building paths.
* This makes it clear which path fragments are allowed to traverse
* to parent directories.
*/
class PathBuilder extends AdvancedBase {
static MODULES = {
path: require('path'),
}
constructor() {
super();
this.path_ = '';
}
static create () {
return new PathBuilder();
}
static add (fragment, options) {
return PathBuilder.create().add(fragment, options);
}
static resolve (fragment) {
const p = PathBuilder.create();
const require = p.require;
const node_path = require('path');
fragment = node_path.resolve(fragment);
return p.add(fragment).build();
}
add (fragment, options) {
options = options || {};
if ( ! options.allow_traversal ) {
fragment = fragment.replace(/(\.\.\/|\.\.\\)/g, '');
if ( fragment === '..' ) {
fragment = '';
}
}
const require = this.require;
const node_path = require('path');
this.path_ = this.path_
? node_path.join(this.path_, fragment)
: fragment;
return this;
}
build () {
return this.path_;
}
}
module.exports = {
PathBuilder,
};