diff options
-rw-r--r-- | README.md | 19 | ||||
-rw-r--r-- | go.mod | 18 | ||||
-rw-r--r-- | go.sum | 34 | ||||
-rw-r--r-- | handlers/handlers.go | 75 | ||||
-rw-r--r-- | hasher/blake2-hash_generator.go | 30 | ||||
-rw-r--r-- | idgen/id_generator.go | 24 | ||||
-rw-r--r-- | message-copy.txt | 1 | ||||
-rw-r--r-- | message-modd.txt | 1 | ||||
-rw-r--r-- | message-orig.txt | 1 | ||||
-rw-r--r-- | models/idhash-pair.go | 6 | ||||
-rw-r--r-- | server.go | 77 | ||||
-rw-r--r-- | utils/blake2b-hasher.go | 20 | ||||
-rw-r--r-- | utils/genid.go | 15 |
13 files changed, 159 insertions, 162 deletions
@@ -1,5 +1,5 @@ -# Golang Backend API for FIC (File Integrity Checker) Application -Developing a simple Golang backend API with the [Echo framework](https://github.com/labstack/echo) for FIC(File Integrity Checker) application. This API stores IDs and their corresponding hashes in a SQL server and provides functionality to verify if a given hash matches the stored hash for a specific ID. All the communication between the Application and API is secured using TLS encryption(HTTPS). +# Golang Backend API for FIS (File Integrity Surveillance) Application +Developing a simple Golang backend API with the [Echo framework](https://github.com/labstack/echo) for FIS(File Integrity Surveillance) application which can be found [here](https://github.com/ayato91/Fair-Files). This API stores IDs and their corresponding hashes in a SQL server and provides functionality to verify if a given hash matches the stored hash for a specific ID. All the communication between the Application and API is secured using TLS encryption(HTTPS). Thereby providing both confidentiality and integrity service that aligns with the CIA (Confidentiality, Integrity, Availability) triad for data security. ## Getting Started @@ -9,15 +9,15 @@ To get started with this project, follow these steps: ### Prerequisites - Go installed on your machine. -- A SQL database server to store IDs and hashes. +- A SQL database server(sqlite) to store IDs and hashes. ### Installation 1. Clone this repository to your local machine: ```bash - git clone https://github.com/justsaumit/go-fic-api.git - cd go-fic-api + git clone https://github.com/justsaumit/go-fis-api.git + cd go-fis-api ``` 2. Initialize and install project dependencies using Go modules: @@ -42,10 +42,11 @@ Once the server is running, you can access the API endpoints to add file hashes - To verify a file hash, make a POST request to `/verify` with JSON data containing the ID and hash. ## To-Do-List -- [x] Perform short ID Generation (API/Application) -- [ ] Perform Hashing (API/Application) -- [ ] Connect with DB -- [ ] Add JSON data to DB +- [x] Handle Uploaded files (API) +- [x] Perform short ID Generation (API) +- [x] Perform Hashing (API) +- [x] Connect with DB +- [x] Store JSON data to DB - [ ] Perform verification ## License @@ -1,16 +1,20 @@ -module github.com/justsaumit/go-fic-api +module github.com/justsaumit/go-fis-api -go 1.21.0 +go 1.21.4 + +require ( + github.com/labstack/echo/v4 v4.11.3 + github.com/mattn/go-sqlite3 v1.14.18 + golang.org/x/crypto v0.16.0 +) require ( - github.com/labstack/echo/v4 v4.11.1 // indirect github.com/labstack/gommon v0.4.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect - golang.org/x/crypto v0.12.0 // indirect - golang.org/x/net v0.12.0 // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/text v0.12.0 // indirect + golang.org/x/net v0.17.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect ) @@ -1,7 +1,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/labstack/echo/v4 v4.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUUs4= -github.com/labstack/echo/v4 v4.11.1/go.mod h1:YuYRTSM3CHs2ybfrL8Px48bO6BAnYIN4l8wSTMP6BDQ= +github.com/labstack/echo/v4 v4.11.3 h1:Upyu3olaqSHkCjs1EJJwQ3WId8b8b1hxbogyommKktM= +github.com/labstack/echo/v4 v4.11.3/go.mod h1:UcGuQ8V6ZNRmSweBIJkPvGfwCMIlFmiqrPqiEBfPYws= github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= @@ -11,33 +12,34 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-sqlite3 v1.14.18 h1:JL0eqdCOq6DJVNPSvArO/bIV9/P7fbGrV00LZHc+5aI= +github.com/mattn/go-sqlite3 v1.14.18/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/handlers/handlers.go b/handlers/handlers.go new file mode 100644 index 0000000..f350589 --- /dev/null +++ b/handlers/handlers.go @@ -0,0 +1,75 @@ +package handlers + +import ( + "database/sql" + "github.com/justsaumit/go-fis-api/models" + "github.com/justsaumit/go-fis-api/utils" + "github.com/labstack/echo/v4" + _ "github.com/mattn/go-sqlite3" + "log" + "net/http" +) + +var db *sql.DB + +func init() { + var err error + db, err = sql.Open("sqlite3", "hashstore.db") + if err != nil { + log.Fatalf("sqlite3 not installed: %v", err) + } + + if err = db.Ping(); err != nil { + log.Fatalf("Failed to connect to database: %v", err) + } + + // Create the 'hashes' table if it does not exist + _, err = db.Exec(` + CREATE TABLE IF NOT EXISTS hashes ( + ID TEXT PRIMARY KEY, + HashValue TEXT NOT NULL + ); + `) +} + +// AddHash handles the file upload, store and response +func AddHash(c echo.Context) error { + file, err := c.FormFile("file") + if err != nil { + log.Println("Failed to bind request:", err) + return c.JSON(http.StatusBadRequest, map[string]string{"message": "Invalid request"}) + } + + src, err := file.Open() + if err != nil { + log.Println("Failed to Open File", err) + return err + } + defer src.Close() + + id, err := utils.GenerateID() + if err != nil { + log.Println("Failed to Generate ID", err) + } + + hash, err := utils.GenerateHash(src) + if err != nil { + log.Println("Failed to Generate Hash", err) + } + + // Store id and hash in the database + _, err := db.Exec("INSERT INTO hashes (ID, HashValue) VALUES (?, ?)", id, hash) + if err != nil { + log.Println("Failed to insert into database:", err) + //return c.JSON(http.StatusInternalServerError, map[string]string{"message": "Failed to store hash"}) + } + //return c.JSON(http.StatusOK, map[string]string{"id": id, "message": "Hash added successfully"}) + + data := models.FileHashPair{ + ID: id, + FileHash: hash, + } + + log.Println("Hash added successfully") + return c.JSON(http.StatusOK, data) +} diff --git a/hasher/blake2-hash_generator.go b/hasher/blake2-hash_generator.go deleted file mode 100644 index e71a736..0000000 --- a/hasher/blake2-hash_generator.go +++ /dev/null @@ -1,30 +0,0 @@ -package hasher - -import ( - "fmt" - "golang.org/x/crypto/blake2b" - "io" - "os" -) - -func CalculateBLAKE2Hash(filePath string) (string, error) { - file, err := os.Open(filePath) - if err != nil { - return "", err - } - defer file.Close() - - hash, err := blake2b.New256(nil) - if err != nil { - return "", err - } - - _, err = io.Copy(hash, file) - if err != nil { - return "", err - } - - hashBytes := hash.Sum(nil) - hashString := fmt.Sprintf("%x", hashBytes) - return hashString, nil -} diff --git a/idgen/id_generator.go b/idgen/id_generator.go deleted file mode 100644 index 3659d0e..0000000 --- a/idgen/id_generator.go +++ /dev/null @@ -1,24 +0,0 @@ -package idgen - -import ( - "math/rand" - "time" -) - -const ( - chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" - - idLength = 8 -) - -func init() { - rand.Seed(time.Now().UnixNano()) -} - -func GenerateID() string { - id := make([]byte, idLength) - for i := 0; i < idLength; i++ { - id[i] = chars[rand.Intn(len(chars))] - } - return string(id) -} diff --git a/message-copy.txt b/message-copy.txt deleted file mode 100644 index 43be410..0000000 --- a/message-copy.txt +++ /dev/null @@ -1 +0,0 @@ -This is a sample message. diff --git a/message-modd.txt b/message-modd.txt deleted file mode 100644 index ac508a3..0000000 --- a/message-modd.txt +++ /dev/null @@ -1 +0,0 @@ -This is a modified message. diff --git a/message-orig.txt b/message-orig.txt deleted file mode 100644 index 43be410..0000000 --- a/message-orig.txt +++ /dev/null @@ -1 +0,0 @@ -This is a sample message. diff --git a/models/idhash-pair.go b/models/idhash-pair.go new file mode 100644 index 0000000..b78dcb7 --- /dev/null +++ b/models/idhash-pair.go @@ -0,0 +1,6 @@ +package models + +type FileHashPair struct { + ID string `json:"id"` + FileHash string `json:"fileHash"` +} @@ -1,82 +1,13 @@ package main import ( - "net/http" - + "github.com/justsaumit/go-fis-api/handlers" "github.com/labstack/echo/v4" - - "fmt" - "github.com/justsaumit/go-fic-api/hasher" - "github.com/justsaumit/go-fic-api/idgen" ) -type HelloWorld struct { - Message string `json:"message"` -} - func main() { e := echo.New() - e.GET("/hello", Greetings) - e.GET("/hello/:name", GreetingsWithParams) - e.GET("/hello-queries", GreetingsWithQuery) - e.GET("/genid", GenerateIDHandler) - e.GET("/hasher", hasherHandler) - e.GET("/", func(c echo.Context) error { - return c.String(http.StatusOK, "Hello, World!") - }) - e.Logger.Fatal(e.Start(":3000")) -} - -func Greetings(c echo.Context) error { - return c.JSON(http.StatusOK, HelloWorld{ - Message: "Hello World", - }) -} - -func GreetingsWithParams(c echo.Context) error { - params := c.Param("name") - return c.JSON(http.StatusOK, HelloWorld{ - Message: "Hello World, my name is " + params, - }) -} - -func GreetingsWithQuery(c echo.Context) error { - query := c.QueryParam("name") - return c.JSON(http.StatusOK, HelloWorld{ - Message: "Hello World, I'm using queries and my name is " + query, - }) -} - -func GenerateIDHandler(c echo.Context) error { - id := idgen.GenerateID() - //Print the generated ID to the console. - fmt.Println("Generated ID:", id) - return c.JSON(http.StatusOK, map[string]string{"message": "Generated ID: " + id}) - // return c.JSON(http.StatusOK, HelloWorld{ - // Message: "Generated ID: " + id, - //}) -} - -func hasherHandler(c echo.Context) error { - filePaths := []string{ - "./message-orig.txt", - "./message-copy.txt", - "./message-modd.txt", - } - hashResults := make(map[string]string) - - for _, filePath := range filePaths { - hash, err := hasher.CalculateBLAKE2Hash(filePath) - if err != nil { - return c.String(http.StatusInternalServerError, "Error calculating hash") - } - hashResults[filePath] = hash - } - - response := "BLAKE2b hashes:\n" - for filePath, hash := range hashResults { - response += fmt.Sprintf("%s: %s\n", filePath, hash) - } - - return c.String(http.StatusOK, response) + e.POST("/upload", handlers.AddHash) + //e.POST("/verify", handlers.VerifyHash) + e.Logger.Fatal(e.StartTLS(":3000", "/etc/letsencrypt/live/draconyan.xyz/fullchain.pem", "/etc/letsencrypt/live/draconyan.xyz/privkey.pem")) } diff --git a/utils/blake2b-hasher.go b/utils/blake2b-hasher.go new file mode 100644 index 0000000..38d13a1 --- /dev/null +++ b/utils/blake2b-hasher.go @@ -0,0 +1,20 @@ +package utils + +import ( + "fmt" + "io" + + "golang.org/x/crypto/blake2b" +) + +func GenerateHash(file io.Reader) (string, error) { + //hasher is an instance hash writer provided by the blake2b, nil - no key provided + hasher, err := blake2b.New256(nil) + if err != nil { + return "", err + } + if _, err := io.Copy(hasher, file); err != nil { + return "", err + } + return fmt.Sprintf("%x", hasher.Sum(nil)), nil +} diff --git a/utils/genid.go b/utils/genid.go new file mode 100644 index 0000000..8525125 --- /dev/null +++ b/utils/genid.go @@ -0,0 +1,15 @@ +package utils + +import ( + "crypto/rand" + "fmt" +) + +// GenerateID creates a random 6-digit ID +func GenerateID() (string, error) { + b := make([]byte, 3) // 3 bytes make 6 hex characters + if _, err := rand.Read(b); err != nil { + return "", err + } + return fmt.Sprintf("%x", b), nil +} |