Validation.

This commit is contained in:
Vasyl Palamarchuk
2026-09-04 13:20:43 -07:00
parent e1cf46c9a1
commit eb5bdafb04
7 changed files with 43 additions and 28 deletions
+3 -1
View File
@@ -12,7 +12,9 @@ export function cloneBytes(data){ requireBytes(data); return new Uint8Array(data
export function sliceBytes(data,offset,length){ assertRange(data,offset,length); return data.slice(offset,offset+length); }
export function bytesToHex(data,separator=" "){ requireBytes(data); return Array.from(data,b=>b.toString(16).padStart(2,"0")).join(separator).toUpperCase(); }
export function hexToBytes(text){
const s=String(text).replace(/[^0-9a-f]/gi,"");
const input=String(text);
if(/[^0-9a-f\s,:-]/i.test(input)) throw new Error("Invalid character in hex text");
const s=input.replace(/[\s,:-]/g,"");
if(s.length%2) throw new Error("Hex text must contain complete bytes");
const out=new Uint8Array(s.length/2); for(let i=0;i<out.length;i++) out[i]=parseInt(s.slice(i*2,i*2+2),16); return out;
}
@@ -6,16 +6,18 @@ export function verifyChecksumRegion(data, region, checksum, algorithm) {
assertRange(data, region.start, region.length);
assertRange(data, checksum.offset, checksum.length);
if (![1, 2, 4].includes(checksum.length)) throw new RangeError("Checksum length must be 1, 2, or 4 bytes");
const endian = checksum.endian || "LE";
if (endian !== "LE" && endian !== "BE") throw new RangeError("Checksum endian must be LE or BE");
const computed = algorithm(data.slice(region.start, region.start + region.length)) >>> 0;
let stored = 0;
for (let index = 0; index < checksum.length; index++) {
const shift = checksum.endian === "BE" ? 8 * (checksum.length - index - 1) : 8 * index;
const shift = endian === "BE" ? 8 * (checksum.length - index - 1) : 8 * index;
stored = (stored | (data[checksum.offset + index] << shift)) >>> 0;
}
const mask = checksum.length === 4 ? 0xFFFFFFFF : (2 ** (checksum.length * 8)) - 1;
return {
region: { start: region.start, length: region.length },
checksum: { offset: checksum.offset, length: checksum.length, endian: checksum.endian || "LE" },
checksum: { offset: checksum.offset, length: checksum.length, endian },
stored: stored & mask,
computed: computed & mask,
matches: (stored & mask) === (computed & mask)
@@ -1,5 +1,5 @@
import { strict as assert } from "node:assert";
import { adler32 } from "../binary_utils.mjs";
import { adler32, hexToBytes } from "../binary_utils.mjs";
import { verifyChecksumRegion } from "../templates/checksum_region_verifier.mjs";
import { fingerprintDump } from "../examples/32_dump_fingerprint.mjs";
import { buildChangeReport } from "../examples/33_structured_change_report.mjs";
@@ -11,6 +11,9 @@ new DataView(withChecksum.buffer).setUint32(4, adler32(payload), false);
assert.equal(verifyChecksumRegion(withChecksum, { start: 0, length: 4 }, { offset: 4, length: 4, endian: "BE" }, adler32).matches, true);
withChecksum[0] = 9;
assert.equal(verifyChecksumRegion(withChecksum, { start: 0, length: 4 }, { offset: 4, length: 4, endian: "BE" }, adler32).matches, false);
assert.deepEqual(hexToBytes("00:0f ff"), new Uint8Array([0, 15, 255]));
assert.throws(() => hexToBytes("12zz34"), /Invalid character/);
assert.throws(() => verifyChecksumRegion(withChecksum, { start: 0, length: 4 }, { offset: 4, length: 4, endian: "BIG" }, adler32), /endian must be LE or BE/);
const fingerprint = fingerprintDump(payload, "fixture.bin");
assert.equal(fingerprint.length, 4);
+5 -5
View File
@@ -64,7 +64,7 @@ Support legitimate, authorized automotive shop operations and educational resear
- Submit a pull request with a clear description
### 4. Contribute Safe Examples
- Base on the [03_Script_Starter_Kit/](../03_Script_Starter_Kit/) templates
- Base on the [03_Script_Starter_Kit/](03_Script_Starter_Kit/) templates
- Include detailed comments explaining the script's purpose
- Add test cases or validation examples
- Document assumptions and dependencies
@@ -73,7 +73,7 @@ Support legitimate, authorized automotive shop operations and educational resear
- Preserve all source attribution
### 5. Contribute Tests
- Add to [16_Tests/](../16_Tests/) directory
- Add to [16_Tests/](16_Tests/) directory
- Use synthetic, non-confidential test data
- Document test purpose and coverage
- Include expected results
@@ -134,12 +134,12 @@ If you discover a security vulnerability or suspicious content:
4. **Allow time** for response and remediation
5. **Do not share** the vulnerability publicly until patched
See [SECURITY.md](../SECURITY.md) for full details.
See [SECURITY.md](SECURITY.md) for full details.
## Questions?
- Check existing [documentation](../01_Knowledge_Base/)
- Review [SECURITY.md](../SECURITY.md) and [LICENSES.md](../LICENSES.md)
- Check existing [documentation](01_Knowledge_Base/)
- Review [SECURITY.md](SECURITY.md) and [LICENSES.md](LICENSES.md)
- Open a discussion or issue if unclear
- Be patient and respectful in all interactions
+1 -1
View File
@@ -1,4 +1,4 @@
sd# XHorse Multi-PROG Ultimate Kit
# XHorse Multi-PROG Ultimate Kit
A comprehensive, auditable knowledge base and development toolkit for safe, authorized XHorse Multi-PROG scripting and ECU/immobilizer module repair operations.
+19 -16
View File
@@ -3,10 +3,15 @@
# Generated: 2026-09-04
param(
[string]$RepositoryRoot = "\\unas\Workspace\CDiag\Scripts\XHorse_MultiPROG_Ultimate_Kit",
[string]$OutputDir = "$RepositoryRoot\14_Repository_Review"
[string]$RepositoryRoot = (Join-Path $PSScriptRoot ".."),
[string]$OutputDir
)
$RepositoryRoot = (Resolve-Path -LiteralPath $RepositoryRoot).Path
if ([string]::IsNullOrWhiteSpace($OutputDir)) {
$OutputDir = Join-Path $RepositoryRoot "14_Repository_Review"
}
$problems = @{
EmptyFiles = @()
UnknownFileTypes = @()
@@ -154,7 +159,6 @@ Write-Host " Found $suspiciousCount files with suspicious patterns"
# 6. Hash-based duplicate detection
Write-Host "Detecting duplicate files by content..."
$hashMap = @{}
$duplicates = @()
foreach ($file in $files) {
if ($file.Length -gt 0) {
@@ -165,9 +169,9 @@ foreach ($file in $files) {
$stream.Close()
if ($hashMap.ContainsKey($sha256)) {
$duplicates += @($hashMap[$sha256], $file.FullName)
$hashMap[$sha256] += $file.FullName
} else {
$hashMap[$sha256] = $file.FullName
$hashMap[$sha256] = @($file.FullName)
}
}
catch {
@@ -177,23 +181,22 @@ foreach ($file in $files) {
}
$groupedDuplicates = @{}
foreach ($dup in $duplicates) {
$relPath = $dup.Substring($RepositoryRoot.Length + 1)
$hash = (Get-FileHash -Path $dup -Algorithm SHA256 -ErrorAction SilentlyContinue).Hash
if (-not $groupedDuplicates.ContainsKey($hash)) {
$groupedDuplicates[$hash] = @()
foreach ($hash in $hashMap.Keys) {
if ($hashMap[$hash].Count -gt 1) {
$groupedDuplicates[$hash] = @($hashMap[$hash] | ForEach-Object {
$_.Substring($RepositoryRoot.Length + 1)
})
}
$groupedDuplicates[$hash] += $relPath
}
Write-Host " Found $($groupedDuplicates.Count) groups of duplicate files"
foreach ($hash in $groupedDuplicates.Keys) {
$files = $groupedDuplicates[$hash]
if ($files.Count -gt 1) {
$duplicatePaths = $groupedDuplicates[$hash]
if ($duplicatePaths.Count -gt 1) {
$problems.DuplicatesByHash += @{
SHA256 = $hash
Count = $files.Count
Files = $files
Count = $duplicatePaths.Count
Files = $duplicatePaths
}
}
}
@@ -223,7 +226,7 @@ if ($problems.LargeFiles.Count -gt 0) {
$reportPath = Join-Path $OutputDir "suspicious_files.csv"
if ($problems.SuspiciousFiles.Count -gt 0) {
$problems.SuspiciousFiles | ConvertTo-Csv -NoTypeInformation | Set-Content -Path $reportPath -Encoding UTF8 -Force
$problems.SuspiciousFiles | ForEach-Object { [PSCustomObject]$_ } | ConvertTo-Csv -NoTypeInformation | Set-Content -Path $reportPath -Encoding UTF8 -Force
Write-Host " Exported: suspicious_files.csv ($($problems.SuspiciousFiles.Count) files)"
}
+7 -2
View File
@@ -3,10 +3,15 @@
# Generated: 2026-09-04
param(
[string]$RepositoryRoot = "\\unas\Workspace\CDiag\Scripts\XHorse_MultiPROG_Ultimate_Kit",
[string]$OutputDir = "$RepositoryRoot\14_Repository_Review"
[string]$RepositoryRoot = (Join-Path $PSScriptRoot ".."),
[string]$OutputDir
)
$RepositoryRoot = (Resolve-Path -LiteralPath $RepositoryRoot).Path
if ([string]::IsNullOrWhiteSpace($OutputDir)) {
$OutputDir = Join-Path $RepositoryRoot "14_Repository_Review"
}
function Get-FileCategory {
param([string]$Extension)