Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: plgd-dev/device
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v2.0.1
Choose a base ref
...
head repository: plgd-dev/device
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v2.0.2
Choose a head ref
  • 11 commits
  • 21 files changed
  • 2 contributors

Commits on Nov 10, 2022

  1. Copy the full SHA
    b072bc1 View commit details

Commits on Nov 11, 2022

  1. Add FindDeviceAddress function to test package

    Danielius1922 authored and Daniel Adam committed Nov 11, 2022
    Copy the full SHA
    4f16439 View commit details

Commits on Nov 15, 2022

  1. Add FindDeviceEndpoints function to test package

    Danielius1922 authored and Daniel Adam committed Nov 15, 2022
    Copy the full SHA
    3e7fb46 View commit details

Commits on Nov 30, 2022

  1. Copy the full SHA
    badce86 View commit details

Commits on Dec 2, 2022

  1. Upgrade dependencies

    Direct:
    github.com/golang-jwt/jwt/v4 v4.4.3
    github.com/plgd-dev/go-coap/v3 v3.0.1
    google.golang.org/grpc v1.51.0
    
    Indirect:
    github.com/pion/transport v0.14.1
    go.uber.org/zap v1.24.0
    golang.org/x/crypto v0.3.0
    golang.org/x/exp v0.0.0-20221126150942-6ab00d035af9
    golang.org/x/net v0.2.0
    golang.org/x/sys v0.2.0
    google.golang.org/genproto v0.0.0-20221130183247-a2ec334bae6f
    Danielius1922 authored and Daniel Adam committed Dec 2, 2022
    Copy the full SHA
    c8b6cfb View commit details
  2. Add TestDeviceGetResourcesIterator test case

    Danielius1922 authored and Daniel Adam committed Dec 2, 2022
    Copy the full SHA
    f9f57f7 View commit details

Commits on Dec 7, 2022

  1. getDevice/getDevices: for UnknownAuthorityError sets ownedByOther to …

    …ownership status (#323)
    
    * getDevice/getDevices: for UnknownAuthorityError sets ownedByOther to ownership status
    jkralik committed Dec 7, 2022
    Copy the full SHA
    16146ad View commit details

Commits on Dec 19, 2022

  1. Copy the full SHA
    68ae442 View commit details

Commits on Jan 9, 2023

  1. Update dependencies

    Direct:
    github.com/pion/dtls/v2 v2.1.6-0.20230104045405-f40c61d83b5f
    github.com/plgd-dev/go-coap/v3 v3.0.2-0.20230109094200-ac1d6381a9ba
    github.com/ugorji/go/codec v1.2.8
    
    Indirect:
    github.com/hashicorp/errwrap v1.1.0
    github.com/pion/udp v0.1.2-0.20221201030934-a2465bb5d508
    go.uber.org/multierr v1.9.0
    golang.org/x/crypto v0.5.0
    golang.org/x/exp v0.0.0-20230108222341-4b8118a2686a
    golang.org/x/net v0.5.0
    golang.org/x/sys v0.4.0
    google.golang.org/genproto v0.0.0-20230106154932-a12b697841d9
    Danielius1922 authored and Daniel Adam committed Jan 9, 2023
    Copy the full SHA
    45415c6 View commit details
  2. Copy the full SHA
    440fb9a View commit details
  3. update go-coap to v3.0.2

    jkralik committed Jan 9, 2023
    Copy the full SHA
    d3d7622 View commit details
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -49,7 +49,7 @@ env: clean certificates
unit-test:
mkdir -p $(TMP_PATH)
go test -race -v ./schema/... -covermode=atomic -coverprofile=$(TMP_PATH)/schema.coverage.txt
go test -race -v ./pkg/... -covermode=atomic -coverprofile=$(TMP_PATH)/pkg.coverage.txt
ROOT_CA_CRT="$(CERT_PATH)/cloudca.pem" ROOT_CA_KEY="$(CERT_PATH)/cloudcakey.pem" go test -race -v ./pkg/... -covermode=atomic -coverprofile=$(TMP_PATH)/pkg.coverage.txt

test: env build-testcontainer
docker run \
51 changes: 40 additions & 11 deletions client/client_test.go
Original file line number Diff line number Diff line change
@@ -18,16 +18,20 @@ package client_test

import (
"context"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/tls"
"crypto/x509"
"encoding/pem"
"fmt"
"testing"
"time"

"github.com/pion/logging"
"github.com/plgd-dev/device/v2/client"
"github.com/plgd-dev/device/v2/client/core"
"github.com/plgd-dev/device/v2/test"
"github.com/plgd-dev/kit/v2/security/generateCertificate"
"github.com/stretchr/testify/require"
)

@@ -61,6 +65,40 @@ func (c *testSetupSecureClient) GetRootCertificateAuthorities() ([]*x509.Certifi
}

func NewTestSecureClient() (*client.Client, error) {
return newTestSecureClient(test.IdentityIntermediateCA, test.IdentityIntermediateCAKey)
}

func NewTestSecureClientWithGeneratedCertificate() (*client.Client, error) {
var cfgCA generateCertificate.Configuration
cfgCA.Subject.CommonName = "anotherClient"
cfgCA.ValidFrom = "now"
cfgCA.ValidFor = time.Hour

priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return nil, fmt.Errorf("cannot generate private key: %w", err)
}
cert, err := generateCertificate.GenerateRootCA(cfgCA, priv)
if err != nil {
return nil, fmt.Errorf("cannot generate root ca: %w", err)
}
derKey, err := x509.MarshalECPrivateKey(priv)
if err != nil {
return nil, fmt.Errorf("cannot marhsal private key: %w", err)
}
key := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: derKey})
return newTestSecureClient(cert, key)
}

func newTestSecureClient(signerCert, signerKey []byte) (*client.Client, error) {
cfg := client.Config{
DeviceOwnershipSDK: &client.DeviceOwnershipSDKConfig{
ID: CertIdentity,
Cert: string(signerCert),
CertKey: string(signerKey),
CreateSignerFunc: test.NewIdentityCertificateSigner,
},
}
mfgTrustedCABlock, _ := pem.Decode(test.RootCACrt)
if mfgTrustedCABlock == nil {
return nil, fmt.Errorf("mfgTrustedCABlock is empty")
@@ -73,19 +111,11 @@ func NewTestSecureClient() (*client.Client, error) {
if err != nil {
return nil, fmt.Errorf("cannot X509KeyPair: %w", err)
}
cfg := client.Config{
DeviceOwnershipSDK: &client.DeviceOwnershipSDKConfig{
ID: CertIdentity,
Cert: string(test.IdentityIntermediateCA),
CertKey: string(test.IdentityIntermediateCAKey),
CreateSignerFunc: test.NewIdentityCertificateSigner,
},
}

client, err := client.NewClientFromConfig(&cfg, &testSetupSecureClient{
mfgCA: mfgCA,
mfgCert: mfgCert,
}, logging.NewDefaultLoggerFactory().NewLogger("test"),
}, core.NewNilLogger(),
)
if err != nil {
return nil, err
@@ -94,7 +124,6 @@ func NewTestSecureClient() (*client.Client, error) {
if err != nil {
return nil, err
}

return client, nil
}

19 changes: 10 additions & 9 deletions client/core/device.go
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@ import (
"sync"
"sync/atomic"

"github.com/hashicorp/go-multierror"
"github.com/pion/dtls/v2"
"github.com/plgd-dev/device/v2/pkg/net/coap"
"github.com/plgd-dev/device/v2/schema"
@@ -186,21 +187,21 @@ func (d *Device) popConnections() []*conn {

// Close closes open connections to the device.
func (d *Device) Close(ctx context.Context) error {
var errs []error
var errs *multierror.Error
if err := d.closeObservations(ctx); err != nil {
errs = append(errs, err)
errs = multierror.Append(errs, err)
}

for _, conn := range d.popConnections() {
if errC := conn.Close(); errC != nil && !errors.Is(errC, goNet.ErrClosed) {
errs = append(errs, errC)
errs = multierror.Append(errs, errC)
}
// wait for closing socket
<-conn.Done()
}

if len(errs) > 0 {
return MakeInternal(fmt.Errorf("cannot close device %v: %v", d.DeviceID(), errs))
if errs.ErrorOrNil() != nil {
return MakeInternal(fmt.Errorf("cannot close device %v: %w", d.DeviceID(), errs))
}
return nil
}
@@ -328,18 +329,18 @@ func (d *Device) connectToEndpoint(ctx context.Context, endpoint schema.Endpoint
}

func (d *Device) connectToEndpoints(ctx context.Context, endpoints schema.Endpoints) (net.Addr, *coap.ClientCloseHandler, error) {
errors := make([]error, 0, 4)
var errors *multierror.Error

for _, endpoint := range endpoints {
addr, conn, err := d.connectToEndpoint(ctx, endpoint)
if err != nil {
errors = append(errors, err)
errors = multierror.Append(errors, err)
continue
}
return addr, conn, nil
}
if len(errors) > 0 {
return net.Addr{}, nil, fmt.Errorf("%v", errors)
if errors.ErrorOrNil() != nil {
return net.Addr{}, nil, errors
}
return net.Addr{}, nil, MakeInternal(fmt.Errorf("cannot connect to empty endpoints"))
}
82 changes: 82 additions & 0 deletions client/core/getResource_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// ************************************************************************
// Copyright (C) 2022 plgd.dev, s.r.o.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ************************************************************************

package core_test

import (
"context"
"testing"
"time"

"github.com/plgd-dev/device/v2/schema"
"github.com/plgd-dev/device/v2/schema/device"
"github.com/plgd-dev/device/v2/schema/platform"
"github.com/plgd-dev/device/v2/test"
"github.com/stretchr/testify/require"
)

func TestDeviceGetResourcesIterator(t *testing.T) {
ip := test.MustFindDeviceIP(test.DevsimName, test.IP4)
c, err := NewTestSecureClient()
require.NoError(t, err)
defer func() {
errC := c.Close()
require.NoError(t, errC)
}()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()

dev, err := c.GetDeviceByIP(ctx, ip)
require.NoError(t, err)
require.NotEmpty(t, dev)
allLinks, err := dev.GetResourceLinks(ctx, dev.GetEndpoints())
require.NoError(t, err)

// get some public resources only, so we don't have to own
var links schema.ResourceLinks
for _, link := range allLinks {
if link.Href == platform.ResourceURI ||
link.Href == device.ResourceURI {
links = append(links, link)
}
}
it := dev.GetResources(ctx, links)
require.NotEmpty(t, it)

var p platform.Platform
var d device.Device
i := 0
for {
var v interface{}
if i < len(links) {
if links[i].Href == platform.ResourceURI {
v = &p
}
if links[i].Href == device.ResourceURI {
v = &d
}
}

if !it.Next(ctx, v) {
break
}
i++
}
require.NoError(t, it.Err)
require.Equal(t, len(links), i)
require.NotEqual(t, platform.Platform{}, p)
require.NotEqual(t, device.Device{}, d)
}
9 changes: 5 additions & 4 deletions client/core/getSdkOwnerID.go
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@ import (
"crypto/x509"
"fmt"

"github.com/hashicorp/go-multierror"
"github.com/plgd-dev/device/v2/pkg/net/coap"
)

@@ -36,22 +37,22 @@ func getSdkOwnerID(getCertificate GetCertificateFunc) (string, error) {
return "", MakeInternal(getSdkError(err))
}

var errors []error
var errors *multierror.Error

for _, c := range cert.Certificate {
x509cert, err := x509.ParseCertificate(c)
if err != nil {
errors = append(errors, err)
errors = multierror.Append(errors, err)
continue
}
id, err := coap.GetDeviceIDFromIdentityCertificate(x509cert)
if err != nil {
errors = append(errors, err)
errors = multierror.Append(errors, err)
continue
}
return id, nil
}
return "", MakeInternal(fmt.Errorf("cannot get sdk id: %v", errors))
return "", MakeInternal(fmt.Errorf("cannot get sdk id: %w", errors))
}

// GetSdkOwnerID returns sdk ownerID from sdk identity certificate.
10 changes: 4 additions & 6 deletions client/core/observeResource.go
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@ import (
"sync"

"github.com/google/uuid"
"github.com/hashicorp/go-multierror"
"github.com/plgd-dev/device/v2/pkg/codec/ocf"
"github.com/plgd-dev/device/v2/pkg/net/coap"
"github.com/plgd-dev/device/v2/schema"
@@ -91,17 +92,14 @@ func (d *Device) closeObservations(ctx context.Context) error {
obs = append(obs, observationID)
return false
})
var errors []error
var errors *multierror.Error
for _, observationID := range obs {
_, err := d.stopObservingResource(ctx, observationID, true)
if err != nil {
errors = append(errors, err)
errors = multierror.Append(errors, err)
}
}
if len(errors) > 0 {
return MakeInternal(fmt.Errorf("%v", errors))
}
return nil
return errors.ErrorOrNil()
}

type observation struct {
14 changes: 7 additions & 7 deletions client/core/ownDevice.go
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@ import (
"time"

"github.com/google/uuid"
"github.com/hashicorp/go-multierror"
"github.com/pion/dtls/v2"
"github.com/plgd-dev/device/v2/client/core/otm"
"github.com/plgd-dev/device/v2/pkg/net/coap"
@@ -280,25 +281,25 @@ func (d *Device) setDoxmDeviceID(ctx context.Context, cc *coap.ClientCloseHandle
}

func getTLSClient(ctx context.Context, links schema.ResourceLinks, otmClient otm.Client) (*coap.ClientCloseHandler, kitNet.Addr, error) {
var errors []error
var errors *multierror.Error
for _, link := range links {
if addr, err := link.GetUDPSecureAddr(); err == nil {
tlsClient, err := otmClient.Dial(ctx, addr)
if err == nil {
return tlsClient, addr, nil
}
errors = append(errors, fmt.Errorf("cannot connect to %v: %w", addr.URL(), err))
errors = multierror.Append(errors, fmt.Errorf("cannot connect to %v: %w", addr.URL(), err))
}
if addr, err := link.GetTCPSecureAddr(); err == nil {
tlsClient, err := otmClient.Dial(ctx, addr)
if err == nil {
return tlsClient, addr, nil
}
errors = append(errors, fmt.Errorf("cannot connect to %v: %w", addr.URL(), err))
errors = multierror.Append(errors, fmt.Errorf("cannot connect to %v: %w", addr.URL(), err))
}
}
if len(errors) != 0 {
return nil, kitNet.Addr{}, fmt.Errorf("%+v", errors)
if errors.ErrorOrNil() != nil {
return nil, kitNet.Addr{}, errors
}
return nil, kitNet.Addr{}, fmt.Errorf("not found")
}
@@ -543,8 +544,7 @@ func (d deviceConfigurer) configure(ctx context.Context, links schema.ResourceLi

// Own set ownership of device. For owning, the first match in order of otmClients with the device will be used.
// Note: In case if the device fails before changing RFOTM the iotivity-stack invokes disown by itself. This can result
//
// in a state where the disown is invoked two times in a row. Once by the iotivity-stack and second time by device core.
// in a state where the disown is invoked two times in a row. Once by the iotivity-stack and second time by device core.
func (d *Device) Own(
ctx context.Context,
links schema.ResourceLinks,
4 changes: 2 additions & 2 deletions client/core/provisionDevice_test.go
Original file line number Diff line number Diff line change
@@ -116,8 +116,8 @@ func TestSettingCloudResource(t *testing.T) {
require.NoError(t, err)

defer func() {
err = pc.Close(context.Background())
require.NoError(t, err)
errC := pc.Close(context.Background())
require.NoError(t, errC)
}()

require.NoError(t, pc.SetAccessControl(context.Background(), acl.AllPermissions, acl.TLSConnection, acl.AllResources...))
10 changes: 4 additions & 6 deletions client/deviceCache.go
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@ import (
"fmt"
"time"

"github.com/hashicorp/go-multierror"
"github.com/plgd-dev/device/v2/client/core"
"github.com/plgd-dev/go-coap/v3/pkg/cache"
"go.uber.org/atomic"
@@ -210,19 +211,16 @@ func (c *DeviceCache) LoadAndDeleteDevices(deviceIDFilter []string) []*core.Devi
}

func (c *DeviceCache) Close(ctx context.Context) error {
var errors []error
var errors *multierror.Error
if c.closed.CompareAndSwap(false, true) {
close(c.done)
}
for _, val := range c.devicesCache.LoadAndDeleteAll() {
err := val.Data().Close(ctx)
if err != nil {
errors = append(errors, err)
errors = multierror.Append(errors, err)
}
}

if len(errors) > 0 {
return fmt.Errorf("%v", errors)
}
return nil
return errors.ErrorOrNil()
}
Loading