Skip to content

Commit e40ebde

Browse files
umbynoscmaglie
andauthored
Add the ability to generate SSL certs from tray icon (#778)
* move `config.go` to it's own package and make functions public. This way we have a single source of truth. * move `config.ini` in the right package and remove hack * fix linter * move `CrashesIsEmpty` function to the config package and rename it * move `certificate.go` in it's own package and make functions public * update license header * add menu option to generate the certs only if they are not present * systray is useless in this func * add cert install on macos leverage objective C APIs to install our CA certificate in the user's trusted keystore * add cert install on win leverage windows syscalls to install our CA certificate in the user's trusted keystore code heavily inspired by https://github.com/FiloSottile/mkcert * fix certificate not being valid for 127.0.0.1 * disable the generation/install certs menuItem on OS that are not macos * remove the cert generation from the installer, remove duplicate step * parallelization for notarization is no more required * test new version of the installer config * move archive generation in the CI and save a rename operation (we do that in the installer) * removed `-` in arch matrix variable for clarity * Revert "add cert install on win" This reverts commit bcaeb75. * add popup on error * Fixed warnings in obj-c code * remove the certs if the install process errors. The user is able to retry * Revert "test new version of the installer config" This reverts commit fa425dd. --------- Co-authored-by: Cristian Maglie <[email protected]>
1 parent ea1be68 commit e40ebde

File tree

9 files changed

+245
-113
lines changed

9 files changed

+245
-113
lines changed

.github/workflows/release.yml

+25-44
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ jobs:
3131
strategy:
3232
matrix:
3333
os: [ubuntu-20.04, windows-2019, macos-12]
34-
arch: [-amd64]
34+
arch: [amd64]
3535
include:
3636
- os: windows-2019
37-
arch: -386
37+
arch: 386
3838
ext: ".exe"
3939
- os: windows-2019
4040
ext: ".exe"
@@ -104,11 +104,11 @@ jobs:
104104
env:
105105
GOARCH: 386 # 32bit architecture (for support)
106106
run: task go:build-win
107-
if: matrix.os == 'windows-2019' && matrix.arch == '-386'
107+
if: matrix.os == 'windows-2019' && matrix.arch == '386'
108108

109109
- name: Build the Agent for win64
110110
run: task go:build-win # GOARCH=amd64 by default on the runners
111-
if: matrix.os == 'windows-2019' && matrix.arch == '-amd64'
111+
if: matrix.os == 'windows-2019' && matrix.arch == 'amd64'
112112

113113
- name: Build the Agent for macos
114114
env:
@@ -121,7 +121,7 @@ jobs:
121121
# this will create `public/` dir with compressed full bin (<version>/<os>-<arch>.gz) and a json file
122122
- name: Create autoupdate files
123123
run: go-selfupdate ${{ env.PROJECT_NAME }}${{ matrix.ext }} ${TAG_VERSION}
124-
if: matrix.arch != '-386' && steps.prerelease.outputs.IS_PRE != 'true'
124+
if: matrix.arch != '386' && steps.prerelease.outputs.IS_PRE != 'true'
125125

126126
# for now we do not distribute m1 build, this is a workaround for now
127127
- name: Copy autoupdate file for darwin-arm64 (m1 arch)
@@ -132,8 +132,8 @@ jobs:
132132
if: matrix.os == 'macos-12' && steps.prerelease.outputs.IS_PRE != 'true'
133133

134134
- name: Create autoupdate files for win32
135-
run: go-selfupdate -platform windows${{ matrix.arch }} ${{ env.PROJECT_NAME }}${{ matrix.ext }} ${TAG_VERSION}
136-
if: matrix.arch == '-386' && matrix.os == 'windows-2019' && steps.prerelease.outputs.IS_PRE != 'true'
135+
run: go-selfupdate -platform windows-${{ matrix.arch }} ${{ env.PROJECT_NAME }}${{ matrix.ext }} ${TAG_VERSION}
136+
if: matrix.arch == '386' && matrix.os == 'windows-2019' && steps.prerelease.outputs.IS_PRE != 'true'
137137

138138
- name: Upload autoupdate files to Arduino downloads servers
139139
run: |
@@ -144,7 +144,7 @@ jobs:
144144
- name: Upload artifacts
145145
uses: actions/upload-artifact@v3
146146
with:
147-
name: ${{ env.PROJECT_NAME }}-${{ matrix.os }}${{ matrix.arch }}
147+
name: ${{ env.PROJECT_NAME }}-${{ matrix.os }}-${{ matrix.arch }}
148148
path: |
149149
${{ env.PROJECT_NAME }}*
150150
if-no-files-found: error
@@ -334,9 +334,6 @@ jobs:
334334
INSTALLBUILDER_PATH: "/opt/installbuilder-22.10.0/bin/builder"
335335
INSTALLER_VARS: "project.outputDirectory=$PWD project.version=${GITHUB_REF##*/} workspace=$PWD realname=Arduino_Create_Agent"
336336
# vars passed to installbuilder to install https certs automatically
337-
CERT_INSTALL: "ask_certificates_install=CI" # win(edge),mac(safari)
338-
NO_CERT_INSTALL: "ask_certificates_install=CS" # linux
339-
CHOICE_CERT_INSTALL: "ask_certificates_install=CC" # win,mac:(ff,chrome)
340337
CREATE_OSX_BUNDLED_MG: 0 # tell installbuilder to not create the DMG, gon will take care of that later
341338
# installbuilder will read this vars automatically (defined in installer.xml):
342339
INSTALLER_CERT_WINDOWS_PASSWORD: ${{ secrets.INSTALLER_CERT_WINDOWS_PASSWORD }}
@@ -348,29 +345,27 @@ jobs:
348345
fail-fast: false # if one os is failing continue nonetheless
349346
matrix: # used to generate installers for different OS and not for runs-on
350347
os: [ubuntu-20.04, windows-2019, macos-12]
351-
arch: [-amd64]
348+
arch: [amd64]
352349
include:
353350
- os: ubuntu-20.04
354351
install-builder-name: linux
355352
executable-path: artifacts/linux-amd64/
353+
installer-extension: .run
356354
artifact-name: arduino-create-agent-ubuntu-20.04-amd64
357355
- os: windows-2019
358-
arch: -386
359-
browser: edge
356+
arch: 386
360357
install-builder-name: windows
361358
executable-path: artifacts/windows/
362359
extension: .exe
363360
installer-extension: .exe
364361
artifact-name: arduino-create-agent-windows-2019-386
365362
- os: windows-2019
366-
browser: edge
367363
install-builder-name: windows
368364
executable-path: artifacts/windows/
369365
extension: .exe
370366
installer-extension: .exe
371367
artifact-name: arduino-create-agent-windows-2019-amd64
372368
- os: macos-12
373-
browser: safari
374369
install-builder-name: osx
375370
executable-path: artifacts/macos/ArduinoCreateAgent.app
376371
installer-extension: .app
@@ -425,32 +420,19 @@ jobs:
425420
run: echo "${{ secrets.INSTALLER_CERT_MAC_P12 }}" | base64 --decode > ${{ env.INSTALLER_CERT_MAC_P12 }}
426421
if: matrix.os == 'macos-12'
427422

428-
# win(edge),mac(safari) -> CERT_INSTALL and win,mac:(ff,chrome) -> CHOICE_CERT_INSTALL
429423
# installbuilder reads the env vars with certs paths and use it to sign the installer.
430-
- name: Launch Bitrock installbuilder-20 with CERT_INSTALL && CHOICE_CERT_INSTALL
424+
- name: Launch Bitrock installbuilder
431425
run: |
432-
${{ env.INSTALLBUILDER_PATH }} build installer.xml ${{ matrix.install-builder-name }} --verbose --license /tmp/license.xml --setvars ${{ env.INSTALLER_VARS }} ${{ env.CERT_INSTALL }}
433-
mv -v ArduinoCreateAgent-${GITHUB_REF##*/}-${{ matrix.install-builder-name }}-installer-CI${{matrix.installer-extension}} ArduinoCreateAgent-${GITHUB_REF##*/}-${{ matrix.install-builder-name }}${{ matrix.arch }}-installer-${{matrix.browser}}${{matrix.installer-extension}}
434-
${{ env.INSTALLBUILDER_PATH }} build installer.xml ${{ matrix.install-builder-name }} --verbose --license /tmp/license.xml --setvars ${{ env.INSTALLER_VARS }} ${{ env.CHOICE_CERT_INSTALL }}
435-
cp -vr ArduinoCreateAgent-${GITHUB_REF##*/}-${{ matrix.install-builder-name }}-installer-CC${{matrix.installer-extension}} ArduinoCreateAgent-${GITHUB_REF##*/}-${{ matrix.install-builder-name }}${{ matrix.arch }}-installer-chrome${{matrix.installer-extension}}
436-
mv -v ArduinoCreateAgent-${GITHUB_REF##*/}-${{ matrix.install-builder-name }}-installer-CC${{matrix.installer-extension}} ArduinoCreateAgent-${GITHUB_REF##*/}-${{ matrix.install-builder-name }}${{ matrix.arch }}-installer-firefox${{matrix.installer-extension}}
437-
rm -r ArduinoCreateAgent-${GITHUB_REF##*/}-${{ matrix.install-builder-name }}-installer-C*
438-
if: matrix.os == 'windows-2019' || matrix.os == 'macos-12'
439-
440-
# linux
441-
- name: Launch Bitrock installbuilder-20 with NO_CERT_INSTALL
442-
run: |
443-
${{ env.INSTALLBUILDER_PATH }} build installer.xml linux-x64 --verbose --license /tmp/license.xml --setvars ${{ env.INSTALLER_VARS }} ${{ env.NO_CERT_INSTALL }}
444-
cp -v ArduinoCreateAgent-${GITHUB_REF##*/}-linux-x64-installer-CS.run ArduinoCreateAgent-${GITHUB_REF##*/}-${{ matrix.install-builder-name }}${{ matrix.arch }}-installer-chrome.run
445-
mv -v ArduinoCreateAgent-${GITHUB_REF##*/}-linux-x64-installer-CS.run ArduinoCreateAgent-${GITHUB_REF##*/}-${{ matrix.install-builder-name }}${{ matrix.arch }}-installer-firefox.run
446-
cp -v ArduinoCreateAgent-${GITHUB_REF##*/}-linux-x64-installer-CS.tar.gz ArduinoCreateAgent-${GITHUB_REF##*/}-${{ matrix.install-builder-name }}${{ matrix.arch }}-installer-chrome.tar.gz
447-
mv -v ArduinoCreateAgent-${GITHUB_REF##*/}-linux-x64-installer-CS.tar.gz ArduinoCreateAgent-${GITHUB_REF##*/}-${{ matrix.install-builder-name }}${{ matrix.arch }}-installer-firefox.tar.gz
426+
${{ env.INSTALLBUILDER_PATH }} build installer.xml ${{ matrix.install-builder-name }} --verbose --license /tmp/license.xml --setvars ${{ env.INSTALLER_VARS }} architecture=${{ matrix.arch }}
427+
428+
- name: Generate archive
429+
run: tar -czvf ArduinoCreateAgent-${GITHUB_REF##*/}-${{ matrix.install-builder-name }}-${{ matrix.arch }}-installer.tar.gz ArduinoCreateAgent-${GITHUB_REF##*/}-${{ matrix.install-builder-name }}-${{ matrix.arch }}-installer${{matrix.installer-extension}}
448430
if: matrix.os == 'ubuntu-20.04'
449431

450432
- name: Upload artifacts
451433
uses: actions/upload-artifact@v3
452434
with:
453-
name: ArduinoCreateAgent-${{ matrix.install-builder-name }}${{ matrix.arch }}
435+
name: ArduinoCreateAgent-${{ matrix.install-builder-name }}-${{ matrix.arch }}
454436
path: ArduinoCreateAgent*
455437
if-no-files-found: error
456438

@@ -459,20 +441,19 @@ jobs:
459441
needs: package
460442
strategy:
461443
matrix:
462-
browser: [safari, firefox, chrome]
463-
arch: [-amd64]
444+
arch: [amd64]
464445

465446
runs-on: macos-12
466447
steps:
467448
- name: Download artifact
468449
uses: actions/download-artifact@v3
469450
with:
470-
name: ArduinoCreateAgent-osx${{ matrix.arch }}
451+
name: ArduinoCreateAgent-osx-${{ matrix.arch }}
471452
path: ArduinoCreateAgent-osx
472453

473454
# zip artifacts do not mantain executable permission
474455
- name: Make executable
475-
run: chmod -v +x ArduinoCreateAgent-osx/ArduinoCreateAgent-${GITHUB_REF##*/}-osx${{ matrix.arch }}-installer-${{ matrix.browser }}.app/Contents/MacOS/*
456+
run: chmod -v +x ArduinoCreateAgent-osx/ArduinoCreateAgent-${GITHUB_REF##*/}-osx-${{ matrix.arch }}-installer.app/Contents/MacOS/*
476457

477458
- name: Import Code-Signing Certificates
478459
run: |
@@ -502,33 +483,33 @@ jobs:
502483
# gon does not allow env variables in config file (https://github.com/mitchellh/gon/issues/20)
503484
run: |
504485
cat > gon.config_installer.hcl <<EOF
505-
source = ["ArduinoCreateAgent-osx/ArduinoCreateAgent-${GITHUB_REF##*/}-osx${{ matrix.arch }}-installer-${{ matrix.browser }}.app"]
486+
source = ["ArduinoCreateAgent-osx/ArduinoCreateAgent-${GITHUB_REF##*/}-osx-${{ matrix.arch }}-installer.app"]
506487
bundle_id = "cc.arduino.${{ env.PROJECT_NAME }}-installer"
507488
508489
sign {
509490
application_identity = "Developer ID Application: ARDUINO SA (7KT7ZWMCJT)"
510491
}
511492
512493
dmg {
513-
output_path = "ArduinoCreateAgent-${GITHUB_REF##*/}-osx${{ matrix.arch }}-installer-${{ matrix.browser }}.dmg"
494+
output_path = "ArduinoCreateAgent-${GITHUB_REF##*/}-osx-${{ matrix.arch }}-installer.dmg"
514495
volume_name = "ArduinoCreateAgent"
515496
}
516497
EOF
517498
518499
- name: Code sign and notarize app
519500
run: |
520-
echo "gon will notarize executable in ArduinoCreateAgent-osx/ArduinoCreateAgent-${GITHUB_REF##*/}-osx${{ matrix.arch }}-installer-${{ matrix.browser }}.app"
501+
echo "gon will notarize executable in ArduinoCreateAgent-osx/ArduinoCreateAgent-${GITHUB_REF##*/}-osx-${{ matrix.arch }}-installer.app"
521502
gon -log-level=debug -log-json gon.config_installer.hcl
522503
timeout-minutes: 30
523504

524505
# tar dmg file to keep executable permission
525506
- name: Tar files to keep permissions
526-
run: tar -cvf ArduinoCreateAgent-${GITHUB_REF##*/}-osx${{ matrix.arch }}-installer-${{ matrix.browser }}.tar ArduinoCreateAgent-${GITHUB_REF##*/}-osx${{ matrix.arch }}-installer-${{ matrix.browser }}.dmg
507+
run: tar -cvf ArduinoCreateAgent-${GITHUB_REF##*/}-osx-${{ matrix.arch }}-installer.tar ArduinoCreateAgent-${GITHUB_REF##*/}-osx-${{ matrix.arch }}-installer.dmg
527508

528509
- name: Upload artifacts
529510
uses: actions/upload-artifact@v3
530511
with:
531-
name: ArduinoCreateAgent-osx${{ matrix.arch }}
512+
name: ArduinoCreateAgent-osx-${{ matrix.arch }}
532513
path: ArduinoCreateAgent*.tar
533514
if-no-files-found: error
534515

certificates.go renamed to certificates/certificates.go

+31-23
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
1-
// Copyright 2009 The Go Authors. All rights reserved.
2-
// Use of this source code is governed by a BSD-style
3-
// license that can be found in the LICENSE file.
1+
// Copyright 2023 Arduino SA
2+
//
3+
// This program is free software: you can redistribute it and/or modify
4+
// it under the terms of the GNU Affero General Public License as published
5+
// by the Free Software Foundation, either version 3 of the License, or
6+
// (at your option) any later version.
7+
//
8+
// This program is distributed in the hope that it will be useful,
9+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
// GNU Affero General Public License for more details.
12+
//
13+
// You should have received a copy of the GNU Affero General Public License
14+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
415

516
// Generate a self-signed X.509 certificate for a TLS server. Outputs to
617
// 'cert.pem' and 'key.pem' and will overwrite existing files.
718

8-
package main
19+
package certificates
920

1021
import (
1122
"crypto/ecdsa"
@@ -23,6 +34,7 @@ import (
2334
"text/template"
2435
"time"
2536

37+
"github.com/arduino/arduino-create-agent/config"
2638
"github.com/arduino/go-paths-helper"
2739
"github.com/gin-gonic/gin"
2840
log "github.com/sirupsen/logrus"
@@ -115,14 +127,8 @@ func generateSingleCertificate(isCa bool) (*x509.Certificate, error) {
115127
BasicConstraintsValid: true,
116128
}
117129

118-
hosts := strings.Split(host, ",")
119-
for _, h := range hosts {
120-
if ip := net.ParseIP(h); ip != nil {
121-
template.IPAddresses = append(template.IPAddresses, ip)
122-
} else {
123-
template.DNSNames = append(template.DNSNames, h)
124-
}
125-
}
130+
template.IPAddresses = append(template.IPAddresses, net.ParseIP("127.0.0.1"))
131+
template.DNSNames = append(template.DNSNames, "localhost")
126132

127133
if isCa {
128134
template.IsCA = true
@@ -133,10 +139,10 @@ func generateSingleCertificate(isCa bool) (*x509.Certificate, error) {
133139
return &template, nil
134140
}
135141

136-
// migrateCertificatesGeneratedWithOldAgentVersions checks if certificates generated
142+
// MigrateCertificatesGeneratedWithOldAgentVersions checks if certificates generated
137143
// with an old version of the Agent needs to be migrated to the current certificates
138144
// directory, and performs the migration if needed.
139-
func migrateCertificatesGeneratedWithOldAgentVersions(certsDir *paths.Path) {
145+
func MigrateCertificatesGeneratedWithOldAgentVersions(certsDir *paths.Path) {
140146
if certsDir.Join("ca.cert.pem").Exist() {
141147
// The new certificates are already set-up, nothing to do
142148
return
@@ -160,11 +166,8 @@ func migrateCertificatesGeneratedWithOldAgentVersions(certsDir *paths.Path) {
160166
}
161167
}
162168

163-
func generateCertificates(certsDir *paths.Path) {
164-
certsDir.Join("ca.cert.pem").Remove()
165-
certsDir.Join("ca.key.pem").Remove()
166-
certsDir.Join("cert.pem").Remove()
167-
certsDir.Join("key.pem").Remove()
169+
// GenerateCertificates will generate the required certificates useful for a HTTPS connection on localhost
170+
func GenerateCertificates(certsDir *paths.Path) {
168171

169172
// Create the key for the certification authority
170173
caKey, err := generateKey("P256")
@@ -259,7 +262,8 @@ func generateCertificates(certsDir *paths.Path) {
259262
}
260263
}
261264

262-
func certHandler(c *gin.Context) {
265+
// CertHandler will expone the certificate (we do not know why this was required)
266+
func CertHandler(c *gin.Context) {
263267
if strings.Contains(c.Request.UserAgent(), "Firefox") {
264268
c.Header("content-type", "application/x-x509-ca-cert")
265269
c.File("ca.cert.cer")
@@ -270,15 +274,19 @@ func certHandler(c *gin.Context) {
270274
})
271275
}
272276

273-
func deleteCertHandler(c *gin.Context) {
274-
DeleteCertificates(getCertificatesDir())
277+
// DeleteCertHandler will delete the certificates
278+
func DeleteCertHandler(c *gin.Context) {
279+
DeleteCertificates(config.GetCertificatesDir())
275280
}
276281

277282
// DeleteCertificates will delete the certificates
278283
func DeleteCertificates(certDir *paths.Path) {
284+
certDir.Join("ca.key.pem").Remove()
279285
certDir.Join("ca.cert.pem").Remove()
280286
certDir.Join("ca.cert.cer").Remove()
281-
certDir.Join("ca.key.pem").Remove()
287+
certDir.Join("key.pem").Remove()
288+
certDir.Join("cert.pem").Remove()
289+
certDir.Join("cert.cer").Remove()
282290
}
283291

284292
const noFirefoxTemplateHTML = `<!DOCTYPE html>

0 commit comments

Comments
 (0)