@forge/bridge
5.10.3-next.1-experimental-919607a5.11.0-next.2
out/permissions/permissionsUtil.js+
out/permissions/permissionsUtil.jsNew file+143
Index: package/out/permissions/permissionsUtil.js
===================================================================
--- package/out/permissions/permissionsUtil.js
+++ package/out/permissions/permissionsUtil.js
@@ -0,0 +1,143 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.checkPermissions = exports.createPermissionUtils = void 0;
+const egress_1 = require("@forge/egress");
+const view_1 = require("../view");
+function extractUrlString(url) {
+ if (typeof url === 'string') {
+ return url;
+ }
+ if ('address' in url && url.address) {
+ return url.address;
+ }
+ return url.remote || '';
+}
+const RESOURCE_TYPES = ['fonts', 'styles', 'frames', 'images', 'media', 'scripts'];
+const FETCH_TYPES = ['backend', 'client'];
+function createPermissionUtils(runtimePermissions) {
+ if (!runtimePermissions) {
+ return null;
+ }
+ const { scopes, external = {} } = runtimePermissions;
+ const scopeArray = Array.isArray(scopes) ? scopes : Object.keys(scopes || {});
+ return {
+ hasScope: (scope) => scopeArray.includes(scope),
+ canFetchFrom: (type, url) => {
+ var _a;
+ const fetchUrls = (_a = external.fetch) === null || _a === void 0 ? void 0 : _a[type];
+ if (!(fetchUrls === null || fetchUrls === void 0 ? void 0 : fetchUrls.length))
+ return false;
+ const allowList = fetchUrls.map(extractUrlString).filter((u) => u.length > 0);
+ if (allowList.length === 0)
+ return false;
+ const egressFilter = new egress_1.EgressFilteringService(allowList);
+ const egressFilterWithCSP = egressFilter;
+ return type === 'client' ? egressFilterWithCSP.isValidUrlCSP(url) : egressFilter.isValidUrl(url);
+ },
+ canLoadResource: (type, url) => {
+ const resourceUrls = external[type];
+ if (!(resourceUrls === null || resourceUrls === void 0 ? void 0 : resourceUrls.length))
+ return false;
+ const allowList = resourceUrls.map(extractUrlString).filter((u) => u.length > 0);
+ if (allowList.length === 0)
+ return false;
+ const egressFilter = new egress_1.EgressFilteringService(allowList);
+ const egressFilterWithCSP = egressFilter;
+ return egressFilterWithCSP.isValidUrlCSP(url);
+ },
+ getScopes: () => scopeArray,
+ getExternalPermissions: () => external,
+ hasAnyPermissions: () => scopeArray.length > 0 || Object.keys(external).length > 0
+ };
+}
+exports.createPermissionUtils = createPermissionUtils;
+function checkScopes(requiredScopes, permissionUtils) {
+ if (!(requiredScopes === null || requiredScopes === void 0 ? void 0 : requiredScopes.length)) {
+ return undefined;
+ }
+ const missingScopes = requiredScopes.filter((scope) => !permissionUtils.hasScope(scope));
+ return missingScopes.length > 0 ? missingScopes : undefined;
+}
+function checkFetchPermissions(requiredFetch, permissionUtils) {
+ if (!(requiredFetch === null || requiredFetch === void 0 ? void 0 : requiredFetch.fetch)) {
+ return undefined;
+ }
+ const missingFetch = {};
+ FETCH_TYPES.forEach((type) => {
+ var _a;
+ const requiredUrls = (_a = requiredFetch.fetch) === null || _a === void 0 ? void 0 : _a[type];
+ if (requiredUrls === null || requiredUrls === void 0 ? void 0 : requiredUrls.length) {
+ const missingUrls = requiredUrls.filter((url) => !permissionUtils.canFetchFrom(type, url));
+ if (missingUrls.length > 0) {
+ missingFetch[type] = missingUrls;
+ }
+ }
+ });
+ return Object.keys(missingFetch).length > 0 ? missingFetch : undefined;
+}
+function checkResourcePermissions(requiredExternal, permissionUtils) {
+ const missingResources = {};
+ RESOURCE_TYPES.forEach((type) => {
+ const requiredUrls = requiredExternal === null || requiredExternal === void 0 ? void 0 : requiredExternal[type];
+ if (requiredUrls === null || requiredUrls === void 0 ? void 0 : requiredUrls.length) {
+ const missingUrls = requiredUrls.filter((url) => !permissionUtils.canLoadResource(type, url));
+ if (missingUrls.length > 0) {
+ missingResources[type] = missingUrls;
+ }
+ }
+ });
+ return Object.keys(missingResources).length > 0 ? missingResources : undefined;
+}
+function checkExternalPermissions(requiredExternal, permissionUtils) {
+ if (!requiredExternal) {
+ return undefined;
+ }
+ const missingFetch = checkFetchPermissions(requiredExternal, permissionUtils);
+ const missingResources = checkResourcePermissions(requiredExternal, permissionUtils);
+ if (!missingFetch && !missingResources) {
+ return undefined;
+ }
+ const missingExternal = {};
+ if (missingFetch) {
+ missingExternal.fetch = missingFetch;
+ }
+ if (missingResources) {
+ Object.assign(missingExternal, missingResources);
+ }
+ return missingExternal;
+}
+async function checkPermissions(requiredPermissions, runtimePermissions) {
+ var _a;
+ if (!requiredPermissions) {
+ return { granted: false, missing: null };
+ }
+ if (!((_a = requiredPermissions.scopes) === null || _a === void 0 ? void 0 : _a.length) && !requiredPermissions.external) {
+ return { granted: true, missing: null };
+ }
+ let permissionsToCheck = runtimePermissions;
+ if (!permissionsToCheck) {
+ const context = await view_1.view.getContext();
+ permissionsToCheck = context.permissions;
+ }
+ const permissionUtils = createPermissionUtils(permissionsToCheck);
+ if (!permissionUtils) {
+ return { granted: false, missing: null };
+ }
+ const missing = {};
+ let hasAllRequiredPermissions = true;
+ const missingScopes = checkScopes(requiredPermissions.scopes, permissionUtils);
+ if (missingScopes) {
+ missing.scopes = missingScopes;
+ hasAllRequiredPermissions = false;
+ }
+ const missingExternal = checkExternalPermissions(requiredPermissions.external, permissionUtils);
+ if (missingExternal) {
+ missing.external = missingExternal;
+ hasAllRequiredPermissions = false;
+ }
+ return {
+ granted: hasAllRequiredPermissions,
+ missing: hasAllRequiredPermissions ? null : missing
+ };
+}
+exports.checkPermissions = checkPermissions;