Files
codebuddy-scripts/Dat File Script/decrypt-dat-file.ps1

197 lines
5.0 KiB
PowerShell
Raw Normal View History

2025-09-17 10:52:06 -05:00
<#
.SYNOPSIS
Decrypts and edits rIDE SecureLocalStorage store.dat (DPAPI CurrentUser).
Works on Windows PowerShell 5.1 and PowerShell 7+.
.PARAMETER UserId
The userId subfolder under %AppData%\rIDE\. Use "." with -AppDataOverride "." if you're already in the folder.
.PARAMETER Key
Optional. If provided, prints only this key's value.
.PARAMETER ListKeys
Optional. If set, prints only the available keys.
.PARAMETER AppDataOverride
Optional. Override base AppData path (defaults to [Environment]::GetFolderPath("ApplicationData")).
Example: -AppDataOverride "." to use .\store.dat in the current directory.
.PARAMETER Raw
Optional. Output raw strings (no pretty objects / nested JSON parsing).
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$UserId,
[string]$Key,
[switch]$ListKeys,
[string]$AppDataOverride,
[switch]$Raw
)
# Ensure DPAPI types exist
Add-Type -AssemblyName System.Security
# ---- Helpers ----
# Convert PSObject/arrays into pure hashtables/arrays so PS 5.1 works like PS7 -AsHashtable
function Convert-PSObjectToHashtable {
param([Parameter(ValueFromPipeline=$true)]$InputObject)
process {
if ($null -eq $InputObject) { return $null }
if ($InputObject -is [System.Collections.IDictionary]) {
$ht = @{}
foreach ($k in $InputObject.Keys) {
$ht[$k] = Convert-PSObjectToHashtable $InputObject[$k]
}
return $ht
}
if ($InputObject -is [System.Collections.IEnumerable] -and -not ($InputObject -is [string])) {
$arr = @()
foreach ($item in $InputObject) { $arr += ,(Convert-PSObjectToHashtable $item) }
return $arr
}
if ($InputObject -is [psobject]) {
$ht = @{}
foreach ($p in $InputObject.PSObject.Properties) {
$ht[$p.Name] = Convert-PSObjectToHashtable $p.Value
}
return $ht
}
return $InputObject
}
}
function Get-StorePath {
param([string]$UserId, [string]$AppDataOverride)
$appData = if ($AppDataOverride) { $AppDataOverride } else { [Environment]::GetFolderPath("ApplicationData") }
# Code uses "rIDE" but Windows is case-insensitive
$dir = Join-Path (Join-Path $appData "rIDE") $UserId
return Join-Path $dir "store.dat"
}
function Read-DecryptedStore {
param([string]$Path)
if (-not (Test-Path -LiteralPath $Path)) { throw "File not found: $Path" }
try {
$encBytes = [System.IO.File]::ReadAllBytes($Path)
} catch {
throw "Unable to read file '$Path': $($_.Exception.Message)"
}
try {
$decBytes = [System.Security.Cryptography.ProtectedData]::Unprotect(
$encBytes, $null,
[System.Security.Cryptography.DataProtectionScope]::CurrentUser
)
} catch {
throw "DPAPI Unprotect failed. Are you running as the SAME Windows user that created the file? Inner: $($_.Exception.Message)"
}
$json = [System.Text.Encoding]::UTF8.GetString($decBytes)
try {
$obj = $json | ConvertFrom-Json
$dict = Convert-PSObjectToHashtable $obj # PS5.1-safe
if ($dict -isnot [hashtable]) { throw "Expected a JSON object/dictionary at the top level." }
return $dict
} catch {
throw "Decrypted bytes were not valid JSON: $($_.Exception.Message)"
}
}
function Try-ParseJson {
param([string]$s)
try {
if ($null -ne $s -and ($s.TrimStart().StartsWith('{') -or $s.TrimStart().StartsWith('['))) {
return $s | ConvertFrom-Json
}
} catch { }
return $s
}
function Write-EncryptedStore {
param(
[string]$Path,
[hashtable]$Store
)
$json = $Store | ConvertTo-Json -Depth 10 -Compress
$bytes = [System.Text.Encoding]::UTF8.GetBytes($json)
$enc = [System.Security.Cryptography.ProtectedData]::Protect(
$bytes, $null,
[System.Security.Cryptography.DataProtectionScope]::CurrentUser
)
[System.IO.File]::WriteAllBytes($Path, $enc)
}
function Set-StoreValue {
param(
[string]$UserId,
[string]$Key,
[string]$Value,
[string]$AppDataOverride
)
$path = Get-StorePath -UserId $UserId -AppDataOverride $AppDataOverride
$store = Read-DecryptedStore -Path $path
$store[$Key] = $Value
Write-EncryptedStore -Path $path -Store $store
Write-Host "Key '$Key' updated successfully in $path"
}
# ---- Main (print/list/single-key) ----
$path = Get-StorePath -UserId $UserId -AppDataOverride $AppDataOverride
try {
$store = Read-DecryptedStore -Path $path
} catch {
Write-Error $_.Exception.Message
exit 1
}
if ($ListKeys) {
$store.Keys | Sort-Object
exit 0
}
if ($Key) {
if ($store.ContainsKey($Key)) {
$val = $store[$Key]
if ($Raw) {
$val
} else {
$parsed = Try-ParseJson -s $val
$parsed | ConvertTo-Json -Depth 10
}
exit 0
} else {
Write-Error "Key '$Key' not found. Use -ListKeys to see available keys."
exit 2
}
}
# No key specified: show entire dictionary (pretty where possible)
if ($Raw) {
$store.GetEnumerator() | Sort-Object Name | ForEach-Object {
"{0} = {1}" -f $_.Key, $_.Value
}
} else {
$pretty = @{}
foreach ($k in $store.Keys) { $pretty[$k] = Try-ParseJson -s $store[$k] }
$pretty | ConvertTo-Json -Depth 10
}