From 64bb34650ea3d50d828212ea543e7af1436a8103 Mon Sep 17 00:00:00 2001 From: MatteoPologruto Date: Tue, 23 Apr 2024 11:07:14 +0200 Subject: [PATCH 01/19] Add function to retrieve certificates expiration date --- certificates/install_darwin.go | 46 +++++++++++++++++++++++++++++++++ certificates/install_default.go | 6 +++++ 2 files changed, 52 insertions(+) diff --git a/certificates/install_darwin.go b/certificates/install_darwin.go index 2c84d7dc..8dc48423 100644 --- a/certificates/install_darwin.go +++ b/certificates/install_darwin.go @@ -89,11 +89,46 @@ const char *uninstallCert() { } return ""; } + +const char *getExpirationDate(){ + // Create a key-value dictionary used to query the Keychain and look for the "Arduino" root certificate. + NSDictionary *getquery = @{ + (id)kSecClass: (id)kSecClassCertificate, + (id)kSecAttrLabel: @"Arduino", + (id)kSecReturnRef: @YES, + }; + + OSStatus err = noErr; + SecCertificateRef cert = NULL; + + // Use this function to check for errors + err = SecItemCopyMatching((CFDictionaryRef)getquery, (CFTypeRef *)&cert); + + if (err != errSecItemNotFound && err != noErr){ + NSString *errString = [@"Error: " stringByAppendingFormat:@"%d", err]; + NSLog(@"%@", errString); + return ""; + } + + // Get data from the certificate. We just need the "invalidity date" property. + CFDictionaryRef valuesDict = SecCertificateCopyValues(cert, (__bridge CFArrayRef)@[(__bridge id)kSecOIDInvalidityDate], NULL); + + // TODO: Error checking. + CFDictionaryRef invalidityDateDictionaryRef = CFDictionaryGetValue(valuesDict, kSecOIDInvalidityDate); + CFTypeRef invalidityRef = CFDictionaryGetValue(invalidityDateDictionaryRef, kSecPropertyKeyValue); + id expirationDateValue = CFBridgingRelease(invalidityRef); + + CFRelease(valuesDict); + + NSString *outputString = [@"" stringByAppendingFormat:@"%@", expirationDateValue]; + return [outputString cStringUsingEncoding:[NSString defaultCStringEncoding]]; +} */ import "C" import ( "errors" "os/exec" + "strings" "unsafe" log "github.com/sirupsen/logrus" @@ -131,3 +166,14 @@ func UninstallCertificates() error { } return nil } + +// GetExpirationDate returns the expiration date of a certificate stored in the keychain +func GetExpirationDate() (string, error) { + log.Infof("Retrieving certificate's expiration date") + p := C.getExpirationDate() + s := strings.ReplaceAll(C.GoString(p), " +0000", "") + if len(s) != 0 { + return s, nil + } + return "", nil +} diff --git a/certificates/install_default.go b/certificates/install_default.go index 1b7f24bb..ab10e194 100644 --- a/certificates/install_default.go +++ b/certificates/install_default.go @@ -36,3 +36,9 @@ func UninstallCertificates() error { log.Warn("platform not supported for the certificates uninstall") return errors.New("platform not supported for the certificates uninstall") } + +// GetExpirationDate won't do anything on unsupported Operative Systems +func GetExpirationDate() (string, error) { + log.Warn("platform not supported for retrieving certificates expiration date") + return "", errors.New("platform not supported for retrieving certificates expiration date") +} From 0cb308aacea43a1e0430b331a00774959d75eeb2 Mon Sep 17 00:00:00 2001 From: MatteoPologruto Date: Tue, 23 Apr 2024 11:07:42 +0200 Subject: [PATCH 02/19] Check the certificate expiration date --- certificates/certificates.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/certificates/certificates.go b/certificates/certificates.go index 990fa2e0..cef2138e 100644 --- a/certificates/certificates.go +++ b/certificates/certificates.go @@ -267,3 +267,12 @@ func DeleteCertificates(certDir *paths.Path) { certDir.Join("cert.pem").Remove() certDir.Join("cert.cer").Remove() } + +// isExpired checks if a certificate is expired or about to expire (less than 1 month) +func isExpired() bool { + bound := time.Now().AddDate(0, 1, 0) + // TODO: manage errors + dateS, _ := GetExpirationDate() + date, _ := time.Parse(time.DateTime, dateS) + return date.Before(bound) +} From 431dc589ecfcdf4a9d574e3a7eae183581e3e106 Mon Sep 17 00:00:00 2001 From: MatteoPologruto Date: Wed, 24 Apr 2024 10:50:29 +0200 Subject: [PATCH 03/19] Obtain certificates info using the systray icon --- systray/systray_real.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/systray/systray_real.go b/systray/systray_real.go index 62e52e21..4a3c732d 100644 --- a/systray/systray_real.go +++ b/systray/systray_real.go @@ -21,6 +21,7 @@ package systray import ( "os" + "os/exec" "runtime" "fyne.io/systray" @@ -65,11 +66,13 @@ func (s *Systray) start() { mGenCerts := systray.AddMenuItem("Generate and Install HTTPS certificates", "HTTPS Certs") mRemoveCerts := systray.AddMenuItem("Remove HTTPS certificates", "") + mCertsInfo := systray.AddMenuItem("Show HTTPS certificates info", "") // On linux/windows chrome/firefox/edge(chromium) the agent works without problems on plain HTTP, // so we disable the menuItem to generate/install the certificates if runtime.GOOS != "darwin" { s.updateMenuItem(mGenCerts, true) s.updateMenuItem(mRemoveCerts, true) + s.updateMenuItem(mCertsInfo, true) } else { s.updateMenuItem(mGenCerts, config.CertsExist()) s.updateMenuItem(mRemoveCerts, !config.CertsExist()) @@ -115,6 +118,19 @@ func (s *Systray) start() { cert.DeleteCertificates(certDir) } s.Restart() + case <-mCertsInfo.ClickedCh: + infoMsg := "The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\n\nYour HTTPS certificate status:\n" + if config.CertsExist() { + expDate, err := cert.GetExpirationDate() + if err != nil { + log.Errorf("cannot get certificates expiration date, something went wrong: %s", err) + } + infoMsg = infoMsg + "- Certificate installed: Yes\n- Certificate trusted: Yes\n- Certificate expiration date: " + expDate + } else { + infoMsg = infoMsg + "- Certificate installed: No\n- Certificate trusted: N/A\n- Certificate expiration date: N/A" + } + oscmd := exec.Command("osascript", "-e", "display dialog \""+infoMsg+"\" buttons \"OK\" with title \"Arduino Agent: certificates info\"") + _ = oscmd.Run() case <-mPause.ClickedCh: s.Pause() case <-mQuit.ClickedCh: From 046397668cfa1051d53bf86621aed3889bc4c4c8 Mon Sep 17 00:00:00 2001 From: MatteoPologruto Date: Wed, 24 Apr 2024 15:10:50 +0200 Subject: [PATCH 04/19] Manage errors that may occur retrieving certificates expiration date --- certificates/certificates.go | 10 ++++--- certificates/install_darwin.go | 48 ++++++++++++++++++++++++---------- 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/certificates/certificates.go b/certificates/certificates.go index cef2138e..2287fe43 100644 --- a/certificates/certificates.go +++ b/certificates/certificates.go @@ -269,10 +269,12 @@ func DeleteCertificates(certDir *paths.Path) { } // isExpired checks if a certificate is expired or about to expire (less than 1 month) -func isExpired() bool { +func isExpired() (bool, error) { bound := time.Now().AddDate(0, 1, 0) - // TODO: manage errors - dateS, _ := GetExpirationDate() + dateS, err := GetExpirationDate() + if err != nil { + return false, err + } date, _ := time.Parse(time.DateTime, dateS) - return date.Before(bound) + return date.Before(bound), nil } diff --git a/certificates/install_darwin.go b/certificates/install_darwin.go index 8dc48423..b059515a 100644 --- a/certificates/install_darwin.go +++ b/certificates/install_darwin.go @@ -90,7 +90,7 @@ const char *uninstallCert() { return ""; } -const char *getExpirationDate(){ +const char *getExpirationDate(char *expirationDate){ // Create a key-value dictionary used to query the Keychain and look for the "Arduino" root certificate. NSDictionary *getquery = @{ (id)kSecClass: (id)kSecClassCertificate, @@ -104,24 +104,39 @@ const char *getExpirationDate(){ // Use this function to check for errors err = SecItemCopyMatching((CFDictionaryRef)getquery, (CFTypeRef *)&cert); - if (err != errSecItemNotFound && err != noErr){ + if (err != noErr){ NSString *errString = [@"Error: " stringByAppendingFormat:@"%d", err]; NSLog(@"%@", errString); - return ""; + return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]]; } // Get data from the certificate. We just need the "invalidity date" property. CFDictionaryRef valuesDict = SecCertificateCopyValues(cert, (__bridge CFArrayRef)@[(__bridge id)kSecOIDInvalidityDate], NULL); - // TODO: Error checking. - CFDictionaryRef invalidityDateDictionaryRef = CFDictionaryGetValue(valuesDict, kSecOIDInvalidityDate); - CFTypeRef invalidityRef = CFDictionaryGetValue(invalidityDateDictionaryRef, kSecPropertyKeyValue); - id expirationDateValue = CFBridgingRelease(invalidityRef); - - CFRelease(valuesDict); + id expirationDateValue; + if(valuesDict){ + CFDictionaryRef invalidityDateDictionaryRef = CFDictionaryGetValue(valuesDict, kSecOIDInvalidityDate); + if(invalidityDateDictionaryRef){ + CFTypeRef invalidityRef = CFDictionaryGetValue(invalidityDateDictionaryRef, kSecPropertyKeyValue); + if(invalidityRef){ + expirationDateValue = CFBridgingRelease(invalidityRef); + } + } + CFRelease(valuesDict); + } NSString *outputString = [@"" stringByAppendingFormat:@"%@", expirationDateValue]; - return [outputString cStringUsingEncoding:[NSString defaultCStringEncoding]]; + if([outputString isEqualToString:@""]){ + NSString *errString = @"Error: the expiration date of the certificate could not be found"; + NSLog(@"%@", errString); + return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]]; + } + + // This workaround allows to obtain the expiration date alongside the error message + strncpy(expirationDate, [outputString cStringUsingEncoding:[NSString defaultCStringEncoding]], 32); + expirationDate[32-1] = 0; + + return ""; } */ import "C" @@ -170,10 +185,15 @@ func UninstallCertificates() error { // GetExpirationDate returns the expiration date of a certificate stored in the keychain func GetExpirationDate() (string, error) { log.Infof("Retrieving certificate's expiration date") - p := C.getExpirationDate() - s := strings.ReplaceAll(C.GoString(p), " +0000", "") + dateString := C.CString("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") // 32 characters string + defer C.free(unsafe.Pointer(dateString)) + p := C.getExpirationDate(dateString) + s := C.GoString(p) if len(s) != 0 { - return s, nil + oscmd := exec.Command("osascript", "-e", "display dialog \""+s+"\" buttons \"OK\" with title \"Arduino Agent: Error retrieving expiration date\"") + _ = oscmd.Run() + return "", errors.New(s) } - return "", nil + date := C.GoString(dateString) + return strings.ReplaceAll(date, " +0000", ""), nil } From 6a0017fe2152b4df41ce8c2195914b2cfaee705d Mon Sep 17 00:00:00 2001 From: MatteoPologruto Date: Tue, 30 Apr 2024 09:38:29 +0200 Subject: [PATCH 05/19] Obtain default browser name on macOS --- certificates/install_darwin.go | 19 +++++++++++++++++++ certificates/install_default.go | 6 ++++++ 2 files changed, 25 insertions(+) diff --git a/certificates/install_darwin.go b/certificates/install_darwin.go index b059515a..8c999c40 100644 --- a/certificates/install_darwin.go +++ b/certificates/install_darwin.go @@ -138,6 +138,18 @@ const char *getExpirationDate(char *expirationDate){ return ""; } + +const char *getDefaultBrowserName() { + NSURL *defaultBrowserURL = [[NSWorkspace sharedWorkspace] URLForApplicationToOpenURL:[NSURL URLWithString:@"http://"]]; + if (defaultBrowserURL) { + NSBundle *defaultBrowserBundle = [NSBundle bundleWithURL:defaultBrowserURL]; + NSString *defaultBrowser = [defaultBrowserBundle objectForInfoDictionaryKey:@"CFBundleDisplayName"]; + + return [defaultBrowser cStringUsingEncoding:[NSString defaultCStringEncoding]]; + } + + return ""; +} */ import "C" import ( @@ -197,3 +209,10 @@ func GetExpirationDate() (string, error) { date := C.GoString(dateString) return strings.ReplaceAll(date, " +0000", ""), nil } + +// GetDefaultBrowserName returns the name of the default browser +func GetDefaultBrowserName() string { + log.Infof("Retrieving default browser name") + p := C.getDefaultBrowserName() + return C.GoString(p) +} diff --git a/certificates/install_default.go b/certificates/install_default.go index ab10e194..8013c018 100644 --- a/certificates/install_default.go +++ b/certificates/install_default.go @@ -42,3 +42,9 @@ func GetExpirationDate() (string, error) { log.Warn("platform not supported for retrieving certificates expiration date") return "", errors.New("platform not supported for retrieving certificates expiration date") } + +// GetDefaultBrowserName won't do anything on unsupported Operative Systems +func GetDefaultBrowserName() string { + log.Warn("platform not supported for retrieving default browser name") + return "" +} From f80791d84cb9a7b7c8bb0c0d06b55087c31a8bf6 Mon Sep 17 00:00:00 2001 From: MatteoPologruto Date: Tue, 30 Apr 2024 15:22:04 +0200 Subject: [PATCH 06/19] Prompt Safari users to install HTTPS certificates and check if they are outdated when the Agent is started --- certificates/certificates.go | 35 +++++++++++++++++++++ main.go | 60 ++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/certificates/certificates.go b/certificates/certificates.go index 2287fe43..18a300fa 100644 --- a/certificates/certificates.go +++ b/certificates/certificates.go @@ -30,6 +30,7 @@ import ( "math/big" "net" "os" + "os/exec" "time" "github.com/arduino/go-paths-helper" @@ -278,3 +279,37 @@ func isExpired() (bool, error) { date, _ := time.Parse(time.DateTime, dateS) return date.Before(bound), nil } + +// PromptInstallCertsSafari prompts the user to install the HTTPS certificates if they are using Safari +func PromptInstallCertsSafari() bool { + if GetDefaultBrowserName() != "Safari" { + return false + } + oscmd := exec.Command("osascript", "-e", "display dialog \"The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\nIf you use Safari, you need to install it.\" buttons {\"Do not install\", \"Install the certificate for Safari\"} default button 2 with title \"Install Certificates\"") + pressed, _ := oscmd.Output() + return string(pressed) == "button returned:Install the certificate for Safari" +} + +// PromptExpiredCerts prompts the user to update the HTTPS certificates if they are using Safari +func PromptExpiredCerts(certDir *paths.Path) { + if expired, err := isExpired(); err != nil { + log.Errorf("cannot check if certificates are expired something went wrong: %s", err) + } else if expired { + oscmd := exec.Command("osascript", "-e", "display dialog \"The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\nYour certificate is expired or close to expiration. Do you want to update it?\" buttons {\"Do not update\", \"Update the certificate for Safari\"} default button 2 with title \"Update Certificates\"") + if pressed, _ := oscmd.Output(); string(pressed) == "button returned:Update the certificate for Safari" { + err := UninstallCertificates() + if err != nil { + log.Errorf("cannot uninstall certificates something went wrong: %s", err) + } else { + DeleteCertificates(certDir) + GenerateCertificates(certDir) + err := InstallCertificate(certDir.Join("ca.cert.cer")) + // if something goes wrong during the cert install we remove them, so the user is able to retry + if err != nil { + log.Errorf("cannot install certificates something went wrong: %s", err) + DeleteCertificates(certDir) + } + } + } + } +} diff --git a/main.go b/main.go index 45ae5259..245d4247 100755 --- a/main.go +++ b/main.go @@ -86,6 +86,7 @@ var ( verbose = iniConf.Bool("v", true, "show debug logging") crashreport = iniConf.Bool("crashreport", false, "enable crashreport logging") autostartMacOS = iniConf.Bool("autostartMacOS", true, "the Arduino Create Agent is able to start automatically after login on macOS (launchd agent)") + installCerts = iniConf.Bool("installCerts", false, "install the HTTPS certificate for Safari and keep it updated") ) // the ports filter provided by the user via the -regex flag, if any @@ -220,6 +221,34 @@ func loop() { configPath = config.GenerateConfig(configDir) } + // if the default browser is Safari, prompt the user to install HTTPS certificates + // and eventually install them + if runtime.GOOS == "darwin" { + if exist, err := installCertsKeyExists(configPath.String()); err != nil { + log.Panicf("config.ini cannot be parsed: %s", err) + } else if !exist { + if cert.PromptInstallCertsSafari() { + err = modifyIni(configPath.String(), "true") + if err != nil { + log.Panicf("config.ini cannot be parsed: %s", err) + } + certDir := config.GetCertificatesDir() + cert.GenerateCertificates(certDir) + err := cert.InstallCertificate(certDir.Join("ca.cert.cer")) + // if something goes wrong during the cert install we remove them, so the user is able to retry + if err != nil { + log.Errorf("cannot install certificates something went wrong: %s", err) + cert.DeleteCertificates(certDir) + } + } else { + err = modifyIni(configPath.String(), "false") + if err != nil { + log.Panicf("config.ini cannot be parsed: %s", err) + } + } + } + } + // Parse the config.ini args, err := parseIni(configPath.String()) if err != nil { @@ -342,6 +371,13 @@ func loop() { } } + // check if the HTTPS certificates are expired and prompt the user to update them on macOS + if runtime.GOOS == "darwin" { + if *installCerts && config.CertsExist() { + cert.PromptExpiredCerts(config.GetCertificatesDir()) + } + } + // launch the discoveries for the running system go serialPorts.Run() // launch the hub routine which is the singleton for the websocket server @@ -487,3 +523,27 @@ func parseIni(filename string) (args []string, err error) { return args, nil } + +func modifyIni(filename string, value string) error { + cfg, err := ini.LoadSources(ini.LoadOptions{IgnoreInlineComment: false, AllowPythonMultilineValues: true}, filename) + if err != nil { + return err + } + _, err = cfg.Section("").NewKey("installCerts", value) + if err != nil { + return err + } + err = cfg.SaveTo(filename) + if err != nil { + return err + } + return nil +} + +func installCertsKeyExists(filename string) (bool, error) { + cfg, err := ini.LoadSources(ini.LoadOptions{IgnoreInlineComment: false, AllowPythonMultilineValues: true}, filename) + if err != nil { + return false, err + } + return cfg.Section("").HasKey("installCerts"), nil +} From 40f50f469c829ffb10024d1b9afdd16c548a7227 Mon Sep 17 00:00:00 2001 From: MatteoPologruto Date: Thu, 2 May 2024 15:18:16 +0200 Subject: [PATCH 07/19] Skip some tests on macOS because the user is prompted to install certificates --- tests/test_info.py | 6 ++++++ tests/test_v2.py | 6 ++++++ tests/test_ws.py | 9 +++++++++ 3 files changed, 21 insertions(+) diff --git a/tests/test_info.py b/tests/test_info.py index 6982ca35..efda3bce 100644 --- a/tests/test_info.py +++ b/tests/test_info.py @@ -15,8 +15,14 @@ import re import requests +import pytest +from sys import platform +@pytest.mark.skipif( + platform == "darwin", + reason="on macOS the user is prompted to install certificates", +) def test_version(base_url, agent): resp = requests.get(f"{base_url}/info") diff --git a/tests/test_v2.py b/tests/test_v2.py index 9a377802..5fa44034 100644 --- a/tests/test_v2.py +++ b/tests/test_v2.py @@ -14,8 +14,14 @@ # along with this program. If not, see . import requests +import pytest +from sys import platform +@pytest.mark.skipif( + platform == "darwin", + reason="on macOS the user is prompted to install certificates", +) def test_get_tools(base_url, agent): resp = requests.get(f"{base_url}/v2/pkgs/tools/installed") diff --git a/tests/test_ws.py b/tests/test_ws.py index c2623da5..b8004649 100644 --- a/tests/test_ws.py +++ b/tests/test_ws.py @@ -17,16 +17,25 @@ import json import base64 import pytest +from sys import platform from common import running_on_ci message = [] +@pytest.mark.skipif( + platform == "darwin", + reason="on macOS the user is prompted to install certificates", +) def test_ws_connection(socketio): print('my sid is', socketio.sid) assert socketio.sid is not None +@pytest.mark.skipif( + platform == "darwin", + reason="on macOS the user is prompted to install certificates", +) def test_list(socketio, message): socketio.emit('command', 'list') time.sleep(.2) From f1f76a3f8e94f1e03763e63e4b02486a934a297e Mon Sep 17 00:00:00 2001 From: MatteoPologruto Date: Thu, 2 May 2024 15:41:45 +0200 Subject: [PATCH 08/19] Set installCerts value in config.ini if certicates are manually installed --- config/config.go | 18 ++++++++++++++++++ main.go | 20 ++------------------ systray/systray_real.go | 4 ++++ 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/config/config.go b/config/config.go index 437437e5..69d29eee 100644 --- a/config/config.go +++ b/config/config.go @@ -21,6 +21,7 @@ import ( "os" "github.com/arduino/go-paths-helper" + "github.com/go-ini/ini" log "github.com/sirupsen/logrus" ) @@ -124,3 +125,20 @@ func GenerateConfig(destDir *paths.Path) *paths.Path { log.Infof("generated config in %s", configPath) return configPath } + +// SetInstallCertsIni sets installCerts value to true in the config +func SetInstallCertsIni(filename string, value string) error { + cfg, err := ini.LoadSources(ini.LoadOptions{IgnoreInlineComment: false, AllowPythonMultilineValues: true}, filename) + if err != nil { + return err + } + _, err = cfg.Section("").NewKey("installCerts", value) + if err != nil { + return err + } + err = cfg.SaveTo(filename) + if err != nil { + return err + } + return nil +} diff --git a/main.go b/main.go index 245d4247..6d8f72aa 100755 --- a/main.go +++ b/main.go @@ -228,7 +228,7 @@ func loop() { log.Panicf("config.ini cannot be parsed: %s", err) } else if !exist { if cert.PromptInstallCertsSafari() { - err = modifyIni(configPath.String(), "true") + err = config.SetInstallCertsIni(configPath.String(), "true") if err != nil { log.Panicf("config.ini cannot be parsed: %s", err) } @@ -241,7 +241,7 @@ func loop() { cert.DeleteCertificates(certDir) } } else { - err = modifyIni(configPath.String(), "false") + err = config.SetInstallCertsIni(configPath.String(), "false") if err != nil { log.Panicf("config.ini cannot be parsed: %s", err) } @@ -524,22 +524,6 @@ func parseIni(filename string) (args []string, err error) { return args, nil } -func modifyIni(filename string, value string) error { - cfg, err := ini.LoadSources(ini.LoadOptions{IgnoreInlineComment: false, AllowPythonMultilineValues: true}, filename) - if err != nil { - return err - } - _, err = cfg.Section("").NewKey("installCerts", value) - if err != nil { - return err - } - err = cfg.SaveTo(filename) - if err != nil { - return err - } - return nil -} - func installCertsKeyExists(filename string) (bool, error) { cfg, err := ini.LoadSources(ini.LoadOptions{IgnoreInlineComment: false, AllowPythonMultilineValues: true}, filename) if err != nil { diff --git a/systray/systray_real.go b/systray/systray_real.go index 4a3c732d..4d70b703 100644 --- a/systray/systray_real.go +++ b/systray/systray_real.go @@ -108,6 +108,10 @@ func (s *Systray) start() { log.Errorf("cannot install certificates something went wrong: %s", err) cert.DeleteCertificates(certDir) } + err = config.SetInstallCertsIni(s.currentConfigFilePath.String(), "true") + if err != nil { + log.Errorf("cannot set installCerts value in config.ini: %s", err) + } s.Restart() case <-mRemoveCerts.ClickedCh: err := cert.UninstallCertificates() From 88495ca2395468e41d476b4206622fdabb768d1a Mon Sep 17 00:00:00 2001 From: MatteoPologruto Date: Thu, 2 May 2024 16:40:21 +0200 Subject: [PATCH 09/19] Always set installCerts if the certificates exist --- main.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/main.go b/main.go index 6d8f72aa..07ab5598 100755 --- a/main.go +++ b/main.go @@ -227,7 +227,12 @@ func loop() { if exist, err := installCertsKeyExists(configPath.String()); err != nil { log.Panicf("config.ini cannot be parsed: %s", err) } else if !exist { - if cert.PromptInstallCertsSafari() { + if config.CertsExist() { + err = config.SetInstallCertsIni(configPath.String(), "true") + if err != nil { + log.Panicf("config.ini cannot be parsed: %s", err) + } + } else if cert.PromptInstallCertsSafari() { err = config.SetInstallCertsIni(configPath.String(), "true") if err != nil { log.Panicf("config.ini cannot be parsed: %s", err) From a438fed65194575146e4748fe980cf70fd6e04da Mon Sep 17 00:00:00 2001 From: Xayton <30591904+Xayton@users.noreply.github.com> Date: Thu, 2 May 2024 17:31:08 +0200 Subject: [PATCH 10/19] Add "Arduino Agent" to the title of dialogs --- certificates/certificates.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/certificates/certificates.go b/certificates/certificates.go index 18a300fa..d1c31697 100644 --- a/certificates/certificates.go +++ b/certificates/certificates.go @@ -285,7 +285,7 @@ func PromptInstallCertsSafari() bool { if GetDefaultBrowserName() != "Safari" { return false } - oscmd := exec.Command("osascript", "-e", "display dialog \"The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\nIf you use Safari, you need to install it.\" buttons {\"Do not install\", \"Install the certificate for Safari\"} default button 2 with title \"Install Certificates\"") + oscmd := exec.Command("osascript", "-e", "display dialog \"The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\nIf you use Safari, you need to install it.\" buttons {\"Do not install\", \"Install the certificate for Safari\"} default button 2 with title \"Arduino Agent: Install Certificates\"") pressed, _ := oscmd.Output() return string(pressed) == "button returned:Install the certificate for Safari" } @@ -295,7 +295,7 @@ func PromptExpiredCerts(certDir *paths.Path) { if expired, err := isExpired(); err != nil { log.Errorf("cannot check if certificates are expired something went wrong: %s", err) } else if expired { - oscmd := exec.Command("osascript", "-e", "display dialog \"The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\nYour certificate is expired or close to expiration. Do you want to update it?\" buttons {\"Do not update\", \"Update the certificate for Safari\"} default button 2 with title \"Update Certificates\"") + oscmd := exec.Command("osascript", "-e", "display dialog \"The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\nYour certificate is expired or close to expiration. Do you want to update it?\" buttons {\"Do not update\", \"Update the certificate for Safari\"} default button 2 with title \"Arduino Agent: Update Certificates\"") if pressed, _ := oscmd.Output(); string(pressed) == "button returned:Update the certificate for Safari" { err := UninstallCertificates() if err != nil { From 66ba136928bff6e5f9fd32057d14e3062ee0830b Mon Sep 17 00:00:00 2001 From: Xayton <30591904+Xayton@users.noreply.github.com> Date: Thu, 2 May 2024 17:56:56 +0200 Subject: [PATCH 11/19] Fix check for pressed buttons --- certificates/certificates.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/certificates/certificates.go b/certificates/certificates.go index d1c31697..e2256699 100644 --- a/certificates/certificates.go +++ b/certificates/certificates.go @@ -287,7 +287,7 @@ func PromptInstallCertsSafari() bool { } oscmd := exec.Command("osascript", "-e", "display dialog \"The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\nIf you use Safari, you need to install it.\" buttons {\"Do not install\", \"Install the certificate for Safari\"} default button 2 with title \"Arduino Agent: Install Certificates\"") pressed, _ := oscmd.Output() - return string(pressed) == "button returned:Install the certificate for Safari" + return strings.Contains(string(pressed), "button returned:Install the certificate for Safari") } // PromptExpiredCerts prompts the user to update the HTTPS certificates if they are using Safari @@ -296,7 +296,7 @@ func PromptExpiredCerts(certDir *paths.Path) { log.Errorf("cannot check if certificates are expired something went wrong: %s", err) } else if expired { oscmd := exec.Command("osascript", "-e", "display dialog \"The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\nYour certificate is expired or close to expiration. Do you want to update it?\" buttons {\"Do not update\", \"Update the certificate for Safari\"} default button 2 with title \"Arduino Agent: Update Certificates\"") - if pressed, _ := oscmd.Output(); string(pressed) == "button returned:Update the certificate for Safari" { + if pressed, _ := oscmd.Output(); strings.Contains(string(pressed), "button returned:Update the certificate for Safari") { err := UninstallCertificates() if err != nil { log.Errorf("cannot uninstall certificates something went wrong: %s", err) From 52961e28e121d93a3c3bb8ea8c1d7610656a180f Mon Sep 17 00:00:00 2001 From: MatteoPologruto Date: Mon, 6 May 2024 13:00:49 +0200 Subject: [PATCH 12/19] Move osascript execution function to Utilities to avoid code duplication --- certificates/certificates.go | 12 ++++++------ certificates/install_darwin.go | 13 +++++-------- main.go | 10 ++-------- systray/systray_real.go | 5 ++--- utilities/utilities.go | 7 +++++++ 5 files changed, 22 insertions(+), 25 deletions(-) diff --git a/certificates/certificates.go b/certificates/certificates.go index e2256699..f612d0cc 100644 --- a/certificates/certificates.go +++ b/certificates/certificates.go @@ -30,9 +30,10 @@ import ( "math/big" "net" "os" - "os/exec" + "strings" "time" + "github.com/arduino/arduino-create-agent/utilities" "github.com/arduino/go-paths-helper" log "github.com/sirupsen/logrus" ) @@ -285,9 +286,8 @@ func PromptInstallCertsSafari() bool { if GetDefaultBrowserName() != "Safari" { return false } - oscmd := exec.Command("osascript", "-e", "display dialog \"The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\nIf you use Safari, you need to install it.\" buttons {\"Do not install\", \"Install the certificate for Safari\"} default button 2 with title \"Arduino Agent: Install Certificates\"") - pressed, _ := oscmd.Output() - return strings.Contains(string(pressed), "button returned:Install the certificate for Safari") + buttonPressed := utilities.UserPrompt("display dialog \"The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\nIf you use Safari, you need to install it.\" buttons {\"Do not install\", \"Install the certificate for Safari\"} default button 2 with title \"Arduino Agent: Install Certificates\"") + return strings.Contains(string(buttonPressed), "button returned:Install the certificate for Safari") } // PromptExpiredCerts prompts the user to update the HTTPS certificates if they are using Safari @@ -295,8 +295,8 @@ func PromptExpiredCerts(certDir *paths.Path) { if expired, err := isExpired(); err != nil { log.Errorf("cannot check if certificates are expired something went wrong: %s", err) } else if expired { - oscmd := exec.Command("osascript", "-e", "display dialog \"The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\nYour certificate is expired or close to expiration. Do you want to update it?\" buttons {\"Do not update\", \"Update the certificate for Safari\"} default button 2 with title \"Arduino Agent: Update Certificates\"") - if pressed, _ := oscmd.Output(); strings.Contains(string(pressed), "button returned:Update the certificate for Safari") { + buttonPressed := utilities.UserPrompt("display dialog \"The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\nYour certificate is expired or close to expiration. Do you want to update it?\" buttons {\"Do not update\", \"Update the certificate for Safari\"} default button 2 with title \"Arduino Agent: Update Certificates\"") + if strings.Contains(string(buttonPressed), "button returned:Update the certificate for Safari") { err := UninstallCertificates() if err != nil { log.Errorf("cannot uninstall certificates something went wrong: %s", err) diff --git a/certificates/install_darwin.go b/certificates/install_darwin.go index 8c999c40..892c390b 100644 --- a/certificates/install_darwin.go +++ b/certificates/install_darwin.go @@ -154,12 +154,12 @@ const char *getDefaultBrowserName() { import "C" import ( "errors" - "os/exec" "strings" "unsafe" log "github.com/sirupsen/logrus" + "github.com/arduino/arduino-create-agent/utilities" "github.com/arduino/go-paths-helper" ) @@ -172,9 +172,8 @@ func InstallCertificate(cert *paths.Path) error { p := C.installCert(ccert) s := C.GoString(p) if len(s) != 0 { - oscmd := exec.Command("osascript", "-e", "display dialog \""+s+"\" buttons \"OK\" with title \"Arduino Agent: Error installing certificates\"") - _ = oscmd.Run() - _ = UninstallCertificates() + utilities.UserPrompt("display dialog \"" + s + "\" buttons \"OK\" with title \"Arduino Agent: Error installing certificates\"") + UninstallCertificates() return errors.New(s) } return nil @@ -187,8 +186,7 @@ func UninstallCertificates() error { p := C.uninstallCert() s := C.GoString(p) if len(s) != 0 { - oscmd := exec.Command("osascript", "-e", "display dialog \""+s+"\" buttons \"OK\" with title \"Arduino Agent: Error uninstalling certificates\"") - _ = oscmd.Run() + utilities.UserPrompt("display dialog \"" + s + "\" buttons \"OK\" with title \"Arduino Agent: Error uninstalling certificates\"") return errors.New(s) } return nil @@ -202,8 +200,7 @@ func GetExpirationDate() (string, error) { p := C.getExpirationDate(dateString) s := C.GoString(p) if len(s) != 0 { - oscmd := exec.Command("osascript", "-e", "display dialog \""+s+"\" buttons \"OK\" with title \"Arduino Agent: Error retrieving expiration date\"") - _ = oscmd.Run() + utilities.UserPrompt("display dialog \"" + s + "\" buttons \"OK\" with title \"Arduino Agent: Error retrieving expiration date\"") return "", errors.New(s) } date := C.GoString(dateString) diff --git a/main.go b/main.go index 07ab5598..8d3f7c33 100755 --- a/main.go +++ b/main.go @@ -25,7 +25,6 @@ import ( "html/template" "io" "os" - "os/exec" "regexp" "runtime" "runtime/debug" @@ -40,6 +39,7 @@ import ( "github.com/arduino/arduino-create-agent/systray" "github.com/arduino/arduino-create-agent/tools" "github.com/arduino/arduino-create-agent/updater" + "github.com/arduino/arduino-create-agent/utilities" v2 "github.com/arduino/arduino-create-agent/v2" paths "github.com/arduino/go-paths-helper" cors "github.com/gin-contrib/cors" @@ -178,7 +178,7 @@ func loop() { // If we are updating manually from 1.2.7 to 1.3.0 we have to uninstall the old agent manually first. // This check will inform the user if he needs to run the uninstall first if runtime.GOOS == "darwin" && oldInstallExists() { - printDialog("Old agent installation of the Arduino Create Agent found, please uninstall it before launching the new one") + utilities.UserPrompt("display dialog \"Old agent installation of the Arduino Create Agent found, please uninstall it before launching the new one\" buttons \"OK\" with title \"Error\"") os.Exit(0) } @@ -498,12 +498,6 @@ func oldInstallExists() bool { return oldAgentPath.Join("ArduinoCreateAgent.app").Exist() } -// printDialog will print a GUI error dialog on macos -func printDialog(dialogText string) { - oscmd := exec.Command("osascript", "-e", "display dialog \""+dialogText+"\" buttons \"OK\" with title \"Error\"") - _ = oscmd.Run() -} - func parseIni(filename string) (args []string, err error) { cfg, err := ini.LoadSources(ini.LoadOptions{IgnoreInlineComment: false, AllowPythonMultilineValues: true}, filename) if err != nil { diff --git a/systray/systray_real.go b/systray/systray_real.go index 4d70b703..57e2e9e7 100644 --- a/systray/systray_real.go +++ b/systray/systray_real.go @@ -21,13 +21,13 @@ package systray import ( "os" - "os/exec" "runtime" "fyne.io/systray" cert "github.com/arduino/arduino-create-agent/certificates" "github.com/arduino/arduino-create-agent/config" "github.com/arduino/arduino-create-agent/icon" + "github.com/arduino/arduino-create-agent/utilities" "github.com/go-ini/ini" log "github.com/sirupsen/logrus" "github.com/skratchdot/open-golang/open" @@ -133,8 +133,7 @@ func (s *Systray) start() { } else { infoMsg = infoMsg + "- Certificate installed: No\n- Certificate trusted: N/A\n- Certificate expiration date: N/A" } - oscmd := exec.Command("osascript", "-e", "display dialog \""+infoMsg+"\" buttons \"OK\" with title \"Arduino Agent: certificates info\"") - _ = oscmd.Run() + utilities.UserPrompt("display dialog \"" + infoMsg + "\" buttons \"OK\" with title \"Arduino Agent: certificates info\"") case <-mPause.ClickedCh: s.Pause() case <-mQuit.ClickedCh: diff --git a/utilities/utilities.go b/utilities/utilities.go index 4f40aaf7..63f09103 100644 --- a/utilities/utilities.go +++ b/utilities/utilities.go @@ -149,3 +149,10 @@ func VerifyInput(input string, signature string) error { d := h.Sum(nil) return rsa.VerifyPKCS1v15(rsaKey, crypto.SHA256, d, sign) } + +// UserPrompt executes an osascript and returns the pressed button +func UserPrompt(dialog string) string { + oscmd := exec.Command("osascript", "-e", dialog) + pressedButton, _ := oscmd.Output() + return string(pressedButton) +} From a759046a13069c82508e9e611b56339fb2eb6f0e Mon Sep 17 00:00:00 2001 From: MatteoPologruto Date: Mon, 6 May 2024 14:36:17 +0200 Subject: [PATCH 13/19] Modify certificate management from the systray menu --- systray/systray_real.go | 67 ++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/systray/systray_real.go b/systray/systray_real.go index 57e2e9e7..31ea460c 100644 --- a/systray/systray_real.go +++ b/systray/systray_real.go @@ -22,6 +22,7 @@ package systray import ( "os" "runtime" + "strings" "fyne.io/systray" cert "github.com/arduino/arduino-create-agent/certificates" @@ -64,18 +65,11 @@ func (s *Systray) start() { mRmCrashes := systray.AddMenuItem("Remove crash reports", "") s.updateMenuItem(mRmCrashes, config.LogsIsEmpty()) - mGenCerts := systray.AddMenuItem("Generate and Install HTTPS certificates", "HTTPS Certs") - mRemoveCerts := systray.AddMenuItem("Remove HTTPS certificates", "") - mCertsInfo := systray.AddMenuItem("Show HTTPS certificates info", "") + mManageCerts := systray.AddMenuItem("Manage HTTPS certificates", "HTTPS Certs") // On linux/windows chrome/firefox/edge(chromium) the agent works without problems on plain HTTP, // so we disable the menuItem to generate/install the certificates if runtime.GOOS != "darwin" { - s.updateMenuItem(mGenCerts, true) - s.updateMenuItem(mRemoveCerts, true) - s.updateMenuItem(mCertsInfo, true) - } else { - s.updateMenuItem(mGenCerts, config.CertsExist()) - s.updateMenuItem(mRemoveCerts, !config.CertsExist()) + s.updateMenuItem(mManageCerts, true) } // Add pause/quit @@ -99,41 +93,46 @@ func (s *Systray) start() { case <-mRmCrashes.ClickedCh: RemoveCrashes() s.updateMenuItem(mRmCrashes, config.LogsIsEmpty()) - case <-mGenCerts.ClickedCh: - certDir := config.GetCertificatesDir() - cert.GenerateCertificates(certDir) - err := cert.InstallCertificate(certDir.Join("ca.cert.cer")) - // if something goes wrong during the cert install we remove them, so the user is able to retry - if err != nil { - log.Errorf("cannot install certificates something went wrong: %s", err) - cert.DeleteCertificates(certDir) - } - err = config.SetInstallCertsIni(s.currentConfigFilePath.String(), "true") - if err != nil { - log.Errorf("cannot set installCerts value in config.ini: %s", err) - } - s.Restart() - case <-mRemoveCerts.ClickedCh: - err := cert.UninstallCertificates() - if err != nil { - log.Errorf("cannot uninstall certificates something went wrong: %s", err) - } else { - certDir := config.GetCertificatesDir() - cert.DeleteCertificates(certDir) - } - s.Restart() - case <-mCertsInfo.ClickedCh: + case <-mManageCerts.ClickedCh: infoMsg := "The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\n\nYour HTTPS certificate status:\n" + buttons := "{\"OK\", \"Install certificate for Safari\"}" + certDir := config.GetCertificatesDir() if config.CertsExist() { expDate, err := cert.GetExpirationDate() if err != nil { log.Errorf("cannot get certificates expiration date, something went wrong: %s", err) } infoMsg = infoMsg + "- Certificate installed: Yes\n- Certificate trusted: Yes\n- Certificate expiration date: " + expDate + buttons = "{\"OK\", \"Uninstall certificate for Safari\"}" } else { infoMsg = infoMsg + "- Certificate installed: No\n- Certificate trusted: N/A\n- Certificate expiration date: N/A" } - utilities.UserPrompt("display dialog \"" + infoMsg + "\" buttons \"OK\" with title \"Arduino Agent: certificates info\"") + pressedButton := utilities.UserPrompt("display dialog \"" + infoMsg + "\" buttons " + buttons + " with title \"Arduino Agent: manage HTTPS certificates\"") + if strings.Contains(pressedButton, "Install certificate for Safari") { + cert.GenerateCertificates(certDir) + err := cert.InstallCertificate(certDir.Join("ca.cert.cer")) + // if something goes wrong during the cert install we remove them, so the user is able to retry + if err != nil { + log.Errorf("cannot install certificates something went wrong: %s", err) + cert.DeleteCertificates(certDir) + } + err = config.SetInstallCertsIni(s.currentConfigFilePath.String(), "true") + if err != nil { + log.Errorf("cannot set installCerts value in config.ini: %s", err) + } + } else if strings.Contains(pressedButton, "Uninstall certificate for Safari") { + err := cert.UninstallCertificates() + if err != nil { + log.Errorf("cannot uninstall certificates something went wrong: %s", err) + } else { + cert.DeleteCertificates(certDir) + err = config.SetInstallCertsIni(s.currentConfigFilePath.String(), "false") + if err != nil { + log.Errorf("cannot set installCerts value in config.ini: %s", err) + } + } + } + s.Restart() case <-mPause.ClickedCh: s.Pause() case <-mQuit.ClickedCh: From 46ceb5d16227900e3a6c41312c90ee616fe87cf4 Mon Sep 17 00:00:00 2001 From: MatteoPologruto Date: Tue, 7 May 2024 11:16:31 +0200 Subject: [PATCH 14/19] Install certificates if they are missing and the flag inside the config is set to true --- main.go | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index 8d3f7c33..4e4f371b 100755 --- a/main.go +++ b/main.go @@ -378,8 +378,26 @@ func loop() { // check if the HTTPS certificates are expired and prompt the user to update them on macOS if runtime.GOOS == "darwin" { - if *installCerts && config.CertsExist() { - cert.PromptExpiredCerts(config.GetCertificatesDir()) + if *installCerts { + if config.CertsExist() { + cert.PromptExpiredCerts(config.GetCertificatesDir()) + } else if cert.PromptInstallCertsSafari() { + // installing the certificates from scratch at this point should only happen if + // something went wrong during previous installation attempts + certDir := config.GetCertificatesDir() + cert.GenerateCertificates(certDir) + err := cert.InstallCertificate(certDir.Join("ca.cert.cer")) + // if something goes wrong during the cert install we remove them, so the user is able to retry + if err != nil { + log.Errorf("cannot install certificates something went wrong: %s", err) + cert.DeleteCertificates(certDir) + } + } else { + err = config.SetInstallCertsIni(configPath.String(), "false") + if err != nil { + log.Panicf("config.ini cannot be parsed: %s", err) + } + } } } From 144515b135088a2c51cf3190ccb1451d69bb1fb6 Mon Sep 17 00:00:00 2001 From: MatteoPologruto Date: Tue, 7 May 2024 11:56:36 +0200 Subject: [PATCH 15/19] Avoid code duplication --- certificates/certificates.go | 19 ++++++++++++------- main.go | 18 ++---------------- systray/systray_real.go | 10 ++-------- 3 files changed, 16 insertions(+), 31 deletions(-) diff --git a/certificates/certificates.go b/certificates/certificates.go index f612d0cc..a3a236a2 100644 --- a/certificates/certificates.go +++ b/certificates/certificates.go @@ -302,14 +302,19 @@ func PromptExpiredCerts(certDir *paths.Path) { log.Errorf("cannot uninstall certificates something went wrong: %s", err) } else { DeleteCertificates(certDir) - GenerateCertificates(certDir) - err := InstallCertificate(certDir.Join("ca.cert.cer")) - // if something goes wrong during the cert install we remove them, so the user is able to retry - if err != nil { - log.Errorf("cannot install certificates something went wrong: %s", err) - DeleteCertificates(certDir) - } + GenerateAndInstallCertificates(certDir) } } } } + +// GenerateAndInstallCertificates generates and installs the certificates +func GenerateAndInstallCertificates(certDir *paths.Path) { + GenerateCertificates(certDir) + err := InstallCertificate(certDir.Join("ca.cert.cer")) + // if something goes wrong during the cert install we remove them, so the user is able to retry + if err != nil { + log.Errorf("cannot install certificates something went wrong: %s", err) + DeleteCertificates(certDir) + } +} diff --git a/main.go b/main.go index 4e4f371b..8cefa995 100755 --- a/main.go +++ b/main.go @@ -237,14 +237,7 @@ func loop() { if err != nil { log.Panicf("config.ini cannot be parsed: %s", err) } - certDir := config.GetCertificatesDir() - cert.GenerateCertificates(certDir) - err := cert.InstallCertificate(certDir.Join("ca.cert.cer")) - // if something goes wrong during the cert install we remove them, so the user is able to retry - if err != nil { - log.Errorf("cannot install certificates something went wrong: %s", err) - cert.DeleteCertificates(certDir) - } + cert.GenerateAndInstallCertificates(config.GetCertificatesDir()) } else { err = config.SetInstallCertsIni(configPath.String(), "false") if err != nil { @@ -384,14 +377,7 @@ func loop() { } else if cert.PromptInstallCertsSafari() { // installing the certificates from scratch at this point should only happen if // something went wrong during previous installation attempts - certDir := config.GetCertificatesDir() - cert.GenerateCertificates(certDir) - err := cert.InstallCertificate(certDir.Join("ca.cert.cer")) - // if something goes wrong during the cert install we remove them, so the user is able to retry - if err != nil { - log.Errorf("cannot install certificates something went wrong: %s", err) - cert.DeleteCertificates(certDir) - } + cert.GenerateAndInstallCertificates(config.GetCertificatesDir()) } else { err = config.SetInstallCertsIni(configPath.String(), "false") if err != nil { diff --git a/systray/systray_real.go b/systray/systray_real.go index 31ea460c..d4ff48da 100644 --- a/systray/systray_real.go +++ b/systray/systray_real.go @@ -109,14 +109,8 @@ func (s *Systray) start() { } pressedButton := utilities.UserPrompt("display dialog \"" + infoMsg + "\" buttons " + buttons + " with title \"Arduino Agent: manage HTTPS certificates\"") if strings.Contains(pressedButton, "Install certificate for Safari") { - cert.GenerateCertificates(certDir) - err := cert.InstallCertificate(certDir.Join("ca.cert.cer")) - // if something goes wrong during the cert install we remove them, so the user is able to retry - if err != nil { - log.Errorf("cannot install certificates something went wrong: %s", err) - cert.DeleteCertificates(certDir) - } - err = config.SetInstallCertsIni(s.currentConfigFilePath.String(), "true") + cert.GenerateAndInstallCertificates(certDir) + err := config.SetInstallCertsIni(s.currentConfigFilePath.String(), "true") if err != nil { log.Errorf("cannot set installCerts value in config.ini: %s", err) } From e9c71b34f1be5be6fc07d488cb4db55d8d6c6902 Mon Sep 17 00:00:00 2001 From: Xayton <30591904+Xayton@users.noreply.github.com> Date: Tue, 7 May 2024 14:47:25 +0200 Subject: [PATCH 16/19] Fix button order and title --- systray/systray_real.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/systray/systray_real.go b/systray/systray_real.go index d4ff48da..41f27bd2 100644 --- a/systray/systray_real.go +++ b/systray/systray_real.go @@ -65,7 +65,7 @@ func (s *Systray) start() { mRmCrashes := systray.AddMenuItem("Remove crash reports", "") s.updateMenuItem(mRmCrashes, config.LogsIsEmpty()) - mManageCerts := systray.AddMenuItem("Manage HTTPS certificates", "HTTPS Certs") + mManageCerts := systray.AddMenuItem("Manage HTTPS certificate", "HTTPS Certs") // On linux/windows chrome/firefox/edge(chromium) the agent works without problems on plain HTTP, // so we disable the menuItem to generate/install the certificates if runtime.GOOS != "darwin" { @@ -95,7 +95,7 @@ func (s *Systray) start() { s.updateMenuItem(mRmCrashes, config.LogsIsEmpty()) case <-mManageCerts.ClickedCh: infoMsg := "The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\n\nYour HTTPS certificate status:\n" - buttons := "{\"OK\", \"Install certificate for Safari\"}" + buttons := "{\"Install certificate for Safari\", \"OK\"} default button \"OK\"" certDir := config.GetCertificatesDir() if config.CertsExist() { expDate, err := cert.GetExpirationDate() @@ -103,11 +103,11 @@ func (s *Systray) start() { log.Errorf("cannot get certificates expiration date, something went wrong: %s", err) } infoMsg = infoMsg + "- Certificate installed: Yes\n- Certificate trusted: Yes\n- Certificate expiration date: " + expDate - buttons = "{\"OK\", \"Uninstall certificate for Safari\"}" + buttons = "{\"Uninstall certificate for Safari\", \"OK\"} default button \"OK\"" } else { infoMsg = infoMsg + "- Certificate installed: No\n- Certificate trusted: N/A\n- Certificate expiration date: N/A" } - pressedButton := utilities.UserPrompt("display dialog \"" + infoMsg + "\" buttons " + buttons + " with title \"Arduino Agent: manage HTTPS certificates\"") + pressedButton := utilities.UserPrompt("display dialog \"" + infoMsg + "\" buttons " + buttons + " with title \"Arduino Agent: Manage HTTPS certificate\"") if strings.Contains(pressedButton, "Install certificate for Safari") { cert.GenerateAndInstallCertificates(certDir) err := config.SetInstallCertsIni(s.currentConfigFilePath.String(), "true") From 1ba5ed19b47a62af03e35acba197c6d77d9f8026 Mon Sep 17 00:00:00 2001 From: MatteoPologruto Date: Tue, 7 May 2024 14:49:40 +0200 Subject: [PATCH 17/19] Do not restart the Agent if no action is performed on the certificate --- systray/systray_real.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/systray/systray_real.go b/systray/systray_real.go index 41f27bd2..2b06b24c 100644 --- a/systray/systray_real.go +++ b/systray/systray_real.go @@ -114,6 +114,7 @@ func (s *Systray) start() { if err != nil { log.Errorf("cannot set installCerts value in config.ini: %s", err) } + s.Restart() } else if strings.Contains(pressedButton, "Uninstall certificate for Safari") { err := cert.UninstallCertificates() if err != nil { @@ -125,8 +126,8 @@ func (s *Systray) start() { log.Errorf("cannot set installCerts value in config.ini: %s", err) } } + s.Restart() } - s.Restart() case <-mPause.ClickedCh: s.Pause() case <-mQuit.ClickedCh: From 1ec717132cd610049f11db3d7db052319ba37cd9 Mon Sep 17 00:00:00 2001 From: MatteoPologruto Date: Tue, 7 May 2024 15:07:13 +0200 Subject: [PATCH 18/19] Do not modify the config if the default browser is not Safari --- certificates/certificates.go | 3 --- main.go | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/certificates/certificates.go b/certificates/certificates.go index a3a236a2..34ca9865 100644 --- a/certificates/certificates.go +++ b/certificates/certificates.go @@ -283,9 +283,6 @@ func isExpired() (bool, error) { // PromptInstallCertsSafari prompts the user to install the HTTPS certificates if they are using Safari func PromptInstallCertsSafari() bool { - if GetDefaultBrowserName() != "Safari" { - return false - } buttonPressed := utilities.UserPrompt("display dialog \"The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\nIf you use Safari, you need to install it.\" buttons {\"Do not install\", \"Install the certificate for Safari\"} default button 2 with title \"Arduino Agent: Install Certificates\"") return strings.Contains(string(buttonPressed), "button returned:Install the certificate for Safari") } diff --git a/main.go b/main.go index 8cefa995..0231548d 100755 --- a/main.go +++ b/main.go @@ -223,7 +223,7 @@ func loop() { // if the default browser is Safari, prompt the user to install HTTPS certificates // and eventually install them - if runtime.GOOS == "darwin" { + if runtime.GOOS == "darwin" && cert.GetDefaultBrowserName() == "Safari" { if exist, err := installCertsKeyExists(configPath.String()); err != nil { log.Panicf("config.ini cannot be parsed: %s", err) } else if !exist { @@ -370,7 +370,7 @@ func loop() { } // check if the HTTPS certificates are expired and prompt the user to update them on macOS - if runtime.GOOS == "darwin" { + if runtime.GOOS == "darwin" && cert.GetDefaultBrowserName() == "Safari" { if *installCerts { if config.CertsExist() { cert.PromptExpiredCerts(config.GetCertificatesDir()) From 27d8b765568bbe4125893c42293ef6cd844fd724 Mon Sep 17 00:00:00 2001 From: Xayton <30591904+Xayton@users.noreply.github.com> Date: Tue, 7 May 2024 17:41:49 +0200 Subject: [PATCH 19/19] Small messages/titles fixes --- certificates/certificates.go | 4 ++-- systray/systray_real.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/certificates/certificates.go b/certificates/certificates.go index 34ca9865..baac7c33 100644 --- a/certificates/certificates.go +++ b/certificates/certificates.go @@ -283,7 +283,7 @@ func isExpired() (bool, error) { // PromptInstallCertsSafari prompts the user to install the HTTPS certificates if they are using Safari func PromptInstallCertsSafari() bool { - buttonPressed := utilities.UserPrompt("display dialog \"The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\nIf you use Safari, you need to install it.\" buttons {\"Do not install\", \"Install the certificate for Safari\"} default button 2 with title \"Arduino Agent: Install Certificates\"") + buttonPressed := utilities.UserPrompt("display dialog \"The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\nIf you use Safari, you need to install it.\" buttons {\"Do not install\", \"Install the certificate for Safari\"} default button 2 with title \"Arduino Agent: Install certificate\"") return strings.Contains(string(buttonPressed), "button returned:Install the certificate for Safari") } @@ -292,7 +292,7 @@ func PromptExpiredCerts(certDir *paths.Path) { if expired, err := isExpired(); err != nil { log.Errorf("cannot check if certificates are expired something went wrong: %s", err) } else if expired { - buttonPressed := utilities.UserPrompt("display dialog \"The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\nYour certificate is expired or close to expiration. Do you want to update it?\" buttons {\"Do not update\", \"Update the certificate for Safari\"} default button 2 with title \"Arduino Agent: Update Certificates\"") + buttonPressed := utilities.UserPrompt("display dialog \"The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\nYour certificate is expired or close to expiration. Do you want to update it?\" buttons {\"Do not update\", \"Update the certificate for Safari\"} default button 2 with title \"Arduino Agent: Update certificate\"") if strings.Contains(string(buttonPressed), "button returned:Update the certificate for Safari") { err := UninstallCertificates() if err != nil { diff --git a/systray/systray_real.go b/systray/systray_real.go index 2b06b24c..503373d8 100644 --- a/systray/systray_real.go +++ b/systray/systray_real.go @@ -95,7 +95,7 @@ func (s *Systray) start() { s.updateMenuItem(mRmCrashes, config.LogsIsEmpty()) case <-mManageCerts.ClickedCh: infoMsg := "The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\n\nYour HTTPS certificate status:\n" - buttons := "{\"Install certificate for Safari\", \"OK\"} default button \"OK\"" + buttons := "{\"Install the certificate for Safari\", \"OK\"} default button \"OK\"" certDir := config.GetCertificatesDir() if config.CertsExist() { expDate, err := cert.GetExpirationDate() @@ -103,7 +103,7 @@ func (s *Systray) start() { log.Errorf("cannot get certificates expiration date, something went wrong: %s", err) } infoMsg = infoMsg + "- Certificate installed: Yes\n- Certificate trusted: Yes\n- Certificate expiration date: " + expDate - buttons = "{\"Uninstall certificate for Safari\", \"OK\"} default button \"OK\"" + buttons = "{\"Uninstall the certificate for Safari\", \"OK\"} default button \"OK\"" } else { infoMsg = infoMsg + "- Certificate installed: No\n- Certificate trusted: N/A\n- Certificate expiration date: N/A" } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy