@kubilaycakmak/projectfreeze 0.0.0-stage → 0.1.0-dev.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +50 -2
  3. package/bin/projectfreeze.js +4 -0
  4. package/docs/interfaces.md +98 -0
  5. package/docs/operations.md +42 -0
  6. package/examples/demo.js +72 -0
  7. package/examples/stream-test.mjs +71 -0
  8. package/examples/workload.js +29 -0
  9. package/helpers/.gitkeep +0 -0
  10. package/helpers/projectfreeze-darwin-arm64 +0 -0
  11. package/helpers/projectfreeze-darwin-arm64.sha256 +1 -0
  12. package/helpers/projectfreeze-darwin-x64 +0 -0
  13. package/helpers/projectfreeze-darwin-x64.sha256 +1 -0
  14. package/helpers/projectfreeze-linux-arm64 +0 -0
  15. package/helpers/projectfreeze-linux-arm64.sha256 +1 -0
  16. package/helpers/projectfreeze-linux-x64 +0 -0
  17. package/helpers/projectfreeze-linux-x64.sha256 +1 -0
  18. package/helpers/projectfreeze-win32-arm64.exe +0 -0
  19. package/helpers/projectfreeze-win32-arm64.exe.sha256 +1 -0
  20. package/helpers/projectfreeze-win32-x64.exe +0 -0
  21. package/helpers/projectfreeze-win32-x64.exe.sha256 +1 -0
  22. package/package.json +17 -4
  23. package/src/cli.js +135 -0
  24. package/src/contracts.d.ts +28 -0
  25. package/src/discovery.js +112 -0
  26. package/src/engine.js +820 -0
  27. package/src/errors.js +20 -0
  28. package/src/integrations.js +195 -0
  29. package/src/inventory.js +37 -0
  30. package/src/ipc.js +258 -0
  31. package/src/line-menu.js +147 -0
  32. package/src/mcp.js +113 -0
  33. package/src/platform.js +320 -0
  34. package/src/recipe.js +69 -0
  35. package/src/store.js +61 -0
  36. package/src/supervisors.js +163 -0
  37. package/src/systemd.js +104 -0
  38. package/src/tui.js +596 -0
  39. package/src/windows-supervisors.ps1 +83 -0
@@ -0,0 +1,83 @@
1
+ param([string]$Kind, [string]$Name, [string]$Action, [string]$Expected = '-')
2
+ $ErrorActionPreference = 'Stop'
3
+ [Console]::OutputEncoding = [Text.UTF8Encoding]::new($false)
4
+ $user = [Security.Principal.WindowsIdentity]::GetCurrent().User.Value
5
+ function Get-Sid([string]$Account) {
6
+ if ($Account -match '^S-1-[0-9-]+$') { return $Account }
7
+ return ([Security.Principal.NTAccount]::new($Account)).Translate([Security.Principal.SecurityIdentifier]).Value
8
+ }
9
+ function Digest($Value) {
10
+ $sha = [Security.Cryptography.SHA256]::Create()
11
+ try { return [BitConverter]::ToString($sha.ComputeHash([Text.Encoding]::UTF8.GetBytes(($Value | ConvertTo-Json -Compress -Depth 6)))).Replace('-','').ToLowerInvariant() }
12
+ finally { $sha.Dispose() }
13
+ }
14
+ try {
15
+ if ($Kind -eq 'task') {
16
+ if ($Name -notmatch '^\\(?:[A-Za-z0-9][A-Za-z0-9_.-]{0,80}\\)*[A-Za-z0-9][A-Za-z0-9_.-]{0,80}$') { exit 2 }
17
+ $at = $Name.LastIndexOf('\')
18
+ $folder = if ($at -eq 0) { '\' } else { $Name.Substring(0,$at) }
19
+ $scheduler = New-Object -ComObject 'Schedule.Service'
20
+ $scheduler.Connect()
21
+ $task = $scheduler.GetFolder($folder).GetTask($Name.Substring($at + 1))
22
+ $definition = $task.Definition
23
+ $acl = [Security.AccessControl.RawSecurityDescriptor]::new($task.GetSecurityDescriptor(5))
24
+ if (!$acl.DiscretionaryAcl) { exit 4 }
25
+ if ($definition.Actions.Count -ne 1 -or $definition.Actions.Item(1).Type -ne 0 -or
26
+ (Get-Sid $definition.Principal.UserId) -ne $user -or $definition.Principal.RunLevel -ne 0 -or
27
+ ($acl.Owner.Value -ne $user -and $acl.Owner.Value -ne 'S-1-5-32-544')) { exit 4 }
28
+ foreach ($ace in $acl.DiscretionaryAcl) {
29
+ if ($ace.AceType -eq [Security.AccessControl.AceType]::AccessAllowed -and ($ace.AccessMask -band 0x500D0156) -ne 0 -and
30
+ $ace.SecurityIdentifier.Value -notin @($user,'S-1-5-18','S-1-5-32-544')) { exit 4 }
31
+ }
32
+ $exec = $definition.Actions.Item(1)
33
+ $xml = [xml]$task.Xml
34
+ $mutable = $xml.DocumentElement.SelectSingleNode('*[local-name()="Settings"]/*[local-name()="Enabled"]')
35
+ if ($mutable) { [void]$mutable.ParentNode.RemoveChild($mutable) }
36
+ $fingerprint = Digest @($task.Path,$xml.OuterXml,$acl.Owner.Value,$exec.Path,$exec.WorkingDirectory)
37
+ if ($Action -ne 'probe') {
38
+ if ($fingerprint -ne $Expected) { exit 4 }
39
+ if ($Action -notin @('disable','enable')) { exit 5 }
40
+ if ($Action -eq 'disable' -and ($task.GetInstances(0).Count -ne 0 -or $task.State -eq 2)) { exit 6 }
41
+ $task.Enabled = $Action -eq 'enable'
42
+ }
43
+ @{ path=$task.Path; fingerprint=$fingerprint; executable=$exec.Path; cwd=$exec.WorkingDirectory;
44
+ enabled=[bool]$task.Enabled; active=($task.GetInstances(0).Count -ne 0 -or $task.State -eq 2) } | ConvertTo-Json -Compress
45
+ } elseif ($Kind -eq 'scm') {
46
+ Add-Type -AssemblyName System.ServiceProcess
47
+ if ($Name -notmatch '^[A-Za-z0-9][A-Za-z0-9_.-]{0,100}$') { exit 2 }
48
+ $service = Get-CimInstance Win32_Service -Filter "Name='$Name'"
49
+ if (!$service) { exit 3 }
50
+ if ($service.ServiceType -ne 'Own Process' -or $service.StartMode -ne 'Manual' -or
51
+ (Get-Sid $service.StartName) -notin @($user,'S-1-5-19') -or $service.PathName -notmatch '^"([^"]+\.exe)"(?:\s|$)|^([^\s"]+\.exe)(?:\s|$)') { exit 4 }
52
+ $binary = if ($Matches[1]) { $Matches[1] } else { $Matches[2] }
53
+ $registry = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey("SYSTEM\CurrentControlSet\Services\$Name")
54
+ if (!$registry) { exit 4 }
55
+ try {
56
+ if (($registry.GetSubKeyNames() -contains 'TriggerInfo') -or $null -ne $registry.GetValue('FailureActions')) { exit 5 }
57
+ } finally { $registry.Dispose() }
58
+ $controller = [System.ServiceProcess.ServiceController]::new($Name)
59
+ try {
60
+ if ($controller.DependentServices.Count -or $controller.ServicesDependedOn.Count) { exit 4 }
61
+ $fingerprint = Digest @($service.Name,$service.PathName,$service.StartName,$service.ServiceType,$service.StartMode)
62
+ if ($Action -ne 'probe') {
63
+ if ($fingerprint -ne $Expected) { exit 4 }
64
+ $method = @{ pause='PauseService'; resume='ResumeService'; stop='StopService'; start='StartService' }[$Action]
65
+ if (!$method) { exit 5 }
66
+ $result = Invoke-CimMethod -InputObject $service -MethodName $method
67
+ if ($result.ReturnValue -eq 2) { exit 4 }
68
+ if ($result.ReturnValue -in @(6,10)) { exit 6 }
69
+ if ($result.ReturnValue -in @(1,5)) { exit 5 }
70
+ if ($result.ReturnValue -ne 0) { exit 7 }
71
+ }
72
+ @{ path=$service.Name; fingerprint=$fingerprint; executable=$binary; state=$service.State; pid=$service.ProcessId;
73
+ canPause=$service.AcceptPause; canStop=$service.AcceptStop } | ConvertTo-Json -Compress
74
+ } finally { $controller.Dispose() }
75
+ } else { exit 2 }
76
+ } catch {
77
+ if ($env:PF_SUPERVISOR_TEST_DIAGNOSTICS -eq '1') {
78
+ [Console]::Error.WriteLine(('{0}: HRESULT {1}, line {2}' -f $_.FullyQualifiedErrorId,$_.Exception.HResult,$_.InvocationInfo.ScriptLineNumber))
79
+ }
80
+ if ($_.Exception.HResult -in @(-2147024891,-2147217405)) { exit 4 }
81
+ if ($_.Exception.HResult -in @(-2147024894,-2147217406)) { exit 3 }
82
+ exit 7
83
+ }