From 44efa194fc5f9275322d46162d579d48aff3dc80 Mon Sep 17 00:00:00 2001 From: Senad Uka Date: Thu, 19 Oct 2023 07:57:48 +0200 Subject: [PATCH] upstream sync --- controllers/contracts_controller.go | 2 +- controllers/devices_controller.go | 41 +++++++++++++++++++++--- database/contract/contract.go | 49 +++++++++++++++++++++++++++-- services/blockchain/service.go | 6 ++-- shared/encryption.go | 7 +++++ 5 files changed, 93 insertions(+), 12 deletions(-) diff --git a/controllers/contracts_controller.go b/controllers/contracts_controller.go index 467d5f7..98d3750 100644 --- a/controllers/contracts_controller.go +++ b/controllers/contracts_controller.go @@ -248,7 +248,7 @@ func GetContractByID(c *gin.Context) { } // Fetch contract - contract, st, err := contract.GetContractByID(contractID) + contract, st, err := contract.GetContractByID(uint(contractID)) if err != nil { c.JSON(st, gin.H{"error": err.Error()}) return diff --git a/controllers/devices_controller.go b/controllers/devices_controller.go index 0e00d9b..efd92bf 100644 --- a/controllers/devices_controller.go +++ b/controllers/devices_controller.go @@ -1,17 +1,22 @@ package controllers import ( + "context" "encoding/json" "errors" "log" + "math/big" "net/http" "strconv" + "time" "github.com/gin-gonic/gin" "github.com/jinzhu/gorm" + "gitlab.com/pactual1/backend/config" "gitlab.com/pactual1/backend/database/contract" "gitlab.com/pactual1/backend/database/device" "gitlab.com/pactual1/backend/models" + "gitlab.com/pactual1/backend/services/blockchain" "gitlab.com/pactual1/backend/shared" ) @@ -37,18 +42,18 @@ func SaveDeviceInfo(c *gin.Context) { if err := shared.GetDb().Unscoped().Where("device_id = ?", deviceInfo.ExternalDeviceID).First(&device).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { // Create new device - newDevice := models.Device{ + device = models.Device{ IMEI: deviceInfo.IMEI, IMSI: deviceInfo.IMSI, DeviceID: deviceInfo.ExternalDeviceID, DeviceConfiguration: string(rawData), } - if err := shared.GetDb().Create(&newDevice).Error; err != nil { + if err := shared.GetDb().Create(&device).Error; err != nil { log.Printf("CREATE -Device DB Error: %v", err) c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not create new device"}) return } - deviceInfo.DeviceID = newDevice.ID + deviceInfo.DeviceID = device.ID } else { log.Printf("CREATE -Device DB Error: %v", err) c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"}) @@ -76,6 +81,33 @@ func SaveDeviceInfo(c *gin.Context) { c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not save device info"}) return } + + if device.CurrentContractID != nil { + deviceContract, _, err := contract.GetContractByID(*device.CurrentContractID) + if err != nil { + log.Printf("SaveDeviceInfo - GetContractByID error : %v", err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not fetch device contract"}) + return + } + + if deviceContract.Status == models.ContractStatusActive { + deviceInfoBytes, _ := json.Marshal(deviceInfo) + deviceInfoEncryptedStr, err := shared.NewEncryptionClient(config.AppConfig.Service.BlockchainSecret).Encrypt(string(deviceInfoBytes)) + if err != nil { + log.Printf("SaveDeviceInfo - Enrypt error : %v", err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not encrypt device info"}) + return + } + + err = blockchain.NewService(config.AppConfig.Blockchain).AddIOTData(context.Background(), shared.CovertUintToByte32(deviceContract.ID), shared.CovertUintToByte32(device.ID), big.NewInt(time.Now().Unix()), []byte(deviceInfoEncryptedStr)) + if err != nil { + log.Printf("SaveDeviceInfo CREATE -DeviceInfo Blockchain Error: %v", err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not save device info in blockchain"}) + return + } + } + } + log.Printf("Successfully received and saved device info: %v", deviceInfo) c.JSON(http.StatusOK, gin.H{"message": "Successfully received and saved device info", "data": deviceInfo}) } @@ -105,8 +137,7 @@ func GetDeviceData(c *gin.Context) { return } - contract, st, err := contract.GetContractByID(contractID) - + contract, st, err := contract.GetContractByID(uint(contractID)) if err != nil { c.JSON(st, gin.H{"error": err.Error()}) return diff --git a/database/contract/contract.go b/database/contract/contract.go index e84f8f6..d0b7241 100644 --- a/database/contract/contract.go +++ b/database/contract/contract.go @@ -1,6 +1,7 @@ package contract import ( + "context" "errors" "fmt" "log" @@ -9,8 +10,10 @@ import ( "github.com/jinzhu/gorm" "github.com/lib/pq" + "gitlab.com/pactual1/backend/config" "gitlab.com/pactual1/backend/database/device" "gitlab.com/pactual1/backend/models" + "gitlab.com/pactual1/backend/services/blockchain" "gitlab.com/pactual1/backend/shared" ) @@ -128,6 +131,12 @@ func UpdateContract(contract models.Contract) (models.Contract, int, error) { } } + // get old contract to compare updates + oldContract, status, err := GetContractByID(contract.ID) + if err != nil { + return contract, status, err + } + err = shared.GetDb().Transaction(func(tx *gorm.DB) error { // Update contract if err := tx.Model(contract).Updates(contract).Error; err != nil { @@ -151,14 +160,48 @@ func UpdateContract(contract models.Contract) (models.Contract, int, error) { return contract, http.StatusInternalServerError, err } - return GetContractByID(uint64(contract.ID)) + contract, status, err = GetContractByID(contract.ID) + if err != nil { + return contract, status, err + } + + // Create contract in blockchain only when it is signed + if oldContract.Status != contract.Status && contract.Status == models.ContractStatusSigned { + err = blockchain.NewService(config.AppConfig.Blockchain).CreateContract(context.Background(), shared.CovertUintToByte32(contract.ID)) + if err != nil { + log.Printf("UpdateContract Error: Could not create contract in blockchain: %v", err) + return contract, http.StatusInternalServerError, err + } + } + + if contract.Status == models.ContractStatusSigned { + // Register devices in blockchain if contract is signed + for _, device := range devices { + var found bool + for _, deviceID := range oldContract.DeviceIDs { + if device.ID == uint(deviceID) { + found = true + break + } + } + if !found { + err = blockchain.NewService(config.AppConfig.Blockchain).RegisterNewDeviceID(context.Background(), shared.CovertUintToByte32(contract.ID), shared.CovertUintToByte32(device.ID)) + if err != nil { + log.Printf("UpdateContract Error: Could not register contract device in blockchain: %v", err) + return contract, http.StatusInternalServerError, err + } + } + } + } + + return contract, status, err } func validateContractDevices(contractID uint, devices []models.Device) (int, error) { for _, device := range devices { if device.CurrentContractID != nil && *device.CurrentContractID != contractID { - currentDeviceContract, status, err := GetContractByID(uint64(*device.CurrentContractID)) + currentDeviceContract, status, err := GetContractByID(*device.CurrentContractID) if err != nil { return status, err } @@ -173,7 +216,7 @@ func validateContractDevices(contractID uint, devices []models.Device) (int, err return http.StatusOK, nil } -func GetContractByID(contractID uint64) (models.Contract, int, error) { +func GetContractByID(contractID uint) (models.Contract, int, error) { // Fetch the contract creation date based on contractID var contract models.Contract diff --git a/services/blockchain/service.go b/services/blockchain/service.go index ee8a67d..78add8e 100644 --- a/services/blockchain/service.go +++ b/services/blockchain/service.go @@ -29,7 +29,7 @@ func NewService(blockchainConfig config.Blockchain) Service { type Service interface { CreateContract(ctx context.Context, contractID [32]byte) error AddIOTData(ctx context.Context, contractID [32]byte, deviceID [32]byte, timestamp *big.Int, data []byte) error - RegisterNewDeviceIDs(ctx context.Context, contractID [32]byte, deviceIDs [][32]byte) error + RegisterNewDeviceID(ctx context.Context, contractID [32]byte, deviceID [32]byte) error } func (s *service) signerFunc(address common.Address, txn *types.Transaction) (*types.Transaction, error) { @@ -100,13 +100,13 @@ func (s *service) CreateContract(ctx context.Context, contractID [32]byte) error } // map devices with blockchain contract -func (s *service) RegisterNewDeviceIDs(ctx context.Context, contractID [32]byte, deviceIDs [][32]byte) error { +func (s *service) RegisterNewDeviceID(ctx context.Context, contractID [32]byte, deviceID [32]byte) error { conn, contract, err := s.getClient(ctx) if err != nil { return err } - txn, err := contract.RegisterNewDeviceIds(s.getTransactOpts(), contractID, deviceIDs) + txn, err := contract.RegisterNewDeviceId(s.getTransactOpts(), contractID, deviceID) if err != nil { return err } diff --git a/shared/encryption.go b/shared/encryption.go index 140a8d6..4468d59 100644 --- a/shared/encryption.go +++ b/shared/encryption.go @@ -7,10 +7,17 @@ import ( "crypto/cipher" "crypto/rand" "encoding/base64" + "encoding/binary" "fmt" "io" ) +func CovertUintToByte32(id uint) [32]byte { + b := make([]byte, 32) + binary.LittleEndian.PutUint32(b, uint32(id)) + return [32]byte(b) +} + type EncryptionClient interface { Encrypt(string) (string, error) Decrypt(string) (string, error)