From 67e1a9f186bac4d7a6be7d6e891ba44673f24b78 Mon Sep 17 00:00:00 2001 From: Daniel Adam Date: Wed, 24 Jan 2024 12:07:22 +0100 Subject: [PATCH] bridge: Add sign up unit tests --- bridge/device/cloud/manager.go | 62 ------------ bridge/device/cloud/requestsResponses.go | 17 ---- bridge/device/cloud/signUp.go | 121 +++++++++++++++++++++++ bridge/device/cloud/signUp_test.go | 40 ++++++++ 4 files changed, 161 insertions(+), 79 deletions(-) create mode 100644 bridge/device/cloud/signUp.go create mode 100644 bridge/device/cloud/signUp_test.go diff --git a/bridge/device/cloud/manager.go b/bridge/device/cloud/manager.go index 8cf1ba91..7bf66baf 100644 --- a/bridge/device/cloud/manager.go +++ b/bridge/device/cloud/manager.go @@ -346,68 +346,6 @@ func (c *Manager) dial(ctx context.Context) error { return nil } -func (c *Manager) newSignUpReq(ctx context.Context) (*pool.Message, error) { - cfg := c.getCloudConfiguration() - if cfg.AuthorizationCode == "" { - return nil, fmt.Errorf("cannot sign up: no authorization code") - } - if cfg.AuthorizationProvider == "" { - return nil, fmt.Errorf("cannot sign up: no authorization provider") - } - - signUpRequest := CoapSignUpRequest{ - DeviceID: c.deviceID.String(), - AuthorizationCode: cfg.AuthorizationCode, - AuthorizationProvider: cfg.AuthorizationProvider, - } - inputCbor, err := cbor.Encode(signUpRequest) - if err != nil { - return nil, err - } - req := c.client.AcquireMessage(ctx) - token, err := message.GetToken() - if err != nil { - return nil, err - } - req.SetCode(codes.POST) - req.SetToken(token) - err = req.SetPath(SignUp) - if err != nil { - return nil, err - } - req.SetContentFormat(message.AppOcfCbor) - req.SetBody(bytes.NewReader(inputCbor)) - return req, nil -} - -func (c *Manager) signUp(ctx context.Context) error { - creds := c.getCreds() - if creds.AccessToken != "" { - return nil - } - req, err := c.newSignUpReq(ctx) - if err != nil { - return fmt.Errorf("cannot sign up: %w", err) - } - c.setProvisioningStatus(cloud.ProvisioningStatus_REGISTERING) - resp, err := c.client.Do(req) - if err != nil { - return fmt.Errorf("cannot sign up: %w", err) - } - if resp.Code() != codes.Changed { - return fmt.Errorf("cannot sign up: unexpected status code %v", resp.Code()) - } - var signUpResp CoapSignUpResponse - err = cbor.ReadFrom(resp.Body(), &signUpResp) - if err != nil { - return fmt.Errorf("cannot sign up: %w", err) - } - c.setCreds(signUpResp) - log.Printf("signed up\n") - c.save() - return nil -} - func (c *Manager) newSignOffReq(ctx context.Context) (*pool.Message, error) { req := c.client.AcquireMessage(ctx) token, err := message.GetToken() diff --git a/bridge/device/cloud/requestsResponses.go b/bridge/device/cloud/requestsResponses.go index 22161f58..2108de7f 100644 --- a/bridge/device/cloud/requestsResponses.go +++ b/bridge/device/cloud/requestsResponses.go @@ -19,27 +19,10 @@ package cloud import ( - "time" - "github.com/plgd-dev/device/v2/schema" "github.com/plgd-dev/device/v2/schema/cloud" ) -type CoapSignUpRequest struct { - DeviceID string `json:"di"` - AuthorizationCode string `json:"accesstoken"` - AuthorizationProvider string `json:"authprovider"` -} - -type CoapSignUpResponse struct { - AccessToken string `yaml:"accessToken" json:"accesstoken"` - UserID string `yaml:"userID" json:"uid"` - RefreshToken string `yaml:"refreshToken" json:"refreshtoken"` - RedirectURI string `yaml:"-" json:"redirecturi"` - ExpiresIn int64 `yaml:"-" json:"expiresin"` - ValidUntil time.Time `yaml:"-" jsom:"-"` -} - type CoapSignInRequest struct { DeviceID string `json:"di"` UserID string `json:"uid"` diff --git a/bridge/device/cloud/signUp.go b/bridge/device/cloud/signUp.go new file mode 100644 index 00000000..17cc2f59 --- /dev/null +++ b/bridge/device/cloud/signUp.go @@ -0,0 +1,121 @@ +/**************************************************************************** + * + * Copyright (c) 2024 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 cloud + +import ( + "bytes" + "context" + "fmt" + "log" + "time" + + "github.com/plgd-dev/device/v2/pkg/codec/cbor" + "github.com/plgd-dev/device/v2/schema/cloud" + "github.com/plgd-dev/go-coap/v3/message" + "github.com/plgd-dev/go-coap/v3/message/codes" + "github.com/plgd-dev/go-coap/v3/message/pool" +) + +type CoapSignUpRequest struct { + DeviceID string `json:"di"` + AuthorizationCode string `json:"accesstoken"` + AuthorizationProvider string `json:"authprovider"` +} + +type CoapSignUpResponse struct { + AccessToken string `yaml:"accessToken" json:"accesstoken"` + UserID string `yaml:"userID" json:"uid"` + RefreshToken string `yaml:"refreshToken" json:"refreshtoken"` + RedirectURI string `yaml:"-" json:"redirecturi"` + ExpiresIn int64 `yaml:"-" json:"expiresin"` + ValidUntil time.Time `yaml:"-" jsom:"-"` +} + +var ( + ErrMissingAuthorizationCode = fmt.Errorf("authorization code missing") + ErrMissingAuthorizationProvider = fmt.Errorf("authorization provider missing") + ErrCannotSignUp = fmt.Errorf("cannot sign up") +) + +func MakeSignUpRequest(deviceID, code, provider string) (CoapSignUpRequest, error) { + if code == "" { + return CoapSignUpRequest{}, ErrMissingAuthorizationCode + } + if provider == "" { + return CoapSignUpRequest{}, ErrMissingAuthorizationProvider + } + + return CoapSignUpRequest{ + DeviceID: deviceID, + AuthorizationCode: code, + AuthorizationProvider: provider, + }, nil +} + +func setSignUpRequest(req *pool.Message, cfg Configuration, deviceID string) error { + signUpRequest, err := MakeSignUpRequest(deviceID, cfg.AuthorizationCode, cfg.AuthorizationProvider) + if err != nil { + return err + } + inputCbor, err := cbor.Encode(signUpRequest) + if err != nil { + return err + } + req.SetCode(codes.POST) + token, err := message.GetToken() + if err != nil { + return err + } + req.SetToken(token) + if err = req.SetPath(SignUp); err != nil { + return err + } + req.SetContentFormat(message.AppOcfCbor) + req.SetBody(bytes.NewReader(inputCbor)) + return nil +} + +func (c *Manager) signUp(ctx context.Context) error { + creds := c.getCreds() + if creds.AccessToken != "" { + return nil + } + req := c.client.AcquireMessage(ctx) + err := setSignUpRequest(req, c.getCloudConfiguration(), c.deviceID.String()) + if err != nil { + return fmt.Errorf("%w: %w", ErrCannotSignUp, err) + } + c.setProvisioningStatus(cloud.ProvisioningStatus_REGISTERING) + resp, err := c.client.Do(req) + if err != nil { + return fmt.Errorf("%w: %w", ErrCannotSignUp, err) + } + if resp.Code() != codes.Changed { + return fmt.Errorf("%w: unexpected status code %v", ErrCannotSignUp, resp.Code()) + } + var signUpResp CoapSignUpResponse + err = cbor.ReadFrom(resp.Body(), &signUpResp) + if err != nil { + return fmt.Errorf("%w: %w", ErrCannotSignUp, err) + } + c.setCreds(signUpResp) + log.Printf("signed up\n") + c.save() + return nil +} diff --git a/bridge/device/cloud/signUp_test.go b/bridge/device/cloud/signUp_test.go new file mode 100644 index 00000000..123d0b64 --- /dev/null +++ b/bridge/device/cloud/signUp_test.go @@ -0,0 +1,40 @@ +/**************************************************************************** + * + * Copyright (c) 2024 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 cloud_test + +import ( + "testing" + + "github.com/plgd-dev/device/v2/bridge/device/cloud" + "github.com/stretchr/testify/require" +) + +func TestMakeSignUpRequest(t *testing.T) { + _, err := cloud.MakeSignUpRequest("id", "", "provider") + require.ErrorIs(t, err, cloud.ErrMissingAuthorizationCode) + + _, err = cloud.MakeSignUpRequest("id", "code", "") + require.ErrorIs(t, err, cloud.ErrMissingAuthorizationProvider) + + req, err := cloud.MakeSignUpRequest("id", "code", "provider") + require.NoError(t, err) + require.Equal(t, "id", req.DeviceID) + require.Equal(t, "code", req.AuthorizationCode) + require.Equal(t, "provider", req.AuthorizationProvider) +}