mirror of
https://github.com/HeyPuter/puter.git
synced 2026-01-10 15:10:40 -06:00
Dav (#1450)
* Windows WebDav support * feat: 2fa support for dav * fix auth cookie when Basic auth present * dev: dav: refactor handler, support root level navigation * dev: dav: JSDOCing important things * fix: possible edge case of password containing colon character * feat: direct token login for webdav * set cookie to not be session cookie * fx: webdav undefined origin support
This commit is contained in:
@@ -388,6 +388,8 @@ const install = async ({ services, app, useapi, modapi }) => {
|
||||
|
||||
const { WispService } = require('./services/WispService');
|
||||
services.registerService('wisp', WispService);
|
||||
const { WebDavFS } = require('./services/WebDavFS');
|
||||
services.registerService('dav', WebDavFS);
|
||||
|
||||
const { RequestMeasureService } = require('./services/RequestMeasureService');
|
||||
services.registerService('request-measure', RequestMeasureService);
|
||||
|
||||
@@ -117,7 +117,7 @@ class LLRead extends LLFilesystemOperation {
|
||||
const context = a.iget('context');
|
||||
const storage = context.get('storage');
|
||||
|
||||
const { fsNode, version_id, offset, length, has_range } = a.values();
|
||||
const { fsNode, version_id, offset, length, has_range, range } = a.values();
|
||||
|
||||
// Empty object here is in the case of local fiesystem,
|
||||
// where s3:location will return null.
|
||||
@@ -130,9 +130,9 @@ class LLRead extends LLFilesystemOperation {
|
||||
bucket_region: location.bucket_region,
|
||||
version_id,
|
||||
key: location.key,
|
||||
...(has_range ? {
|
||||
...(range? {range} : (has_range ? {
|
||||
range: `bytes=${offset}-${offset+length-1}`
|
||||
} : {}),
|
||||
} : {})),
|
||||
}));
|
||||
|
||||
a.set('stream', stream);
|
||||
|
||||
@@ -55,7 +55,7 @@ const configurable_auth = options => async (req, res, next) => {
|
||||
if(req.body && req.body.auth_token)
|
||||
token = req.body.auth_token;
|
||||
// HTTML Auth header
|
||||
else if(req.header && req.header('Authorization')) {
|
||||
else if (req.header && req.header('Authorization') && !req.header('Authorization').startsWith("Basic ")) {
|
||||
token = req.header('Authorization');
|
||||
token = token.replace('Bearer ', '').trim();
|
||||
if ( token === 'undefined' ) {
|
||||
@@ -74,7 +74,7 @@ const configurable_auth = options => async (req, res, next) => {
|
||||
else if(req.handshake && req.handshake.query && req.handshake.query.auth_token)
|
||||
token = req.handshake.query.auth_token;
|
||||
|
||||
if(!token) {
|
||||
if(!token || token.startsWith("Basic ")) {
|
||||
if ( optional ) {
|
||||
next();
|
||||
return;
|
||||
|
||||
@@ -628,10 +628,11 @@ class WebServerService extends BaseService {
|
||||
}
|
||||
|
||||
// Request methods to allow
|
||||
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
|
||||
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK');
|
||||
|
||||
const allowed_headers = [
|
||||
"Origin", "X-Requested-With", "Content-Type", "Accept", "Authorization", "sentry-trace", "baggage"
|
||||
"Origin", "X-Requested-With", "Content-Type", "Accept", "Authorization", "sentry-trace", "baggage",
|
||||
"Depth", "Destination", "Overwrite", "If", "Lock-Token", "DAV"
|
||||
];
|
||||
|
||||
// Request headers to allow
|
||||
@@ -663,7 +664,22 @@ class WebServerService extends BaseService {
|
||||
});
|
||||
|
||||
// Options for all requests (for CORS)
|
||||
app.options('/*', (_, res) => {
|
||||
app.options('/*', (req, res) => {
|
||||
if (req.path.startsWith('/dav/')) {
|
||||
res.set({
|
||||
'Allow': 'OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, COPY, MOVE, MKCOL, PROPFIND, PROPPATCH, LOCK, UNLOCK, ORDERPATCH',
|
||||
'DAV': '1, 2, ordered-collections', // WebDAV compliance classes with ordered-collections for macOS
|
||||
'MS-Author-Via': 'DAV', // Microsoft compatibility
|
||||
'Server': 'Puter/WebDAV', // Server identification
|
||||
'Accept-Ranges': 'bytes',
|
||||
'Content-Type': 'text/plain; charset=utf-8', // Explicit content type
|
||||
'Content-Length': '0',
|
||||
'Cache-Control': 'no-cache', // Prevent caching issues
|
||||
'Connection': 'Keep-Alive' // Keep connection alive for macOS
|
||||
});
|
||||
res.status(200).end();
|
||||
console.log("OPTIONS request completed for macOS compatibility");
|
||||
}
|
||||
return res.sendStatus(200);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -193,22 +193,57 @@ module.exports = function eggspress (route, settings, handler) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if ( settings.allowedMethods.includes('GET') ) {
|
||||
if (settings.allowedMethods.includes('GET')) {
|
||||
router.get(route, ...mw, errorHandledHandler, ...afterMW);
|
||||
}
|
||||
|
||||
if ( settings.allowedMethods.includes('POST') ) {
|
||||
if (settings.allowedMethods.includes('HEAD')) {
|
||||
router.head(route, ...mw, errorHandledHandler, ...afterMW);
|
||||
}
|
||||
|
||||
if (settings.allowedMethods.includes('POST')) {
|
||||
router.post(route, ...mw, errorHandledHandler, ...afterMW);
|
||||
}
|
||||
|
||||
if ( settings.allowedMethods.includes('PUT') ) {
|
||||
if (settings.allowedMethods.includes('PUT')) {
|
||||
router.put(route, ...mw, errorHandledHandler, ...afterMW);
|
||||
}
|
||||
|
||||
if ( settings.allowedMethods.includes('DELETE') ) {
|
||||
if (settings.allowedMethods.includes('DELETE')) {
|
||||
router.delete(route, ...mw, errorHandledHandler, ...afterMW);
|
||||
}
|
||||
|
||||
if (settings.allowedMethods.includes('PROPFIND')) {
|
||||
router.propfind(route, ...mw, errorHandledHandler, ...afterMW);
|
||||
}
|
||||
|
||||
if (settings.allowedMethods.includes('PROPPATCH')) {
|
||||
router.proppatch(route, ...mw, errorHandledHandler, ...afterMW);
|
||||
}
|
||||
|
||||
if (settings.allowedMethods.includes('MKCOL')) {
|
||||
router.mkcol(route, ...mw, errorHandledHandler, ...afterMW);
|
||||
}
|
||||
|
||||
if (settings.allowedMethods.includes('COPY')) {
|
||||
router.copy(route, ...mw, errorHandledHandler, ...afterMW);
|
||||
}
|
||||
|
||||
if (settings.allowedMethods.includes('MOVE')) {
|
||||
router.move(route, ...mw, errorHandledHandler, ...afterMW);
|
||||
}
|
||||
|
||||
if (settings.allowedMethods.includes('LOCK')) {
|
||||
router.lock(route, ...mw, errorHandledHandler, ...afterMW);
|
||||
}
|
||||
|
||||
if (settings.allowedMethods.includes('UNLOCK')) {
|
||||
router.unlock(route, ...mw, errorHandledHandler, ...afterMW);
|
||||
}
|
||||
|
||||
if (settings.allowedMethods.includes('OPTIONS')) {
|
||||
router.options(route, ...mw, errorHandledHandler, ...afterMW);
|
||||
}
|
||||
|
||||
return router;
|
||||
}
|
||||
1194
src/backend/src/services/WebDavFS.js
Normal file
1194
src/backend/src/services/WebDavFS.js
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user