diff --git a/auth_utility.go b/auth_utility.go new file mode 100644 index 0000000..1ffab64 --- /dev/null +++ b/auth_utility.go @@ -0,0 +1,164 @@ +package restutility + +import ( +// "fmt" + "errors" +// "os" + "time" + "crypto/sha256" + "crypto/rand" + "encoding/hex" + "strings" + "github.com/dgrijalva/jwt-go" +// "github.com/SermoDigital/jose/jwt" +) + +const OneDay = time.Hour*24 +const OneWeek = OneDay*7 +const saltSize = 32 +const appName = "korisnicki-centar" +const secret = "korisnicki-centar-api" + +type Token struct { + TokenString string `json:"token"` +} + +type TokenClaims struct { + Username string `json:"username"` + Role string `json:"role"` + jwt.StandardClaims +} + +type CredentialsStruct struct { + Username string `json:"username"` + Password string `json:"password"` +} + +func generateSalt() (string, error) { + salt := "" + + rawsalt := make([]byte, saltSize) + _, err := rand.Read(rawsalt) + if err != nil { + return "", err + } + salt = hex.EncodeToString(rawsalt) + return salt, nil +} + +func hashMessage(message string, presalt string) (string, string, error) { + hash, salt := "", "" + var err error + + // chech if message is presalted + if presalt == "" { + salt, err = generateSalt() + if err != nil { + return "", "", err + } + } else { + salt = presalt + } + + // convert strings to raw byte slices + rawmessage := []byte(message) + rawsalt, err := hex.DecodeString(salt) + if err != nil { + return "", "", err + } + rawdata := make([]byte, len(rawmessage) + len(rawsalt)) + rawdata = append(rawdata, rawmessage...) + rawdata = append(rawdata, rawsalt...) + + // hash message + salt + hasher := sha256.New() + hasher.Write(rawdata) + rawhash := hasher.Sum(nil) + hash = hex.EncodeToString(rawhash) + return hash, salt, nil +} + +func issueAPIToken(username, role string) (Token, error) { + var apiToken Token + var err error + + if err != nil { + return Token{}, err + } + + claims := TokenClaims{ + username, + role, + jwt.StandardClaims{ + ExpiresAt: (time.Now().Add(OneWeek)).Unix(), + Issuer: appName, + }, + } + + jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + apiToken.TokenString, err = jwtToken.SignedString([]byte(secret)) + if err != nil { + return Token{}, err + } + return apiToken, nil +} + +func refreshAPIToken(tokenString string) (Token, error) { + var newToken Token + tokenString = strings.TrimPrefix(tokenString, "Bearer ") + token, err := parseTokenFunc(tokenString) + if err != nil { + return Token{}, err + } + + // type assertion + claims, ok := token.Claims.(*TokenClaims) + if !ok || !token.Valid { + return Token{}, errors.New("token is not valid") + } + + claims.ExpiresAt = (time.Now().Add(OneWeek)).Unix() + jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + + newToken.TokenString, err = jwtToken.SignedString([]byte(secret)) + if err != nil { + return Token{}, err + } + + return newToken, nil +} + +func parseAPIToken(tokenString string) (*TokenClaims, error) { + 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) + if err != nil { + return &TokenClaims{}, err + } + + // type assertion + claims, ok := token.Claims.(*TokenClaims) + if !ok || !token.Valid { + return &TokenClaims{}, errors.New("token is not valid") + } + 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 +} + +func authMinRegReq(uname, pword string) (bool, error) { + return true, nil +} + diff --git a/format_utility.go b/format_utility.go index 4d45a6a..bcfefa2 100644 --- a/format_utility.go +++ b/format_utility.go @@ -1,4 +1,4 @@ -package main +package restutility import ( "strings" diff --git a/http_utility.go b/http_utility.go index c531a7c..ecc5baf 100644 --- a/http_utility.go +++ b/http_utility.go @@ -5,6 +5,8 @@ import ( "encoding/json" ) +const APIVersion = "/api/v1" + //// //// ERROR UTILITY //// diff --git a/json_utility.go b/json_utility.go index 81fa7eb..b95ab72 100644 --- a/json_utility.go +++ b/json_utility.go @@ -5,8 +5,6 @@ import ( "strings" ) -const APIVersion "/api/v1" - type LangMap map[string]map[string]string type Field struct { diff --git a/tables_utility.go b/tables_utility.go index 30e7728..5074d70 100644 --- a/tables_utility.go +++ b/tables_utility.go @@ -2,11 +2,7 @@ package restutility import ( "encoding/json" - "io" - "io/ioutil" "errors" - "fmt" - "gopkg.in/rana/ora.v3" ) type TableConfig struct { @@ -86,46 +82,10 @@ func (tl TableConfig) LoadCorrelations(tableType string) []CorrelationField { var _tables TableConfig var _prevProject string -func getTablesConfigJSON(project string) error { - _prevProject = project - stmt, err := Oracle.Ses.Prep(`SELECT - JSON_CLOB - FROM TABLES_CONFIG - WHERE PROJEKAT` + project, ora.S) - defer stmt.Close() +func loadTablesConfig(jsonbuf []byte) error { + json.Unmarshal(jsonbuf, &_tables.Tables) - if err != nil { - return err - } - - rset, err := stmt.Qry() - if err != nil { - return err - } - - if rset.Next() { - lob := rset.Row[0].(io.Reader) - bytes, err := ioutil.ReadAll(lob) - if err != nil { - fmt.Printf("mega error: %v\n", err) - } - json.Unmarshal(bytes, &_tables.Tables) - } - - return nil -} - -func loadTablesConfig(project string) error { - err := getTablesConfigJSON(putQuotes(project)) - //file, err := ioutil.ReadFile("./config/tables-config.json") - if err != nil { - fmt.Printf("%v\n", err); - return errors.New("unable to load tables config") - } - - //json.Unmarshal(file, &_TABLES_CONFIG.Tables) - - if len(_TABLES_CONFIG.Tables) == 0 { + if len(_tables.Tables) == 0 { return errors.New("tables config is corrupt") } @@ -139,6 +99,3 @@ func loadTable(table string) JSONParams { _tables.LoadCorrelations(table)) } -func refreshTables() error { - return getTablesConfigJSON(_prevProject) -}