From d451bda6b592baa2220147b8880679dfa74bcf3f Mon Sep 17 00:00:00 2001 From: George Shaw Date: Thu, 26 Oct 2017 14:50:25 -0500 Subject: [PATCH] boltdb is working as well as authentication and registration for users. you can take it in index.html of the webhost --- .gitignore | 1 + document_roots/webhost/index.html | 63 +++++++++++++------ pkg/api/api_handler.go | 4 +- pkg/api/authentication.go | 41 ------------ pkg/api/user.go | 96 ++++++++++++++++++++++++++++ pkg/database/database.go | 101 +++++++++++++++++++++++++++--- 6 files changed, 238 insertions(+), 68 deletions(-) delete mode 100644 pkg/api/authentication.go create mode 100644 pkg/api/user.go diff --git a/.gitignore b/.gitignore index 6a80402..b960a4b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ main gpanel +datastore.db diff --git a/document_roots/webhost/index.html b/document_roots/webhost/index.html index f0d770b..5f2cad4 100644 --- a/document_roots/webhost/index.html +++ b/document_roots/webhost/index.html @@ -5,7 +5,7 @@ -
+ @@ -28,30 +28,55 @@
+
+ + + + + + + + + + + + + + + + + + + +
gPanel Registration
Username:
Password:
+
+ diff --git a/pkg/api/api_handler.go b/pkg/api/api_handler.go index 9d43aed..0d09820 100644 --- a/pkg/api/api_handler.go +++ b/pkg/api/api_handler.go @@ -15,7 +15,9 @@ func HandleAPI(path string, res http.ResponseWriter, req *http.Request) (bool, b switch suspectApi { case "authentication": - return true, Authentication(res, req) + return true, UserAuthentication(res, req) + case "registration": + return true, UserRegistration(res, req) default: return false, false } diff --git a/pkg/api/authentication.go b/pkg/api/authentication.go deleted file mode 100644 index 3e2a364..0000000 --- a/pkg/api/authentication.go +++ /dev/null @@ -1,41 +0,0 @@ -// Package api handles all API calls -package api - -import ( - "encoding/json" - "net/http" -) - -// auth struct is the structure of the JSON data to be retrieved from -// the authentication API request -var auth struct { - User string `json:"user"` - Pass string `json:"pass"` -} - -// Authentication function is accessed by an API call from the webhost root -// by accessing /authentication and sending it a post request with -func Authentication(res http.ResponseWriter, req *http.Request) bool { - if req.Method != "POST" { - http.Error(res, req.Method+" HTTP method is unsupported for this API.", http.StatusMethodNotAllowed) - return false - } - - err := json.NewDecoder(req.Body).Decode(&auth) - - if err != nil { - http.Error(res, err.Error(), http.StatusBadRequest) - return false - } else { - - if auth.User == "root" && auth.Pass == "root" { - res.WriteHeader(http.StatusNoContent) - return true - } else { - http.Error(res, "Authentication failed", http.StatusUnauthorized) - return false - } - - } - -} diff --git a/pkg/api/user.go b/pkg/api/user.go new file mode 100644 index 0000000..5964be0 --- /dev/null +++ b/pkg/api/user.go @@ -0,0 +1,96 @@ +// Package api handles all API calls +package api + +import ( + "encoding/json" + "net/http" + + "github.com/Ennovar/gPanel/pkg/database" +) + +// userRequestData struct is the structure of the JSON data to be +// retrieved from the authentication API request +var userRequestData struct { + User string `json:"user"` + Pass string `json:"pass"` +} + +// userDatabaseData struct is the structure of the JSON data to be retrieved from +// the bolt database inside of the user bucket, using the username as the key. +var userDatabaseData struct { + Pass string `json:"pass"` +} + +// UserAuthentication function is accessed by an API call from the webhost root +// by accessing /authentication and sending it a post request with +func UserAuthentication(res http.ResponseWriter, req *http.Request) bool { + if req.Method != "POST" { + http.Error(res, req.Method+" HTTP method is unsupported for this API.", http.StatusMethodNotAllowed) + return false + } + + err := json.NewDecoder(req.Body).Decode(&userRequestData) + if err != nil { + http.Error(res, err.Error(), http.StatusBadRequest) + return false + } + + ds, err := database.Open(database.DBLOC_MAIN) + if err != nil || ds == nil { + http.Error(res, err.Error(), http.StatusBadRequest) + return false + } + defer ds.Close() + + err = ds.Get(database.BUCKET_USERS, []byte(userRequestData.User), &userDatabaseData) + + if err == database.ErrKeyNotExist { + http.Error(res, "User does not exist in database", http.StatusUnauthorized) + return false + } + + if userRequestData.Pass != userDatabaseData.Pass { + http.Error(res, "Invalid password", http.StatusUnauthorized) + return false + } + + res.WriteHeader(http.StatusNoContent) + return true + +} + +// UserAuthentication function is accessed by an API call from the webhost root +// by accessing /authentication and sending it a post request with +func UserRegistration(res http.ResponseWriter, req *http.Request) bool { + if req.Method != "POST" { + http.Error(res, req.Method+" HTTP method is unsupported for this API.", http.StatusMethodNotAllowed) + return false + } + + err := json.NewDecoder(req.Body).Decode(&userRequestData) + if err != nil { + http.Error(res, err.Error(), http.StatusBadRequest) + return false + } else if len(userRequestData.User) == 0 || len(userRequestData.Pass) == 0 { + http.Error(res, "Username or password field cannot be blank", http.StatusBadRequest) + return false + } + + ds, err := database.Open(database.DBLOC_MAIN) + if err != nil || ds == nil { + http.Error(res, err.Error(), http.StatusBadRequest) + return false + } + defer ds.Close() + + userDatabaseData.Pass = userRequestData.Pass + err = ds.Put(database.BUCKET_USERS, []byte(userRequestData.User), userDatabaseData) + if err != nil { + http.Error(res, err.Error(), http.StatusBadRequest) + return false + } + + res.WriteHeader(http.StatusNoContent) + return true + +} diff --git a/pkg/database/database.go b/pkg/database/database.go index ec1b767..330381b 100644 --- a/pkg/database/database.go +++ b/pkg/database/database.go @@ -2,16 +2,103 @@ package database import ( - "log" + "encoding/json" + "errors" "time" "github.com/boltdb/bolt" ) -func init() { - db, err := bolt.Open("test.db", 0600, &bolt.Options{Timeout: 5 * time.Second}) - if err != nil { - log.Fatal(err) - } - defer db.Close() +// Database constants +const ( + DBLOC_MAIN string = "datastore.db" +) + +// Bucket constants +const ( + BUCKET_USERS string = "users" +) + +// Error codes +var ( + ErrKeyNotExist error = errors.New("key does not exist") +) + +type Datastore struct { + handle *bolt.DB +} + +// Open function will open the database and return a Datastore struct +// that has a handle within it for various datastore functions. +func Open(filename string) (*Datastore, error) { + db, err := bolt.Open(filename, 0666, &bolt.Options{Timeout: 15 * time.Second}) + + if err != nil { + return nil, err + } + + ds := &Datastore{ + handle: db, + } + + // Ensure that all top-level buckets exist + err = ds.handle.Update(func(tx *bolt.Tx) error { + _, err := tx.CreateBucketIfNotExists([]byte(BUCKET_USERS)) + + if err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return ds, nil +} + +// Close is a function attached to the Datastore struct that will close the current bolt instance +func (ds *Datastore) Close() error { + return ds.handle.Close() +} + +// Get is a function attached to the Datastore struct that will get data from the current bolt instance +func (ds *Datastore) Get(bucket string, key []byte, result interface{}) error { + return ds.handle.View(func(tx *bolt.Tx) error { + dsValue := tx.Bucket([]byte(bucket)).Get(key) + + if dsValue == nil { + return ErrKeyNotExist + } + + return json.Unmarshal(dsValue, result) + }) +} + +// Put is a function attached to the Datastore struct that will put data into the current bolt instance +func (ds *Datastore) Put(bucket string, key []byte, value interface{}) error { + var err error + dsValue, ok := value.([]byte) + + if !ok { + dsValue, err = json.Marshal(value) + + if err != nil { + return err + } + + } + + return ds.handle.Update(func(tx *bolt.Tx) error { + return tx.Bucket([]byte(bucket)).Put(key, dsValue) + }) +} + +// Delete is a function attached to the Datastore struct that will delete data from the current bolt instance +func (ds *Datastore) Delete(bucket string, key []byte) error { + return ds.handle.Update(func(tx *bolt.Tx) error { + return tx.Bucket([]byte(bucket)).Delete(key) + }) }