diff --git a/auth_utility.go b/auth_utility.go index b15f7e2..c82de4d 100644 --- a/auth_utility.go +++ b/auth_utility.go @@ -27,6 +27,7 @@ type CredentialsStruct struct { Password string `json:"password"` } +// generateSalt returns a random string of 'saltSize' length to be used for hashing. func generateSalt() (salt string, err error) { rawsalt := make([]byte, saltSize) @@ -39,6 +40,8 @@ func generateSalt() (salt string, err error) { return salt, nil } +// HashString hashes input string with SHA256 algorithm. +// If the presalt parameter is not provided HashString will generate new salt string. func HashString(str string, presalt string) (hash, salt string, err error) { // chech if message is presalted if presalt == "" { @@ -70,6 +73,8 @@ func HashString(str string, presalt string) (hash, salt string, err error) { return hash, salt, nil } +// CreateAPIToken creates JWT token encoding username, role, +// expiration date and issuer claims in it. func CreateAPIToken(username, role string) (string, error) { var apiToken string var err error @@ -95,10 +100,11 @@ func CreateAPIToken(username, role string) (string, error) { return apiToken, nil } +// RefreshAPIToken prolongs JWT token's expiration date. func RefreshAPIToken(tokenString string) (string, error) { var newToken string tokenString = strings.TrimPrefix(tokenString, "Bearer ") - token, err := parseTokenFunc(tokenString) + token, err := jwt.ParseWithClaims(tokenString, &TokenClaims{}, secretFunc) if err != nil { return "", err } @@ -120,14 +126,15 @@ func RefreshAPIToken(tokenString string) (string, error) { return newToken, nil } +// ParseAPIToken parses JWT token claims. func ParseAPIToken(tokenString string) (*TokenClaims, error) { - if ok := strings.HasPrefix(tokenString, "Bearer"); ok { + if ok := strings.HasPrefix(tokenString, "Bearer "); ok { tokenString = strings.TrimPrefix(tokenString, "Bearer ") } else { return &TokenClaims{}, errors.New("Authorization header is incomplete") } - token, err := parseTokenFunc(tokenString) + token, err := jwt.ParseWithClaims(tokenString, &TokenClaims{}, secretFunc) if err != nil { return &TokenClaims{}, err } @@ -140,12 +147,7 @@ func ParseAPIToken(tokenString string) (*TokenClaims, error) { return claims, nil } -func parseTokenFunc(tokenString string) (*jwt.Token, error) { - token, err := jwt.ParseWithClaims(tokenString, - &TokenClaims{}, - func(token *jwt.Token) (interface{}, error) { - return []byte(secret), nil - }, - ) - return token, err +// secretFunc returns byte slice of 'secret'. +func secretFunc(token *jwt.Token) (interface{}, error) { + return []byte(secret), nil } diff --git a/format_utility.go b/format_utility.go index 4d93975..2046db9 100644 --- a/format_utility.go +++ b/format_utility.go @@ -5,10 +5,13 @@ import ( "fmt" ) +// UnixToDate converts given Unix time to local time in format and returns result: +// YYYY-MM-DD hh:mm:ss +zzzz UTC func UnixToDate(unix int64) time.Time { return time.Unix(unix, 0) } +// DateToUnix converts given date in Unix timestamp. func DateToUnix(date interface{}) int64 { if date != nil { t := date.(time.Time) @@ -18,6 +21,8 @@ func DateToUnix(date interface{}) int64 { return 0 } +// EqualQuotes encapsulates given string in SQL 'equal' statement and returns result. +// Example: "hello" -> " = 'hello'" func EqualQuotes(stmt string) string { if stmt != "" { stmt = fmt.Sprintf(" = '%s'", stmt) @@ -25,6 +30,8 @@ func EqualQuotes(stmt string) string { return stmt } +// LikeQuotes encapsulates given string in SQL 'like' statement and returns result. +// Example: "hello" -> " LIKE UPPER('%hello%')" func LikeQuotes(stmt string) string { if stmt != "" { stmt = fmt.Sprintf(" LIKE UPPER('%s%s%s')", "%", stmt, "%") diff --git a/http_utility.go b/http_utility.go index 55065aa..76d2b57 100644 --- a/http_utility.go +++ b/http_utility.go @@ -22,12 +22,14 @@ type HttpErrorDesc struct { Desc string `json:"description"` } +// ErrorResponse writes HTTP error to w. func ErrorResponse(w http.ResponseWriter, r *http.Request, code int, desc []HttpErrorDesc) { err := httpError{ desc, r.Method + " " + r.URL.Path } w.WriteHeader(code) json.NewEncoder(w).Encode(err) } +// BadRequestResponse writes HTTP error 400 to w. func BadRequestResponse(w http.ResponseWriter, req *http.Request) { ErrorResponse(w, req, http.StatusBadRequest, []HttpErrorDesc{ { "en", templateHttpErr400_EN }, @@ -35,6 +37,7 @@ func BadRequestResponse(w http.ResponseWriter, req *http.Request) { }) } +// InternalSeverErrorResponse writes HTTP error 500 to w. func InternalServerErrorResponse(w http.ResponseWriter, req *http.Request) { ErrorResponse(w, req, http.StatusInternalServerError, []HttpErrorDesc{ { "en", templateHttpErr500_EN }, @@ -42,6 +45,7 @@ func InternalServerErrorResponse(w http.ResponseWriter, req *http.Request) { }) } +// UnauthorizedError writes HTTP error 401 to w. func UnauthorizedResponse(w http.ResponseWriter, req *http.Request) { ErrorResponse(w, req, http.StatusUnauthorized, []HttpErrorDesc{ { "en", templateHttpErr500_EN }, @@ -50,7 +54,7 @@ func UnauthorizedResponse(w http.ResponseWriter, req *http.Request) { } // TODO: Check for content type -// Sets common headers and checks for token validity. +// Sets common headers, checks for token validity and performs access control. func WrapHandler(handlerFunc http.HandlerFunc, auth bool) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") @@ -87,6 +91,7 @@ func WrapHandler(handlerFunc http.HandlerFunc, auth bool) http.HandlerFunc { } } +// NotFoundHandler writes HTTP error 404 to w. func NotFoundHandler(w http.ResponseWriter, req *http.Request) { ErrorResponse(w, req, http.StatusNotFound, []HttpErrorDesc{ { "en", "Not found." }, diff --git a/json_utility.go b/json_utility.go index 00a446d..5457131 100644 --- a/json_utility.go +++ b/json_utility.go @@ -33,8 +33,6 @@ type Translation struct { FieldsLabels map[string]string `json:"fieldsLabels"` } -// Field 'Type' is not required in payload. -// 'payloadBuff' type is only a bridge between ORACLE CLOB and 'Payload' type. type payloadBuff struct { Type string `json:"tableType"` Method string `json:"method"` @@ -54,15 +52,16 @@ type Payload struct { Fields []Field `json:"fields"` Correlations []CorrelationField `json:"correlationFields"` IdField string `json:"idField"` + // Data can only hold slices of any type. It can't be used for itteration Data interface{} `json:"data"` } +// NewPayload returs payload for provided table. func NewPayload(r *http.Request, table string) Payload { var pload Payload pload.Method = r.Method + " " + r.URL.Path - if table != "" { pload.Params = make(map[string]string, 0) pload.Lang = loadTranslations(table) @@ -70,15 +69,16 @@ func NewPayload(r *http.Request, table string) Payload { pload.IdField = loadIdField(table) pload.Correlations = loadCorrelations(table) } - return pload } +// DeliverPayload writes payload to w. func DeliverPayload(w http.ResponseWriter, payload Payload) { json.NewEncoder(w).Encode(payload) payload.Data = nil } +// loadTranslations loads translations for a payload of the given data type. func loadTranslations(id string) []Translation { translations := make([]Translation, 0) @@ -97,6 +97,7 @@ func loadTranslations(id string) []Translation { return translations } +// loadFields loads fields for a payload of the given data type. func loadFields(id string) []Field { fields := make([]Field, 0) @@ -111,6 +112,7 @@ func loadFields(id string) []Field { return fields } +// loadIdField loads ID field for a payload of the given data type. func loadIdField(id string) string { for _, pload := range allPayloads { if pload.Type == id { @@ -120,6 +122,7 @@ func loadIdField(id string) string { return "" } +// loadCorrelations loads correlations field for a payload of the given data type. func loadCorrelations(id string) []CorrelationField { resp := make([]CorrelationField, 0) @@ -134,6 +137,7 @@ func loadCorrelations(id string) []CorrelationField { return resp } +// InitTables loads all payloads in the memory. func InitTables(db *ora.Ses, project string) error { jsonbuf, _ := fetchJSON(db, EqualQuotes(project)) mu.Lock() @@ -145,6 +149,7 @@ func InitTables(db *ora.Ses, project string) error { return nil } +// fetchJSON fetches JSON configuration file from TABLES_CONFIG table. func fetchJSON(db *ora.Ses, project string) ([]byte, error) { stmt, err := db.Prep(`SELECT JSON_CLOB @@ -175,6 +180,8 @@ func fetchJSON(db *ora.Ses, project string) ([]byte, error) { return bytes, nil } +// DecodeJSON decodes JSON data from r to v and returns any error +// that happens during decoding process. func DecodeJSON(r io.Reader, v interface{}) error { return json.NewDecoder(r).Decode(v) } diff --git a/list_config.go b/list_config.go index 785c807..8a1a58f 100644 --- a/list_config.go +++ b/list_config.go @@ -28,7 +28,7 @@ type ListFilter struct { type Dropdown struct { ObjectType string `json:"objectType"` FiltersField string `json:"filtersField"` - IdField string `json:"idField"` + IDField string `json:"idField"` LabelField string `json:"labelField"` } @@ -55,7 +55,7 @@ type ListNavNode struct { LabelField string `json:"label"` Icon string `json:"icon"` ParentObjectType string `json:"parentObjectType"` - ParentIdField string `json:"parentIdField"` + ParentIDField string `json:"parentIdField"` } type ListParentNode struct { @@ -93,8 +93,9 @@ type ListConfig struct { Details ListDetails `json:"details"` } +// GetListConfig returns list configuration for the given object type for the front-end application. func GetListConfig(db *ora.Ses, objType string) (ListConfig, error) { - resp := NewDefaultList(objType) + resp := newDefaultList(objType) var err error err = setListParams(db, &resp, objType) @@ -114,7 +115,8 @@ func GetListConfig(db *ora.Ses, objType string) (ListConfig, error) { return resp, nil } -func GetListConfigObjectIdField(db *ora.Ses, otype string) string { +// GetListConfigObjectIDField returns ID field for the given object type. +func GetListConfigObjectIDField(db *ora.Ses, otype string) string { var resp string var err error var stmt *ora.Stmt @@ -143,7 +145,8 @@ func GetListConfigObjectIdField(db *ora.Ses, otype string) string { return resp } -func NewDefaultList(objType string) ListConfig { +// newDefaultList returns default configuration for the given object type. +func newDefaultList(objType string) ListConfig { list := ListConfig{ ObjectType: objType, Title: objType, @@ -171,6 +174,7 @@ func NewDefaultList(objType string) ListConfig { return list } +// setListParams sets the default parameters of the provided configuration list for the given object type. func setListParams(db *ora.Ses, list *ListConfig, objType string) error { var err error var stmt *ora.Stmt @@ -208,6 +212,7 @@ func setListParams(db *ora.Ses, list *ListConfig, objType string) error { return nil } +// getListNavigation returns list navigation node slice for the given objectType. func getListNavigation(db *ora.Ses, listObjType string) ([]ListNavNode, error) { resp := make([]ListNavNode, 0) var err error @@ -235,7 +240,7 @@ func getListNavigation(db *ora.Ses, listObjType string) ([]ListNavNode, error) { ParentObjectType: rset.Row[1].(string), LabelField: rset.Row[2].(string), Icon: rset.Row[3].(string), - ParentIdField: rset.Row[4].(string), + ParentIDField: rset.Row[4].(string), }) } if rset.Err != nil { @@ -245,6 +250,7 @@ func getListNavigation(db *ora.Ses, listObjType string) ([]ListNavNode, error) { return resp, nil } +// getListActions returns list actions for the given objectType. func getListActions(db *ora.Ses, objType string) (ListActions, error) { var resp ListActions var err error @@ -280,6 +286,7 @@ func getListActions(db *ora.Ses, objType string) (ListActions, error) { return resp, nil } +// getListFiters returns list filter slice for the given object type. func getListFilters(db *ora.Ses, objType string) ([]ListFilter, error) { resp := make([]ListFilter, 0) filtersFields, err := getFilterFieldsAndPosition(db, objType) @@ -311,6 +318,7 @@ func getListFilters(db *ora.Ses, objType string) ([]ListFilter, error) { return resp, nil } +// getFilterFieldsAndPosition returns a map of filter fields and their respective position in the menu. func getFilterFieldsAndPosition(db *ora.Ses, objType string) (map[string]uint32, error) { filtersField := make(map[string]uint32, 0) var err error @@ -345,6 +353,7 @@ type _filter struct { Type string } +// getFiltersByFilterField returns filter slice for the given filter field. func getFiltersByFilterField(db *ora.Ses, filtersField string) ([]_filter, error) { resp := make([]_filter, 0) var err error @@ -377,6 +386,7 @@ func getFiltersByFilterField(db *ora.Ses, filtersField string) ([]_filter, error return resp, nil } +// getFilterDropdownConfig returns dropdown menu for the given filter field. func getFilterDropdownConfig(db *ora.Ses, filtersField string) (Dropdown, error) { var resp Dropdown var err error @@ -399,7 +409,7 @@ func getFilterDropdownConfig(db *ora.Ses, filtersField string) (Dropdown, error) if rset.Next() { resp.FiltersField = rset.Row[0].(string) resp.ObjectType = rset.Row[1].(string) - resp.IdField = rset.Row[2].(string) + resp.IDField = rset.Row[2].(string) resp.LabelField = rset.Row[3].(string) } if rset.Err != nil { @@ -408,6 +418,7 @@ func getFilterDropdownConfig(db *ora.Ses, filtersField string) (Dropdown, error) return resp, nil } +// sortFilters bubble sorts provided filters slice by position field. func sortFilters(filters []ListFilter) { done := false var temp ListFilter @@ -424,6 +435,7 @@ func sortFilters(filters []ListFilter) { } } +// getListGraph return list graph slice for the given object type. func getListGraph(db *ora.Ses, objType string) ([]ListGraph, error) { resp := make([]ListGraph, 0) var err error @@ -458,6 +470,7 @@ func getListGraph(db *ora.Ses, objType string) ([]ListGraph, error) { return resp, nil } +// getListOptions returns list options for the given object type. func getListOptions(db *ora.Ses, objType string) (ListOptions, error) { var resp ListOptions var err error @@ -495,6 +508,7 @@ func getListOptions(db *ora.Ses, objType string) (ListOptions, error) { return resp, nil } +// getListParent returns list parent node slice for the given object type. func getListParent(db *ora.Ses, objType string) ([]ListParentNode, error) { resp := make([]ListParentNode, 0) var err error @@ -528,6 +542,7 @@ func getListParent(db *ora.Ses, objType string) ([]ListParentNode, error) { return resp, nil } +// getListPivot list pivot slice for the given object type. func getListPivot(db *ora.Ses, objType string) ([]ListPivot, error) { resp := make([]ListPivot, 0) var err error @@ -562,6 +577,7 @@ func getListPivot(db *ora.Ses, objType string) ([]ListPivot, error) { return resp, nil } +// getListDetails returns list details for the given object type. func getListDetails(db *ora.Ses, objType string) (ListDetails, error) { var resp ListDetails var err error diff --git a/select_config.go b/select_config.go index 2e04bde..792959b 100644 --- a/select_config.go +++ b/select_config.go @@ -13,6 +13,7 @@ type SelectConfig struct { ValueField string `json:"valueField"` } +// GetSelectConfig returns select configuration slice for the given object type. func GetSelectConfig(db *ora.Ses, otype string) ([]SelectConfig, error) { resp := make([]SelectConfig, 0) var err error diff --git a/sql_sequrity.go b/sql_sequrity.go index db9af9b..6ddecb4 100644 --- a/sql_sequrity.go +++ b/sql_sequrity.go @@ -6,9 +6,10 @@ import ( var patern string = "\"';&*<>=\\`:" -func SQLSafeString(s string) string { +// SQLSafeString removes characters from s found in patern and returns new modified string. +func SQLSafeString(s string) (safe string) { for _, c := range patern { - s = strings.Replace(s, string(c), "", -1) + safe = strings.Replace(s, string(c), "", -1) } - return s + return safe }