Commit b291ac8c49a98a8c273e85fcc4000db6348a4d1f

Authored by Marko Tikvić
1 parent 25e0015504
Exists in master and in 1 other branch v2

clened up

1 package restutility 1 package restutility
2 2
3 import ( 3 import (
4 // "fmt"
5 "errors" 4 "errors"
6 // "os"
7 "time" 5 "time"
8 "crypto/sha256" 6 "crypto/sha256"
9 "crypto/rand" 7 "crypto/rand"
10 "encoding/hex" 8 "encoding/hex"
11 "strings" 9 "strings"
12 "github.com/dgrijalva/jwt-go" 10 "github.com/dgrijalva/jwt-go"
13 // "github.com/SermoDigital/jose/jwt"
14 ) 11 )
15 12
16 const OneDay = time.Hour*24 13 const OneDay = time.Hour*24
17 const OneWeek = OneDay*7 14 const OneWeek = OneDay*7
18 const saltSize = 32 15 const saltSize = 32
19 const appName = "korisnicki-centar" 16 const appName = "korisnicki-centar"
20 const secret = "korisnicki-centar-api" 17 const secret = "korisnicki-centar-api"
21 18
22 type Token struct { 19 type Token struct {
23 TokenString string `json:"token"` 20 TokenString string `json:"token"`
24 } 21 }
25 22
26 type TokenClaims struct { 23 type TokenClaims struct {
27 Username string `json:"username"` 24 Username string `json:"username"`
28 Role string `json:"role"` 25 Role string `json:"role"`
29 jwt.StandardClaims 26 jwt.StandardClaims
30 } 27 }
31 28
32 type CredentialsStruct struct { 29 type CredentialsStruct struct {
33 Username string `json:"username"` 30 Username string `json:"username"`
34 Password string `json:"password"` 31 Password string `json:"password"`
35 } 32 }
36 33
37 func generateSalt() (string, error) { 34 func GenerateSalt() (string, error) {
38 salt := "" 35 salt := ""
39 36
40 rawsalt := make([]byte, saltSize) 37 rawsalt := make([]byte, saltSize)
41 _, err := rand.Read(rawsalt) 38 _, err := rand.Read(rawsalt)
42 if err != nil { 39 if err != nil {
43 return "", err 40 return "", err
44 } 41 }
45 salt = hex.EncodeToString(rawsalt) 42 salt = hex.EncodeToString(rawsalt)
46 return salt, nil 43 return salt, nil
47 } 44 }
48 45
49 func hashMessage(message string, presalt string) (string, string, error) { 46 func HashMessage(message string, presalt string) (string, string, error) {
50 hash, salt := "", "" 47 hash, salt := "", ""
51 var err error 48 var err error
52 49
53 // chech if message is presalted 50 // chech if message is presalted
54 if presalt == "" { 51 if presalt == "" {
55 salt, err = generateSalt() 52 salt, err = GenerateSalt()
56 if err != nil { 53 if err != nil {
57 return "", "", err 54 return "", "", err
58 } 55 }
59 } else { 56 } else {
60 salt = presalt 57 salt = presalt
61 } 58 }
62 59
63 // convert strings to raw byte slices 60 // convert strings to raw byte slices
64 rawmessage := []byte(message) 61 rawmessage := []byte(message)
65 rawsalt, err := hex.DecodeString(salt) 62 rawsalt, err := hex.DecodeString(salt)
66 if err != nil { 63 if err != nil {
67 return "", "", err 64 return "", "", err
68 } 65 }
69 rawdata := make([]byte, len(rawmessage) + len(rawsalt)) 66 rawdata := make([]byte, len(rawmessage) + len(rawsalt))
70 rawdata = append(rawdata, rawmessage...) 67 rawdata = append(rawdata, rawmessage...)
71 rawdata = append(rawdata, rawsalt...) 68 rawdata = append(rawdata, rawsalt...)
72 69
73 // hash message + salt 70 // hash message + salt
74 hasher := sha256.New() 71 hasher := sha256.New()
75 hasher.Write(rawdata) 72 hasher.Write(rawdata)
76 rawhash := hasher.Sum(nil) 73 rawhash := hasher.Sum(nil)
77 hash = hex.EncodeToString(rawhash) 74 hash = hex.EncodeToString(rawhash)
78 return hash, salt, nil 75 return hash, salt, nil
79 } 76 }
80 77
81 func issueAPIToken(username, role string) (Token, error) { 78 func IssueAPIToken(username, role string) (Token, error) {
82 var apiToken Token 79 var apiToken Token
83 var err error 80 var err error
84 81
85 if err != nil { 82 if err != nil {
86 return Token{}, err 83 return Token{}, err
87 } 84 }
88 85
89 claims := TokenClaims{ 86 claims := TokenClaims{
90 username, 87 username,
91 role, 88 role,
92 jwt.StandardClaims{ 89 jwt.StandardClaims{
93 ExpiresAt: (time.Now().Add(OneWeek)).Unix(), 90 ExpiresAt: (time.Now().Add(OneWeek)).Unix(),
94 Issuer: appName, 91 Issuer: appName,
95 }, 92 },
96 } 93 }
97 94
98 jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) 95 jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
99 apiToken.TokenString, err = jwtToken.SignedString([]byte(secret)) 96 apiToken.TokenString, err = jwtToken.SignedString([]byte(secret))
100 if err != nil { 97 if err != nil {
101 return Token{}, err 98 return Token{}, err
102 } 99 }
103 return apiToken, nil 100 return apiToken, nil
104 } 101 }
105 102
106 func refreshAPIToken(tokenString string) (Token, error) { 103 func RefreshAPIToken(tokenString string) (Token, error) {
107 var newToken Token 104 var newToken Token
108 tokenString = strings.TrimPrefix(tokenString, "Bearer ") 105 tokenString = strings.TrimPrefix(tokenString, "Bearer ")
109 token, err := parseTokenFunc(tokenString) 106 token, err := parseTokenFunc(tokenString)
110 if err != nil { 107 if err != nil {
111 return Token{}, err 108 return Token{}, err
112 } 109 }
113 110
114 // type assertion 111 // type assertion
115 claims, ok := token.Claims.(*TokenClaims) 112 claims, ok := token.Claims.(*TokenClaims)
116 if !ok || !token.Valid { 113 if !ok || !token.Valid {
117 return Token{}, errors.New("token is not valid") 114 return Token{}, errors.New("token is not valid")
118 } 115 }
119 116
120 claims.ExpiresAt = (time.Now().Add(OneWeek)).Unix() 117 claims.ExpiresAt = (time.Now().Add(OneWeek)).Unix()
121 jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) 118 jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
122 119
123 newToken.TokenString, err = jwtToken.SignedString([]byte(secret)) 120 newToken.TokenString, err = jwtToken.SignedString([]byte(secret))
124 if err != nil { 121 if err != nil {
125 return Token{}, err 122 return Token{}, err
126 } 123 }
127 124
128 return newToken, nil 125 return newToken, nil
129 } 126 }
130 127
131 func parseAPIToken(tokenString string) (*TokenClaims, error) { 128 func ParseAPIToken(tokenString string) (*TokenClaims, error) {
132 if ok := strings.HasPrefix(tokenString, "Bearer"); ok { 129 if ok := strings.HasPrefix(tokenString, "Bearer"); ok {
133 tokenString = strings.TrimPrefix(tokenString, "Bearer ") 130 tokenString = strings.TrimPrefix(tokenString, "Bearer ")
134 } else { 131 } else {
135 return &TokenClaims{}, errors.New("Authorization header is incomplete") 132 return &TokenClaims{}, errors.New("Authorization header is incomplete")
136 } 133 }
137 134
138 token, err := parseTokenFunc(tokenString) 135 token, err := parseTokenFunc(tokenString)
139 if err != nil { 136 if err != nil {
140 return &TokenClaims{}, err 137 return &TokenClaims{}, err
141 } 138 }
142 139
143 // type assertion 140 // type assertion
144 claims, ok := token.Claims.(*TokenClaims) 141 claims, ok := token.Claims.(*TokenClaims)
145 if !ok || !token.Valid { 142 if !ok || !token.Valid {
146 return &TokenClaims{}, errors.New("token is not valid") 143 return &TokenClaims{}, errors.New("token is not valid")
147 } 144 }
148 return claims, nil 145 return claims, nil
149 } 146 }
150 147
151 func parseTokenFunc(tokenString string) (*jwt.Token, error) { 148 func parseTokenFunc(tokenString string) (*jwt.Token, error) {
152 token, err := jwt.ParseWithClaims(tokenString, 149 token, err := jwt.ParseWithClaims(tokenString,
153 &TokenClaims{}, 150 &TokenClaims{},
154 func(token *jwt.Token) (interface{}, error) { 151 func(token *jwt.Token) (interface{}, error) {
155 return []byte(secret), nil 152 return []byte(secret), nil
156 }, 153 },
157 ) 154 )
158 return token, err 155 return token, err
159 } 156 }
160
161 func authMinRegReq(uname, pword string) (bool, error) {
162 return true, nil
163 }
164
165 157
format_utility.go
1 package restutility 1 package restutility
2 2
3 import ( 3 import (
4 "strings"
5 "time" 4 "time"
6 "strconv"
7 ) 5 )
8 6
9 func UnixToDate(input int64) time.Time { 7 func UnixToDate(input int64) time.Time {
10 return time.Unix(input, 0) 8 return time.Unix(input, 0)
11 } 9 }
12 10
13 func DateToUnix(input interface{}) int64 { 11 func DateToUnix(input interface{}) int64 {
14 if input != nil { 12 if input != nil {
15 t := input.(time.Time) 13 t := input.(time.Time)
16 return t.Unix() 14 return t.Unix()
17 15
18 } 16 }
19 return 0 17 return 0
20 } 18 }
21 19
22 func EqualQuotes(input string) string { 20 func EqualQuotes(input string) string {
23 if input != "" { 21 if input != "" {
24 return " = '" + input + "'" 22 return " = '" + input + "'"
25 } 23 }
26 return "" 24 return ""
27 } 25 }
28 26
29 func LikeQuotes(input string) string { 27 func LikeQuotes(input string) string {
30 if input != "" { 28 if input != "" {
31 return " LIKE UPPER('%" + input + "%')" 29 return " LIKE UPPER('%" + input + "%')"
32 } 30 }
33 return "" 31 return ""
34 } 32 }
35 33
36 34
1 package restutility 1 package restutility
2 2
3 import ( 3 import (
4 "net/http" 4 "net/http"
5 "encoding/json" 5 "encoding/json"
6 ) 6 )
7 7
8 var _apiVersion = "/api/v1" 8 var _apiVersion = "/api/v1"
9 9
10 func SetApiVersion(ver string) string { 10 func SetApiVersion(ver string) string {
11 _apiVersion = ver 11 _apiVersion = ver
12 return _apiVeresion 12 return _apiVersion
13 } 13 }
14 14
15 //// 15 ////
16 //// ERROR UTILITY 16 //// ERROR UTILITY
17 //// 17 ////
18 18
19 const templateHttpErr500_EN = "An internal server error has occurred." 19 const templateHttpErr500_EN = "An internal server error has occurred."
20 const templateHttpErr500_RS = "Došlo je do greške na serveru." 20 const templateHttpErr500_RS = "Došlo je do greške na serveru."
21 const templateHttpErr400_EN = "Bad request: invalid request body." 21 const templateHttpErr400_EN = "Bad request: invalid request body."
22 const templateHttpErr400_RS = "Neispravan zahtev." 22 const templateHttpErr400_RS = "Neispravan zahtev."
23 23
24 type HttpError struct { 24 type HttpError struct {
25 Error []HttpErrorDesc `json:"error"` 25 Error []HttpErrorDesc `json:"error"`
26 Request string `json:"request"` 26 Request string `json:"request"`
27 } 27 }
28 28
29 type HttpErrorDesc struct { 29 type HttpErrorDesc struct {
30 Lang string `json:"lang"` 30 Lang string `json:"lang"`
31 Desc string `json:"description"` 31 Desc string `json:"description"`
32 } 32 }
33 33
34 func RespondWithHttpError(w http.ResponseWriter, 34 func RespondWithHttpError(w http.ResponseWriter,
35 req *http.Request, 35 req *http.Request,
36 code int, 36 code int,
37 httpErr []HttpErrorDesc) { 37 httpErr []HttpErrorDesc) {
38 38
39 err := HttpError{ 39 err := HttpError{
40 Error: httpErr, 40 Error: httpErr,
41 Request: req.Method + " " + req.URL.Path, 41 Request: req.Method + " " + req.URL.Path,
42 } 42 }
43 w.WriteHeader(code) 43 w.WriteHeader(code)
44 json.NewEncoder(w).Encode(err) 44 json.NewEncoder(w).Encode(err)
45 } 45 }
46 46
47 func RespondWithHttpError400(w http.ResponseWriter, req *http.Request) { 47 func RespondWithHttpError400(w http.ResponseWriter, req *http.Request) {
48 RespondWithHttpError(w, req, http.StatusBadRequest, []HttpErrorDesc{ 48 RespondWithHttpError(w, req, http.StatusBadRequest, []HttpErrorDesc{
49 {Lang: "en", Desc: templateHttpErr400_EN}, 49 {Lang: "en", Desc: templateHttpErr400_EN},
50 {Lang: "rs", Desc: templateHttpErr400_RS}, 50 {Lang: "rs", Desc: templateHttpErr400_RS},
51 }) 51 })
52 } 52 }
53 53
54 func RespondWithHttpError500(w http.ResponseWriter, req *http.Request) { 54 func RespondWithHttpError500(w http.ResponseWriter, req *http.Request) {
55 RespondWithHttpError(w, req, http.StatusInternalServerError, []HttpErrorDesc{ 55 RespondWithHttpError(w, req, http.StatusInternalServerError, []HttpErrorDesc{
56 {Lang: "en", Desc: templateHttpErr500_EN}, 56 {Lang: "en", Desc: templateHttpErr500_EN},
57 {Lang: "rs", Desc: templateHttpErr500_RS}, 57 {Lang: "rs", Desc: templateHttpErr500_RS},
58 }) 58 })
59 } 59 }
60 60
61 func DeliverPayload(w http.ResponseWriter, payload JSONPayload) { 61 func DeliverPayload(w http.ResponseWriter, payload JSONPayload) {
62 json.NewEncoder(w).Encode(payload) 62 json.NewEncoder(w).Encode(payload)
63 payload.Data = nil 63 payload.Data = nil
64 } 64 }
65 65
66 //// 66 ////
67 //// HANDLER FUNC WRAPPER 67 //// HANDLER FUNC WRAPPER
68 //// 68 ////
69 69
70 // wrapHandlerFunc is as wrapper function for route handlers. 70 // wrapHandlerFunc is as wrapper function for route handlers.
71 // Sets common headers and checks for token validity. 71 // Sets common headers and checks for token validity.
72 func HandleFuncWrap(fn http.HandlerFunc) http.HandlerFunc { 72 func HandleFuncWrap(fn http.HandlerFunc) http.HandlerFunc {
73 return func(w http.ResponseWriter, req *http.Request) { 73 return func(w http.ResponseWriter, req *http.Request) {
74 // @TODO: check Content-type header (must be application/json) 74 // @TODO: check Content-type header (must be application/json)
75 // ctype := w.Header.Get("Content-Type") 75 // ctype := w.Header.Get("Content-Type")
76 // if req.Method != "GET" && ctype != "application/json" { 76 // if req.Method != "GET" && ctype != "application/json" {
77 // replyWithHttpError(w, req, http.StatusBadRequest, 77 // replyWithHttpError(w, req, http.StatusBadRequest,
78 // "Not a supported content type: " + ctype) 78 // "Not a supported content type: " + ctype)
79 // } 79 // }
80 80
81 w.Header().Set("Access-Control-Allow-Origin", "*") 81 w.Header().Set("Access-Control-Allow-Origin", "*")
82 w.Header().Set("Access-Control-Allow-Methods", 82 w.Header().Set("Access-Control-Allow-Methods",
83 `POST, 83 `POST,
84 GET, 84 GET,
85 PUT, 85 PUT,
86 DELETE, 86 DELETE,
87 OPTIONS`) 87 OPTIONS`)
88 w.Header().Set("Access-Control-Allow-Headers", 88 w.Header().Set("Access-Control-Allow-Headers",
89 `Accept, 89 `Accept,
90 Content-Type, 90 Content-Type,
91 Content-Length, 91 Content-Length,
92 Accept-Encoding, 92 Accept-Encoding,
93 X-CSRF-Token, 93 X-CSRF-Token,
94 Authorization`) 94 Authorization`)
95 w.Header().Set("Content-Type", "application/json; charset=utf-8") 95 w.Header().Set("Content-Type", "application/json; charset=utf-8")
96 96
97 if req.Method == "OPTIONS" { 97 if req.Method == "OPTIONS" {
98 return 98 return
99 } 99 }
100 100
101 if req.URL.Path != _apiVersion + "/token/new" { 101 if req.URL.Path != _apiVersion + "/token/new" {
102 token := req.Header.Get("Authorization") 102 token := req.Header.Get("Authorization")
103 if _, err := ParseAPIToken(token); err != nil { 103 if _, err := ParseAPIToken(token); err != nil {
104 RespondWithHttpError(w, req, http.StatusUnauthorized, 104 RespondWithHttpError(w, req, http.StatusUnauthorized,
105 []HttpErrorDesc{ 105 []HttpErrorDesc{
106 {Lang: "en", Desc: "Unauthorized request."}, 106 {Lang: "en", Desc: "Unauthorized request."},
107 {Lang: "rs", Desc: "Neautorizovani zahtev."}, 107 {Lang: "rs", Desc: "Neautorizovani zahtev."},
108 }) 108 })
109 return 109 return
110 } 110 }
111 } 111 }
112 112
113 err := req.ParseForm() 113 err := req.ParseForm()
114 if err != nil { 114 if err != nil {
115 RespondWithHttpError(w, req, http.StatusBadRequest, 115 RespondWithHttpError(w, req, http.StatusBadRequest,
116 []HttpErrorDesc{ 116 []HttpErrorDesc{
117 {Lang: "en", Desc: templateHttpErr400_EN}, 117 {Lang: "en", Desc: templateHttpErr400_EN},
118 {Lang: "rs", Desc: templateHttpErr400_RS}, 118 {Lang: "rs", Desc: templateHttpErr400_RS},
119 }) 119 })
120 return 120 return
121 } 121 }
122 fn(w, req) 122 fn(w, req)
123 } 123 }
124 } 124 }
125 125
126 //// 126 ////
127 //// NOT FOUND HANDLER 127 //// NOT FOUND HANDLER
128 //// 128 ////
129 129
130 func NotFoundHandler(w http.ResponseWriter, req *http.Request) { 130 func NotFoundHandler(w http.ResponseWriter, req *http.Request) {
131 RespondWithHttpError(w, req, http.StatusNotFound, []HttpErrorDesc{ 131 RespondWithHttpError(w, req, http.StatusNotFound, []HttpErrorDesc{
132 {Lang: "en", Desc: "Not found."}, 132 {Lang: "en", Desc: "Not found."},
133 {Lang: "rs", Desc: "Traženi resurs ne postoji."}, 133 {Lang: "rs", Desc: "Traženi resurs ne postoji."},
134 }) 134 })
135 } 135 }
136 136