noid-privacy/Core/Config.ps1
NexusOne23 74b73eda81 fix: cleanup loader lists, update New-DefaultConfig, fix CHANGELOG numbers
- Remove non-existent Backup/Restore-AntiAISettings from AntiAI.psm1 loader

- Remove non-existent Restore-PrivacySettings from Privacy.psm1 loader

- Update New-DefaultConfig: EdgeHardening 20->24, AdvancedSecurity 36->50

- Add missing options: nonInteractive, autoConfirm, module-specific settings

- Fix CHANGELOG.md: AntiAI 24->32, EdgeHardening 20->24, AdvancedSecurity 44->50
2025-12-24 21:15:09 +01:00

487 lines
16 KiB
PowerShell

<#
.SYNOPSIS
Configuration management for NoID Privacy Framework
.DESCRIPTION
Handles loading, saving, and validating configuration settings
from JSON configuration files.
.NOTES
Author: NexusOne23
Version: 2.2.2
Requires: PowerShell 5.1+
#>
# Global configuration object
$script:Config = $null
function Initialize-Config {
<#
.SYNOPSIS
Initialize configuration system
.PARAMETER ConfigPath
Path to configuration file (JSON)
.PARAMETER CreateDefault
Create default configuration if file doesn't exist
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $false)]
[string]$ConfigPath = (Join-Path $PSScriptRoot "..\config.json"),
[Parameter(Mandatory = $false)]
[bool]$CreateDefault = $true
)
# Check if config file exists
if (-not (Test-Path -Path $ConfigPath)) {
if ($CreateDefault) {
Write-Log -Level INFO -Message "Configuration file not found, creating default" -Module "Config"
New-DefaultConfig -Path $ConfigPath
}
else {
throw "Configuration file not found: $ConfigPath"
}
}
# Load configuration
try {
$configContent = Get-Content -Path $ConfigPath -Raw -Encoding UTF8
$script:Config = $configContent | ConvertFrom-Json
Write-Log -Level INFO -Message "Configuration loaded successfully" -Module "Config"
}
catch {
Write-Log -Level ERROR -Message "Failed to load configuration" -Module "Config" -Exception $_.Exception
throw
}
# Validate configuration
if (-not (Test-ConfigValid)) {
throw "Configuration validation failed"
}
}
function New-DefaultConfig {
<#
.SYNOPSIS
Create default configuration file
.PARAMETER Path
Path where configuration file should be created
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$Path
)
$defaultConfig = @{
version = "2.2.2"
modules = @{
SecurityBaseline = @{
enabled = $true
priority = 1
status = "IMPLEMENTED"
bitLockerUSBEnforcement = $false
}
ASR = @{
enabled = $true
priority = 2
status = "IMPLEMENTED"
usesManagementTools = $false
allowNewSoftware = $false
continueWithoutCloud = $true
}
DNS = @{
enabled = $true
priority = 3
status = "IMPLEMENTED"
provider = "Quad9"
dohMode = "REQUIRE"
}
Privacy = @{
enabled = $true
priority = 4
status = "IMPLEMENTED"
mode = "MSRecommended"
disableCloudClipboard = $true
removeBloatware = $true
}
AntiAI = @{
enabled = $true
priority = 5
status = "IMPLEMENTED"
description = "Disable all Windows 11 AI features (Recall, Copilot, Paint AI, etc.)"
}
EdgeHardening = @{
enabled = $true
priority = 6
status = "IMPLEMENTED"
description = "Microsoft Edge v139 Security Baseline: 24 security policies"
allowExtensions = $true
version = "2.2.2"
baseline = "Edge v139"
policies = 24
features = @{
smartscreen_enforcement = $true
site_isolation = $true
ssl_error_blocking = $true
extension_blocklist = $true
ie_mode_restrictions = $true
spectre_mitigations = $true
application_encryption = $true
auth_scheme_restrictions = $true
}
}
AdvancedSecurity = @{
enabled = $true
priority = 7
status = "IMPLEMENTED"
description = "Advanced Security hardening beyond MS Baseline"
securityProfile = "Balanced"
disableRDP = $true
forceAdminShares = $false
disableUPnP = $true
disableWirelessDisplay = $false
disableDiscoveryProtocols = $true
disableIPv6 = $false
version = "2.2.2"
policies = 50
features = @{
rdp_hardening = $true
wdigest_protection = $true
admin_shares_disable = $true
risky_ports_closure = $true
risky_services_stop = $true
legacy_tls_disable = $true
wpad_disable = $true
powershell_v2_removal = $true
srp_lnk_protection = $true
windows_update_config = $true
finger_protocol_block = $true
wireless_display_security = $true
discovery_protocols_security = $true
firewall_shields_up = $true
ipv6_disable = $true
}
profiles = @("Balanced", "Enterprise", "Maximum")
}
}
options = @{
dryRun = $false
createBackup = $true
verboseLogging = $true
autoReboot = $false
nonInteractive = $false
autoConfirm = $false
}
}
try {
$defaultConfig | ConvertTo-Json -Depth 10 | Set-Content -Path $Path -Encoding UTF8 | Out-Null
Write-Log -Level SUCCESS -Message "Default configuration created: $Path" -Module "Config"
}
catch {
Write-Log -Level ERROR -Message "Failed to create default configuration" -Module "Config" -Exception $_.Exception
throw
}
}
function Test-ConfigValid {
<#
.SYNOPSIS
Validate configuration structure and values
.OUTPUTS
Boolean indicating if configuration is valid
#>
[CmdletBinding()]
[OutputType([bool])]
param()
if ($null -eq $script:Config) {
Write-Log -Level ERROR -Message "Configuration is null" -Module "Config"
return $false
}
# Check required properties
$requiredProps = @('version', 'modules', 'options')
foreach ($prop in $requiredProps) {
if (-not (Get-Member -InputObject $script:Config -Name $prop -MemberType NoteProperty)) {
Write-Log -Level ERROR -Message "Missing required property: $prop" -Module "Config"
return $false
}
}
# Validate modules
if ($null -eq $script:Config.modules) {
Write-Log -Level ERROR -Message "Modules configuration is missing" -Module "Config"
return $false
}
# Validate each module configuration
foreach ($prop in $script:Config.modules.PSObject.Properties) {
$moduleName = $prop.Name
$moduleConfig = $prop.Value
# Check required module properties
$requiredModuleProps = @('enabled', 'priority')
foreach ($moduleProp in $requiredModuleProps) {
if (-not (Get-Member -InputObject $moduleConfig -Name $moduleProp -MemberType NoteProperty)) {
Write-Log -Level ERROR -Message "Module '$moduleName' missing required property: $moduleProp" -Module "Config"
return $false
}
}
# Validate property types
if ($moduleConfig.enabled -isnot [bool]) {
Write-Log -Level ERROR -Message "Module '$moduleName' property 'enabled' must be boolean" -Module "Config"
return $false
}
if ($moduleConfig.priority -isnot [int] -and $moduleConfig.priority -isnot [long]) {
Write-Log -Level ERROR -Message "Module '$moduleName' property 'priority' must be integer" -Module "Config"
return $false
}
# Module-specific validation
if ($moduleName -eq "DNS") {
# Validate DNS provider if specified
if (Get-Member -InputObject $moduleConfig -Name 'provider' -MemberType NoteProperty) {
$validProviders = @('Cloudflare', 'Quad9', 'AdGuard', '', 'KEEP')
# Empty string means interactive selection
if ($moduleConfig.provider -eq '') {
Write-Log -Level DEBUG -Message "DNS provider not specified - will prompt user for selection" -Module "Config"
}
elseif ($moduleConfig.provider -eq 'KEEP') {
Write-Log -Level DEBUG -Message "DNS provider set to KEEP - will detect and preserve current provider" -Module "Config"
}
elseif ($validProviders -notcontains $moduleConfig.provider) {
Write-Log -Level ERROR -Message "DNS module has invalid provider: '$($moduleConfig.provider)'. Valid providers: $($validProviders -join ', ')" -Module "Config"
return $false
}
else {
Write-Log -Level DEBUG -Message "DNS provider validated: $($moduleConfig.provider)" -Module "Config"
}
}
else {
# Provider property missing - will prompt for selection
Write-Log -Level DEBUG -Message "DNS provider not specified - will prompt user for selection" -Module "Config"
}
}
if ($moduleName -eq "Privacy") {
# Validate Privacy mode if specified
if (Get-Member -InputObject $moduleConfig -Name 'mode' -MemberType NoteProperty) {
$validModes = @('MSRecommended', 'Strict', 'Paranoid', '')
# Empty string means interactive selection
if ($moduleConfig.mode -eq '') {
Write-Log -Level DEBUG -Message "Privacy mode not specified - will prompt user for selection" -Module "Config"
}
elseif ($validModes -notcontains $moduleConfig.mode) {
Write-Log -Level ERROR -Message "Privacy module has invalid mode: '$($moduleConfig.mode)'. Valid modes: $($validModes -join ', ')" -Module "Config"
return $false
}
else {
Write-Log -Level DEBUG -Message "Privacy mode validated: $($moduleConfig.mode)" -Module "Config"
}
}
else {
# Mode property missing - will prompt for selection
Write-Log -Level DEBUG -Message "Privacy mode not specified - will prompt user for selection" -Module "Config"
}
}
}
# Validate options
if ($null -eq $script:Config.options) {
Write-Log -Level ERROR -Message "Options configuration is missing" -Module "Config"
return $false
}
# Check required option properties
$requiredOptions = @('dryRun', 'createBackup', 'verboseLogging', 'autoReboot')
foreach ($option in $requiredOptions) {
if (-not (Get-Member -InputObject $script:Config.options -Name $option -MemberType NoteProperty)) {
Write-Log -Level ERROR -Message "Missing required option: $option" -Module "Config"
return $false
}
}
Write-Log -Level INFO -Message "Configuration validation passed" -Module "Config"
return $true
}
function Get-Config {
<#
.SYNOPSIS
Get current configuration object
.OUTPUTS
Configuration object
#>
return $script:Config
}
function Get-ModuleConfig {
<#
.SYNOPSIS
Get configuration for specific module
.PARAMETER ModuleName
Name of the module
.OUTPUTS
Module configuration object or $null if not found
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$ModuleName
)
if ($null -eq $script:Config -or $null -eq $script:Config.modules) {
Write-Log -Level WARNING -Message "Configuration not initialized" -Module "Config"
return $null
}
$moduleConfig = $script:Config.modules | Get-Member -Name $ModuleName -MemberType NoteProperty
if ($null -eq $moduleConfig) {
Write-Log -Level WARNING -Message "Module configuration not found: $ModuleName" -Module "Config"
return $null
}
return $script:Config.modules.$ModuleName
}
function Test-ModuleAvailability {
<#
.SYNOPSIS
Check if a module is actually implemented and available
.DESCRIPTION
Checks if module directory exists and contains the required .psd1 manifest file
.PARAMETER ModuleName
Name of the module to check
.OUTPUTS
Boolean - True if module is implemented, False otherwise
.EXAMPLE
Test-ModuleAvailability -ModuleName "SecurityBaseline"
#>
[CmdletBinding()]
[OutputType([bool])]
param(
[Parameter(Mandatory = $true)]
[string]$ModuleName
)
# Get framework root (3 levels up from Config.ps1)
$frameworkRoot = Split-Path $PSScriptRoot -Parent
$modulePath = Join-Path $frameworkRoot "Modules\$ModuleName"
$manifestPath = Join-Path $modulePath "$ModuleName.psd1"
# Check if module directory exists
if (-not (Test-Path $modulePath)) {
Write-Log -Level DEBUG -Message "Module directory not found: $modulePath" -Module "Config"
return $false
}
# Check if module manifest exists
if (-not (Test-Path $manifestPath)) {
Write-Log -Level DEBUG -Message "Module manifest not found: $manifestPath" -Module "Config"
return $false
}
Write-Log -Level DEBUG -Message "Module $ModuleName is available" -Module "Config"
return $true
}
function Get-EnabledModules {
<#
.SYNOPSIS
Get list of enabled modules sorted by priority
.DESCRIPTION
Returns only modules that are both enabled in config AND actually implemented
.OUTPUTS
Array of enabled module names sorted by priority
#>
[CmdletBinding()]
[OutputType([string[]])]
param()
if ($null -eq $script:Config -or $null -eq $script:Config.modules) {
Write-Log -Level WARNING -Message "Configuration not initialized" -Module "Config"
return @()
}
$enabledModules = @()
foreach ($prop in $script:Config.modules.PSObject.Properties) {
$moduleName = $prop.Name
$moduleConfig = $prop.Value
if ($moduleConfig.enabled -eq $true) {
# Check if module is actually implemented
if (Test-ModuleAvailability -ModuleName $moduleName) {
$enabledModules += [PSCustomObject]@{
Name = $moduleName
Priority = $moduleConfig.priority
}
}
else {
$status = if ($moduleConfig.PSObject.Properties.Name -contains 'status') { $moduleConfig.status } else { 'UNKNOWN' }
Write-Log -Level WARNING -Message "Module '$moduleName' is enabled in config but not implemented (Status: $status)" -Module "Config"
}
}
}
# Sort by priority
$sorted = $enabledModules | Sort-Object -Property Priority
return $sorted | ForEach-Object { $_.Name }
}
function Set-ModuleEnabled {
<#
.SYNOPSIS
Enable or disable a module
.PARAMETER ModuleName
Name of the module
.PARAMETER Enabled
Enable (true) or disable (false) the module
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$ModuleName,
[Parameter(Mandatory = $true)]
[bool]$Enabled
)
if ($null -eq $script:Config -or $null -eq $script:Config.modules) {
throw "Configuration not initialized"
}
$moduleConfig = $script:Config.modules | Get-Member -Name $ModuleName -MemberType NoteProperty
if ($null -eq $moduleConfig) {
throw "Module not found: $ModuleName"
}
$script:Config.modules.$ModuleName.enabled = $Enabled
Write-Log -Level INFO -Message "Module '$ModuleName' set to: $Enabled" -Module "Config"
}
# Note: Export-ModuleMember not used - this script is dot-sourced, not imported as module