diff --git a/.gitignore b/.gitignore index 54985c8..775b28f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ # Output of the go coverage tool, specifically when used with LiteIDE *.out +backend debug .vscode .vs/ diff --git a/config/config.go b/config/config.go index b975d4d..97b566c 100644 --- a/config/config.go +++ b/config/config.go @@ -20,11 +20,12 @@ func Load() error { } AppConfig = Config{ - + Service: Service{ // 9000 DEFAULT FOR DEV ENVIRONMENT - Port: getEnv("NOVATECH_SERVICE_PORT", "9000"), - Environment: getEnv("NOVATECH_SERVICE_ENVIRONMENT", "DEV"), + Port: getEnv("NOVATECH_SERVICE_PORT", "9000"), + Environment: getEnv("NOVATECH_SERVICE_ENVIRONMENT", "DEV"), + BlockchainSecret: getEnv("NOVATECH_SERVICE_BLOCKCHAIN_SECRET", "novatech_service_blockchain_secret"), }, AdminService: Service{ // 8080 DEFAULT FOR DEV ENVIRONMENT @@ -32,14 +33,12 @@ func Load() error { Environment: getEnv("NOVATECH_ADMIN_SERVICE_ENVIRONMENT", "DEV"), }, Database: Database{ - UserName: getEnv("NOVATECH_DATABASE_USERNAME", "root"), - Password: getEnv("NOVATECH_DATABASE_PASSWORD", "root"), - DatabaseName: getEnv("NOVATECH_DATABASE_NAME", "postgres"), - HostName: getEnv("NOVATECH_DATABASE_ADDRESS", "localhost"), - Port: getEnv("NOVATECH_DATABASE_PORT", " "), - + UserName: getEnv("NOVATECH_DATABASE_USERNAME", "root"), + Password: getEnv("NOVATECH_DATABASE_PASSWORD", "root"), + DatabaseName: getEnv("NOVATECH_DATABASE_NAME", "postgres"), + HostName: getEnv("NOVATECH_DATABASE_ADDRESS", "localhost"), + Port: getEnv("NOVATECH_DATABASE_PORT", " "), }, - } return nil diff --git a/config/models.go b/config/models.go index f0de75e..1fa7014 100644 --- a/config/models.go +++ b/config/models.go @@ -2,25 +2,24 @@ package config // Config stores application configuration type Config struct { - Service Service - AdminService Service - Database Database + Service Service + AdminService Service + Database Database } - // Service contains configuration for service type Service struct { - Port string - Environment string - WebPageURL string + Port string + Environment string + WebPageURL string + BlockchainSecret string } // Database configuration type Database struct { - UserName string - Password string - DatabaseName string - HostName string - Port string + UserName string + Password string + DatabaseName string + HostName string + Port string } - diff --git a/controllers/auth_controller.go b/controllers/auth_controller.go index 203ca47..b364c3e 100644 --- a/controllers/auth_controller.go +++ b/controllers/auth_controller.go @@ -13,16 +13,15 @@ import ( type AuthController struct{} - -func (AuthController)HandleLogin(c *gin.Context) { - userId:="123" - username:="Beast" - roles:= []string{shared.RoleAdmin, shared.RoleProUser} +func (AuthController) HandleLogin(c *gin.Context) { + userId := "123" + username := "Beast" + roles := []string{shared.RoleAdmin, shared.RoleProUser} // do user auth here //issue token - token, err := middlewares.GenerateToken([]byte(middlewares.SigningKey), userId,username, roles) + token, err := middlewares.GenerateToken([]byte(middlewares.SigningKey), userId, username, roles) if err != nil { log.Printf("Unable to generate token %v", err) c.JSON(http.StatusInternalServerError, err) diff --git a/controllers/devices_controller.go b/controllers/devices_controller.go index f395192..5835427 100644 --- a/controllers/devices_controller.go +++ b/controllers/devices_controller.go @@ -20,42 +20,40 @@ func SaveDeviceInfofunc(c *gin.Context) { err := json.Unmarshal(rawData, &deviceInfo) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid JSON payload"}) - log.Printf("Invalid json pyload : %v",err) + log.Printf("Invalid json pyload : %v", err) return } - deviceInfo.RawJSON = string(rawData) - // Attempt to find the device by IMEI; if not found, create a new device - var device models.Device - if err := shared.GetDb().Where("imei = ?", deviceInfo.IMEI).First(&device).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - // Create new device - newDevice := models.Device{ - IMEI: deviceInfo.IMEI, - IMSI: deviceInfo.IMSI, - DeviceConfiguration: string(rawData), - } - if err := shared.GetDb().Create(&newDevice).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 - } else { - log.Printf("CREATE -Device DB Error: %v",err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"}) + // Attempt to find the device by IMEI; if not found, create a new device + var device models.Device + if err := shared.GetDb().Where("imei = ?", deviceInfo.IMEI).First(&device).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + // Create new device + newDevice := models.Device{ + IMEI: deviceInfo.IMEI, + IMSI: deviceInfo.IMSI, + DeviceConfiguration: string(rawData), + } + if err := shared.GetDb().Create(&newDevice).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 } else { - deviceInfo.DeviceID = device.ID + log.Printf("CREATE -Device DB Error: %v", err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"}) + return } - + } else { + deviceInfo.DeviceID = device.ID + } // Save deviceInfo to your database if err := shared.GetDb().Create(&deviceInfo).Error; err != nil { - log.Printf("SaveDeviceInfo CREATE -DeviceInfo DB Error: %v",err) + log.Printf("SaveDeviceInfo CREATE -DeviceInfo DB Error: %v", err) c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not save device info"}) return } diff --git a/controllers/devices_controller_test.go b/controllers/devices_controller_test.go index 1c7c9ba..d0d7790 100644 --- a/controllers/devices_controller_test.go +++ b/controllers/devices_controller_test.go @@ -26,7 +26,7 @@ func runTestServer() *httptest.Server { if err != nil { log.Fatal(err) } - + shared.Init() r := gin.Default() r.POST("/device_info", SaveDeviceInfofunc) @@ -45,7 +45,6 @@ func TestSaveDeviceInfofunc(t *testing.T) { if err != nil { t.Fatalf("Expected no error, got %v", err) } - assert.Equal(t, 400, resp.StatusCode) }) @@ -65,7 +64,7 @@ func TestSaveDeviceInfofunc(t *testing.T) { t.Run("it should return 200 when all conditions are correct", func(t *testing.T) { // Add a valid payload deviceInfo := map[string]interface{}{ - "IMEI": "SOME_VALID_IMEI", + "IMEI": "SOME_VALID_IMEI", "SomeOtherField": "Value", } diff --git a/controllers/simple_controller.go b/controllers/simple_controller.go index d98a719..7ae21f6 100644 --- a/controllers/simple_controller.go +++ b/controllers/simple_controller.go @@ -6,10 +6,10 @@ package controllers import "github.com/gin-gonic/gin" -func GetSecretText(c *gin.Context){ +func GetSecretText(c *gin.Context) { c.JSON(200, "Hi this is a secret message. Auth was successful!") } -func GetPublicText(c *gin.Context){ +func GetPublicText(c *gin.Context) { c.JSON(200, "Hi this is a public message!") } diff --git a/env-example b/env-example index f624e85..6151284 100644 --- a/env-example +++ b/env-example @@ -6,4 +6,5 @@ NOVATECH_DATABASE_USERNAME=username NOVATECH_DATABASE_PASSWORD=password NOVATECH_DATABASE_NAME=dbname NOVATECH_DATABASE_ADDRESS=localhost -NOVATECH_DATABASE_PORT=5432 \ No newline at end of file +NOVATECH_DATABASE_PORT=5432 +NOVATECH_SERVICE_BLOCKCHAIN_SECRET="abc&1*~#^2^#s0^=)^^7%b34" \ No newline at end of file diff --git a/go.mod b/go.mod index 0d76ab8..dd412f5 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module gitlab.com/pactual1/backend -go 1.21.0 +go 1.21 require ( github.com/dgrijalva/jwt-go v3.2.0+incompatible @@ -59,6 +59,7 @@ require ( golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 9421c2a..059a605 100644 --- a/go.sum +++ b/go.sum @@ -206,8 +206,9 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= diff --git a/main.go b/main.go index cfb5b3e..d24d5cf 100644 --- a/main.go +++ b/main.go @@ -8,7 +8,7 @@ import ( "gitlab.com/pactual1/backend/config" "gitlab.com/pactual1/backend/models" "gitlab.com/pactual1/backend/routes" - "gitlab.com/pactual1/backend/services/contact" + "gitlab.com/pactual1/backend/services/contract" "gitlab.com/pactual1/backend/services/erp" "gitlab.com/pactual1/backend/services/messaging" "gitlab.com/pactual1/backend/shared" @@ -22,7 +22,6 @@ var DB *gorm.DB func main() { - // LOAD APPLICATION CONFIGURATION err := config.Load() if err != nil { @@ -44,7 +43,7 @@ func main() { company.Meta(&admin.Meta{Name: "Users", Config: &admin.SelectManyConfig{SelectMode: "bottom_sheet"}}) company.Meta(&admin.Meta{Name: "Devices", Config: &admin.SelectManyConfig{SelectMode: "bottom_sheet"}}) // company.Meta(&admin.Meta{Name: "DeviceInfos", Config: &admin.SelectManyConfig{SelectMode: "bottom_sheet"}}) - + // Add User and Device resources Admin.AddResource(&models.User{}) Admin.AddResource(&models.Device{}) @@ -55,31 +54,34 @@ func main() { // Start the admin server in a separate goroutine go func() { - port := config.AppConfig.Service.Port + port := config.AppConfig.Service.Port fmt.Println("Admin server listening on :" + port) - http.ListenAndServe(":" + port, mux) + http.ListenAndServe(":"+port, mux) }() // Initialize channels messagingChannel := make(chan string) erpChannel := make(chan string) - contactChannel := make(chan string) + contractChannel := make(chan string) // Start services and pass the respective channels go messaging.MessagingService(messagingChannel) go erp.ERPService(erpChannel) - go contact.ContactService(contactChannel) + + encryptionClient := shared.NewEncryptionClient(config.AppConfig.Service.BlockchainSecret) + contractService := contract.NewService(contractChannel, shared.GetDb(), encryptionClient) + go contractService.ContractService() // Sending messages via channels messagingChannel <- "Send an email" erpChannel <- "Update ERP record" - contactChannel <- "Update contact info" + contractChannel <- "Update contract info" // Initialize Gin r := gin.Default() routes.InitRouter(r) // Start the Gin server on another port - port := config.AppConfig.AdminService.Port + port := config.AppConfig.AdminService.Port fmt.Println("Application server listening on :" + port) r.Run(":" + port) diff --git a/middlewares/cors.go b/middlewares/cors.go index ff61df1..603a871 100644 --- a/middlewares/cors.go +++ b/middlewares/cors.go @@ -20,4 +20,4 @@ func CORSMiddleware() gin.HandlerFunc { c.Next() } -} \ No newline at end of file +} diff --git a/middlewares/jwt.go b/middlewares/jwt.go index 9682e6e..2578072 100644 --- a/middlewares/jwt.go +++ b/middlewares/jwt.go @@ -5,9 +5,9 @@ package middlewares import ( - "strings" - "github.com/gin-gonic/gin" "github.com/dgrijalva/jwt-go" + "github.com/gin-gonic/gin" + "strings" "time" ) @@ -83,7 +83,7 @@ func GenerateToken(key []byte, userId string, username string, roles []string) ( claims := make(jwt.MapClaims) claims["user_id"] = userId claims["username"] = username - claims["exp"]=time.Now().Add(time.Hour * 72).UnixNano() / int64(time.Millisecond) + claims["exp"] = time.Now().Add(time.Hour*72).UnixNano() / int64(time.Millisecond) //Set user roles claims["roles"] = roles @@ -102,4 +102,3 @@ func ValidateToken(tokenString string, key string) (*jwt.Token, error) { return token, err } - diff --git a/models/company.go b/models/company.go index 3d0dcd2..2cd5611 100644 --- a/models/company.go +++ b/models/company.go @@ -4,7 +4,7 @@ import "github.com/jinzhu/gorm" type Company struct { gorm.Model - Name string + Name string Password string Email string Avatar string @@ -12,7 +12,6 @@ type Company struct { Devices []Device } - // func FetchCompanies(companies *[]Company) (err error) { // db := gorm.GetDb() @@ -22,12 +21,12 @@ type Company struct { // return nil // } -func (Company)Update() (bool, error) { +func (Company) Update() (bool, error) { return false, nil } -func (Company)Create() (bool, error) { +func (Company) Create() (bool, error) { return false, nil } -func (Company)Delete() (bool, error) { +func (Company) Delete() (bool, error) { return false, nil } diff --git a/models/contract.go b/models/contract.go new file mode 100644 index 0000000..fb2be07 --- /dev/null +++ b/models/contract.go @@ -0,0 +1,23 @@ +package models + +import "github.com/jinzhu/gorm" + +type Contract struct { + gorm.Model + Name string + DeviceID []uint + BuyerID uint + Status string + BlockchainID string + ContractInfos []ContractInfo +} + +func (Contract) Update() (bool, error) { + return false, nil +} +func (Contract) Create() (bool, error) { + return false, nil +} +func (Contract) Delete() (bool, error) { + return false, nil +} diff --git a/models/contract_info.go b/models/contract_info.go new file mode 100644 index 0000000..718eb05 --- /dev/null +++ b/models/contract_info.go @@ -0,0 +1,18 @@ +package models + +import "github.com/jinzhu/gorm" + +type ContractInfo struct { + gorm.Model + RawJSON string `json:"raw_json" gorm:"type:json"` +} + +func (ContractInfo) Update() (bool, error) { + return false, nil +} +func (ContractInfo) Create() (bool, error) { + return false, nil +} +func (ContractInfo) Delete() (bool, error) { + return false, nil +} diff --git a/models/crudInterface.go b/models/crudInterface.go index 5c9406b..48927fe 100644 --- a/models/crudInterface.go +++ b/models/crudInterface.go @@ -1,8 +1,7 @@ package models type SimpleCRUD interface { - Create() (bool,error) - Update()( bool,error) - Delete() (bool,error) - + Create() (bool, error) + Update() (bool, error) + Delete() (bool, error) } diff --git a/models/device.go b/models/device.go index f18c8cb..cc746ec 100644 --- a/models/device.go +++ b/models/device.go @@ -4,20 +4,20 @@ import "github.com/jinzhu/gorm" type Device struct { gorm.Model - DeviceName string - IMEI string `json:"imei"` - IMSI string `json:"imsi"` - DeviceConfiguration string `gorm:"type:json"` - CompanyID uint - DeviceInfos []DeviceInfo + DeviceName string + IMEI string `json:"imei"` + IMSI string `json:"imsi"` + DeviceConfiguration string `gorm:"type:json"` + CompanyID uint + DeviceInfos []DeviceInfo } -func (Device)Update() (bool, error) { +func (Device) Update() (bool, error) { return false, nil } -func (Device)Create() (bool, error) { +func (Device) Create() (bool, error) { return false, nil } -func (Device)Delete() (bool, error) { +func (Device) Delete() (bool, error) { return false, nil } diff --git a/models/device_info.go b/models/device_info.go index 8c66742..fa124ff 100644 --- a/models/device_info.go +++ b/models/device_info.go @@ -10,30 +10,29 @@ type Location struct { // ImportantInfo holds fields that are important for quick access. type SensorData struct { - IMEI string `json:"imei"` - IMSI string `json:"imsi"` - Timestamp int64 `json:"timestamp"` - Lat float64 `json:"lat"` - Lon float64 `json:"lon"` - WifiLoc Location `json:"wifi_location"` - CellLoc Location `json:"cell_location"` - Temperature float64 `json:"temperature"` + IMEI string `json:"imei"` + IMSI string `json:"imsi"` + Timestamp int64 `json:"timestamp"` + Lat float64 `json:"lat"` + Lon float64 `json:"lon"` + WifiLoc Location `json:"wifi_location"` + CellLoc Location `json:"cell_location"` + Temperature float64 `json:"temperature"` } - type DeviceInfo struct { gorm.Model RawJSON string `json:"raw_json" gorm:"type:json"` - SensorData - DeviceID uint + SensorData + DeviceID uint } -func (DeviceInfo)Update() (bool, error) { +func (DeviceInfo) Update() (bool, error) { return false, nil } -func (DeviceInfo)Create() (bool, error) { +func (DeviceInfo) Create() (bool, error) { return false, nil } -func (DeviceInfo)Delete() (bool, error) { +func (DeviceInfo) Delete() (bool, error) { return false, nil } diff --git a/models/user.go b/models/user.go index 9257e21..6159378 100644 --- a/models/user.go +++ b/models/user.go @@ -4,19 +4,19 @@ import "github.com/jinzhu/gorm" type User struct { gorm.Model - Username string - Password string - Email string - Avatar string - CompanyID uint + Username string + Password string + Email string + Avatar string + CompanyID uint } -func (User)Update() (bool, error) { +func (User) Update() (bool, error) { return false, nil } -func (User)Create() (bool, error) { +func (User) Create() (bool, error) { return false, nil } -func (User)Delete() (bool, error) { +func (User) Delete() (bool, error) { return false, nil } diff --git a/routes/protected_routes.go b/routes/protected_routes.go index 5e174ee..e283ba3 100644 --- a/routes/protected_routes.go +++ b/routes/protected_routes.go @@ -12,12 +12,12 @@ import ( "github.com/gin-gonic/gin" ) -func RegisterProtectedRoutes(r *gin.Engine){ +func RegisterProtectedRoutes(r *gin.Engine) { authGroup := r.Group("/auth") authGroup.Use(middlewares.AuthHandler("admin")) { - authGroup.GET("/getmessage",controllers.GetSecretText) + authGroup.GET("/getmessage", controllers.GetSecretText) } } diff --git a/routes/public_routes.go b/routes/public_routes.go index 9069c1b..3cdf975 100644 --- a/routes/public_routes.go +++ b/routes/public_routes.go @@ -6,9 +6,8 @@ import ( "github.com/gin-gonic/gin" ) -func RegisterPublicRoutes(r *gin.Engine){ +func RegisterPublicRoutes(r *gin.Engine) { r.GET("/publicmessage", controllers.GetPublicText) r.POST("/device_info", controllers.SaveDeviceInfofunc) } - diff --git a/routes/router.go b/routes/router.go index 7aa8968..4a6efb1 100644 --- a/routes/router.go +++ b/routes/router.go @@ -15,12 +15,12 @@ import ( func InitRouter(engine *gin.Engine) { InitMiddleware(engine) authController := new(controllers.AuthController) - engine.POST("/login", authController.HandleLogin) + engine.POST("/login", authController.HandleLogin) RegisterProtectedRoutes(engine) RegisterPublicRoutes(engine) RegisterUtilityRoutes(engine) } -func InitMiddleware(engine *gin.Engine){ - engine.Use(middlewares.CORSMiddleware()); -} \ No newline at end of file +func InitMiddleware(engine *gin.Engine) { + engine.Use(middlewares.CORSMiddleware()) +} diff --git a/routes/utility_routes.go b/routes/utility_routes.go index a34d93e..9834f1e 100644 --- a/routes/utility_routes.go +++ b/routes/utility_routes.go @@ -6,13 +6,13 @@ package routes import "github.com/gin-gonic/gin" -func RegisterUtilityRoutes(r *gin.Engine){ +func RegisterUtilityRoutes(r *gin.Engine) { registerRing(r) } -func registerRing(r *gin.Engine){ +func registerRing(r *gin.Engine) { // Ping test r.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) -} \ No newline at end of file +} diff --git a/services/contact/contact_service.go b/services/contact/contact_service.go deleted file mode 100644 index 97600ba..0000000 --- a/services/contact/contact_service.go +++ /dev/null @@ -1,11 +0,0 @@ -package contact - -import ( - "fmt" -) - -func ContactService(ch chan string) { - for msg := range ch { - fmt.Println("Contact Service: ", msg) - } -} diff --git a/services/contract/contract_service.go b/services/contract/contract_service.go new file mode 100644 index 0000000..7af8622 --- /dev/null +++ b/services/contract/contract_service.go @@ -0,0 +1,28 @@ +package contract + +import ( + "fmt" + + "github.com/jinzhu/gorm" + "gitlab.com/pactual1/backend/shared" +) + +type service struct { + ch chan string + db *gorm.DB + encryptionClient shared.EncryptionClient +} + +func NewService(ch chan string, db *gorm.DB, encryptionClient shared.EncryptionClient) service { + return service{ + ch: ch, + db: db, + encryptionClient: encryptionClient, + } +} + +func (s service) ContractService() { + for msg := range s.ch { + fmt.Println("Contract Service: ", msg) + } +} diff --git a/shared/database.go b/shared/database.go index 7bf023e..4e0b577 100644 --- a/shared/database.go +++ b/shared/database.go @@ -11,36 +11,32 @@ import ( _ "github.com/jinzhu/gorm/dialects/postgres" ) - var db *gorm.DB -var err error - -func Init() error{ - host := config.AppConfig.Database.HostName - user := config.AppConfig.Database.UserName +func Init() error { + host := config.AppConfig.Database.HostName + user := config.AppConfig.Database.UserName // port := config.AppConfig.Database.Port - dbName := config.AppConfig.Database.DatabaseName - password := config.AppConfig.Database.Password + dbName := config.AppConfig.Database.DatabaseName + password := config.AppConfig.Database.Password - dbString:= fmt.Sprintf("host=%s user=%s dbname=%s sslmode=disable password=%s",host,user,dbName,password) + dbString := fmt.Sprintf("host=%s user=%s dbname=%s sslmode=disable password=%s", host, user, dbName, password) // db, err = gorm.Open("postgres", "host=localhost user=postgres dbname=postgres sslmode=disable password=root") var err error // //PostgreSQL - db, err = gorm.Open("postgres",dbString) + db, err = gorm.Open("postgres", dbString) if err != nil { log.Println("Error initializing the database: ", err) return err } //TODO AUTOMIGRATE models once we have them - db.AutoMigrate(&models.User{}, &models.Company{}, &models.Device{}, &models.DeviceInfo{}) + db.AutoMigrate(&models.User{}, &models.Company{}, &models.Device{}, &models.DeviceInfo{}, &models.Contract{}, &models.ContractInfo{}) return nil } - func GetDb() *gorm.DB { return db } diff --git a/shared/encryption.go b/shared/encryption.go new file mode 100644 index 0000000..140a8d6 --- /dev/null +++ b/shared/encryption.go @@ -0,0 +1,88 @@ +package shared + +import ( + "bytes" + "compress/flate" + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/base64" + "fmt" + "io" +) + +type EncryptionClient interface { + Encrypt(string) (string, error) + Decrypt(string) (string, error) +} + +type encryptionClient struct { + Secret string +} + +func NewEncryptionClient(secret string) EncryptionClient { + return &encryptionClient{Secret: secret} +} + +func compress(text string) ([]byte, error) { + var compressedBytes bytes.Buffer + w, err := flate.NewWriter(&compressedBytes, flate.BestCompression) + w.Write([]byte(text)) + w.Close() + return compressedBytes.Bytes(), err +} + +func decompress(compressedBytes []byte) (string, error) { + reader := flate.NewReader(bytes.NewReader(compressedBytes)) + defer reader.Close() + textBytes := new(bytes.Buffer) + _, err := textBytes.ReadFrom(reader) + return textBytes.String(), err +} + +// Encrypt method is to encrypt or hide any classified text +func (e encryptionClient) Encrypt(text string) (string, error) { + block, err := aes.NewCipher([]byte(e.Secret)) + if err != nil { + return "", err + } + compressedText, err := compress(text) + if err != nil { + return "", err + } + gcm, err := cipher.NewGCM(block) + if err != nil { + return "", err + } + bytes := make([]byte, gcm.NonceSize()) + if _, err = io.ReadFull(rand.Reader, bytes); err != nil { + return "", err + } + encodedText := gcm.Seal(bytes, bytes, compressedText, nil) + return base64.StdEncoding.EncodeToString(encodedText), nil +} + +// Decrypt method is to extract back the encrypted text +func (e encryptionClient) Decrypt(text string) (string, error) { + block, err := aes.NewCipher([]byte(e.Secret)) + if err != nil { + return "", err + } + cipherText, err := base64.StdEncoding.DecodeString(text) + if err != nil { + return "", err + } + gcm, err := cipher.NewGCM(block) + if err != nil { + return "", err + } + if len(cipherText) < gcm.NonceSize() { + return "", fmt.Errorf("text is too small") + } + bytes, cipherText := cipherText[:gcm.NonceSize()], cipherText[gcm.NonceSize():] + compressedTextBytes, err := gcm.Open(nil, bytes, cipherText, nil) + if err != nil { + return "", err + } + return decompress(compressedTextBytes) +} diff --git a/shared/encryption_test.go b/shared/encryption_test.go new file mode 100644 index 0000000..a6085f6 --- /dev/null +++ b/shared/encryption_test.go @@ -0,0 +1,22 @@ +package shared + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestEncryptionClient(t *testing.T) { + + client := encryptionClient{Secret: `abc&1*~#^2^#s0^=)^^7%b34`} + + t.Run("encrypt/ decyrpt works", func(t *testing.T) { + text := "sample text to test encryption" + encodedText, err := client.Encrypt(text) + assert.NoError(t, err) + assert.NotEqual(t, text, encodedText) + decodedText, err := client.Decrypt(encodedText) + assert.NoError(t, err) + assert.Equal(t, text, decodedText) + }) +} diff --git a/shared/user_data.go b/shared/user_data.go index 9001054..7df8ed5 100644 --- a/shared/user_data.go +++ b/shared/user_data.go @@ -5,6 +5,6 @@ package shared const ( - RoleAdmin string = "admin" + RoleAdmin string = "admin" RoleProUser string = "pro-user" )