Skip to content

Commit 4c76f31

Browse files
committed
chore(ci): update ci configurations
1 parent 68411aa commit 4c76f31

6 files changed

Lines changed: 687 additions & 34 deletions

File tree

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
# Connect-SimplySign-Enhanced.ps1
2+
# Registry-Enhanced TOTP Authentication for SimplySign Desktop
3+
# Uses registry pre-configuration + TOTP credential injection approach
4+
5+
param(
6+
[string]$OtpUri = $env:CERTUM_OTP_URI,
7+
[string]$UserId = $env:CERTUM_USERNAME,
8+
[string]$ExePath = $env:CERTUM_EXE_PATH
9+
)
10+
11+
# Validate required parameters
12+
if (-not $OtpUri) {
13+
Write-Host "ERROR: CERTUM_OTP_URI environment variable not provided"
14+
exit 1
15+
}
16+
17+
if (-not $UserId) {
18+
Write-Host "ERROR: CERTUM_USERNAME environment variable not provided"
19+
exit 1
20+
}
21+
22+
if (-not $ExePath) {
23+
$ExePath = "C:\Program Files\Certum\SimplySign Desktop\SimplySignDesktop.exe"
24+
}
25+
26+
Write-Host "=== REGISTRY-ENHANCED TOTP AUTHENTICATION ==="
27+
Write-Host "Using registry pre-configuration + credential injection"
28+
Write-Host "OTP URI provided (length: $($OtpUri.Length))"
29+
Write-Host "User ID: $UserId"
30+
Write-Host "Executable: $ExePath"
31+
Write-Host ""
32+
33+
# Verify SimplySign Desktop exists
34+
if (-not (Test-Path $ExePath)) {
35+
Write-Host "ERROR: SimplySign Desktop not found at: $ExePath"
36+
exit 1
37+
}
38+
39+
# Parse the otpauth:// URI
40+
$uri = [Uri]$OtpUri
41+
42+
# Parse query parameters (compatible with both PowerShell 5.1 and 7+)
43+
try {
44+
$q = [System.Web.HttpUtility]::ParseQueryString($uri.Query)
45+
} catch {
46+
$q = @{}
47+
foreach ($part in $uri.Query.TrimStart('?') -split '&') {
48+
$kv = $part -split '=', 2
49+
if ($kv.Count -eq 2) {
50+
$q[$kv[0]] = [Uri]::UnescapeDataString($kv[1])
51+
}
52+
}
53+
}
54+
55+
$Base32 = $q['secret']
56+
$Digits = if ($q['digits']) { [int]$q['digits'] } else { 6 }
57+
$Period = if ($q['period']) { [int]$q['period'] } else { 30 }
58+
$Algorithm = if ($q['algorithm']) { $q['algorithm'].ToUpper() } else { 'SHA256' }
59+
60+
# Validate supported algorithms
61+
$SupportedAlgorithms = @('SHA1', 'SHA256', 'SHA512')
62+
if ($Algorithm -notin $SupportedAlgorithms) {
63+
Write-Host "ERROR: Unsupported algorithm: $Algorithm. Supported: $($SupportedAlgorithms -join ', ')"
64+
exit 1
65+
}
66+
67+
# TOTP Generator (inline C# implementation)
68+
Add-Type -Language CSharp @"
69+
using System;
70+
using System.Security.Cryptography;
71+
72+
public static class Totp
73+
{
74+
private const string B32 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
75+
76+
private static byte[] Base32Decode(string s)
77+
{
78+
s = s.TrimEnd('=').ToUpperInvariant();
79+
int byteCount = s.Length * 5 / 8;
80+
byte[] bytes = new byte[byteCount];
81+
82+
int bitBuffer = 0, bitsLeft = 0, idx = 0;
83+
foreach (char c in s)
84+
{
85+
int val = B32.IndexOf(c);
86+
if (val < 0) throw new ArgumentException("Invalid Base32 char: " + c);
87+
88+
bitBuffer = (bitBuffer << 5) | val;
89+
bitsLeft += 5;
90+
91+
if (bitsLeft >= 8)
92+
{
93+
bytes[idx++] = (byte)(bitBuffer >> (bitsLeft - 8));
94+
bitsLeft -= 8;
95+
}
96+
}
97+
return bytes;
98+
}
99+
100+
private static HMAC GetHmacAlgorithm(string algorithm, byte[] key)
101+
{
102+
switch (algorithm.ToUpper())
103+
{
104+
case "SHA1":
105+
return new HMACSHA1(key);
106+
case "SHA256":
107+
return new HMACSHA256(key);
108+
case "SHA512":
109+
return new HMACSHA512(key);
110+
default:
111+
throw new ArgumentException("Unsupported algorithm: " + algorithm);
112+
}
113+
}
114+
115+
public static string Now(string secret, int digits, int period, string algorithm = "SHA256")
116+
{
117+
byte[] key = Base32Decode(secret);
118+
long counter = DateTimeOffset.UtcNow.ToUnixTimeSeconds() / period;
119+
120+
byte[] cnt = BitConverter.GetBytes(counter);
121+
if (BitConverter.IsLittleEndian) Array.Reverse(cnt);
122+
123+
byte[] hash;
124+
using (var hmac = GetHmacAlgorithm(algorithm, key))
125+
{
126+
hash = hmac.ComputeHash(cnt);
127+
}
128+
129+
int offset = hash[hash.Length - 1] & 0x0F;
130+
int binary =
131+
((hash[offset] & 0x7F) << 24) |
132+
((hash[offset + 1] & 0xFF) << 16) |
133+
((hash[offset + 2] & 0xFF) << 8) |
134+
(hash[offset + 3] & 0xFF);
135+
136+
int otp = binary % (int)Math.Pow(10, digits);
137+
return otp.ToString(new string('0', digits));
138+
}
139+
}
140+
"@
141+
142+
function Get-TotpCode {
143+
param([string]$Secret, [int]$Digits = 6, [int]$Period = 30, [string]$Algorithm = 'SHA256')
144+
[Totp]::Now($Secret, $Digits, $Period, $Algorithm)
145+
}
146+
147+
# Generate current TOTP code
148+
$otp = Get-TotpCode -Secret $Base32 -Digits $Digits -Period $Period -Algorithm $Algorithm
149+
Write-Host "Generated TOTP: $otp (using $Algorithm algorithm)"
150+
Write-Host ""
151+
152+
# Launch SimplySign Desktop (registry should auto-open login dialog)
153+
Write-Host "Launching SimplySign Desktop..."
154+
Write-Host "Registry pre-configuration should auto-open login dialog"
155+
$proc = Start-Process -FilePath $ExePath -PassThru
156+
Write-Host "Process started with ID: $($proc.Id)"
157+
Write-Host ""
158+
159+
# Wait for the application to initialize
160+
Write-Host "Waiting for SimplySign Desktop to initialize..."
161+
Start-Sleep -Seconds 3
162+
163+
# Create WScript.Shell for window interaction
164+
$wshell = New-Object -ComObject WScript.Shell
165+
166+
# Try to focus the SimplySign Desktop window
167+
Write-Host "Attempting to focus SimplySign Desktop window..."
168+
$focused = $false
169+
170+
# Method 1: Focus by process ID (most reliable)
171+
$focused = $wshell.AppActivate($proc.Id)
172+
173+
# Method 2: Focus by window title (fallback)
174+
if (-not $focused) {
175+
$focused = $wshell.AppActivate('SimplySign Desktop')
176+
}
177+
178+
# Method 3: Multiple attempts with slight delays
179+
for ($i = 0; (-not $focused) -and ($i -lt 10); $i++) {
180+
Start-Sleep -Milliseconds 500
181+
$focused = $wshell.AppActivate($proc.Id) -or $wshell.AppActivate('SimplySign Desktop')
182+
Write-Host "Focus attempt $($i + 1): $focused"
183+
}
184+
185+
if (-not $focused) {
186+
Write-Host "ERROR: Could not bring SimplySign Desktop to foreground"
187+
Write-Host "Login dialog may not be visible for credential injection"
188+
exit 1
189+
}
190+
191+
Write-Host "Successfully focused SimplySign Desktop window"
192+
Write-Host ""
193+
194+
# Small delay to ensure window is ready for input
195+
Start-Sleep -Milliseconds 400
196+
197+
# Inject credentials: Username + TAB + TOTP + ENTER
198+
Write-Host "Injecting credentials into login dialog..."
199+
Write-Host "Sending: Username -> TAB -> TOTP -> ENTER"
200+
201+
# Send the credential sequence
202+
$wshell.SendKeys($UserId)
203+
Start-Sleep -Milliseconds 200
204+
$wshell.SendKeys("{TAB}")
205+
Start-Sleep -Milliseconds 200
206+
$wshell.SendKeys($otp)
207+
Start-Sleep -Milliseconds 200
208+
$wshell.SendKeys("{ENTER}")
209+
210+
Write-Host "Credentials injected successfully"
211+
Write-Host ""
212+
213+
# Wait for authentication to process
214+
Write-Host "Waiting for authentication to complete..."
215+
Start-Sleep -Seconds 5
216+
217+
# Verify SimplySign Desktop is still running
218+
$stillRunning = Get-Process -Id $proc.Id -ErrorAction SilentlyContinue
219+
if ($stillRunning) {
220+
Write-Host "SUCCESS: SimplySign Desktop is running"
221+
Write-Host "Authentication should be complete"
222+
Write-Host "Cloud certificate should now be available"
223+
} else {
224+
Write-Host "WARNING: SimplySign Desktop process has exited"
225+
Write-Host "This may indicate authentication failure"
226+
}
227+
228+
Write-Host ""
229+
Write-Host "=== TOTP AUTHENTICATION COMPLETE ==="
230+
Write-Host "Registry pre-configuration + credential injection finished"

0 commit comments

Comments
 (0)