@frontegg/client
Advanced tools
Comparing version 1.0.23-2 to 1.0.23-3
import { AuditsClient } from './src/audits'; | ||
import { frontegg } from './src/middleware'; | ||
export { AuditsClient, frontegg, }; | ||
import { FronteggPermissions } from './src/permissions'; | ||
export { AuditsClient, frontegg, FronteggPermissions, }; |
@@ -7,1 +7,3 @@ "use strict"; | ||
exports.frontegg = middleware_1.frontegg; | ||
var permissions_1 = require("./src/permissions"); | ||
exports.FronteggPermissions = permissions_1.FronteggPermissions; |
@@ -0,4 +1,6 @@ | ||
import { FronteggPermissions } from '../permissions'; | ||
declare type fronteggContextResolver = (req: Request) => Promise<{ | ||
tenantId: string; | ||
userEmail: string; | ||
permissions: FronteggPermissions[]; | ||
}>; | ||
@@ -5,0 +7,0 @@ export declare function frontegg(options: { |
@@ -41,6 +41,11 @@ "use strict"; | ||
var logger_1 = require("../helpers/logger"); | ||
var permissions_1 = require("../permissions"); | ||
var proxy = httpProxy.createProxyServer({ secure: false, changeOrigin: true }); | ||
var target = process.env.FRONTEGG_API_GATEWAY_URL || "https://api.frontegg.com/"; | ||
var authenticator = new authenticator_1.FronteggAuthenticator(); | ||
var Whitelist = ['/metadata']; | ||
var MAX_RETRIES = 3; | ||
function getUrlWithoutQueryParams(req) { | ||
return req.url.split("?").shift(); | ||
} | ||
function proxyRequest(req, res, context) { | ||
@@ -66,2 +71,73 @@ return __awaiter(this, void 0, void 0, function () { | ||
} | ||
function flattenPermissions(permissions) { | ||
var output = []; | ||
for (var _i = 0, permissions_2 = permissions; _i < permissions_2.length; _i++) { | ||
var p = permissions_2[_i]; | ||
if (typeof (p) === 'string') { | ||
output.push(p); | ||
} | ||
else if (Array.isArray(p)) { | ||
for (var _a = 0, p_1 = p; _a < p_1.length; _a++) { | ||
var item = p_1[_a]; | ||
output.push(item); | ||
} | ||
} | ||
else { | ||
logger_1.default.log('running keys on - ', p); | ||
var keys = Object.keys(p); | ||
for (var _b = 0, keys_1 = keys; _b < keys_1.length; _b++) { | ||
var key = keys_1[_b]; | ||
output.push.apply(output, flattenPermissions([p[key]])); | ||
} | ||
} | ||
} | ||
return output; | ||
} | ||
function validatePermissions(req, res, context) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var permissions, url, allowedOperations, _i, allowedOperations_1, operation, method, route; | ||
return __generator(this, function (_a) { | ||
permissions = context.permissions; | ||
if (permissions === null) { | ||
logger_1.default.error('No permissions were passed for frontegg middleware'); | ||
res.status(403).send(); | ||
} | ||
if (!permissions.length) { | ||
logger_1.default.error('Permissions array is empty for frontegg middleware'); | ||
res.status(403).send(); | ||
} | ||
// We allow OPTIONS | ||
if (req.method === 'OPTIONS') { | ||
logger_1.default.log('OPTIONS is allowed'); | ||
return [2 /*return*/]; | ||
} | ||
if (permissions.includes(permissions_1.FronteggPermissions.All)) { | ||
logger_1.default.log('User is authorized for ALL actions in the system'); | ||
return [2 /*return*/]; | ||
} | ||
url = getUrlWithoutQueryParams(req); | ||
if (Whitelist.includes(url)) { | ||
logger_1.default.log("URL " + url + " is whitelisted"); | ||
return [2 /*return*/]; | ||
} | ||
allowedOperations = flattenPermissions(permissions); | ||
logger_1.default.log("allowedOperations for this user - ", allowedOperations); | ||
for (_i = 0, allowedOperations_1 = allowedOperations; _i < allowedOperations_1.length; _i++) { | ||
operation = allowedOperations_1[_i]; | ||
if (operation === '*') { | ||
continue; | ||
} | ||
method = operation.split(' ')[0]; | ||
route = operation.split(' ')[1]; | ||
if (req.method === method && url === route) { | ||
logger_1.default.log("User is authorized for " + req.method + " " + req.baseUrl); | ||
return [2 /*return*/]; | ||
} | ||
} | ||
logger_1.default.error("No matching permission for " + req.method + " " + url); | ||
res.status(403).send(); | ||
return [2 /*return*/]; | ||
}); | ||
}); | ||
} | ||
function frontegg(options) { | ||
@@ -77,3 +153,3 @@ var _this = this; | ||
if (!options.apiKey) { | ||
throw new Error('Missing client ID'); | ||
throw new Error('Missing api key'); | ||
} | ||
@@ -145,2 +221,3 @@ if (!options.contextResolver) { | ||
context = _a.sent(); | ||
validatePermissions(req, res, context); | ||
if (!req.frontegg) { | ||
@@ -147,0 +224,0 @@ req.frontegg = {}; |
import { AuditsClient } from './src/audits'; | ||
import { frontegg } from './src/middleware'; | ||
import { FronteggPermissions } from './src/permissions'; | ||
@@ -7,2 +8,3 @@ export { | ||
frontegg, | ||
FronteggPermissions, | ||
}; |
{ | ||
"name": "@frontegg/client", | ||
"version": "1.0.23-2", | ||
"version": "1.0.23-3", | ||
"description": "Frontegg Javascript Library for backend", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -18,3 +18,3 @@ # Frontegg Client | ||
Frontegg offers multiple components for integration with the Frontegg's scaleable back-end and front end libraries | ||
Frontegg offers multiple components for integration with the Frontegg's scaleable back end and front end libraries | ||
@@ -25,6 +25,6 @@ ### Middleware | ||
To use the Frontegg's middleware import the frontegg middleware from the frontegg-client library | ||
To use the Frontegg's middleware import the ***frontegg*** middleware from the ***@frontegg/client*** library | ||
```javascript | ||
const { frontegg } = require('@frontegg/client'); | ||
const { frontegg, FronteggPermissions } = require('@frontegg/client'); | ||
``` | ||
@@ -41,7 +41,9 @@ | ||
const tenantId = req.context.tenantId; // The tenantId context (after JWT verification) | ||
const permissions = [FronteggPermissions.All]; | ||
return { | ||
email, | ||
tenantId | ||
} | ||
tenantId, | ||
permissions | ||
}; | ||
} | ||
@@ -51,2 +53,27 @@ })) | ||
#### Frontegg permissions | ||
When using the Frontegg middleware library, you can choose which functionality is enabled for your user based on his role or based on any other business logic your application holds. | ||
##### Controlling Frontegg permissions | ||
Controlling the permissions is done via the Frontegg middleware by injecting the permissions array | ||
```javascript | ||
/// Allow the user to do everything on all enabled Frontegg modules | ||
const permissions = [FronteggPermissions.All]; | ||
``` | ||
```javascript | ||
/// Allow the user to do everything on Frontegg audits module | ||
const permissions = [FronteggPermissions.Audit]; | ||
``` | ||
```javascript | ||
/// Allow the user to read audits and audits stats but not exporting it | ||
const permissions = [FronteggPermissions.Audit.Read, FronteggPermissions.Audit.Stats]; | ||
``` | ||
### Audits | ||
@@ -53,0 +80,0 @@ |
import * as httpProxy from 'http-proxy'; | ||
import { FronteggAuthenticator } from '../authenticator'; | ||
import Logger from '../helpers/logger'; | ||
import { FronteggPermissions } from '../permissions'; | ||
const proxy = httpProxy.createProxyServer({ secure: false, changeOrigin: true }); | ||
const target = process.env.FRONTEGG_API_GATEWAY_URL || "https://api.frontegg.com/"; | ||
const authenticator = new FronteggAuthenticator(); | ||
const Whitelist = ['/metadata']; | ||
const MAX_RETRIES = 3; | ||
declare type fronteggContextResolver = (req: Request) => Promise<{ tenantId: string, userEmail: string }>; | ||
function getUrlWithoutQueryParams(req) { | ||
return req.url.split("?").shift(); | ||
} | ||
declare type fronteggContextResolver = (req: Request) => Promise<{ tenantId: string, userEmail: string, permissions: FronteggPermissions[] }>; | ||
async function proxyRequest(req, res, context) { | ||
@@ -25,2 +32,76 @@ Logger.log(`going to proxy request - ${req.originalUrl} to ${target}`); | ||
function flattenPermissions(permissions: FronteggPermissions[]): string[] { | ||
const output: string[] = []; | ||
for (const p of permissions) { | ||
if (typeof (p) === 'string') { | ||
output.push(p); | ||
} else if (Array.isArray(p)) { | ||
for (const item of p) { | ||
output.push(item); | ||
} | ||
} else { | ||
Logger.log('running keys on - ', p); | ||
const keys = Object.keys(p); | ||
for (const key of keys) { | ||
output.push(...flattenPermissions([p[key]])); | ||
} | ||
} | ||
} | ||
return output; | ||
} | ||
async function validatePermissions(req, res, context) { | ||
const permissions: FronteggPermissions[] = context.permissions; | ||
if (permissions === null) { | ||
Logger.error('No permissions were passed for frontegg middleware'); | ||
res.status(403).send(); | ||
} | ||
if (!permissions.length) { | ||
Logger.error('Permissions array is empty for frontegg middleware'); | ||
res.status(403).send(); | ||
} | ||
// We allow OPTIONS | ||
if (req.method === 'OPTIONS') { | ||
Logger.log('OPTIONS is allowed'); | ||
return; | ||
} | ||
if (permissions.includes(FronteggPermissions.All)) { | ||
Logger.log('User is authorized for ALL actions in the system'); | ||
return; | ||
} | ||
const url = getUrlWithoutQueryParams(req); | ||
if (Whitelist.includes(url)) { | ||
Logger.log(`URL ${url} is whitelisted`); | ||
return; | ||
} | ||
const allowedOperations = flattenPermissions(permissions); | ||
Logger.log(`allowedOperations for this user - `, allowedOperations); | ||
for (const operation of allowedOperations) { | ||
if (operation === '*') { | ||
continue; | ||
} | ||
const method = operation.split(' ')[0]; | ||
const route = operation.split(' ')[1]; | ||
if (req.method === method && url === route) { | ||
Logger.log(`User is authorized for ${req.method} ${req.baseUrl}`); | ||
return; | ||
} | ||
} | ||
Logger.error(`No matching permission for ${req.method} ${url}`); | ||
res.status(403).send(); | ||
} | ||
export function frontegg(options: { clientId: string, apiKey: string, contextResolver: fronteggContextResolver }) { | ||
@@ -31,3 +112,3 @@ Logger.log('you got to my frontegg middleware'); | ||
if (!options.clientId) { throw new Error('Missing client ID'); } | ||
if (!options.apiKey) { throw new Error('Missing client ID'); } | ||
if (!options.apiKey) { throw new Error('Missing api key'); } | ||
if (!options.contextResolver) { throw new Error('Missing context resolver'); } | ||
@@ -80,2 +161,5 @@ | ||
const context = await options.contextResolver(req); | ||
validatePermissions(req, res, context); | ||
if (!req.frontegg) { req.frontegg = {}; } | ||
@@ -82,0 +166,0 @@ req.frontegg.retryCount = 0; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
124
1
54419
26
1154