Skip to content

Commit 67650ba

Browse files
CopilotMariusStorhaugCopilot
authored
🚀 [Feature]: Refactor Context classes and separate JWT Creation and Signing Logic (#477)
This pull request introduces several changes to enhance GitHub context classes, improve JWT handling. Key updates include renaming classes for consistency, adding token expiration handling, and refactoring JWT-related functionality by splitting it into modular functions. - Fixes #471 ### Improvements to JWT handling * Removed the `GitHubJsonWebToken` class, simplifying the JWT implementation. * Introduced modular private functions for JWT management: - `New-GitHubUnsignedJWT`: Generates an unsigned JWT with header and payload. - `Add-GitHubJWTSignature`: Signs an unsigned JWT using an RSA private key. * Removed the monolithic `Get-GitHubAppJSONWebToken` function, replacing it with the modular approach. * Added `Update-GitHubAppJWT` to handle JWT updates for the `GitHubAppContext` type. ### Enhancements to GitHub classes * 🌟 Renamed context classes for consistency, and updated the belonging format files: - `AppGitHubContext` → `GitHubAppContext` - `InstallationGitHubContext` → `GitHubAppInstallationContext` - `UserGitHubContext` → `GitHubUserContext` * 🌟 The context property value of `TokenType` on `GitHubAppContext` is renamed from 'PEM' to 'JWT' to correctly represent the type of the Token property. * Moved `TokenExpiresAt` property to the `GitHubContext` class to store token expiration dates. * All types that previously added a `ScriptProperty` that copied the value of another, is now converted to a `AliasProperty`. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: MariusStorhaug <17722253+MariusStorhaug@users.noreply.github.com> Co-authored-by: Marius Storhaug <marstor@hotmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 2575b03 commit 67650ba

30 files changed

+311
-258
lines changed

‎src/classes/public/Context/GitHubContext.ps1

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,13 @@
4444
[securestring] $Token
4545

4646
# The token type.
47-
# ghu / gho / ghp / github_pat / PEM / ghs /
47+
# ghu / gho / ghp / github_pat / JWT / ghs /
4848
[string] $TokenType
4949

50+
# The token expiration date.
51+
# 2024-01-01-00:00:00
52+
[System.Nullable[datetime]] $TokenExpiresAt
53+
5054
# The default value for the Enterprise parameter.
5155
[string] $Enterprise
5256

‎src/classes/public/Context/GitHubContext/AppGitHubContext.ps1 renamed to ‎src/classes/public/Context/GitHubContext/GitHubAppContext.ps1

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
class AppGitHubContext : GitHubContext {
1+
class GitHubAppContext : GitHubContext {
22
# Client ID for GitHub Apps
33
[string] $ClientID
44

@@ -17,9 +17,9 @@
1717
# The events that the app is subscribing to once installed
1818
[string[]] $Events
1919

20-
AppGitHubContext() {}
20+
GitHubAppContext() {}
2121

22-
AppGitHubContext([pscustomobject]$Object) {
22+
GitHubAppContext([pscustomobject]$Object) {
2323
$this.ID = $Object.ID
2424
$this.Name = $Object.Name
2525
$this.DisplayName = $Object.DisplayName
@@ -33,6 +33,7 @@
3333
$this.UserName = $Object.UserName
3434
$this.Token = $Object.Token
3535
$this.TokenType = $Object.TokenType
36+
$this.TokenExpiresAt = $Object.TokenExpiresAt
3637
$this.Enterprise = $Object.Enterprise
3738
$this.Owner = $Object.Owner
3839
$this.Repository = $Object.Repository

‎src/classes/public/Context/GitHubContext/InstallationGitHubContext.ps1 renamed to ‎src/classes/public/Context/GitHubContext/GitHubAppInstallationContext.ps1

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1-
class InstallationGitHubContext : GitHubContext {
1+
class GitHubAppInstallationContext : GitHubContext {
22
# Client ID for GitHub Apps
33
[string] $ClientID
44

5-
# The token expiration date.
6-
# 2024-01-01-00:00:00
7-
[System.Nullable[datetime]] $TokenExpiresAt
8-
95
# The installation ID.
106
[System.Nullable[uint64]] $InstallationID
117

@@ -21,9 +17,9 @@
2117
# The target login or slug of the installation.
2218
[string] $InstallationName
2319

24-
InstallationGitHubContext() {}
20+
GitHubAppInstallationContext() {}
2521

26-
InstallationGitHubContext([pscustomobject]$Object) {
22+
GitHubAppInstallationContext([pscustomobject]$Object) {
2723
$this.ID = $Object.ID
2824
$this.Name = $Object.Name
2925
$this.DisplayName = $Object.DisplayName
@@ -37,13 +33,13 @@
3733
$this.UserName = $Object.UserName
3834
$this.Token = $Object.Token
3935
$this.TokenType = $Object.TokenType
36+
$this.TokenExpiresAt = $Object.TokenExpiresAt
4037
$this.Enterprise = $Object.Enterprise
4138
$this.Owner = $Object.Owner
4239
$this.Repository = $Object.Repository
4340
$this.HttpVersion = $Object.HttpVersion
4441
$this.PerPage = $Object.PerPage
4542
$this.ClientID = $Object.ClientID
46-
$this.TokenExpiresAt = $Object.TokenExpiresAt
4743
$this.InstallationID = $Object.InstallationID
4844
$this.Permissions = $Object.Permissions
4945
$this.Events = $Object.Events

‎src/classes/public/Context/GitHubContext/UserGitHubContext.ps1 renamed to ‎src/classes/public/Context/GitHubContext/GitHubUserContext.ps1

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
class UserGitHubContext : GitHubContext {
1+
class GitHubUserContext : GitHubContext {
22
# The authentication client ID.
33
# Client ID for UAT
44
[string] $AuthClientID
@@ -11,20 +11,16 @@
1111
# 'gist read:org repo workflow'
1212
[string] $Scope
1313

14-
# The token expiration date.
15-
# 2024-01-01-00:00:00
16-
[System.Nullable[datetime]] $TokenExpiresAt
17-
1814
# The refresh token.
1915
[securestring] $RefreshToken
2016

2117
# The refresh token expiration date.
2218
# 2024-01-01-00:00:00
2319
[System.Nullable[datetime]] $RefreshTokenExpiresAt
2420

25-
UserGitHubContext() {}
21+
GitHubUserContext() {}
2622

27-
UserGitHubContext([PSCustomObject]$Object) {
23+
GitHubUserContext([PSCustomObject]$Object) {
2824
$this.ID = $Object.ID
2925
$this.Name = $Object.Name
3026
$this.DisplayName = $Object.DisplayName
@@ -38,6 +34,7 @@
3834
$this.UserName = $Object.UserName
3935
$this.Token = $Object.Token
4036
$this.TokenType = $Object.TokenType
37+
$this.TokenExpiresAt = $Object.TokenExpiresAt
4138
$this.Enterprise = $Object.Enterprise
4239
$this.Owner = $Object.Owner
4340
$this.Repository = $Object.Repository
@@ -46,7 +43,6 @@
4643
$this.AuthClientID = $Object.AuthClientID
4744
$this.DeviceFlowType = $Object.DeviceFlowType
4845
$this.Scope = $Object.Scope
49-
$this.TokenExpiresAt = $Object.TokenExpiresAt
5046
$this.RefreshToken = $Object.RefreshToken
5147
$this.RefreshTokenExpiresAt = $Object.RefreshTokenExpiresAt
5248
}

‎src/classes/public/GitHubJsonWebToken.ps1

Lines changed: 0 additions & 15 deletions
This file was deleted.

‎src/formats/GitHubContext.Format.ps1xml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
<View>
55
<Name>GitHubContextTableView</Name>
66
<ViewSelectedBy>
7-
<TypeName>AppGitHubContext</TypeName>
8-
<TypeName>InstallationGitHubContext</TypeName>
9-
<TypeName>UserGitHubContext</TypeName>
7+
<TypeName>GitHubAppContext</TypeName>
8+
<TypeName>GitHubAppInstallationContext</TypeName>
9+
<TypeName>GitHubUserContext</TypeName>
1010
<TypeName>GitHubContext</TypeName>
1111
</ViewSelectedBy>
1212
<TableControl>
@@ -152,9 +152,9 @@
152152
</ListControl>
153153
</View>
154154
<View>
155-
<Name>AppGitHubContextListView</Name>
155+
<Name>GitHubAppContextListView</Name>
156156
<ViewSelectedBy>
157-
<TypeName>AppGitHubContext</TypeName>
157+
<TypeName>GitHubAppContext</TypeName>
158158
</ViewSelectedBy>
159159
<ListControl>
160160
<ListEntries>
@@ -217,9 +217,9 @@
217217
</ListControl>
218218
</View>
219219
<View>
220-
<Name>InstallationGitHubContextListView</Name>
220+
<Name>GitHubAppInstallationContextListView</Name>
221221
<ViewSelectedBy>
222-
<TypeName>InstallationGitHubContext</TypeName>
222+
<TypeName>GitHubAppInstallationContext</TypeName>
223223
</ViewSelectedBy>
224224
<ListControl>
225225
<ListEntries>
@@ -291,9 +291,9 @@
291291
</ListControl>
292292
</View>
293293
<View>
294-
<Name>UserGitHubContextListView</Name>
294+
<Name>GitHubUserContextListView</Name>
295295
<ViewSelectedBy>
296-
<TypeName>UserGitHubContext</TypeName>
296+
<TypeName>GitHubUserContext</TypeName>
297297
</ViewSelectedBy>
298298
<ListControl>
299299
<ListEntries>
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
function Add-GitHubJWTSignature {
2+
<#
3+
.SYNOPSIS
4+
Signs a JSON Web Token (JWT) using a local RSA private key.
5+
6+
.DESCRIPTION
7+
Takes an unsigned JWT (header.payload) and adds a signature using the provided RSA private key.
8+
This function handles the RSA signing process and returns the complete signed JWT.
9+
10+
.EXAMPLE
11+
Add-GitHubJWTSignature -UnsignedJWT 'eyJ0eXAiOi...' -PrivateKey '--- BEGIN RSA PRIVATE KEY --- ... --- END RSA PRIVATE KEY ---'
12+
13+
Adds a signature to the unsigned JWT using the provided private key.
14+
15+
.OUTPUTS
16+
String
17+
18+
.NOTES
19+
This function isolates the signing logic to enable support for multiple signing methods.
20+
21+
.LINK
22+
https://psmodule.io/GitHub/Functions/Apps/GitHub%20App/Add-GitHubJWTSignature
23+
#>
24+
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
25+
'PSAvoidUsingConvertToSecureStringWithPlainText',
26+
'',
27+
Justification = 'Used to handle secure string private keys.'
28+
)]
29+
[CmdletBinding()]
30+
[OutputType([string])]
31+
param(
32+
# The unsigned JWT (header.payload) to sign.
33+
[Parameter(Mandatory)]
34+
[string] $UnsignedJWT,
35+
36+
# The private key of the GitHub App.
37+
[Parameter(Mandatory)]
38+
[object] $PrivateKey
39+
)
40+
41+
begin {
42+
$stackPath = Get-PSCallStackPath
43+
Write-Debug "[$stackPath] - Start"
44+
}
45+
46+
process {
47+
if ($PrivateKey -is [securestring]) {
48+
$PrivateKey = $PrivateKey | ConvertFrom-SecureString -AsPlainText
49+
}
50+
51+
$rsa = [System.Security.Cryptography.RSA]::Create()
52+
$rsa.ImportFromPem($PrivateKey)
53+
54+
try {
55+
$signature = [Convert]::ToBase64String(
56+
$rsa.SignData(
57+
[System.Text.Encoding]::UTF8.GetBytes($UnsignedJWT),
58+
[System.Security.Cryptography.HashAlgorithmName]::SHA256,
59+
[System.Security.Cryptography.RSASignaturePadding]::Pkcs1
60+
)
61+
).TrimEnd('=').Replace('+', '-').Replace('/', '_')
62+
return "$UnsignedJWT.$signature"
63+
} finally {
64+
if ($rsa) {
65+
$rsa.Dispose()
66+
}
67+
}
68+
}
69+
70+
end {
71+
Write-Debug "[$stackPath] - End"
72+
}
73+
}

‎src/functions/private/Apps/GitHub Apps/Get-GitHubAppJSONWebToken.ps1

Lines changed: 0 additions & 134 deletions
This file was deleted.

0 commit comments

Comments
 (0)