| import { readFileSync } from '../fileRead.js' |
| import { getFsImplementation, safeResolvePath } from '../fsOperations.js' |
| import { safeParseJSON } from '../json.js' |
| import { logError } from '../log.js' |
| import { |
| type EditableSettingSource, |
| getEnabledSettingSources, |
| type SettingSource, |
| } from '../settings/constants.js' |
| import { |
| getSettingsFilePathForSource, |
| getSettingsForSource, |
| updateSettingsForSource, |
| } from '../settings/settings.js' |
| import type { SettingsJson } from '../settings/types.js' |
| import type { |
| PermissionBehavior, |
| PermissionRule, |
| PermissionRuleSource, |
| PermissionRuleValue, |
| } from './PermissionRule.js' |
| import { |
| permissionRuleValueFromString, |
| permissionRuleValueToString, |
| } from './permissionRuleParser.js' |
|
|
| |
| |
| |
| |
| export function shouldAllowManagedPermissionRulesOnly(): boolean { |
| return ( |
| getSettingsForSource('policySettings')?.allowManagedPermissionRulesOnly === |
| true |
| ) |
| } |
|
|
| |
| |
| |
| |
| export function shouldShowAlwaysAllowOptions(): boolean { |
| return !shouldAllowManagedPermissionRulesOnly() |
| } |
|
|
| const SUPPORTED_RULE_BEHAVIORS = [ |
| 'allow', |
| 'deny', |
| 'ask', |
| ] as const satisfies PermissionBehavior[] |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| function getSettingsForSourceLenient_FOR_EDITING_ONLY_NOT_FOR_READING( |
| source: SettingSource, |
| ): SettingsJson | null { |
| const filePath = getSettingsFilePathForSource(source) |
| if (!filePath) { |
| return null |
| } |
|
|
| try { |
| const { resolvedPath } = safeResolvePath(getFsImplementation(), filePath) |
| const content = readFileSync(resolvedPath) |
| if (content.trim() === '') { |
| return {} |
| } |
|
|
| const data = safeParseJSON(content, false) |
| |
| |
| return data && typeof data === 'object' ? (data as SettingsJson) : null |
| } catch { |
| return null |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| function settingsJsonToRules( |
| data: SettingsJson | null, |
| source: PermissionRuleSource, |
| ): PermissionRule[] { |
| if (!data || !data.permissions) { |
| return [] |
| } |
|
|
| const { permissions } = data |
| const rules: PermissionRule[] = [] |
| for (const behavior of SUPPORTED_RULE_BEHAVIORS) { |
| const behaviorArray = permissions[behavior] |
| if (behaviorArray) { |
| for (const ruleString of behaviorArray) { |
| rules.push({ |
| source, |
| ruleBehavior: behavior, |
| ruleValue: permissionRuleValueFromString(ruleString), |
| }) |
| } |
| } |
| } |
| return rules |
| } |
|
|
| |
| |
| |
| |
| export function loadAllPermissionRulesFromDisk(): PermissionRule[] { |
| |
| if (shouldAllowManagedPermissionRulesOnly()) { |
| return getPermissionRulesForSource('policySettings') |
| } |
|
|
| |
| const rules: PermissionRule[] = [] |
|
|
| for (const source of getEnabledSettingSources()) { |
| rules.push(...getPermissionRulesForSource(source)) |
| } |
| return rules |
| } |
|
|
| |
| |
| |
| |
| |
| export function getPermissionRulesForSource( |
| source: SettingSource, |
| ): PermissionRule[] { |
| const settingsData = getSettingsForSource(source) |
| return settingsJsonToRules(settingsData, source) |
| } |
|
|
| export type PermissionRuleFromEditableSettings = PermissionRule & { |
| source: EditableSettingSource |
| } |
|
|
| |
| const EDITABLE_SOURCES: EditableSettingSource[] = [ |
| 'userSettings', |
| 'projectSettings', |
| 'localSettings', |
| ] |
|
|
| |
| |
| |
| |
| |
| export function deletePermissionRuleFromSettings( |
| rule: PermissionRuleFromEditableSettings, |
| ): boolean { |
| |
| if (!EDITABLE_SOURCES.includes(rule.source as EditableSettingSource)) { |
| return false |
| } |
|
|
| const ruleString = permissionRuleValueToString(rule.ruleValue) |
| const settingsData = getSettingsForSource(rule.source) |
|
|
| |
| if (!settingsData || !settingsData.permissions) { |
| return false |
| } |
|
|
| const behaviorArray = settingsData.permissions[rule.ruleBehavior] |
| if (!behaviorArray) { |
| return false |
| } |
|
|
| |
| |
| const normalizeEntry = (raw: string): string => |
| permissionRuleValueToString(permissionRuleValueFromString(raw)) |
|
|
| if (!behaviorArray.some(raw => normalizeEntry(raw) === ruleString)) { |
| return false |
| } |
|
|
| try { |
| |
| const updatedSettingsData = { |
| ...settingsData, |
| permissions: { |
| ...settingsData.permissions, |
| [rule.ruleBehavior]: behaviorArray.filter( |
| raw => normalizeEntry(raw) !== ruleString, |
| ), |
| }, |
| } |
|
|
| const { error } = updateSettingsForSource(rule.source, updatedSettingsData) |
| if (error) { |
| |
| return false |
| } |
|
|
| return true |
| } catch (error) { |
| logError(error) |
| return false |
| } |
| } |
|
|
| function getEmptyPermissionSettingsJson(): SettingsJson { |
| return { |
| permissions: {}, |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| export function addPermissionRulesToSettings( |
| { |
| ruleValues, |
| ruleBehavior, |
| }: { |
| ruleValues: PermissionRuleValue[] |
| ruleBehavior: PermissionBehavior |
| }, |
| source: EditableSettingSource, |
| ): boolean { |
| |
| if (shouldAllowManagedPermissionRulesOnly()) { |
| return false |
| } |
|
|
| if (ruleValues.length < 1) { |
| |
| return true |
| } |
|
|
| const ruleStrings = ruleValues.map(permissionRuleValueToString) |
| |
| |
| |
| const settingsData = |
| getSettingsForSource(source) || |
| getSettingsForSourceLenient_FOR_EDITING_ONLY_NOT_FOR_READING(source) || |
| getEmptyPermissionSettingsJson() |
|
|
| try { |
| |
| const existingPermissions = settingsData.permissions || {} |
| const existingRules = existingPermissions[ruleBehavior] || [] |
|
|
| |
| |
| const existingRulesSet = new Set( |
| existingRules.map(raw => |
| permissionRuleValueToString(permissionRuleValueFromString(raw)), |
| ), |
| ) |
| const newRules = ruleStrings.filter(rule => !existingRulesSet.has(rule)) |
|
|
| |
| if (newRules.length === 0) { |
| return true |
| } |
|
|
| |
| const updatedSettingsData = { |
| ...settingsData, |
| permissions: { |
| ...existingPermissions, |
| [ruleBehavior]: [...existingRules, ...newRules], |
| }, |
| } |
| const result = updateSettingsForSource(source, updatedSettingsData) |
|
|
| if (result.error) { |
| throw result.error |
| } |
|
|
| return true |
| } catch (error) { |
| logError(error) |
| return false |
| } |
| } |
|
|