Skip to content

Commit 4ee9327

Browse files
committed
Improve static file handling, URL path derivation, and add MQTT port support
- Refactor static.ts to properly handle index.html paths, simplify path joining, and log received entries. - Fix deriveURLPath to standardize Windows-style paths and eliminate incorrect path joining for URLs. - Enhance checkAllowedModulePath for precise error reporting and improved URL-to-path conversion. - Add MQTT and MQTTS port constants to harperLifecycle and update lifecycle variables to prevent port conflicts in integration tests.
1 parent a8a6b5c commit 4ee9327

4 files changed

Lines changed: 17 additions & 8 deletions

File tree

components/deriveURLPath.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ function pathStartsWithBase(base: string, path: string) {
88
}
99

1010
export function deriveURLPath(component: Component | ComponentV1, path: string, type: 'file' | 'directory'): string {
11+
path = path.replace(/\\/g, '/'); // converting from potential windows path to URL paths
1112
if (path.startsWith('./')) {
1213
path = path.slice(2); // remove leading './'
1314
}
@@ -53,5 +54,5 @@ export function deriveURLPath(component: Component | ComponentV1, path: string,
5354
}
5455
}
5556

56-
return join(component.baseURLPath, path);
57+
return component.baseURLPath + path; // note, do NOT use join here, this is not a file system path, this is a URL path
5758
}

integrationTests/utils/harperLifecycle.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import { equal } from 'node:assert';
1111
// Constants
1212
const HTTP_PORT = 9926;
1313
const HTTPS_PORT = 9927;
14+
const MQTT_PORT = 1883;
15+
const MQTTS_PORT = 8883;
1416
export const OPERATIONS_API_PORT = 9925;
1517
export const DEFAULT_ADMIN_USERNAME = 'admin';
1618
export const DEFAULT_ADMIN_PASSWORD = 'Abc1234!';
@@ -310,6 +312,8 @@ export async function startHarper(ctx: ContextWithHarper, options?: StartHarperO
310312
`--NODE_HOSTNAME=${loopbackAddress}`,
311313
`--HTTP_PORT=${loopbackAddress}:${HTTP_PORT}`,
312314
`--OPERATIONSAPI_NETWORK_PORT=${loopbackAddress}:${OPERATIONS_API_PORT}`,
315+
`--MQTT_NETWORK_PORT=${loopbackAddress}:${MQTT_PORT}`,
316+
`--MQTT_NETWORK_SECUREPORT=${loopbackAddress}:${MQTTS_PORT}`,
313317
'--LOGGING_LEVEL=debug',
314318
'--LOGGING_STDSTREAMS=false',
315319
];

security/jsLoader.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -922,14 +922,14 @@ function createSpawn(spawnFunction: (...args: any) => child_process.ChildProcess
922922
*/
923923
function checkAllowedModulePath(moduleUrl: string, allowedPath?: string): boolean {
924924
if (moduleUrl.startsWith('file:')) {
925-
let path = moduleUrl.slice(7);
925+
let path = fileURLToPath(moduleUrl);
926926
try {
927927
path = realpathSync(path);
928928
} catch {}
929929
if (!allowedPath || path.startsWith(allowedPath)) {
930930
return;
931931
}
932-
throw new Error(`Can not load module outside of allowed path`);
932+
throw new Error(`Can not load module at ${path} outside of allowed path ${allowedPath}`);
933933
}
934934
let simpleName = moduleUrl.startsWith('node:') ? moduleUrl.slice(5) : moduleUrl;
935935
simpleName = simpleName.split('/')[0];

server/static.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { realpathSync, existsSync } from 'node:fs';
2-
import { dirname, join } from 'node:path';
2+
import { join } from 'node:path';
33
import { Scope } from '../components/Scope';
44
import send from 'send';
55

@@ -36,6 +36,7 @@ export function handleApplication(scope: Scope) {
3636

3737
// Handle entry events for the default entry handler based on the `files` and `urlPath` options
3838
scope.handleEntry((entry) => {
39+
logger.error('static received entry', entry);
3940
switch (entry.eventType) {
4041
// Directories only matter for the `index` files
4142
case 'addDir':
@@ -53,17 +54,20 @@ export function handleApplication(scope: Scope) {
5354
// If the file is an index.html, also store it in the index entries
5455
if (entry.urlPath.endsWith('index.html')) {
5556
// Without trailing slash; null -> 301 redirect to trailing slash
56-
indexEntries.set(dirname(entry.urlPath), null);
57+
let lastSlashIndex = entry.urlPath.lastIndexOf('/');
58+
indexEntries.set(entry.urlPath.slice(0, lastSlashIndex), null);
5759
// With trailing slash; serves the index.html file
58-
indexEntries.set(join(dirname(entry.urlPath), '/'), entry.absolutePath);
60+
indexEntries.set(entry.urlPath.slice(0, lastSlashIndex + 1), entry.absolutePath);
5961
}
6062
break;
6163
case 'unlink':
6264
// Remove the file from memory when it is deleted
6365
staticFiles.delete(entry.urlPath);
6466
// If the file is an index.html, remove it from the index entries as well
6567
if (entry.urlPath.endsWith('index.html')) {
66-
indexEntries.delete(dirname(entry.urlPath));
68+
let lastSlashIndex = entry.urlPath.lastIndexOf('/');
69+
indexEntries.delete(entry.urlPath.slice(0, lastSlashIndex));
70+
indexEntries.delete(entry.urlPath.slice(0, lastSlashIndex + 1));
6771
}
6872
break;
6973
}
@@ -101,7 +105,7 @@ export function handleApplication(scope: Scope) {
101105
return {
102106
status: 301,
103107
headers: {
104-
Location: join(req.pathname, '/'),
108+
Location: req.pathname + '/',
105109
},
106110
};
107111
}

0 commit comments

Comments
 (0)