Skip to content

Commit 461ea3e

Browse files
committed
feat: add feature flag for /share
1 parent d4319ea commit 461ea3e

File tree

5 files changed

+73
-1
lines changed

5 files changed

+73
-1
lines changed

src/backend/src/CoreModule.js

+3
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,9 @@ const install = async ({ services, app, useapi }) => {
314314

315315
const { BootScriptService } = require('./services/BootScriptService');
316316
services.registerService('boot-script', BootScriptService);
317+
318+
const { FeatureFlagService } = require('./services/FeatureFlagService');
319+
services.registerService('feature-flag', FeatureFlagService);
317320
}
318321

319322
const install_legacy = async ({ services }) => {

src/backend/src/data/hardcoded-permissions.js

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ const hardcoded_user_group_permissions = {
7474
system: {
7575
'ca342a5e-b13d-4dee-9048-58b11a57cc55': {
7676
'service': {},
77+
'feature': {},
7778
},
7879
'b7220104-7905-4985-b996-649fdcdb3c8f': {
7980
'service:hello-world:ii:hello-world': policy_perm('temp.es'),
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const APIError = require("../api/APIError");
2+
const { Context } = require("../util/context");
3+
4+
const featureflag = options => async (req, res, next) => {
5+
const { feature } = options;
6+
7+
const context = Context.get();
8+
const services = context.get('services');
9+
const svc_featureFlag = services.get('feature-flag');
10+
11+
if ( ! await svc_featureFlag.check({
12+
actor: req.actor,
13+
}, feature) ) {
14+
const e = APIError.create('forbidden');
15+
e.write(res);
16+
return;
17+
}
18+
19+
next();
20+
};
21+
22+
module.exports = featureflag;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
const { Context } = require("../util/context");
2+
const { whatis } = require("../util/langutil");
3+
const { PermissionUtil } = require("./auth/PermissionService");
4+
const BaseService = require("./BaseService");
5+
6+
/**
7+
* FeatureFlagService is a way to let the client (frontend) know what features
8+
* are enabled or disabled for the current user.
9+
*/
10+
class FeatureFlagService extends BaseService {
11+
async check (...a) {
12+
// allows binding call with multiple options objects;
13+
// the last argument is the permission to check
14+
const { options, value: permission } = (() => {
15+
let value;
16+
const options = {};
17+
for ( const arg of a ) {
18+
if ( whatis(arg) === 'object' ) {
19+
Object.assign(options, arg);
20+
continue;
21+
}
22+
value = arg;
23+
break;
24+
}
25+
return { options, value };
26+
})();
27+
28+
29+
30+
const actor = options.actor ?? Context.get('actor');
31+
32+
const svc_permission = this.services.get('permission');
33+
const reading = await svc_permission.scan(actor, `feature:${permission}`);
34+
const l = PermissionUtil.reading_to_options(reading);
35+
if ( l.length === 0 ) return false;
36+
return true;
37+
}
38+
}
39+
40+
module.exports = {
41+
FeatureFlagService
42+
};

src/backend/src/services/ShareService.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
const APIError = require("../api/APIError");
2020
const { get_user } = require("../helpers");
2121
const configurable_auth = require("../middleware/configurable_auth");
22+
const featureflag = require("../middleware/featureflag.js");
2223
const { Context } = require("../util/context");
2324
const { Endpoint } = require("../util/expressutil");
2425
const { whatis } = require("../util/langutil");
@@ -246,7 +247,10 @@ class ShareService extends BaseService {
246247
Endpoint({
247248
route: '/',
248249
methods: ['POST'],
249-
mw: [configurable_auth()],
250+
mw: [
251+
configurable_auth(),
252+
featureflag({ feature: 'share' }),
253+
],
250254
handler: async (req, res) => {
251255
const actor = Actor.adapt(req.user);
252256
return await share_sequence.call(this, {

0 commit comments

Comments
 (0)