From 4a782f28b96ce51579e28cdbf9ecc223ff705ee8 Mon Sep 17 00:00:00 2001
From: MB-X Bilibili Pipeline <mbx-bili-pipeline@localhost>
Date: Sat, 05 Sep 2026 22:25:47 +0800
Subject: [PATCH] chore(project-info): archive Bilibili dynamic 2eb133e6d0b9

---
 dev/project-dev/bili_authenticated_extension/install_native_host.ps1 |  552 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 500 insertions(+), 52 deletions(-)

diff --git a/dev/project-dev/bili_authenticated_extension/install_native_host.ps1 b/dev/project-dev/bili_authenticated_extension/install_native_host.ps1
index b491b9f..04d4936 100644
--- a/dev/project-dev/bili_authenticated_extension/install_native_host.ps1
+++ b/dev/project-dev/bili_authenticated_extension/install_native_host.ps1
@@ -22,7 +22,11 @@
     [Parameter(DontShow = $true)]
     [string]$TestRegistryRoot,
     [Parameter(DontShow = $true)]
-    [ValidateSet('none', 'after-root', 'after-payload', 'after-config', 'after-manifest', 'after-registry-key', 'after-registry-value')]
+    [string]$TestPreviousInstallRoot,
+    [Parameter(DontShow = $true)]
+    [string]$TestPreviousArtifactReceipt,
+    [Parameter(DontShow = $true)]
+    [ValidateSet('none', 'after-root', 'after-payload', 'after-config', 'after-manifest', 'after-registry-key', 'after-registry-value', 'after-registry-value-mixed')]
     [string]$InjectFailure = 'none'
 )
 
@@ -31,9 +35,17 @@
 $expectedOrigin = 'chrome-extension://oidmclckpdmpabbfedplkbdplmfcenbb/'
 $expectedHostName = 'com.project_info.bili_auth_ingress'
 $expectedPublicDerHash = 'E83C2B2AF3CF011543FBA13FBC524D1122EEA68548F9F27B9F7A82B5D594666C'
-$expectedExtensionBuild = 'project-info-bili-auth-ingress/1.0.0+20260805.v002'
-$expectedHostBuild = 'project-info-bili-auth-native-host/1.0.0+20260805.v002'
+$expectedExtensionBuild = 'project-info-bili-auth-ingress/1.2.25+20260829.generic.v027'
+$expectedHostBuild = 'project-info-bili-auth-native-host/1.2.25+20260829.generic.v027'
 $expectedHostExecutable = 'project-info-bili-auth-native-host.exe'
+$expectedPreviousExtensionBuild = 'project-info-bili-auth-ingress/1.2.24+20260829.generic.v026'
+$expectedPreviousVersion = '1.2.24+20260829.generic.v026'
+$expectedPreviousManifestBytes = 381
+$expectedPreviousManifestSha256 = '9FFAC5073A5839F030ED321840C5715ECBE2CC7276DD057A7236B3CF78AA5C38'
+$expectedPreviousHostBytes = 21452778
+$expectedPreviousHostSha256 = '24E0C15B9E8269F55F25E55A0614DD96BEF58CB0F7EE069C41F86AF95CD19762'
+$expectedPreviousConfigBytes = 1870
+$expectedPreviousConfigSha256 = 'ACA285C700CD970A846A824BD32E6826195B0204640F8445C288C7476EC475E3'
 $publicKey = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt2dT1HGYaI0DXM7zZwOTNBWXTKlMBJMpyDVjRUc+v6bUotmLyoraC+ay2scy9UQluSZVYq0tS8qvQNNvuZOlc5w2bOExm4TH2IIKvaVO8nVthHBnNz2kXdiM8ItN0vPZEmS+8gpTCI1+6wPTuUglMoXpqYBYhii8fJ5RkENRF3PRJBBigGt8soqdBFRY1QZUmpQv9dYw4dRq4L2C4QtBgClUg4bQpuCppiVZ9LHbePi9IAjc9r9R93KLzpaBuXdJpfVRE5w/6YHnxP8ovXxBdl7XktmrdH3xj7mWT7Q7ZBxkDNwn2RkruD45XgDD3yuNxOYSkLFMkseN+Ua69gSS4wIDAQAB'
 
 function Stop-Injected([string]$Point) {
@@ -86,6 +98,26 @@
     }
 }
 
+function Assert-ExactSourceSnapshot([string]$Root, [string]$ManifestPath, [string[]]$ExpectedFiles, [object]$Manifest) {
+    Assert-ExactSourceTree $Root $ManifestPath $ExpectedFiles
+    foreach ($entry in $Manifest.files) {
+        if ($entry.path -notmatch '^[A-Za-z0-9._/-]+$' -or $entry.path.Contains('..') -or
+            $entry.sha256 -notmatch '^[A-F0-9]{64}$' -or $entry.bytes -lt 1) {
+            throw 'Source artifact manifest contains an invalid entry.'
+        }
+        $candidate = [System.IO.Path]::GetFullPath((Join-Path $Root $entry.path))
+        if (-not $candidate.StartsWith($Root + [System.IO.Path]::DirectorySeparatorChar, [StringComparison]::OrdinalIgnoreCase)) {
+            throw 'Source artifact path escaped its root.'
+        }
+        $item = Get-Item -LiteralPath $candidate
+        if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -or
+            $item.Length -ne $entry.bytes -or
+            (Get-FileHash -Algorithm SHA256 -LiteralPath $candidate).Hash -cne $entry.sha256) {
+            throw 'Source artifact hash mismatch.'
+        }
+    }
+}
+
 function Copy-CreateNew([string]$Source, [string]$Destination) {
     $input = [System.IO.File]::Open($Source, [IO.FileMode]::Open, [IO.FileAccess]::Read, [IO.FileShare]::Read)
     try {
@@ -110,6 +142,339 @@
     } finally {
         $stream.Dispose()
     }
+}
+
+function Get-FileIdentity([string]$Path) {
+    $item = Get-Item -LiteralPath $Path -Force
+    if ($item.PSIsContainer -or ($item.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
+        throw 'Expected a regular non-reparse file.'
+    }
+    return [pscustomobject]@{
+        Bytes = $item.Length
+        Sha256 = (Get-FileHash -Algorithm SHA256 -LiteralPath $Path).Hash
+    }
+}
+
+function ConvertTo-StrictPositiveInt64 {
+    [CmdletBinding(PositionalBinding = $false)]
+    param(
+        [Parameter(Mandatory = $true)]
+        [AllowNull()]
+        [object]$Value,
+
+        [Parameter(Mandatory = $true)]
+        [ValidateSet(
+            'previous native host manifest bytes',
+            'previous Host executable bytes',
+            'previous config bytes'
+        )]
+        [string]$IdentityName
+    )
+    $isIntegralScalar =
+        $Value -is [byte] -or $Value -is [sbyte] -or
+        $Value -is [int16] -or $Value -is [uint16] -or
+        $Value -is [int32] -or $Value -is [uint32] -or
+        $Value -is [int64]
+    if (-not $isIntegralScalar -or [long]$Value -lt 1) {
+        throw "Pinned $IdentityName must be a positive integer scalar."
+    }
+    return [long]$Value
+}
+
+function ConvertTo-StrictSha256 {
+    [CmdletBinding(PositionalBinding = $false)]
+    param(
+        [Parameter(Mandatory = $true)]
+        [AllowNull()]
+        [object]$Value,
+
+        [Parameter(Mandatory = $true)]
+        [ValidateSet(
+            'previous native host manifest SHA-256',
+            'previous Host executable SHA-256',
+            'previous config SHA-256'
+        )]
+        [string]$IdentityName
+    )
+    if ($Value -isnot [string] -or $Value -cnotmatch '^[A-F0-9]{64}$') {
+        throw "Pinned $IdentityName must be an uppercase 64-character hexadecimal string."
+    }
+    return [string]$Value
+}
+
+function Assert-ExactPreviousInstall {
+    [CmdletBinding(PositionalBinding = $false)]
+    param(
+        [Parameter(Mandatory = $true)]
+        [string]$PreviousRoot,
+
+        [Parameter(Mandatory = $true)]
+        [AllowNull()]
+        [object]$ManifestBytes,
+
+        [Parameter(Mandatory = $true)]
+        [AllowNull()]
+        [object]$ManifestSha256,
+
+        [Parameter(Mandatory = $true)]
+        [AllowNull()]
+        [object]$HostBytes,
+
+        [Parameter(Mandatory = $true)]
+        [AllowNull()]
+        [object]$HostSha256,
+
+        [Parameter(Mandatory = $true)]
+        [AllowNull()]
+        [object]$ConfigBytes,
+
+        [Parameter(Mandatory = $true)]
+        [AllowNull()]
+        [object]$ConfigSha256
+    )
+    $pinnedManifestBytes = ConvertTo-StrictPositiveInt64 -Value $ManifestBytes -IdentityName 'previous native host manifest bytes'
+    $pinnedManifestSha256 = ConvertTo-StrictSha256 -Value $ManifestSha256 -IdentityName 'previous native host manifest SHA-256'
+    $pinnedHostBytes = ConvertTo-StrictPositiveInt64 -Value $HostBytes -IdentityName 'previous Host executable bytes'
+    $pinnedHostSha256 = ConvertTo-StrictSha256 -Value $HostSha256 -IdentityName 'previous Host executable SHA-256'
+    $pinnedConfigBytes = ConvertTo-StrictPositiveInt64 -Value $ConfigBytes -IdentityName 'previous config bytes'
+    $pinnedConfigSha256 = ConvertTo-StrictSha256 -Value $ConfigSha256 -IdentityName 'previous config SHA-256'
+
+    $rootItem = Get-Item -LiteralPath $PreviousRoot -Force
+    if (-not $rootItem.PSIsContainer -or ($rootItem.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
+        throw 'Previous install root must be an ordinary non-reparse directory.'
+    }
+    $children = @(Get-ChildItem -LiteralPath $PreviousRoot -Force)
+    if ($children.Count -ne 3 -or @($children | Where-Object { $_.PSIsContainer }).Count -ne 0 -or
+        (Compare-Object -CaseSensitive @('config.json', 'native-host-manifest.json', $expectedHostExecutable) @($children.Name | Sort-Object))) {
+        throw 'Previous install root does not contain the exact three-file preimage.'
+    }
+    foreach ($child in $children) {
+        if ($child.Attributes -band [IO.FileAttributes]::ReparsePoint) {
+            throw 'Previous install contains a reparse path.'
+        }
+    }
+    $manifestPath = Join-Path $PreviousRoot 'native-host-manifest.json'
+    $hostPath = Join-Path $PreviousRoot $expectedHostExecutable
+    $configPath = Join-Path $PreviousRoot 'config.json'
+    $manifestIdentity = Get-FileIdentity $manifestPath
+    $hostIdentity = Get-FileIdentity $hostPath
+    $configIdentity = Get-FileIdentity $configPath
+    if ($manifestIdentity.Bytes -ne $pinnedManifestBytes) {
+        throw 'Previous native host manifest bytes mismatch.'
+    }
+    if ($manifestIdentity.Sha256 -cne $pinnedManifestSha256) {
+        throw 'Previous native host manifest SHA-256 mismatch.'
+    }
+    if ($hostIdentity.Bytes -ne $pinnedHostBytes) {
+        throw 'Previous Host executable bytes mismatch.'
+    }
+    if ($hostIdentity.Sha256 -cne $pinnedHostSha256) {
+        throw 'Previous Host executable SHA-256 mismatch.'
+    }
+    if ($configIdentity.Bytes -ne $pinnedConfigBytes) {
+        throw 'Previous config bytes mismatch.'
+    }
+    if ($configIdentity.Sha256 -cne $pinnedConfigSha256) {
+        throw 'Previous config SHA-256 mismatch.'
+    }
+    $previousManifest = Get-StrictJson $manifestPath
+    if ((Compare-Object @('allowed_origins', 'description', 'name', 'path', 'type') @($previousManifest.PSObject.Properties.Name | Sort-Object)) -or
+        $previousManifest.name -cne $expectedHostName -or
+        $previousManifest.path -cne $hostPath -or
+        $previousManifest.type -cne 'stdio' -or
+        @($previousManifest.allowed_origins).Count -ne 1 -or
+        $previousManifest.allowed_origins[0] -cne $expectedOrigin) {
+        throw 'Previous native host manifest identity mismatch.'
+    }
+    $previousConfig = Get-StrictJson $configPath
+    if ($previousConfig.schema -ne 2 -or
+        $previousConfig.required_extension_build -cne $expectedPreviousExtensionBuild -or
+        @($previousConfig.creator_allowlist).Count -ne 1 -or
+        $previousConfig.creator_allowlist[0] -cne '1420210197') {
+        throw 'Previous host config identity mismatch.'
+    }
+    return [pscustomobject]@{
+        Root = $PreviousRoot
+        ManifestPath = $manifestPath
+        HostPath = $hostPath
+        ConfigPath = $configPath
+    }
+}
+
+function Get-RegistrySnapshot([string]$Path, [bool]$UseFileProvider) {
+    if (-not (Test-Path -LiteralPath $Path)) {
+        return [pscustomobject]@{
+            Exists = $false
+            ValueNames = @()
+            SubKeyNames = @()
+            DefaultKind = $null
+            DefaultValue = $null
+        }
+    }
+    if ($UseFileProvider) {
+        $item = Get-Item -LiteralPath $Path -Force
+        if (-not $item.PSIsContainer -or ($item.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
+            throw 'Test registry key must be an ordinary non-reparse directory.'
+        }
+        $children = @(Get-ChildItem -LiteralPath $Path -Force)
+        if (@($children | Where-Object { $_.Attributes -band [IO.FileAttributes]::ReparsePoint }).Count -ne 0) {
+            throw 'Test registry contains a reparse path.'
+        }
+        $files = @($children | Where-Object { -not $_.PSIsContainer })
+        $subkeys = @($children | Where-Object { $_.PSIsContainer } | ForEach-Object { $_.Name })
+        $valueNames = @($files | ForEach-Object { if ($_.Name -ceq 'default.value') { '' } else { $_.Name } })
+        $defaultPath = Join-Path $Path 'default.value'
+        $defaultValue = $null
+        $defaultKind = $null
+        if (Test-Path -LiteralPath $defaultPath) {
+            $defaultValue = [System.IO.File]::ReadAllText($defaultPath, [System.Text.UTF8Encoding]::new($false, $true))
+            $defaultKind = 'String'
+        }
+        return [pscustomobject]@{
+            Exists = $true
+            ValueNames = $valueNames
+            SubKeyNames = $subkeys
+            DefaultKind = $defaultKind
+            DefaultValue = $defaultValue
+        }
+    }
+    $key = Get-Item -LiteralPath $Path -Force
+    $valueNames = @($key.GetValueNames())
+    $subKeyNames = @($key.GetSubKeyNames())
+    $defaultValue = $null
+    $defaultKind = $null
+    if ($valueNames -contains '') {
+        $defaultValue = $key.GetValue('', $null, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames)
+        $defaultKind = $key.GetValueKind('').ToString()
+    }
+    return [pscustomobject]@{
+        Exists = $true
+        ValueNames = $valueNames
+        SubKeyNames = $subKeyNames
+        DefaultKind = $defaultKind
+        DefaultValue = $defaultValue
+    }
+}
+
+function Test-RegistrySnapshotExact([object]$Snapshot, [string]$ExpectedDefault) {
+    return $Snapshot.Exists -and
+        @($Snapshot.ValueNames).Count -eq 1 -and $Snapshot.ValueNames[0] -ceq '' -and
+        @($Snapshot.SubKeyNames).Count -eq 0 -and
+        $Snapshot.DefaultKind -ceq 'String' -and
+        $Snapshot.DefaultValue -ceq $ExpectedDefault
+}
+
+function Test-RegistrySnapshotEmpty([object]$Snapshot) {
+    return $Snapshot.Exists -and @($Snapshot.ValueNames).Count -eq 0 -and @($Snapshot.SubKeyNames).Count -eq 0
+}
+
+function Set-RegistryDefaultAtomic([string]$Path, [string]$Value, [bool]$UseFileProvider) {
+    if ($UseFileProvider) {
+        $defaultPath = Join-Path $Path 'default.value'
+        if (-not (Test-Path -LiteralPath $defaultPath)) {
+            Write-Utf8CreateNew $defaultPath $Value
+            return
+        }
+        $pending = Join-Path $Path ('.default.pending.' + [Guid]::NewGuid().ToString('N'))
+        $backup = Join-Path $Path ('.default.backup.' + [Guid]::NewGuid().ToString('N'))
+        try {
+            Write-Utf8CreateNew $pending $Value
+            [System.IO.File]::Replace($pending, $defaultPath, $backup, $true)
+        } finally {
+            if (Test-Path -LiteralPath $pending) {
+                Remove-Item -LiteralPath $pending -Force
+            }
+            if (Test-Path -LiteralPath $backup) {
+                Remove-Item -LiteralPath $backup -Force
+            }
+        }
+        return
+    }
+    Set-Item -LiteralPath $Path -Value $Value -ErrorAction Stop
+}
+
+function Assert-NewInstallRoot(
+    [string]$InstallRootPath,
+    [string]$InstalledHostPath,
+    [string]$InstalledConfigPath,
+    [string]$InstalledManifestPath,
+    [object]$ExpectedBuildEntry,
+    [object]$ExpectedConfigIdentity
+) {
+    $rootItem = Get-Item -LiteralPath $InstallRootPath -Force
+    if (-not $rootItem.PSIsContainer -or ($rootItem.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
+        throw 'Installed root must be an ordinary non-reparse directory.'
+    }
+    $children = @(Get-ChildItem -LiteralPath $InstallRootPath -Force)
+    if ($children.Count -ne 3 -or @($children | Where-Object { $_.PSIsContainer }).Count -ne 0 -or
+        (Compare-Object -CaseSensitive @('config.json', 'native-host-manifest.json', $expectedHostExecutable) @($children.Name | Sort-Object))) {
+        throw 'Installed root does not contain the exact three-file set.'
+    }
+    foreach ($child in $children) {
+        if ($child.Attributes -band [IO.FileAttributes]::ReparsePoint) {
+            throw 'Installed root contains a reparse path.'
+        }
+    }
+    $hostIdentity = Get-FileIdentity $InstalledHostPath
+    $configIdentity = Get-FileIdentity $InstalledConfigPath
+    if ($hostIdentity.Bytes -ne $ExpectedBuildEntry.bytes -or $hostIdentity.Sha256 -cne $ExpectedBuildEntry.sha256 -or
+        $configIdentity.Bytes -ne $ExpectedConfigIdentity.Bytes -or $configIdentity.Sha256 -cne $ExpectedConfigIdentity.Sha256) {
+        throw 'Installed payload identity mismatch.'
+    }
+    $persistedManifest = Get-StrictJson $InstalledManifestPath
+    if ((Compare-Object @('allowed_origins', 'description', 'name', 'path', 'type') @($persistedManifest.PSObject.Properties.Name | Sort-Object)) -or
+        $persistedManifest.name -cne $expectedHostName -or
+        $persistedManifest.path -cne $InstalledHostPath -or
+        $persistedManifest.type -cne 'stdio' -or
+        @($persistedManifest.allowed_origins).Count -ne 1 -or
+        $persistedManifest.allowed_origins[0] -cne $expectedOrigin) {
+        throw 'Installed native host manifest identity mismatch.'
+    }
+}
+
+function Remove-ProvenOwnedInstallRoot(
+    [string]$InstallRootPath,
+    [string]$InstalledHostPath,
+    [string]$InstalledConfigPath,
+    [string]$InstalledManifestPath,
+    [object]$ExpectedBuildEntry,
+    [object]$ExpectedConfigIdentity
+) {
+    if (-not (Test-Path -LiteralPath $InstallRootPath)) {
+        return
+    }
+    $rootItem = Get-Item -LiteralPath $InstallRootPath -Force
+    if (-not $rootItem.PSIsContainer -or ($rootItem.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
+        throw 'RECOVERY_REQUIRED: target root is not a proven owned ordinary directory.'
+    }
+    $children = @(Get-ChildItem -LiteralPath $InstallRootPath -Force)
+    if (@($children | Where-Object { $_.PSIsContainer -or ($_.Attributes -band [IO.FileAttributes]::ReparsePoint) }).Count -ne 0 -or
+        @($children | Where-Object { $_.Name -cnotin @('config.json', 'native-host-manifest.json', $expectedHostExecutable) }).Count -ne 0) {
+        throw 'RECOVERY_REQUIRED: target root contains an unknown or reparse object.'
+    }
+    if (Test-Path -LiteralPath $InstalledHostPath) {
+        $identity = Get-FileIdentity $InstalledHostPath
+        if ($identity.Bytes -ne $ExpectedBuildEntry.bytes -or $identity.Sha256 -cne $ExpectedBuildEntry.sha256) {
+            throw 'RECOVERY_REQUIRED: target host identity is ambiguous.'
+        }
+    }
+    if (Test-Path -LiteralPath $InstalledConfigPath) {
+        $identity = Get-FileIdentity $InstalledConfigPath
+        if ($identity.Bytes -ne $ExpectedConfigIdentity.Bytes -or $identity.Sha256 -cne $ExpectedConfigIdentity.Sha256) {
+            throw 'RECOVERY_REQUIRED: target config identity is ambiguous.'
+        }
+    }
+    if (Test-Path -LiteralPath $InstalledManifestPath) {
+        $persistedManifest = Get-StrictJson $InstalledManifestPath
+        if ($persistedManifest.name -cne $expectedHostName -or
+            $persistedManifest.path -cne $InstalledHostPath -or
+            $persistedManifest.type -cne 'stdio' -or
+            @($persistedManifest.allowed_origins).Count -ne 1 -or
+            $persistedManifest.allowed_origins[0] -cne $expectedOrigin) {
+            throw 'RECOVERY_REQUIRED: target manifest identity is ambiguous.'
+        }
+    }
+    Remove-Item -LiteralPath $InstallRootPath -Recurse -Force
 }
 
 if ($ObservedExtensionId -cne $expectedId) {
@@ -195,14 +560,15 @@
     '__init__.py', 'background.js', 'build_host.ps1', 'config.example.json',
     'constants.py', 'dependencies/dependency-artifact-manifest.json',
     'dependencies/yt_dlp-2026.7.4-py3-none-any.whl',
-    'install_native_host.ps1', 'job.py', 'manifest.json',
+    'formal_legacy_identity_manifest.py', 'install_native_host.ps1', 'job.py', 'manifest.json',
     'native-host-manifest.template.json', 'native_host.py', 'protocol.py',
+    'queue-producer.example.json', 'queue_producer.py', 'queue_state.py',
     'sidepanel.css', 'sidepanel.html', 'sidepanel.js', 'worker.py'
 )
-Assert-ExactSourceTree $sourceRoot $sourceManifestPath $expectedSourceFiles
+Assert-ExactSourceSnapshot $sourceRoot $sourceManifestPath $expectedSourceFiles $sourceManifest
 $dependencyManifestPath = Join-Path $sourceRoot 'dependencies/dependency-artifact-manifest.json'
 $dependencyManifestItem = Get-Item -LiteralPath $dependencyManifestPath
-if ($sourceManifest.schema -ne 1 -or $sourceManifest.target -cne 'BV1HA3o6oEJJ' -or
+if ($sourceManifest.schema -ne 1 -or $sourceManifest.scope -cne 'generic-bilibili-queue' -or
     $sourceManifest.extension_id -cne $expectedId -or
     $sourceManifest.extension_build -cne $expectedExtensionBuild -or
     $sourceManifest.host_build -cne $expectedHostBuild -or
@@ -253,7 +619,7 @@
 
 $buildManifest = Get-StrictJson $buildManifestPath
 $buildScript = Join-Path $sourceRoot 'build_host.ps1'
-if ($buildManifest.schema -ne 2 -or $buildManifest.target -cne 'BV1HA3o6oEJJ' -or
+if ($buildManifest.schema -ne 2 -or $buildManifest.scope -cne 'generic-bilibili-queue' -or
     $buildManifest.extension_id -cne $expectedId -or
     $buildManifest.extension_build -cne $expectedExtensionBuild -or
     $buildManifest.host_build -cne $expectedHostBuild -or
@@ -315,21 +681,26 @@
 if (($configItem.Attributes -band [IO.FileAttributes]::ReparsePoint) -or $configItem.PSIsContainer) {
     throw 'Config file must be a regular non-reparse file.'
 }
+$configIdentity = Get-FileIdentity $config
 $configObject = Get-StrictJson $config
 $expectedConfigKeys = @(
-    'schema', 'target', 'canonical_url', 'ffmpeg', 'ffmpeg_sha256', 'ffprobe',
-    'ffprobe_sha256', 'bridge_python', 'bridge_python_sha256', 'bridge_script',
-    'bridge_script_sha256', 'batch_json', 'batch_json_sha256', 'yt_dlp_executable',
-    'yt_dlp_executable_sha256', 'destination'
+    'schema', 'creator_allowlist', 'queue_path', 'queue_state_path', 'queue_lock_path',
+    'reload_state_path', 'reload_generation', 'required_extension_build',
+    'ffmpeg', 'ffmpeg_sha256', 'ffprobe', 'ffprobe_sha256', 'bridge_python',
+    'bridge_python_sha256', 'bridge_script', 'bridge_script_sha256',
+    'yt_dlp_executable', 'yt_dlp_executable_sha256', 'destination',
+    'creator_name', 'formal_manifest_path', 'processing_handoff_path'
 )
 $actualConfigKeys = @($configObject.PSObject.Properties.Name | Sort-Object)
 if ((Compare-Object ($expectedConfigKeys | Sort-Object) $actualConfigKeys) -or
-    $configObject.schema -ne 1 -or $configObject.target -cne 'BV1HA3o6oEJJ' -or
-    $configObject.canonical_url -cne 'https://www.bilibili.com/video/BV1HA3o6oEJJ' -or
-    $configObject.bridge_script_sha256 -cne '749FC486B0F42315BD463F11771FE2A7C71CAB53DD9AC2E411CE82E1175DFF13') {
+    $configObject.schema -ne 2 -or
+    $configObject.required_extension_build -cne $expectedExtensionBuild -or
+    $null -eq $configObject.creator_allowlist -or @($configObject.creator_allowlist).Count -lt 1 -or
+    $configObject.reload_generation -cne 'bili-auth-generic-v027' -or
+    $configObject.bridge_script_sha256 -cne '00F11DAF8387160DB863C89F0B33AB8480422233FF42199189222C989C7ED07E') {
     throw 'Host config identity mismatch.'
 }
-foreach ($name in @('ffmpeg', 'ffprobe', 'bridge_python', 'bridge_script', 'batch_json', 'yt_dlp_executable')) {
+foreach ($name in @('ffmpeg', 'ffprobe', 'bridge_python', 'bridge_script', 'yt_dlp_executable')) {
     $value = $configObject.$name
     $expectedHash = $configObject."${name}_sha256"
     if (-not [System.IO.Path]::IsPathRooted($value) -or $value.StartsWith('\\') -or
@@ -351,30 +722,100 @@
 if (-not $destinationItem.PSIsContainer -or ($destinationItem.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
     throw 'Host config destination must be an existing non-reparse directory.'
 }
-if (Get-ChildItem -LiteralPath $resolvedDestination -File | Where-Object { $_.Name.StartsWith('BV1HA3o6oEJJ.', [StringComparison]::OrdinalIgnoreCase) }) {
-    throw 'Formal output already exists; overwrite is forbidden.'
+if ([string]::IsNullOrWhiteSpace([string]$configObject.creator_name) -or
+    [Text.Encoding]::UTF8.GetByteCount([string]$configObject.creator_name) -gt 240) {
+    throw 'Host config creator_name is invalid.'
+}
+foreach ($name in @('formal_manifest_path', 'processing_handoff_path')) {
+    $value = [string]$configObject.$name
+    if (-not [System.IO.Path]::IsPathRooted($value) -or $value.StartsWith('\\')) {
+        throw 'Host governed output path must be absolute and local.'
+    }
+    $parent = [System.IO.Path]::GetDirectoryName($value)
+    $parentItem = Get-Item -LiteralPath $parent
+    if (-not $parentItem.PSIsContainer -or ($parentItem.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
+        throw 'Host governed output parent must be an ordinary directory.'
+    }
+    if (Test-Path -LiteralPath $value) {
+        $item = Get-Item -LiteralPath $value
+        if ($item.PSIsContainer -or ($item.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
+            throw 'Host governed output must be an ordinary file.'
+        }
+    } elseif ($name -ceq 'formal_manifest_path') {
+        throw 'Host formal manifest must already exist.'
+    }
+}
+if ($configObject.formal_manifest_path -ceq $configObject.processing_handoff_path) {
+    throw 'Host governed output paths must be distinct.'
 }
 if (Test-Path -LiteralPath $root) {
     throw 'InstallRoot already exists; overwrite is forbidden.'
 }
 
 $registryPath = "HKCU:\Software\Google\Chrome\NativeMessagingHosts\$expectedHostName"
+$previousRoot = [System.IO.Path]::GetFullPath((Join-Path $env:LOCALAPPDATA "project-info\bili-auth-native-host\$expectedPreviousVersion"))
 if ($TestFileRegistryProvider) {
-    if (-not $TestRegistryRoot) {
-        throw 'TestRegistryRoot is required for the test file registry provider.'
+    if (-not $TestRegistryRoot -or -not $TestPreviousInstallRoot -or -not $TestPreviousArtifactReceipt) {
+        throw 'The test file registry provider requires its registry root and previous-install fixture inputs.'
     }
     $testRegistryBase = [System.IO.Path]::GetFullPath($TestRegistryRoot)
     $tempBase = [System.IO.Path]::GetFullPath([System.IO.Path]::GetTempPath())
-    if (-not $testRegistryBase.StartsWith($tempBase, [StringComparison]::OrdinalIgnoreCase)) {
-        throw 'The test registry provider must be under the current temporary directory.'
+    $previousRoot = [System.IO.Path]::GetFullPath($TestPreviousInstallRoot)
+    $previousReceiptPath = (Resolve-Path -LiteralPath $TestPreviousArtifactReceipt).Path
+    if (-not $testRegistryBase.StartsWith($tempBase, [StringComparison]::OrdinalIgnoreCase) -or
+        -not $previousRoot.StartsWith($tempBase, [StringComparison]::OrdinalIgnoreCase) -or
+        -not $previousReceiptPath.StartsWith($tempBase, [StringComparison]::OrdinalIgnoreCase) -or
+        ($root -notlike ($tempBase.TrimEnd('\') + '\*'))) {
+        throw 'Test-only installer paths must be under the current temporary directory.'
     }
+    $previousReceiptItem = Get-Item -LiteralPath $previousReceiptPath -Force
+    if ($previousReceiptItem.PSIsContainer -or ($previousReceiptItem.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
+        throw 'Test previous-artifact receipt must be a regular non-reparse file.'
+    }
+    $previousReceipt = Get-StrictJson $previousReceiptPath
+    $expectedPreviousReceiptKeys = @(
+        'schema', 'manifest_bytes', 'manifest_sha256', 'host_executable_bytes',
+        'host_executable_sha256', 'config_bytes', 'config_sha256'
+    )
+    if ((Compare-Object ($expectedPreviousReceiptKeys | Sort-Object) @($previousReceipt.PSObject.Properties.Name | Sort-Object)) -or
+        $previousReceipt.schema -ne 1) {
+        throw 'Test previous-artifact receipt identity mismatch.'
+    }
+    $expectedPreviousManifestBytes = $previousReceipt.manifest_bytes
+    $expectedPreviousManifestSha256 = $previousReceipt.manifest_sha256
+    $expectedPreviousHostBytes = $previousReceipt.host_executable_bytes
+    $expectedPreviousHostSha256 = $previousReceipt.host_executable_sha256
+    $expectedPreviousConfigBytes = $previousReceipt.config_bytes
+    $expectedPreviousConfigSha256 = $previousReceipt.config_sha256
     $registryPath = Join-Path $testRegistryBase $expectedHostName
-} elseif ($TestRegistryRoot -or $InjectFailure -cne 'none') {
+} elseif ($TestRegistryRoot -or $TestPreviousInstallRoot -or $TestPreviousArtifactReceipt -or $InjectFailure -cne 'none') {
     throw 'Test-only controls require TestFileRegistryProvider.'
+} else {
+    $expectedInstallRoot = [System.IO.Path]::GetFullPath((Join-Path $env:LOCALAPPDATA 'project-info\bili-auth-native-host\1.2.25+20260829.generic.v027'))
+    if ($root -cne $expectedInstallRoot) {
+        throw 'Production InstallRoot does not match the pinned v027 location.'
+    }
 }
-if (Test-Path -LiteralPath $registryPath) {
-    throw 'Native Messaging registration already exists; overwrite is forbidden.'
+
+$previousIdentityParameters = @{
+    PreviousRoot = $previousRoot
+    ManifestBytes = $expectedPreviousManifestBytes
+    ManifestSha256 = $expectedPreviousManifestSha256
+    HostBytes = $expectedPreviousHostBytes
+    HostSha256 = $expectedPreviousHostSha256
+    ConfigBytes = $expectedPreviousConfigBytes
+    ConfigSha256 = $expectedPreviousConfigSha256
 }
+
+$registryPreimage = Get-RegistrySnapshot $registryPath $TestFileRegistryProvider.IsPresent
+if (-not $registryPreimage.Exists) {
+    throw 'Exact v026 Native Messaging registration preimage is required.'
+}
+$previousInstall = Assert-ExactPreviousInstall @previousIdentityParameters
+if (-not (Test-RegistrySnapshotExact $registryPreimage $previousInstall.ManifestPath)) {
+    throw 'Existing Native Messaging registration does not match the pinned v026 preimage.'
+}
+$installMode = 'EXACT_V026_TO_V027_SWITCH'
 
 if (-not $Install) {
     [pscustomobject]@{
@@ -383,16 +824,18 @@
         origin = $expectedOrigin
         host_name = $expectedHostName
         packaging = 'pyinstaller-onefile'
+        install_mode = $installMode
     } | ConvertTo-Json -Compress
     return
 }
 
 if ($PSCmdlet.ShouldProcess($root, 'Install exact-BVID Native Messaging host for current user')) {
+    $installedHost = Join-Path $root $expectedHostExecutable
+    $installedConfig = Join-Path $root 'config.json'
+    $manifestPath = Join-Path $root 'native-host-manifest.json'
     try {
         [System.IO.Directory]::CreateDirectory($root) | Out-Null
         Stop-Injected 'after-root'
-        $installedHost = Join-Path $root $expectedHostExecutable
-        $installedConfig = Join-Path $root 'config.json'
         Copy-CreateNew $resolvedHost $installedHost
         if ((Get-Item -LiteralPath $installedHost).Length -ne $buildEntry.bytes -or
             (Get-FileHash -Algorithm SHA256 -LiteralPath $installedHost).Hash -cne $buildEntry.sha256) {
@@ -405,7 +848,6 @@
             throw 'Installed config reread verification failed.'
         }
         Stop-Injected 'after-config'
-        $manifestPath = Join-Path $root 'native-host-manifest.json'
         $manifest = [ordered]@{
             name = $expectedHostName
             description = 'project-info exact-BVID authenticated ingress'
@@ -414,38 +856,44 @@
             allowed_origins = @($expectedOrigin)
         }
         Write-Utf8CreateNew $manifestPath ($manifest | ConvertTo-Json -Depth 3)
-        $persistedManifest = Get-StrictJson $manifestPath
-        if ($persistedManifest.name -cne $expectedHostName -or
-            $persistedManifest.path -cne $installedHost -or
-            $persistedManifest.type -cne 'stdio' -or
-            $persistedManifest.allowed_origins.Count -ne 1 -or
-            $persistedManifest.allowed_origins[0] -cne $expectedOrigin) {
-            throw 'Native host manifest reread verification failed.'
-        }
+        Assert-NewInstallRoot $root $installedHost $installedConfig $manifestPath $buildEntry $configIdentity
         Stop-Injected 'after-manifest'
 
-        if ($TestFileRegistryProvider) {
-            [System.IO.Directory]::CreateDirectory($registryPath) | Out-Null
-        } else {
-            New-Item -Path $registryPath -ErrorAction Stop | Out-Null
+        $lastRegistryPreimage = Get-RegistrySnapshot $registryPath $TestFileRegistryProvider.IsPresent
+        $null = Assert-ExactPreviousInstall @previousIdentityParameters
+        if (-not (Test-RegistrySnapshotExact $lastRegistryPreimage $previousInstall.ManifestPath)) {
+            throw 'Native Messaging v026 preimage changed before the registry switch.'
         }
         Stop-Injected 'after-registry-key'
-        if ($TestFileRegistryProvider) {
-            Write-Utf8CreateNew (Join-Path $registryPath 'default.value') $manifestPath
-        } else {
-            Set-Item -LiteralPath $registryPath -Value $manifestPath -ErrorAction Stop
+        Set-RegistryDefaultAtomic $registryPath $manifestPath $TestFileRegistryProvider.IsPresent
+        if ($InjectFailure -ceq 'after-registry-value-mixed') {
+            Write-Utf8CreateNew (Join-Path $registryPath 'unexpected.value') 'ambiguous'
+                throw 'Injected ambiguous registry state after v026 switch.'
         }
         Stop-Injected 'after-registry-value'
+        $committedRegistry = Get-RegistrySnapshot $registryPath $TestFileRegistryProvider.IsPresent
+        if (-not (Test-RegistrySnapshotExact $committedRegistry $manifestPath)) {
+            throw 'Native Messaging v026 registry commit reread verification failed.'
+        }
+        Assert-NewInstallRoot $root $installedHost $installedConfig $manifestPath $buildEntry $configIdentity
     } catch {
-        # Both targets were proven absent before the transaction, so any
-        # surviving object belongs to this attempt even if a provider threw
-        # after partially creating it.
-        if (Test-Path -LiteralPath $registryPath) {
-            Remove-Item -LiteralPath $registryPath -Recurse -Force
+        $originalFailure = $_.Exception
+        try {
+            $rollbackRegistry = Get-RegistrySnapshot $registryPath $TestFileRegistryProvider.IsPresent
+            if (Test-RegistrySnapshotExact $rollbackRegistry $manifestPath) {
+                Set-RegistryDefaultAtomic $registryPath $previousInstall.ManifestPath $TestFileRegistryProvider.IsPresent
+            } elseif (-not (Test-RegistrySnapshotExact $rollbackRegistry $previousInstall.ManifestPath)) {
+                throw 'RECOVERY_REQUIRED: Native Messaging registration is neither the pinned v026 preimage nor this v027 attempt.'
+            }
+            $restoredRegistry = Get-RegistrySnapshot $registryPath $TestFileRegistryProvider.IsPresent
+            if (-not (Test-RegistrySnapshotExact $restoredRegistry $previousInstall.ManifestPath)) {
+                throw 'RECOVERY_REQUIRED: Native Messaging v026 registry preimage was not restored.'
+            }
+            $null = Assert-ExactPreviousInstall @previousIdentityParameters
+            Remove-ProvenOwnedInstallRoot $root $installedHost $installedConfig $manifestPath $buildEntry $configIdentity
+        } catch {
+            throw "RECOVERY_REQUIRED: $($_.Exception.Message) Original failure: $($originalFailure.Message)"
         }
-        if (Test-Path -LiteralPath $root) {
-            Remove-Item -LiteralPath $root -Recurse -Force
-        }
-        throw
+        throw $originalFailure
     }
 }

--
Gitblit v1.9.3