Skip to content

Commit c0a2621

Browse files
committed
dev: improve validation for /withapp endpoint
1 parent 7599e51 commit c0a2621

File tree

3 files changed

+39
-12
lines changed

3 files changed

+39
-12
lines changed

src/gui/src/UI/UIDesktop.js

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1676,9 +1676,22 @@ async function UIDesktop(options) {
16761676
//--------------------------------------------------------------------------------------
16771677
// Trying to view a user's public folder?
16781678
// i.e. https://puter.com/@<username>
1679-
// or https://puter.com/withapp/<app-or-uuid>/@<username>
1679+
// Trying to view a public file in a specific app?
1680+
// i.e. https://puter.com/withapp/<app-or-uuid>/@<username>
16801681
//--------------------------------------------------------------------------------------
1681-
const url_paths = window.location.pathname.split('/').filter(element => element);
1682+
const url_paths = window.location.pathname
1683+
.split('/')
1684+
.filter(element => element)
1685+
.map(uriComponent => {
1686+
try {
1687+
return decodeURIComponent(uriComponent);
1688+
} catch (e) {
1689+
// If the URI component was invalid we can treat it literally.
1690+
// There are no security implications because an encoded URI
1691+
// could encode the literal text of this component anyway.
1692+
return uriComponent;
1693+
}
1694+
});
16821695
const publicShareRoute = getPublicShareRouteFromURL();
16831696
if (publicShareRoute) {
16841697
await handlePublicShareRoute(publicShareRoute);
@@ -1693,24 +1706,31 @@ async function UIDesktop(options) {
16931706
}
16941707

16951708
if (window.url_paths[0]?.toLocaleLowerCase() === 'withapp') {
1696-
const encodedIdentifier = window.url_paths[1];
1709+
const specifiedAppIdentifier = window.url_paths[1];
16971710
const usernameSegment = window.url_paths[2];
1711+
const restSegments = window.url_paths.slice(3);
16981712

1699-
if (!encodedIdentifier || !usernameSegment?.startsWith('@')) {
1713+
if (!specifiedAppIdentifier || !usernameSegment?.startsWith('@')) {
17001714
return null;
17011715
}
1702-
1703-
let decodedIdentifier = encodedIdentifier;
1704-
try {
1705-
decodedIdentifier = decodeURIComponent(encodedIdentifier);
1706-
} catch (_err) {
1707-
// ignore decode errors and fall back to the raw segment
1716+
1717+
for ( const pathComponent of restSegments ) {
1718+
try {
1719+
console.log('validating path component', pathComponent);
1720+
window.valdate_fsentry_name(pathComponent);
1721+
} catch (e) {
1722+
UIAlert({
1723+
message: i18n('error_invalid_path_in_url'),
1724+
type: 'error'
1725+
});
1726+
return null;
1727+
}
17081728
}
17091729

17101730
return {
17111731
usernameSegment,
1732+
specifiedAppIdentifier,
17121733
restSegments: window.url_paths.slice(3),
1713-
specifiedAppIdentifier: decodedIdentifier,
17141734
};
17151735
}
17161736

src/gui/src/helpers.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3185,4 +3185,10 @@ window.handle_same_name_exists = async ({
31853185
}
31863186
return false;
31873187
}
3188-
}
3188+
}
3189+
3190+
// TODO: it would be better to define validation rules for both frontend and
3191+
// backend in a common place; maybe we move these to putility?
3192+
window.validate_username = username => {
3193+
return /^[a-z0-9_]+$/i.test(username);
3194+
};

src/gui/src/i18n/translations/en.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,7 @@ const en = {
516516
'set_as_background': 'Set as Desktop Background',
517517

518518
'error_user_or_path_not_found': 'User or path not found.',
519+
'error_invalid_path_in_url': 'The URL does not contain a valid path to a file or directory on Puter.',
519520
'error_invalid_username': 'Invalid username.',
520521
}
521522
};

0 commit comments

Comments
 (0)