import {spawnSync} from 'node:child_process'; // Do not reapply ownership to an already private directory: Windows may require // restore privileges for SetOwner even when the current account already owns it. const command=`$ErrorActionPreference='Stop'; $sid=[System.Security.Principal.WindowsIdentity]::GetCurrent().User; function Test-PrivateAcl($acl){ if(-not $acl.AreAccessRulesProtected -or $acl.GetOwner([System.Security.Principal.SecurityIdentifier]).Value -ne $sid.Value){return $false;} $rules=@($acl.GetAccessRules($true,$true,[System.Security.Principal.SecurityIdentifier])); if($rules.Count -ne 1){return $false;} $rule=$rules[0]; return (-not $rule.IsInherited -and $rule.IdentityReference.Value -eq $sid.Value -and $rule.AccessControlType -eq [System.Security.AccessControl.AccessControlType]::Allow -and $rule.FileSystemRights -eq [System.Security.AccessControl.FileSystemRights]::FullControl -and $rule.InheritanceFlags -eq ([System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [System.Security.AccessControl.InheritanceFlags]::ObjectInherit) -and $rule.PropagationFlags -eq [System.Security.AccessControl.PropagationFlags]::None); } $existing=Get-Acl -LiteralPath $env:SAFETYNET_COLLECTOR_DIRECTORY; $changed=$false; if(-not (Test-PrivateAcl $existing)){ $private=New-Object System.Security.AccessControl.DirectorySecurity; $private.SetOwner($sid);$private.SetAccessRuleProtection($true,$false); $private.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule($sid,'FullControl','ContainerInherit,ObjectInherit','None','Allow'))); Set-Acl -LiteralPath $env:SAFETYNET_COLLECTOR_DIRECTORY -AclObject $private; $changed=$true; } $verified=Get-Acl -LiteralPath $env:SAFETYNET_COLLECTOR_DIRECTORY; if(-not (Test-PrivateAcl $verified)){throw 'Collector directory protection verification failed';} @{verified=$true;changed=$changed}|ConvertTo-Json -Compress;`; export function protectCollectorDirectory(directory,{run=spawnSync}={}){ const result=run('powershell.exe',['-NoProfile','-NonInteractive','-Command',command],{windowsHide:true,timeout:10000,env:{SystemRoot:process.env.SystemRoot,SAFETYNET_COLLECTOR_DIRECTORY:directory},stdio:'pipe',encoding:'utf8'}); if(result.status!==0)throw Error('Collector directory protection failed'); let proof;try{proof=JSON.parse(result.stdout);}catch{throw Error('Collector directory protection verification failed');} if(proof?.verified!==true||typeof proof.changed!=='boolean')throw Error('Collector directory protection verification failed'); return Object.freeze({verified:true,changed:proof.changed}); }