Skip to content

Commit 16f4135

Browse files
authored
Check gpg signature for library_index.json (#1307)
* Download gzipped version of the library index * Check gpg signature for library_index.json * Update docs/UPGRADING.md
1 parent 93ae80c commit 16f4135

File tree

6 files changed

+91
-26
lines changed

6 files changed

+91
-26
lines changed

Diff for: arduino/libraries/librariesmanager/download.go

+6-9
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,13 @@ package librariesmanager
1717

1818
import (
1919
"net/url"
20-
21-
"go.bug.st/downloader/v2"
2220
)
2321

24-
// LibraryIndexURL is the URL where to get library index.
22+
// LibraryIndexURL is the URL where to get the library index.
2523
var LibraryIndexURL, _ = url.Parse("https://downloads.arduino.cc/libraries/library_index.json")
2624

27-
// UpdateIndex downloads the libraries index file from Arduino repository.
28-
func (lm *LibrariesManager) UpdateIndex(config *downloader.Config) (*downloader.Downloader, error) {
29-
lm.IndexFile.Parent().MkdirAll()
30-
// TODO: Download from gzipped URL index
31-
return downloader.DownloadWithConfig(lm.IndexFile.String(), LibraryIndexURL.String(), *config, downloader.NoResume)
32-
}
25+
// LibraryIndexGZURL is the URL where to get the gzipped library index.
26+
var LibraryIndexGZURL, _ = url.Parse("https://downloads.arduino.cc/libraries/library_index.json.gz")
27+
28+
// LibraryIndexSignature is the URL where to get the library index signature.
29+
var LibraryIndexSignature, _ = url.Parse("https://downloads.arduino.cc/libraries/library_index.json.sig")

Diff for: arduino/libraries/librariesmanager/librariesmanager.go

+11-8
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@ type LibrariesManager struct {
3535
LibrariesDir []*LibrariesDir
3636
Libraries map[string]*LibraryAlternatives `json:"libraries"`
3737

38-
Index *librariesindex.Index
39-
IndexFile *paths.Path
40-
DownloadsDir *paths.Path
38+
Index *librariesindex.Index
39+
IndexFile *paths.Path
40+
IndexFileSignature *paths.Path
41+
DownloadsDir *paths.Path
4142
}
4243

4344
// LibrariesDir is a directory containing libraries
@@ -95,15 +96,17 @@ func (lm LibrariesManager) Names() []string {
9596

9697
// NewLibraryManager creates a new library manager
9798
func NewLibraryManager(indexDir *paths.Path, downloadsDir *paths.Path) *LibrariesManager {
98-
var indexFile *paths.Path
99+
var indexFile, indexFileSignature *paths.Path
99100
if indexDir != nil {
100101
indexFile = indexDir.Join("library_index.json")
102+
indexFileSignature = indexDir.Join("library_index.json.sig")
101103
}
102104
return &LibrariesManager{
103-
Libraries: map[string]*LibraryAlternatives{},
104-
IndexFile: indexFile,
105-
DownloadsDir: downloadsDir,
106-
Index: librariesindex.EmptyIndex,
105+
Libraries: map[string]*LibraryAlternatives{},
106+
IndexFile: indexFile,
107+
IndexFileSignature: indexFileSignature,
108+
DownloadsDir: downloadsDir,
109+
Index: librariesindex.EmptyIndex,
107110
}
108111
}
109112

Diff for: commands/instances.go

+53-5
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ package commands
1717

1818
import (
1919
"context"
20-
"errors"
2120
"fmt"
2221
"io/ioutil"
2322
"net/url"
@@ -37,6 +36,7 @@ import (
3736
"github.com/arduino/arduino-cli/configuration"
3837
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
3938
paths "github.com/arduino/go-paths-helper"
39+
"github.com/pkg/errors"
4040
"github.com/sirupsen/logrus"
4141
"go.bug.st/downloader/v2"
4242
)
@@ -179,14 +179,62 @@ func UpdateLibrariesIndex(ctx context.Context, req *rpc.UpdateLibrariesIndexRequ
179179
if err != nil {
180180
return err
181181
}
182-
d, err := lm.UpdateIndex(config)
182+
183+
if err := lm.IndexFile.Parent().MkdirAll(); err != nil {
184+
return err
185+
}
186+
187+
// Create a temp dir to stage all downloads
188+
tmp, err := paths.MkTempDir("", "library_index_download")
183189
if err != nil {
184190
return err
185191
}
186-
Download(d, "Updating index: library_index.json", downloadCB)
187-
if d.Error() != nil {
188-
return d.Error()
192+
defer tmp.RemoveAll()
193+
194+
// Download gzipped library_index
195+
tmpIndexGz := tmp.Join("library_index.json.gz")
196+
if d, err := downloader.DownloadWithConfig(tmpIndexGz.String(), librariesmanager.LibraryIndexGZURL.String(), *config, downloader.NoResume); err == nil {
197+
if err := Download(d, "Updating index: library_index.json.gz", downloadCB); err != nil {
198+
return errors.Wrap(err, "downloading library_index.json.gz")
199+
}
200+
} else {
201+
return err
189202
}
203+
204+
// Download signature
205+
tmpSignature := tmp.Join("library_index.json.sig")
206+
if d, err := downloader.DownloadWithConfig(tmpSignature.String(), librariesmanager.LibraryIndexSignature.String(), *config, downloader.NoResume); err == nil {
207+
if err := Download(d, "Updating index: library_index.json.sig", downloadCB); err != nil {
208+
return errors.Wrap(err, "downloading library_index.json.sig")
209+
}
210+
} else {
211+
return err
212+
}
213+
214+
// Extract the real library_index
215+
tmpIndex := tmp.Join("library_index.json")
216+
if err := paths.GUnzip(tmpIndexGz, tmpIndex); err != nil {
217+
return errors.Wrap(err, "unzipping library_index.json.gz")
218+
}
219+
220+
// Check signature
221+
if ok, _, err := security.VerifyArduinoDetachedSignature(tmpIndex, tmpSignature); err != nil {
222+
return errors.Wrap(err, "verifying signature")
223+
} else if !ok {
224+
return errors.New("library_index.json has an invalid signature")
225+
}
226+
227+
// Copy extracted library_index and signature to final destination
228+
lm.IndexFile.Remove()
229+
lm.IndexFileSignature.Remove()
230+
if err := tmpIndex.CopyTo(lm.IndexFile); err != nil {
231+
return errors.Wrap(err, "writing library_index.json")
232+
}
233+
if err := tmpSignature.CopyTo(lm.IndexFileSignature); err != nil {
234+
return errors.Wrap(err, "writing library_index.json.sig")
235+
}
236+
237+
// Rescan libraries
190238
if _, err := Rescan(req.GetInstance().GetId()); err != nil {
191239
return fmt.Errorf("rescanning filesystem: %s", err)
192240
}

Diff for: docs/UPGRADING.md

+12
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@
22

33
Here you can find a list of migration guides to handle breaking changes between releases of the CLI.
44

5+
## Unreleased
6+
7+
### Removed rarely used golang API
8+
9+
The following function from the `github.com/arduino/arduino-cli/arduino/libraries` module is no longer available:
10+
11+
```go
12+
func (lm *LibrariesManager) UpdateIndex(config *downloader.Config) (*downloader.Downloader, error) {
13+
```
14+
15+
We recommend using the equivalent gRPC API to perform the update of the index.
16+
517
## 0.18.0
618
719
### Breaking changes in gRPC API and CLI JSON output.

Diff for: test/test_lib.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,9 @@ def test_install_with_zip_path(run_command, data_dir, downloads_dir):
404404
def test_update_index(run_command):
405405
result = run_command("lib update-index")
406406
assert result.ok
407-
assert "Updating index: library_index.json downloaded" == result.stdout.splitlines()[-1].strip()
407+
lines = [l.strip() for l in result.stdout.splitlines()]
408+
assert "Updating index: library_index.json.gz downloaded" in lines
409+
assert "Updating index: library_index.json.sig downloaded" in lines
408410

409411

410412
def test_uninstall(run_command):
@@ -454,7 +456,8 @@ def test_search(run_command):
454456
result = run_command("lib search --names")
455457
assert result.ok
456458
lines = [l.strip() for l in result.stdout.strip().splitlines()]
457-
assert "Updating index: library_index.json downloaded" in lines
459+
assert "Updating index: library_index.json.gz downloaded" in lines
460+
assert "Updating index: library_index.json.sig downloaded" in lines
458461
libs = [l[6:].strip('"') for l in lines if "Name:" in l]
459462

460463
expected = {"WiFi101", "WiFi101OTA", "Firebase Arduino based on WiFi101"}

Diff for: test/test_update.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ def test_update(run_command):
2323

2424
assert "Updating index: package_index.json downloaded" in lines
2525
assert "Updating index: package_index.json.sig downloaded" in lines
26-
assert "Updating index: library_index.json downloaded" in lines
26+
assert "Updating index: library_index.json.gz downloaded" in lines
27+
assert "Updating index: library_index.json.sig downloaded" in lines
2728

2829

2930
def test_update_showing_outdated(run_command):
@@ -46,7 +47,8 @@ def test_update_showing_outdated(run_command):
4647

4748
assert "Updating index: package_index.json downloaded" in lines
4849
assert "Updating index: package_index.json.sig downloaded" in lines
49-
assert "Updating index: library_index.json downloaded" in lines
50+
assert "Updating index: library_index.json.gz downloaded" in lines
51+
assert "Updating index: library_index.json.sig downloaded" in lines
5052
assert lines[-5].startswith("Arduino AVR Boards")
5153
assert lines[-2].startswith("USBHost")
5254

0 commit comments

Comments
 (0)