mirror of
https://github.com/HeyPuter/puter.git
synced 2025-02-03 07:48:46 +08:00
dev: add /acl/stat-user-user
This new endpoint shows permissions granted by the current user to the specified user in the scope of a specified filesystem node, including permissions on the affecting parent nodes. This is related to two future tasks: - prevent users from sharing a file with the same user twice - add an endpoint to modify the access mode of a shared file
This commit is contained in:
parent
ea4cde82fc
commit
4396630453
@ -17,13 +17,21 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
const APIError = require("../../api/APIError");
|
const APIError = require("../../api/APIError");
|
||||||
|
const FSNodeParam = require("../../api/filesystem/FSNodeParam");
|
||||||
const { NodePathSelector } = require("../../filesystem/node/selectors");
|
const { NodePathSelector } = require("../../filesystem/node/selectors");
|
||||||
|
const { get_user } = require("../../helpers");
|
||||||
|
const configurable_auth = require("../../middleware/configurable_auth");
|
||||||
const { Context } = require("../../util/context");
|
const { Context } = require("../../util/context");
|
||||||
|
const { Endpoint } = require("../../util/expressutil");
|
||||||
const BaseService = require("../BaseService");
|
const BaseService = require("../BaseService");
|
||||||
const { AppUnderUserActorType, UserActorType, Actor, SystemActorType, AccessTokenActorType } = require("./Actor");
|
const { AppUnderUserActorType, UserActorType, Actor, SystemActorType, AccessTokenActorType } = require("./Actor");
|
||||||
const { PermissionUtil } = require("./PermissionService");
|
const { PermissionUtil } = require("./PermissionService");
|
||||||
|
|
||||||
class ACLService extends BaseService {
|
class ACLService extends BaseService {
|
||||||
|
static MODULES = {
|
||||||
|
express: require('express'),
|
||||||
|
};
|
||||||
|
|
||||||
async _init () {
|
async _init () {
|
||||||
const svc_featureFlag = this.services.get('feature-flag');
|
const svc_featureFlag = this.services.get('feature-flag');
|
||||||
svc_featureFlag.register('public-folders', {
|
svc_featureFlag.register('public-folders', {
|
||||||
@ -44,6 +52,85 @@ class ACLService extends BaseService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async ['__on_install.routes'] (_, { app }) {
|
||||||
|
const r_acl = (() => {
|
||||||
|
const require = this.require;
|
||||||
|
const express = require('express');
|
||||||
|
return express.Router();
|
||||||
|
})();
|
||||||
|
|
||||||
|
app.use('/acl', r_acl);
|
||||||
|
|
||||||
|
Endpoint({
|
||||||
|
route: '/stat-user-user',
|
||||||
|
methods: ['POST'],
|
||||||
|
mw: [configurable_auth()],
|
||||||
|
handler: async (req, res) => {
|
||||||
|
// Only user actor is allowed
|
||||||
|
if ( ! (req.actor.type instanceof UserActorType) ) {
|
||||||
|
return res.status(403).json({
|
||||||
|
error: 'forbidden',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const holder_user = await get_user({
|
||||||
|
username: req.body.user,
|
||||||
|
});
|
||||||
|
|
||||||
|
if ( ! holder_user ) {
|
||||||
|
throw APIError.create('user_does_not_exist', null, {
|
||||||
|
username: req.body.user,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const issuer = req.actor;
|
||||||
|
const holder = new Actor({
|
||||||
|
type: new UserActorType({
|
||||||
|
user: holder_user,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const node = await (new FSNodeParam('path')).consolidate({
|
||||||
|
req,
|
||||||
|
getParam: () => req.body.resource,
|
||||||
|
});
|
||||||
|
|
||||||
|
const permissions = await this.stat_user_user(issuer, holder, node);
|
||||||
|
|
||||||
|
res.json({ permissions });
|
||||||
|
}
|
||||||
|
}).attach(r_acl);
|
||||||
|
}
|
||||||
|
|
||||||
|
async stat_user_user (issuer, holder, resource) {
|
||||||
|
const svc_perm = this.services.get('permission');
|
||||||
|
|
||||||
|
if ( ! (issuer.type instanceof UserActorType) ) {
|
||||||
|
throw new Error('issuer must be a UserActorType');
|
||||||
|
}
|
||||||
|
if ( ! (holder.type instanceof UserActorType) ) {
|
||||||
|
throw new Error('holder must be a UserActorType');
|
||||||
|
}
|
||||||
|
|
||||||
|
const permissions = {};
|
||||||
|
|
||||||
|
let perm_fsNode = resource;
|
||||||
|
while ( ! await perm_fsNode.get('is-root') ) {
|
||||||
|
const prefix = PermissionUtil.join('fs', await perm_fsNode.get('uid'));
|
||||||
|
|
||||||
|
const these_permissions = await
|
||||||
|
svc_perm.query_issuer_holder_permissions_by_prefix(issuer, holder, prefix);
|
||||||
|
|
||||||
|
if ( these_permissions.length > 0 ) {
|
||||||
|
permissions[await perm_fsNode.get('path')] = these_permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
perm_fsNode = await perm_fsNode.getParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
return permissions;
|
||||||
|
}
|
||||||
|
|
||||||
async _check_fsNode (actor, fsNode, mode) {
|
async _check_fsNode (actor, fsNode, mode) {
|
||||||
const context = Context.get();
|
const context = Context.get();
|
||||||
|
|
||||||
|
@ -639,6 +639,34 @@ class PermissionService extends BaseService {
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List the permissions that the specified actor (the "issuer")
|
||||||
|
* has granted to the specified user (the "holder") which have
|
||||||
|
* some specified prefix in the permission key (ex: "fs:FILE-UUID")
|
||||||
|
*
|
||||||
|
* Note that if the prefix contains a literal '%' character
|
||||||
|
* the behavior may not be as expected.
|
||||||
|
*
|
||||||
|
* This is a "flat" (non-cascading) view.
|
||||||
|
*
|
||||||
|
* @param {*} issuer
|
||||||
|
* @param {*} holder
|
||||||
|
* @param {*} prefix
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async query_issuer_holder_permissions_by_prefix (issuer, holder, prefix) {
|
||||||
|
const user_perms = await this.db.read(
|
||||||
|
'SELECT permission ' +
|
||||||
|
'FROM `user_to_user_permissions` ' +
|
||||||
|
'WHERE issuer_user_id = ? ' +
|
||||||
|
'AND holder_user_id = ? ' +
|
||||||
|
'AND permission LIKE ?',
|
||||||
|
[issuer.type.user.id, holder.type.user.id, prefix + '%'],
|
||||||
|
);
|
||||||
|
|
||||||
|
return user_perms.map(row => row.permission);
|
||||||
|
}
|
||||||
|
|
||||||
async get_higher_permissions (permission) {
|
async get_higher_permissions (permission) {
|
||||||
const higher_perms = new Set()
|
const higher_perms = new Set()
|
||||||
higher_perms.add(permission);
|
higher_perms.add(permission);
|
||||||
|
Loading…
Reference in New Issue
Block a user