mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2025-09-06 04:48:01 +00:00
add middleware to route handlers for bags & tiddlers routes
This commit is contained in:
@@ -482,13 +482,21 @@ Server.prototype.requestAuthentication = function(response) {
|
||||
};
|
||||
|
||||
Server.prototype.redirectToLogin = function(response, returnUrl) {
|
||||
if(!response.headersSent) {
|
||||
response.setHeader('Set-Cookie', `returnUrl=${returnUrl}; HttpOnly; Path=/`);
|
||||
const loginUrl = '/login?returnUrl=' + encodeURIComponent(returnUrl);
|
||||
response.writeHead(302, {
|
||||
'Location': loginUrl
|
||||
});
|
||||
response.end();
|
||||
if (!response.headersSent) {
|
||||
const validReturnUrlRegex = /^\/(?!.*\.(ico|png|jpg|jpeg|gif|svg|css|js|woff|woff2|ttf|eot)$).*$/;
|
||||
var sanitizedReturnUrl = '/'; // Default to home page
|
||||
|
||||
if (validReturnUrlRegex.test(returnUrl)) {
|
||||
sanitizedReturnUrl = returnUrl;
|
||||
} else {
|
||||
console.log(`Invalid return URL detected: ${returnUrl}. Redirecting to home page.`);
|
||||
}
|
||||
response.setHeader('Set-Cookie', `returnUrl=${encodeURIComponent(sanitizedReturnUrl)}; HttpOnly; Path=/`);
|
||||
const loginUrl = '/login';
|
||||
response.writeHead(302, {
|
||||
'Location': loginUrl
|
||||
});
|
||||
response.end();
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -12,25 +12,32 @@ DELETE /bags/:bag_name/tiddler/:title
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var aclMiddleware = require("$:/plugins/tiddlywiki/multiwikiserver/modules/routes/helpers/acl-middleware.js").middleware;
|
||||
|
||||
exports.method = "DELETE";
|
||||
|
||||
exports.path = /^\/bags\/([^\/]+)\/tiddlers\/(.+)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
aclMiddleware(request, response, state, "bag", "WRITE");
|
||||
// Get the parameters
|
||||
var bag_name = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
title = $tw.utils.decodeURIComponentSafe(state.params[1]);
|
||||
if(bag_name) {
|
||||
var result = $tw.mws.store.deleteTiddler(title,bag_name);
|
||||
response.writeHead(204, "OK", {
|
||||
"X-Revision-Number": result.tiddler_id.toString(),
|
||||
Etag: state.makeTiddlerEtag(result),
|
||||
"Content-Type": "text/plain"
|
||||
});
|
||||
response.end();
|
||||
if(!response.headersSent) {
|
||||
var result = $tw.mws.store.deleteTiddler(title,bag_name);
|
||||
response.writeHead(204, "OK", {
|
||||
"X-Revision-Number": result.tiddler_id.toString(),
|
||||
Etag: state.makeTiddlerEtag(result),
|
||||
"Content-Type": "text/plain"
|
||||
});
|
||||
response.end();
|
||||
}
|
||||
} else {
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
if(!response.headersSent) {
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -12,17 +12,20 @@ GET /bags/:bag_name/tiddler/:title/blob
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var aclMiddleware = require("$:/plugins/tiddlywiki/multiwikiserver/modules/routes/helpers/acl-middleware.js").middleware;
|
||||
|
||||
exports.method = "GET";
|
||||
|
||||
exports.path = /^\/bags\/([^\/]+)\/tiddlers\/([^\/]+)\/blob$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
aclMiddleware(request, response, state, "bag", "READ");
|
||||
// Get the parameters
|
||||
const bag_name = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
title = $tw.utils.decodeURIComponentSafe(state.params[1]);
|
||||
if(bag_name) {
|
||||
const result = $tw.mws.store.getBagTiddlerStream(title,bag_name);
|
||||
if(result) {
|
||||
if(result && !response.headersSent) {
|
||||
response.writeHead(200, "OK",{
|
||||
Etag: state.makeTiddlerEtag(result),
|
||||
"Content-Type": result.type,
|
||||
@@ -31,8 +34,10 @@ exports.handler = function(request,response,state) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
if (!response.headersSent) {
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
}
|
||||
};
|
||||
|
||||
}());
|
||||
|
@@ -16,11 +16,14 @@ fallback=<url> // Optional redirect if the tiddler is not found
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var aclMiddleware = require("$:/plugins/tiddlywiki/multiwikiserver/modules/routes/helpers/acl-middleware.js").middleware;
|
||||
|
||||
exports.method = "GET";
|
||||
|
||||
exports.path = /^\/bags\/([^\/]+)\/tiddlers\/(.+)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
aclMiddleware(request, response, state, "gab", "READ");
|
||||
// Get the parameters
|
||||
const bag_name = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
title = $tw.utils.decodeURIComponentSafe(state.params[1]),
|
||||
@@ -37,29 +40,37 @@ exports.handler = function(request,response,state) {
|
||||
// This is not a JSON API request, we should return the raw tiddler content
|
||||
const result = $tw.mws.store.getBagTiddlerStream(title,bag_name);
|
||||
if(result) {
|
||||
response.writeHead(200, "OK",{
|
||||
Etag: state.makeTiddlerEtag(result),
|
||||
"Content-Type": result.type
|
||||
});
|
||||
if(!response.headersSent){
|
||||
response.writeHead(200, "OK",{
|
||||
Etag: state.makeTiddlerEtag(result),
|
||||
"Content-Type": result.type
|
||||
});
|
||||
}
|
||||
result.stream.pipe(response);
|
||||
return;
|
||||
} else {
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
if(!response.headersSent){
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Redirect to fallback URL if tiddler not found
|
||||
if(state.queryParameters.fallback) {
|
||||
response.writeHead(302, "OK",{
|
||||
"Location": state.queryParameters.fallback
|
||||
});
|
||||
response.end();
|
||||
if (!response.headersSent){
|
||||
response.writeHead(302, "OK",{
|
||||
"Location": state.queryParameters.fallback
|
||||
});
|
||||
response.end();
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
if(!response.headersSent){
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@@ -16,11 +16,14 @@ fallback=<url> // Optional redirect if the tiddler is not found
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var aclMiddleware = require("$:/plugins/tiddlywiki/multiwikiserver/modules/routes/helpers/acl-middleware.js").middleware;
|
||||
|
||||
exports.method = "GET";
|
||||
|
||||
exports.path = /^\/recipes\/([^\/]+)\/tiddlers\/(.+)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
aclMiddleware(request, response, state, "recipe", "READ");
|
||||
// Get the parameters
|
||||
var recipe_name = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
title = $tw.utils.decodeURIComponentSafe(state.params[1]),
|
||||
@@ -38,27 +41,32 @@ exports.handler = function(request,response,state) {
|
||||
} else {
|
||||
// This is not a JSON API request, we should return the raw tiddler content
|
||||
var type = tiddlerInfo.tiddler.type || "text/plain";
|
||||
response.writeHead(200, "OK",{
|
||||
if(!response.headersSent) {
|
||||
response.writeHead(200, "OK",{
|
||||
Etag: state.makeTiddlerEtag(tiddlerInfo),
|
||||
"Content-Type": type
|
||||
});
|
||||
response.write(tiddlerInfo.tiddler.text || "",($tw.config.contentTypeInfo[type] ||{encoding: "utf8"}).encoding);
|
||||
response.end();;
|
||||
"Content-Type": type
|
||||
});
|
||||
response.write(tiddlerInfo.tiddler.text || "",($tw.config.contentTypeInfo[type] ||{encoding: "utf8"}).encoding);
|
||||
response.end();
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Redirect to fallback URL if tiddler not found
|
||||
if(state.queryParameters.fallback) {
|
||||
response.writeHead(302, "OK",{
|
||||
"Location": state.queryParameters.fallback
|
||||
});
|
||||
response.end();
|
||||
return;
|
||||
} else {
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
return;
|
||||
if(!response.headersSent) {
|
||||
// Redirect to fallback URL if tiddler not found
|
||||
if(state.queryParameters.fallback) {
|
||||
response.writeHead(302, "OK",{
|
||||
"Location": state.queryParameters.fallback
|
||||
});
|
||||
response.end();
|
||||
return;
|
||||
} else {
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -12,27 +12,32 @@ GET /recipes/:recipe_name/tiddlers.json?last_known_tiddler_id=:last_known_tiddle
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var aclMiddleware = require("$:/plugins/tiddlywiki/multiwikiserver/modules/routes/helpers/acl-middleware.js").middleware;
|
||||
|
||||
exports.method = "GET";
|
||||
|
||||
exports.path = /^\/recipes\/([^\/]+)\/tiddlers.json$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
// Get the parameters
|
||||
var recipe_name = $tw.utils.decodeURIComponentSafe(state.params[0]);
|
||||
if(recipe_name) {
|
||||
// Get the tiddlers in the recipe, optionally since the specified last known tiddler_id
|
||||
var recipeTiddlers = $tw.mws.store.getRecipeTiddlers(recipe_name,{
|
||||
include_deleted: state.queryParameters.include_deleted === "true",
|
||||
last_known_tiddler_id: state.queryParameters.last_known_tiddler_id
|
||||
});
|
||||
if(recipeTiddlers) {
|
||||
state.sendResponse(200,{"Content-Type": "application/json"},JSON.stringify(recipeTiddlers),"utf8");
|
||||
return;
|
||||
aclMiddleware(request, response, state, "recipe", "READ");
|
||||
if(!response.headersSent) {
|
||||
// Get the parameters
|
||||
var recipe_name = $tw.utils.decodeURIComponentSafe(state.params[0]);
|
||||
if(recipe_name) {
|
||||
// Get the tiddlers in the recipe, optionally since the specified last known tiddler_id
|
||||
var recipeTiddlers = $tw.mws.store.getRecipeTiddlers(recipe_name,{
|
||||
include_deleted: state.queryParameters.include_deleted === "true",
|
||||
last_known_tiddler_id: state.queryParameters.last_known_tiddler_id
|
||||
});
|
||||
if(recipeTiddlers) {
|
||||
state.sendResponse(200,{"Content-Type": "application/json"},JSON.stringify(recipeTiddlers),"utf8");
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Fail if something went wrong
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
}
|
||||
// Fail if something went wrong
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
|
||||
};
|
||||
|
||||
|
@@ -12,6 +12,8 @@ POST /bags/:bag_name/tiddlers/
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var aclMiddleware = require("$:/plugins/tiddlywiki/multiwikiserver/modules/routes/helpers/acl-middleware.js").middleware;
|
||||
|
||||
exports.method = "POST";
|
||||
|
||||
exports.path = /^\/bags\/([^\/]+)\/tiddlers\/$/;
|
||||
@@ -21,6 +23,7 @@ exports.bodyFormat = "stream";
|
||||
exports.csrfDisable = true;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
aclMiddleware(request, response, state, "bag", "WRITE");
|
||||
const path = require("path"),
|
||||
fs = require("fs"),
|
||||
processIncomingStream = require("$:/plugins/tiddlywiki/multiwikiserver/routes/helpers/multipart-forms.js").processIncomingStream;
|
||||
@@ -39,29 +42,31 @@ exports.handler = function(request,response,state) {
|
||||
"imported-tiddlers": results
|
||||
}));
|
||||
} else {
|
||||
response.writeHead(200, "OK",{
|
||||
"Content-Type": "text/html"
|
||||
});
|
||||
response.write(`
|
||||
<!doctype html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
|
||||
</head>
|
||||
<body>
|
||||
`);
|
||||
// Render the html
|
||||
var html = $tw.mws.store.adminWiki.renderTiddler("text/html","$:/plugins/tiddlywiki/multiwikiserver/templates/post-bag-tiddlers",{
|
||||
variables: {
|
||||
"bag-name": bag_name,
|
||||
"imported-titles": JSON.stringify(results)
|
||||
}
|
||||
});
|
||||
response.write(html);
|
||||
response.write(`
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
response.end();
|
||||
if(!response.headersSent) {
|
||||
response.writeHead(200, "OK",{
|
||||
"Content-Type": "text/html"
|
||||
});
|
||||
response.write(`
|
||||
<!doctype html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
|
||||
</head>
|
||||
<body>
|
||||
`);
|
||||
// Render the html
|
||||
var html = $tw.mws.store.adminWiki.renderTiddler("text/html","$:/plugins/tiddlywiki/multiwikiserver/templates/post-bag-tiddlers",{
|
||||
variables: {
|
||||
"bag-name": bag_name,
|
||||
"imported-titles": JSON.stringify(results)
|
||||
}
|
||||
});
|
||||
response.write(html);
|
||||
response.write(`
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
response.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@@ -17,6 +17,8 @@ description
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var aclMiddleware = require("$:/plugins/tiddlywiki/multiwikiserver/modules/routes/helpers/acl-middleware.js").middleware;
|
||||
|
||||
exports.method = "POST";
|
||||
|
||||
exports.path = /^\/bags$/;
|
||||
@@ -26,6 +28,7 @@ exports.bodyFormat = "www-form-urlencoded";
|
||||
exports.csrfDisable = true;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
aclMiddleware(request, response, state, "bag", "WRITE");
|
||||
if(state.data.bag_name) {
|
||||
const result = $tw.mws.store.createBag(state.data.bag_name,state.data.description);
|
||||
if(!result) {
|
||||
|
@@ -18,6 +18,8 @@ bag_names: space separated list of bags
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var aclMiddleware = require("$:/plugins/tiddlywiki/multiwikiserver/modules/routes/helpers/acl-middleware.js").middleware;
|
||||
|
||||
exports.method = "POST";
|
||||
|
||||
exports.path = /^\/recipes$/;
|
||||
@@ -27,6 +29,7 @@ exports.bodyFormat = "www-form-urlencoded";
|
||||
exports.csrfDisable = true;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
aclMiddleware(request, response, state, "recipe", "WRITE");
|
||||
if(state.data.recipe_name && state.data.bag_names) {
|
||||
const result = $tw.mws.store.createRecipe(state.data.recipe_name,$tw.utils.parseStringArray(state.data.bag_names),state.data.description);
|
||||
if(!result) {
|
||||
|
@@ -12,16 +12,19 @@ PUT /bags/:bag_name
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var aclMiddleware = require("$:/plugins/tiddlywiki/multiwikiserver/modules/routes/helpers/acl-middleware.js").middleware;
|
||||
|
||||
exports.method = "PUT";
|
||||
|
||||
exports.path = /^\/bags\/(.+)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
aclMiddleware(request, response, state, "bag", "WRITE");
|
||||
// Get the parameters
|
||||
var bag_name = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
data = $tw.utils.parseJSONSafe(state.data);
|
||||
if(bag_name && data) {
|
||||
const result = $tw.mws.store.createBag(bag_name,data.description);
|
||||
var result = $tw.mws.store.createBag(bag_name,data.description);
|
||||
if(!result) {
|
||||
state.sendResponse(204,{
|
||||
"Content-Type": "text/plain"
|
||||
@@ -34,8 +37,10 @@ exports.handler = function(request,response,state) {
|
||||
"utf8");
|
||||
}
|
||||
} else {
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
if(!response.headersSent) {
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -12,20 +12,20 @@ PUT /recipes/:recipe_name
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var aclMiddleware = require('$:/plugins/tiddlywiki/multiwikiserver/modules/routes/helpers/acl-middleware.js').middleware;
|
||||
var aclMiddleware = require("$:/plugins/tiddlywiki/multiwikiserver/modules/routes/helpers/acl-middleware.js").middleware;
|
||||
|
||||
exports.method = "PUT";
|
||||
|
||||
exports.path = /^\/recipes\/(.+)$/;
|
||||
|
||||
exports.handler = function (request, response, state) {
|
||||
aclMiddleware(request, response, state, 'recipe', 'WRITE');
|
||||
aclMiddleware(request, response, state, "recipe", "WRITE");
|
||||
// Get the parameters
|
||||
var recipe_name = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
data = $tw.utils.parseJSONSafe(state.data);
|
||||
if (recipe_name && data) {
|
||||
const result = $tw.mws.store.createRecipe(recipe_name, data.bag_names, data.description);
|
||||
if (!result) {
|
||||
if(recipe_name && data) {
|
||||
var result = $tw.mws.store.createRecipe(recipe_name, data.bag_names, data.description);
|
||||
if(!result) {
|
||||
state.sendResponse(204, {
|
||||
"Content-Type": "text/plain"
|
||||
});
|
||||
@@ -37,7 +37,7 @@ PUT /recipes/:recipe_name
|
||||
"utf8");
|
||||
}
|
||||
} else {
|
||||
if (!response.headersSent) {
|
||||
if(!response.headersSent) {
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
}
|
||||
|
@@ -163,7 +163,7 @@ SqlTiddlerDatabase.prototype.createTables = function() {
|
||||
-- ACL table (using bag/recipe ids directly)
|
||||
CREATE TABLE IF NOT EXISTS acl (
|
||||
acl_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
entity_id INTEGER NOT NULL,
|
||||
entity_name TEXT NOT NULL,
|
||||
entity_type TEXT NOT NULL CHECK (entity_type IN ('bag', 'recipe')),
|
||||
role_id INTEGER,
|
||||
permission_id INTEGER,
|
||||
@@ -178,7 +178,7 @@ SqlTiddlerDatabase.prototype.createTables = function() {
|
||||
`,`
|
||||
CREATE INDEX IF NOT EXISTS idx_recipe_bags_recipe_id ON recipe_bags(recipe_id)
|
||||
`,`
|
||||
CREATE INDEX IF NOT EXISTS idx_acl_entity_id ON acl(entity_id)
|
||||
CREATE INDEX IF NOT EXISTS idx_acl_entity_id ON acl(entity_name)
|
||||
`]);
|
||||
};
|
||||
|
||||
@@ -482,7 +482,7 @@ SqlTiddlerDatabase.prototype.hasRecipePermission = function(userId, recipeName)
|
||||
JOIN role_permissions rp ON ur.role_id = rp.role_id
|
||||
JOIN permissions p ON rp.permission_id = p.permission_id
|
||||
JOIN acl ON rp.role_id = acl.role_id AND rp.permission_id = acl.permission_id
|
||||
JOIN recipes r ON acl.entity_id = r.recipe_id
|
||||
JOIN recipes r ON acl.entity_name = r.recipe_id
|
||||
WHERE u.user_id = $user_id
|
||||
AND r.recipe_name = $recipe_name
|
||||
AND p.permission_name = 'read'
|
||||
@@ -507,7 +507,7 @@ SqlTiddlerDatabase.prototype.hasBagPermission = function(userId, bagName, permis
|
||||
JOIN role_permissions rp ON ur.role_id = rp.role_id
|
||||
JOIN permissions p ON rp.permission_id = p.permission_id
|
||||
JOIN acl ON rp.role_id = acl.role_id AND rp.permission_id = acl.permission_id
|
||||
JOIN bags b ON acl.entity_id = b.bag_id
|
||||
JOIN bags b ON acl.entity_name = b.bag_id
|
||||
WHERE u.user_id = $user_id
|
||||
AND b.bag_name = $bag_name
|
||||
AND p.permission_name = 'read'
|
||||
@@ -523,79 +523,46 @@ SqlTiddlerDatabase.prototype.hasBagPermission = function(userId, bagName, permis
|
||||
|
||||
SqlTiddlerDatabase.prototype.checkACLPermission = function(userId, entityType, entityName, permissionName) {
|
||||
const entityTypeToTableMap = {
|
||||
bag: {
|
||||
table: 'bags',
|
||||
column: 'bag_name'
|
||||
},
|
||||
recipe: {
|
||||
table: 'recipes',
|
||||
column: 'recipe_name'
|
||||
}
|
||||
bag: {
|
||||
table: 'bags',
|
||||
column: 'bag_name'
|
||||
},
|
||||
recipe: {
|
||||
table: 'recipes',
|
||||
column: 'recipe_name'
|
||||
}
|
||||
};
|
||||
|
||||
const entityInfo = entityTypeToTableMap[entityType];
|
||||
if (!entityInfo) {
|
||||
throw new Error('Invalid entity type: ' + entityType);
|
||||
throw new Error('Invalid entity type: ' + entityType);
|
||||
}
|
||||
|
||||
console.log("Starting ACL permission check:", { userId, entityType, entityName, permissionName, entityInfo });
|
||||
|
||||
// Step 1: Get the entity ID
|
||||
const entityQuery = `
|
||||
SELECT ${entityInfo.table.slice(0, -1)}_id as entity_id
|
||||
FROM ${entityInfo.table}
|
||||
WHERE ${entityInfo.column} = $entity_name
|
||||
const query = `
|
||||
SELECT 1
|
||||
FROM users u
|
||||
JOIN user_roles ur ON u.user_id = ur.user_id
|
||||
JOIN roles r ON ur.role_id = r.role_id
|
||||
JOIN acl a ON r.role_id = a.role_id
|
||||
JOIN permissions p ON a.permission_id = p.permission_id
|
||||
WHERE u.user_id = $user_id
|
||||
AND a.entity_type = $entity_type
|
||||
AND a.entity_name = $entity_name
|
||||
AND p.permission_name = $permission_name
|
||||
LIMIT 1
|
||||
`;
|
||||
const entityResult = this.engine.runStatementGet(entityQuery, { $entity_name: entityName });
|
||||
console.log("Entity query result:", entityResult);
|
||||
|
||||
if (!entityResult) {
|
||||
console.log(`${entityType} not found: ${entityName}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const entityId = entityResult.entity_id;
|
||||
|
||||
// Step 2: Get user's roles
|
||||
const userRolesQuery = `
|
||||
SELECT r.role_id
|
||||
FROM users u
|
||||
JOIN user_roles ur ON u.user_id = ur.user_id
|
||||
JOIN roles r ON ur.role_id = r.role_id
|
||||
WHERE u.user_id = $user_id
|
||||
`;
|
||||
const userRoles = this.engine.runStatementGetAll(userRolesQuery, { $user_id: userId });
|
||||
console.log("User roles:", userRoles);
|
||||
|
||||
if (userRoles.length === 0) {
|
||||
console.log(`No roles found for user: ${userId}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 3: Check for permission
|
||||
const roleIds = userRoles.map(role => role.role_id);
|
||||
const permissionQuery = `
|
||||
SELECT 1
|
||||
FROM acl a
|
||||
JOIN permissions p ON a.permission_id = p.permission_id
|
||||
WHERE a.role_id IN (${roleIds.join(',')})
|
||||
AND a.entity_type = $entity_type
|
||||
AND a.entity_id = $entity_id
|
||||
AND p.permission_name = $permission_name
|
||||
LIMIT 1
|
||||
`;
|
||||
const permissionResult = this.engine.runStatementGet(permissionQuery, {
|
||||
$entity_type: entityType,
|
||||
$entity_id: entityId,
|
||||
$permission_name: permissionName
|
||||
const result = this.engine.runStatementGet(query, {
|
||||
$user_id: userId,
|
||||
$entity_type: entityType,
|
||||
$entity_name: entityName,
|
||||
$permission_name: permissionName
|
||||
});
|
||||
console.log("Permission query result:", permissionResult);
|
||||
|
||||
const hasPermission = permissionResult !== undefined;
|
||||
console.log("Final permission check result:", hasPermission);
|
||||
const hasPermission = result !== undefined;
|
||||
|
||||
return hasPermission;
|
||||
};
|
||||
};;
|
||||
|
||||
/*
|
||||
Get the titles of the tiddlers in a bag. Returns an empty array for bags that do not exist
|
||||
@@ -1079,7 +1046,7 @@ SqlTiddlerDatabase.prototype.listPermissions = function() {
|
||||
// ACL CRUD operations
|
||||
SqlTiddlerDatabase.prototype.createACL = function(entityId, entityType, roleId, permissionId) {
|
||||
const result = this.engine.runStatement(`
|
||||
INSERT INTO acl (entity_id, entity_type, role_id, permission_id)
|
||||
INSERT INTO acl (entity_name, entity_type, role_id, permission_id)
|
||||
VALUES ($entityId, $entityType, $roleId, $permissionId)
|
||||
`, {
|
||||
$entityId: entityId,
|
||||
@@ -1101,7 +1068,7 @@ SqlTiddlerDatabase.prototype.getACL = function(aclId) {
|
||||
SqlTiddlerDatabase.prototype.updateACL = function(aclId, entityId, entityType, roleId, permissionId) {
|
||||
this.engine.runStatement(`
|
||||
UPDATE acl
|
||||
SET entity_id = $entityId, entity_type = $entityType,
|
||||
SET entity_name = $entityId, entity_type = $entityType,
|
||||
role_id = $roleId, permission_id = $permissionId
|
||||
WHERE acl_id = $aclId
|
||||
`, {
|
||||
@@ -1123,7 +1090,7 @@ SqlTiddlerDatabase.prototype.deleteACL = function(aclId) {
|
||||
|
||||
SqlTiddlerDatabase.prototype.listACLs = function() {
|
||||
return this.engine.runStatementGetAll(`
|
||||
SELECT * FROM acl ORDER BY entity_type, entity_id
|
||||
SELECT * FROM acl ORDER BY entity_type, entity_name
|
||||
`);
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user