Skip to content

Commit f80791d

Browse files
Prompt Safari users to install HTTPS certificates and check if they are outdated when the Agent is started
1 parent 6a0017f commit f80791d

File tree

2 files changed

+95
-0
lines changed

2 files changed

+95
-0
lines changed

certificates/certificates.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"math/big"
3131
"net"
3232
"os"
33+
"os/exec"
3334
"time"
3435

3536
"github.com/arduino/go-paths-helper"
@@ -278,3 +279,37 @@ func isExpired() (bool, error) {
278279
date, _ := time.Parse(time.DateTime, dateS)
279280
return date.Before(bound), nil
280281
}
282+
283+
// PromptInstallCertsSafari prompts the user to install the HTTPS certificates if they are using Safari
284+
func PromptInstallCertsSafari() bool {
285+
if GetDefaultBrowserName() != "Safari" {
286+
return false
287+
}
288+
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\"")
289+
pressed, _ := oscmd.Output()
290+
return string(pressed) == "button returned:Install the certificate for Safari"
291+
}
292+
293+
// PromptExpiredCerts prompts the user to update the HTTPS certificates if they are using Safari
294+
func PromptExpiredCerts(certDir *paths.Path) {
295+
if expired, err := isExpired(); err != nil {
296+
log.Errorf("cannot check if certificates are expired something went wrong: %s", err)
297+
} else if expired {
298+
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\"")
299+
if pressed, _ := oscmd.Output(); string(pressed) == "button returned:Update the certificate for Safari" {
300+
err := UninstallCertificates()
301+
if err != nil {
302+
log.Errorf("cannot uninstall certificates something went wrong: %s", err)
303+
} else {
304+
DeleteCertificates(certDir)
305+
GenerateCertificates(certDir)
306+
err := InstallCertificate(certDir.Join("ca.cert.cer"))
307+
// if something goes wrong during the cert install we remove them, so the user is able to retry
308+
if err != nil {
309+
log.Errorf("cannot install certificates something went wrong: %s", err)
310+
DeleteCertificates(certDir)
311+
}
312+
}
313+
}
314+
}
315+
}

main.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ var (
8686
verbose = iniConf.Bool("v", true, "show debug logging")
8787
crashreport = iniConf.Bool("crashreport", false, "enable crashreport logging")
8888
autostartMacOS = iniConf.Bool("autostartMacOS", true, "the Arduino Create Agent is able to start automatically after login on macOS (launchd agent)")
89+
installCerts = iniConf.Bool("installCerts", false, "install the HTTPS certificate for Safari and keep it updated")
8990
)
9091

9192
// the ports filter provided by the user via the -regex flag, if any
@@ -220,6 +221,34 @@ func loop() {
220221
configPath = config.GenerateConfig(configDir)
221222
}
222223

224+
// if the default browser is Safari, prompt the user to install HTTPS certificates
225+
// and eventually install them
226+
if runtime.GOOS == "darwin" {
227+
if exist, err := installCertsKeyExists(configPath.String()); err != nil {
228+
log.Panicf("config.ini cannot be parsed: %s", err)
229+
} else if !exist {
230+
if cert.PromptInstallCertsSafari() {
231+
err = modifyIni(configPath.String(), "true")
232+
if err != nil {
233+
log.Panicf("config.ini cannot be parsed: %s", err)
234+
}
235+
certDir := config.GetCertificatesDir()
236+
cert.GenerateCertificates(certDir)
237+
err := cert.InstallCertificate(certDir.Join("ca.cert.cer"))
238+
// if something goes wrong during the cert install we remove them, so the user is able to retry
239+
if err != nil {
240+
log.Errorf("cannot install certificates something went wrong: %s", err)
241+
cert.DeleteCertificates(certDir)
242+
}
243+
} else {
244+
err = modifyIni(configPath.String(), "false")
245+
if err != nil {
246+
log.Panicf("config.ini cannot be parsed: %s", err)
247+
}
248+
}
249+
}
250+
}
251+
223252
// Parse the config.ini
224253
args, err := parseIni(configPath.String())
225254
if err != nil {
@@ -342,6 +371,13 @@ func loop() {
342371
}
343372
}
344373

374+
// check if the HTTPS certificates are expired and prompt the user to update them on macOS
375+
if runtime.GOOS == "darwin" {
376+
if *installCerts && config.CertsExist() {
377+
cert.PromptExpiredCerts(config.GetCertificatesDir())
378+
}
379+
}
380+
345381
// launch the discoveries for the running system
346382
go serialPorts.Run()
347383
// launch the hub routine which is the singleton for the websocket server
@@ -487,3 +523,27 @@ func parseIni(filename string) (args []string, err error) {
487523

488524
return args, nil
489525
}
526+
527+
func modifyIni(filename string, value string) error {
528+
cfg, err := ini.LoadSources(ini.LoadOptions{IgnoreInlineComment: false, AllowPythonMultilineValues: true}, filename)
529+
if err != nil {
530+
return err
531+
}
532+
_, err = cfg.Section("").NewKey("installCerts", value)
533+
if err != nil {
534+
return err
535+
}
536+
err = cfg.SaveTo(filename)
537+
if err != nil {
538+
return err
539+
}
540+
return nil
541+
}
542+
543+
func installCertsKeyExists(filename string) (bool, error) {
544+
cfg, err := ini.LoadSources(ini.LoadOptions{IgnoreInlineComment: false, AllowPythonMultilineValues: true}, filename)
545+
if err != nil {
546+
return false, err
547+
}
548+
return cfg.Section("").HasKey("installCerts"), nil
549+
}

0 commit comments

Comments
 (0)