@@ -31,7 +31,7 @@ public class Config
3131
3232 public string HaUrl { get ; set ; } = "" ;
3333 public string HaToken { get ; set ; } = "" ;
34- public bool VerifySsl { get ; set ; } = false ;
34+ public bool VerifySsl { get ; set ; } = true ;
3535 public int SensorInterval { get ; set ; } = 30 ;
3636 public string UpdateChannel { get ; set ; } = "stable" ;
3737 public string Language { get ; set ; } = "de" ;
@@ -50,17 +50,26 @@ private static bool TryKeychainStore(string token)
5050 {
5151 try
5252 {
53+ // Pipe token via stdin to avoid exposing it in `ps aux`
5354 var psi = new System . Diagnostics . ProcessStartInfo
5455 {
5556 FileName = "security" ,
56- Arguments = $ "add-generic-password -a ha-desklink -s ha-desklink-token -w { EscapeShellArg ( token ) } -U",
57+ Arguments = "add-generic-password -a ha-desklink -s ha-desklink-token -w -U" ,
5758 UseShellExecute = false ,
5859 CreateNoWindow = true ,
60+ RedirectStandardInput = true ,
5961 RedirectStandardError = true
6062 } ;
61- var proc = System . Diagnostics . Process . Start ( psi ) ;
62- proc ? . WaitForExit ( 5000 ) ;
63- return proc ? . ExitCode == 0 ;
63+ using var proc = System . Diagnostics . Process . Start ( psi ) ;
64+ if ( proc == null ) return false ;
65+ proc . StandardInput . WriteLine ( token ) ;
66+ proc . StandardInput . Close ( ) ;
67+ // Read stderr BEFORE WaitForExit to prevent deadlock
68+ var stderr = proc . StandardError . ReadToEnd ( ) ;
69+ proc . WaitForExit ( 5000 ) ;
70+ if ( proc . ExitCode != 0 && ! string . IsNullOrWhiteSpace ( stderr ) )
71+ Console . WriteLine ( $ "[Keychain] Store failed: { stderr . Trim ( ) } ") ;
72+ return proc . ExitCode == 0 ;
6473 }
6574 catch { return false ; }
6675 }
@@ -107,7 +116,9 @@ private static byte[] GetOrCreateKey()
107116 RandomNumberGenerator . Fill ( key ) ;
108117 Directory . CreateDirectory ( ConfigDir ) ;
109118 File . WriteAllText ( keyPath , Convert . ToBase64String ( key ) ) ;
110- try { System . Diagnostics . Process . Start ( "chmod" , $ "600 { keyPath } ") ? . WaitForExit ( 2000 ) ; } catch { }
119+ #pragma warning disable CA1416
120+ try { File . SetUnixFileMode ( keyPath , System . IO . UnixFileMode . UserRead | System . IO . UnixFileMode . UserWrite ) ; } catch { }
121+ #pragma warning restore CA1416
111122 return key ;
112123 }
113124
@@ -117,7 +128,7 @@ private static string EncryptAesGcm(string plainText)
117128 var key = GetOrCreateKey ( ) ;
118129 var plainBytes = Encoding . UTF8 . GetBytes ( plainText ) ;
119130
120- using var aes = new AesGcm ( key ) ;
131+ using var aes = new AesGcm ( key , 16 ) ;
121132 var nonce = new byte [ AesGcm . NonceByteSizes . MaxSize ] ;
122133 RandomNumberGenerator . Fill ( nonce ) ;
123134 var ciphertext = new byte [ plainBytes . Length ] ;
@@ -151,7 +162,7 @@ private static string DecryptAesGcm(string encryptedText)
151162 Buffer . BlockCopy ( combined , nonceSize , tag , 0 , tagSize ) ;
152163 Buffer . BlockCopy ( combined , nonceSize + tagSize , ciphertext , 0 , ciphertext . Length ) ;
153164
154- using var aes = new AesGcm ( key ) ;
165+ using var aes = new AesGcm ( key , 16 ) ;
155166 var plainBytes = new byte [ ciphertext . Length ] ;
156167 aes . Decrypt ( nonce , ciphertext , tag , plainBytes ) ;
157168 return Encoding . UTF8 . GetString ( plainBytes ) ;
@@ -245,6 +256,11 @@ public void Save()
245256
246257 var json = JsonSerializer . Serialize ( saveConfig , new JsonSerializerOptions { WriteIndented = true } ) ;
247258 File . WriteAllText ( ConfigPath , json ) ;
259+
260+ // Secure config file permissions (macOS)
261+ #pragma warning disable CA1416
262+ try { File . SetUnixFileMode ( ConfigPath , System . IO . UnixFileMode . UserRead | System . IO . UnixFileMode . UserWrite ) ; } catch { }
263+ #pragma warning restore CA1416
248264 }
249265
250266 public static string GetConfigDir ( ) => ConfigDir ;
0 commit comments