-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path17_EventsDelegates.ps1
More file actions
84 lines (73 loc) · 2.93 KB
/
17_EventsDelegates.ps1
File metadata and controls
84 lines (73 loc) · 2.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<#
.SYNOPSIS
OOP Reference: Events and Delegates
.DESCRIPTION
Topic: System.Action and System.Func delegates as event hooks in PS classes
Category: Behavioral
Agent Task: Add an OnKeyRotated event that receives the new key ID as a string.
Add a subscriber that writes to a [System.Collections.Generic.List[string]] log.
Add Pester tests verifying events fire and can have multiple subscribers.
Done Conditions:
- Multiple subscribers can be chained via += on the Action property
- OnError fires on Encrypt exception
- Pester tests pass: Invoke-Pester -Output Detailed
Non-Scope:
- No .NET EventHandler pattern (that requires Add/Remove methods not supported in PS classes)
#>
class CryptoEventEmitter {
[System.Action[byte[]]]$OnEncrypt
[System.Action[byte[]]]$OnDecrypt
[System.Action[string]]$OnError
[System.Action[string]]$OnKeyRotated # receives new key ID
hidden [byte[]]$_key
hidden [string]$_keyId
CryptoEventEmitter() {
$this._key = [byte[]]::new(32)
$this._keyId = [System.Guid]::NewGuid().ToString('N').Substring(0,8)
[System.Security.Cryptography.RandomNumberGenerator]::Fill($this._key)
# No-op default handlers
$this.OnEncrypt = [System.Action[byte[]]]{}
$this.OnDecrypt = [System.Action[byte[]]]{}
$this.OnError = [System.Action[string]]{}
$this.OnKeyRotated = [System.Action[string]]{}
}
[byte[]] Encrypt([byte[]]$data) {
try {
$gcm = [System.Security.Cryptography.AesGcm]::new($this._key)
$nonce = [byte[]]::new(12); $ct = [byte[]]::new($data.Length); $tag = [byte[]]::new(16)
[System.Security.Cryptography.RandomNumberGenerator]::Fill($nonce)
$gcm.Encrypt($nonce, $data, $ct, $tag); $gcm.Dispose()
$result = $nonce + $tag + $ct
$this.OnEncrypt.Invoke($result)
return $result
} catch {
$this.OnError.Invoke($_.ToString())
throw
}
}
[void] RotateKey() {
[System.Security.Cryptography.RandomNumberGenerator]::Fill($this._key)
$this._keyId = [System.Guid]::NewGuid().ToString('N').Substring(0,8)
$this.OnKeyRotated.Invoke($this._keyId)
}
[string] GetKeyId() { return $this._keyId }
}
# Agent Task: Event subscriber with logging
class EventLogger {
[System.Collections.Generic.List[string]]$Log
EventLogger() {
$this.Log = [System.Collections.Generic.List[string]]::new()
}
[void] LogKeyRotation([string]$keyId) {
$this.Log.Add("KeyRotated: $keyId")
}
[void] LogEncrypt([byte[]]$data) {
$this.Log.Add("Encrypted: $($data.Length) bytes")
}
[void] LogDecrypt([byte[]]$data) {
$this.Log.Add("Decrypted: $($data.Length) bytes")
}
[void] LogError([string]$error) {
$this.Log.Add("Error: $error")
}
}