Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check gpg signature for library_index.json #1307

Merged
merged 6 commits into from
Jun 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions arduino/libraries/librariesmanager/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,13 @@ package librariesmanager

import (
"net/url"

"go.bug.st/downloader/v2"
)

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

// UpdateIndex downloads the libraries index file from Arduino repository.
func (lm *LibrariesManager) UpdateIndex(config *downloader.Config) (*downloader.Downloader, error) {
cmaglie marked this conversation as resolved.
Show resolved Hide resolved
lm.IndexFile.Parent().MkdirAll()
// TODO: Download from gzipped URL index
return downloader.DownloadWithConfig(lm.IndexFile.String(), LibraryIndexURL.String(), *config, downloader.NoResume)
}
// LibraryIndexGZURL is the URL where to get the gzipped library index.
var LibraryIndexGZURL, _ = url.Parse("https://downloads.arduino.cc/libraries/library_index.json.gz")

// LibraryIndexSignature is the URL where to get the library index signature.
var LibraryIndexSignature, _ = url.Parse("https://downloads.arduino.cc/libraries/library_index.json.sig")
19 changes: 11 additions & 8 deletions arduino/libraries/librariesmanager/librariesmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ type LibrariesManager struct {
LibrariesDir []*LibrariesDir
Libraries map[string]*LibraryAlternatives `json:"libraries"`

Index *librariesindex.Index
IndexFile *paths.Path
DownloadsDir *paths.Path
Index *librariesindex.Index
IndexFile *paths.Path
IndexFileSignature *paths.Path
DownloadsDir *paths.Path
}

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

// NewLibraryManager creates a new library manager
func NewLibraryManager(indexDir *paths.Path, downloadsDir *paths.Path) *LibrariesManager {
var indexFile *paths.Path
var indexFile, indexFileSignature *paths.Path
if indexDir != nil {
indexFile = indexDir.Join("library_index.json")
indexFileSignature = indexDir.Join("library_index.json.sig")
}
return &LibrariesManager{
Libraries: map[string]*LibraryAlternatives{},
IndexFile: indexFile,
DownloadsDir: downloadsDir,
Index: librariesindex.EmptyIndex,
Libraries: map[string]*LibraryAlternatives{},
IndexFile: indexFile,
IndexFileSignature: indexFileSignature,
DownloadsDir: downloadsDir,
Index: librariesindex.EmptyIndex,
}
}

Expand Down
58 changes: 53 additions & 5 deletions commands/instances.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ package commands

import (
"context"
"errors"
"fmt"
"io/ioutil"
"net/url"
Expand All @@ -37,6 +36,7 @@ import (
"github.com/arduino/arduino-cli/configuration"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
paths "github.com/arduino/go-paths-helper"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"go.bug.st/downloader/v2"
)
Expand Down Expand Up @@ -179,14 +179,62 @@ func UpdateLibrariesIndex(ctx context.Context, req *rpc.UpdateLibrariesIndexRequ
if err != nil {
return err
}
d, err := lm.UpdateIndex(config)

if err := lm.IndexFile.Parent().MkdirAll(); err != nil {
return err
}

// Create a temp dir to stage all downloads
tmp, err := paths.MkTempDir("", "library_index_download")
if err != nil {
return err
}
Download(d, "Updating index: library_index.json", downloadCB)
if d.Error() != nil {
return d.Error()
defer tmp.RemoveAll()

// Download gzipped library_index
tmpIndexGz := tmp.Join("library_index.json.gz")
if d, err := downloader.DownloadWithConfig(tmpIndexGz.String(), librariesmanager.LibraryIndexGZURL.String(), *config, downloader.NoResume); err == nil {
if err := Download(d, "Updating index: library_index.json.gz", downloadCB); err != nil {
return errors.Wrap(err, "downloading library_index.json.gz")
}
} else {
return err
}

// Download signature
tmpSignature := tmp.Join("library_index.json.sig")
if d, err := downloader.DownloadWithConfig(tmpSignature.String(), librariesmanager.LibraryIndexSignature.String(), *config, downloader.NoResume); err == nil {
if err := Download(d, "Updating index: library_index.json.sig", downloadCB); err != nil {
return errors.Wrap(err, "downloading library_index.json.sig")
}
} else {
return err
}

// Extract the real library_index
tmpIndex := tmp.Join("library_index.json")
if err := paths.GUnzip(tmpIndexGz, tmpIndex); err != nil {
return errors.Wrap(err, "unzipping library_index.json.gz")
}

// Check signature
if ok, _, err := security.VerifyArduinoDetachedSignature(tmpIndex, tmpSignature); err != nil {
return errors.Wrap(err, "verifying signature")
} else if !ok {
return errors.New("library_index.json has an invalid signature")
}

// Copy extracted library_index and signature to final destination
lm.IndexFile.Remove()
lm.IndexFileSignature.Remove()
if err := tmpIndex.CopyTo(lm.IndexFile); err != nil {
return errors.Wrap(err, "writing library_index.json")
}
if err := tmpSignature.CopyTo(lm.IndexFileSignature); err != nil {
return errors.Wrap(err, "writing library_index.json.sig")
}

// Rescan libraries
if _, err := Rescan(req.GetInstance().GetId()); err != nil {
return fmt.Errorf("rescanning filesystem: %s", err)
}
Expand Down
12 changes: 12 additions & 0 deletions docs/UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

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

## Unreleased

### Removed rarely used golang API

The following function from the `github.com/arduino/arduino-cli/arduino/libraries` module is no longer available:

```go
func (lm *LibrariesManager) UpdateIndex(config *downloader.Config) (*downloader.Downloader, error) {
```

We recommend using the equivalent gRPC API to perform the update of the index.

## 0.18.0

### Breaking changes in gRPC API and CLI JSON output.
Expand Down
7 changes: 5 additions & 2 deletions test/test_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,9 @@ def test_install_with_zip_path(run_command, data_dir, downloads_dir):
def test_update_index(run_command):
result = run_command("lib update-index")
assert result.ok
assert "Updating index: library_index.json downloaded" == result.stdout.splitlines()[-1].strip()
lines = [l.strip() for l in result.stdout.splitlines()]
assert "Updating index: library_index.json.gz downloaded" in lines
assert "Updating index: library_index.json.sig downloaded" in lines


def test_uninstall(run_command):
Expand Down Expand Up @@ -454,7 +456,8 @@ def test_search(run_command):
result = run_command("lib search --names")
assert result.ok
lines = [l.strip() for l in result.stdout.strip().splitlines()]
assert "Updating index: library_index.json downloaded" in lines
assert "Updating index: library_index.json.gz downloaded" in lines
assert "Updating index: library_index.json.sig downloaded" in lines
libs = [l[6:].strip('"') for l in lines if "Name:" in l]

expected = {"WiFi101", "WiFi101OTA", "Firebase Arduino based on WiFi101"}
Expand Down
6 changes: 4 additions & 2 deletions test/test_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ def test_update(run_command):

assert "Updating index: package_index.json downloaded" in lines
assert "Updating index: package_index.json.sig downloaded" in lines
assert "Updating index: library_index.json downloaded" in lines
assert "Updating index: library_index.json.gz downloaded" in lines
assert "Updating index: library_index.json.sig downloaded" in lines


def test_update_showing_outdated(run_command):
Expand All @@ -46,7 +47,8 @@ def test_update_showing_outdated(run_command):

assert "Updating index: package_index.json downloaded" in lines
assert "Updating index: package_index.json.sig downloaded" in lines
assert "Updating index: library_index.json downloaded" in lines
assert "Updating index: library_index.json.gz downloaded" in lines
assert "Updating index: library_index.json.sig downloaded" in lines
assert lines[-5].startswith("Arduino AVR Boards")
assert lines[-2].startswith("USBHost")

Expand Down