feat: add feature flag for /share

This commit is contained in:
KernelDeimos 2024-08-14 17:18:34 -04:00 committed by Eric Dubé
parent d4319ea072
commit 461ea3eae6
5 changed files with 73 additions and 1 deletions

View File

@ -314,6 +314,9 @@ const install = async ({ services, app, useapi }) => {
const { BootScriptService } = require('./services/BootScriptService');
services.registerService('boot-script', BootScriptService);
const { FeatureFlagService } = require('./services/FeatureFlagService');
services.registerService('feature-flag', FeatureFlagService);
}
const install_legacy = async ({ services }) => {

View File

@ -74,6 +74,7 @@ const hardcoded_user_group_permissions = {
system: {
'ca342a5e-b13d-4dee-9048-58b11a57cc55': {
'service': {},
'feature': {},
},
'b7220104-7905-4985-b996-649fdcdb3c8f': {
'service:hello-world:ii:hello-world': policy_perm('temp.es'),

View File

@ -0,0 +1,22 @@
const APIError = require("../api/APIError");
const { Context } = require("../util/context");
const featureflag = options => async (req, res, next) => {
const { feature } = options;
const context = Context.get();
const services = context.get('services');
const svc_featureFlag = services.get('feature-flag');
if ( ! await svc_featureFlag.check({
actor: req.actor,
}, feature) ) {
const e = APIError.create('forbidden');
e.write(res);
return;
}
next();
};
module.exports = featureflag;

View File

@ -0,0 +1,42 @@
const { Context } = require("../util/context");
const { whatis } = require("../util/langutil");
const { PermissionUtil } = require("./auth/PermissionService");
const BaseService = require("./BaseService");
/**
* FeatureFlagService is a way to let the client (frontend) know what features
* are enabled or disabled for the current user.
*/
class FeatureFlagService extends BaseService {
async check (...a) {
// allows binding call with multiple options objects;
// the last argument is the permission to check
const { options, value: permission } = (() => {
let value;
const options = {};
for ( const arg of a ) {
if ( whatis(arg) === 'object' ) {
Object.assign(options, arg);
continue;
}
value = arg;
break;
}
return { options, value };
})();
const actor = options.actor ?? Context.get('actor');
const svc_permission = this.services.get('permission');
const reading = await svc_permission.scan(actor, `feature:${permission}`);
const l = PermissionUtil.reading_to_options(reading);
if ( l.length === 0 ) return false;
return true;
}
}
module.exports = {
FeatureFlagService
};

View File

@ -19,6 +19,7 @@
const APIError = require("../api/APIError");
const { get_user } = require("../helpers");
const configurable_auth = require("../middleware/configurable_auth");
const featureflag = require("../middleware/featureflag.js");
const { Context } = require("../util/context");
const { Endpoint } = require("../util/expressutil");
const { whatis } = require("../util/langutil");
@ -246,7 +247,10 @@ class ShareService extends BaseService {
Endpoint({
route: '/',
methods: ['POST'],
mw: [configurable_auth()],
mw: [
configurable_auth(),
featureflag({ feature: 'share' }),
],
handler: async (req, res) => {
const actor = Actor.adapt(req.user);
return await share_sequence.call(this, {