Public/Export-GamAuthSecure.ps1
|
function Export-GamAuthSecure { <# .SYNOPSIS Encrypts individual GAM7 config and auth files into AES-encrypted files. .DESCRIPTION Encrypts specified GAM config files using AES-256 encryption with a provided key. Creates encrypted copies of sensitive files for secure backup and transfer. .EXAMPLE Export-GamAuthSecure -KeyFile ./gam-encryption.key .OUTPUTS .encrypted files in the specified output directory (default: ./gam-secure-export) #> [CmdletBinding()] param( [Parameter()] [string]$GamConfigDir, [Parameter()] [string]$KeyFile = (Join-Path (Get-Location) 'gam-encryption.key'), [Parameter()] [string]$OutputDir = (Join-Path (Get-Location) 'gam-secure-export'), [Parameter()] [switch]$Force ) $activity = 'Export-GamAuthSecure' if (-not $GamConfigDir) { $GamConfigDir = $env:GAMCFGDIR if (-not $GamConfigDir) { $GamConfigDir = Join-Path $HOME '.gam' } } Write-Verbose "$activity : $GamConfigDir -> $OutputDir" if (-not (Test-Path $GamConfigDir)) { Write-Warning "GAM config directory not found: $GamConfigDir" return } if (-not (Test-Path $KeyFile)) { Write-Warning "Encryption key not found: $KeyFile. Run New-GamEncryptionKey first." return } Write-Progress -Activity $activity -Status 'Loading encryption key...' -PercentComplete 10 $keyBase64 = [System.IO.File]::ReadAllText($KeyFile).Trim() [byte[]]$key = [Convert]::FromBase64String($keyBase64) if ($key.Length -notin @(16, 24, 32)) { Write-Warning "Invalid key length: $($key.Length) bytes. Must be 16, 24, or 32." return } $coreFiles = @( 'gam.cfg', 'client_secrets.json', 'oauth2.txt', 'oauth2service.json', 'extra_args.txt' ) if (-not (Test-Path $OutputDir)) { New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null } Write-Progress -Activity $activity -Status 'Encrypting core files...' -PercentComplete 30 $encryptFile = { param([string]$SourcePath, [string]$DestPath, [byte[]]$AesKey) $rawBytes = [System.IO.File]::ReadAllBytes($SourcePath) $encryptedBytes = Protect-GamData -PlainBytes $rawBytes -AesKey $AesKey [System.IO.File]::WriteAllBytes($DestPath, $encryptedBytes) } $exported = 0 foreach ($file in $coreFiles) { $srcPath = Join-Path $GamConfigDir $file if (Test-Path $srcPath) { $destPath = Join-Path $OutputDir "$file.encrypted" if ((Test-Path $destPath) -and -not $Force) { Write-Warning "Skipping (exists): $destPath. Use -Force to overwrite." continue } & $encryptFile $srcPath $destPath $key $exported++ } else { Write-Verbose "Not found, skipping: $srcPath" } } Write-Progress -Activity $activity -Status 'Scanning for section subdirectories...' -PercentComplete 70 $gamCfgPath = Join-Path $GamConfigDir 'gam.cfg' if (Test-Path $gamCfgPath) { $cfgContent = Get-Content $gamCfgPath -Raw $sectionDirs = [regex]::Matches($cfgContent, '(?mi)^\s*config_dir\s*=\s*(.+)$') | ForEach-Object { $_.Groups[1].Value.Trim() } | Where-Object { $_ -and $_ -ne $GamConfigDir -and $_ -notmatch '^[/\\~]' } | Sort-Object -Unique foreach ($subDir in $sectionDirs) { $subDirFull = Join-Path $GamConfigDir $subDir if (Test-Path $subDirFull) { $subOutDir = Join-Path $OutputDir $subDir if (-not (Test-Path $subOutDir)) { New-Item -ItemType Directory -Path $subOutDir -Force | Out-Null } $subFiles = @('client_secrets.json', 'oauth2.txt', 'oauth2service.json') foreach ($sf in $subFiles) { $sfPath = Join-Path $subDirFull $sf if (Test-Path $sfPath) { $destPath = Join-Path $subOutDir "$sf.encrypted" if ((Test-Path $destPath) -and -not $Force) { Write-Warning "Skipping (exists): $destPath. Use -Force to overwrite." continue } & $encryptFile $sfPath $destPath $key $exported++ } } } } } Write-Progress -Activity $activity -Completed [PSCustomObject]@{ SourceDir = $GamConfigDir OutputDir = $OutputDir FilesCount = $exported Encrypted = 'Yes' } | Format-List } |