|
|
|
@@ -77,7 +77,6 @@ func setupApiV1Handler() []apiV1HandlerMap { |
|
|
|
{"GET", "login-available/", apiV1LoginAvailable}, |
|
|
|
|
|
|
|
{"POST", "lender-upload/", apiV1UploadsPost}, |
|
|
|
{"GET", "lender-upload/", apiV1UploadOriginalFileGet}, |
|
|
|
|
|
|
|
{"GET", "upload-analysis/", apiV1UploadAnalysis}, |
|
|
|
{"PUT", "upload-analysis/", apiV1UploadCreateAnalysis}, |
|
|
|
@@ -94,6 +93,8 @@ func setupApiV1Handler() []apiV1HandlerMap { |
|
|
|
|
|
|
|
{"GET", "lender-list/", apiV1LenderList}, |
|
|
|
|
|
|
|
{"GET", "payout-ex/", apiV1PayOutExGet}, |
|
|
|
|
|
|
|
{"GET", "login", apiV1DumpRequest}, |
|
|
|
} |
|
|
|
} else { //production |
|
|
|
@@ -148,7 +149,6 @@ func setupApiV1Handler() []apiV1HandlerMap { |
|
|
|
{"GET", "login-available/", apiV1LoginAvailable}, |
|
|
|
|
|
|
|
{"POST", "lender-upload/", apiV1UploadsPost}, |
|
|
|
{"GET", "lender-upload/", apiV1UploadOriginalFileGet}, |
|
|
|
|
|
|
|
{"GET", "upload-analysis/", apiV1UploadAnalysis}, |
|
|
|
{"PUT", "upload-analysis/", apiV1UploadCreateAnalysis}, |
|
|
|
@@ -165,6 +165,8 @@ func setupApiV1Handler() []apiV1HandlerMap { |
|
|
|
|
|
|
|
{"GET", "lender-list/", apiV1LenderList}, |
|
|
|
|
|
|
|
{"GET", "payout-ex/", apiV1PayOutExGet}, |
|
|
|
|
|
|
|
{"GET", "login", apiV1EmptyResponse}, |
|
|
|
} |
|
|
|
} |
|
|
|
@@ -188,43 +190,69 @@ func apiV1Main(w http.ResponseWriter, r *http.Request) { |
|
|
|
logRequestDebug(httputil.DumpRequest(r, true)) |
|
|
|
} |
|
|
|
|
|
|
|
session := apiV1InitSession(r) |
|
|
|
if config.Debug { |
|
|
|
log.Debugf("session : %+v", session) |
|
|
|
session := loan.Session{} |
|
|
|
session.MarkEmpty() |
|
|
|
bypassSession := apiV1NoNeedSession(r) |
|
|
|
if !bypassSession { // no point to create session for preflight |
|
|
|
session = apiV1InitSession(r) |
|
|
|
if config.Debug { |
|
|
|
log.Debugf("session : %+v", session) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//search through handler |
|
|
|
path := r.URL.Path[len(apiV1Prefix):] //strip API prefix |
|
|
|
handled := false |
|
|
|
for _, node := range apiV1Handler { |
|
|
|
//log.Println(node, path, strings.HasPrefix(path, node.Path)) |
|
|
|
if (r.Method == node.Method || node.Method == "*") && strings.HasPrefix(path, node.Path) { |
|
|
|
if (strings.ToUpper(r.Method) == node.Method || node.Method == "*") && strings.HasPrefix(path, node.Path) { |
|
|
|
handled = true |
|
|
|
node.Handler(w, r, &session) |
|
|
|
e := session.Write() //finish this session to DB |
|
|
|
if e != nil { |
|
|
|
log.Warnf("Failed to Save Session %+v \n reason \n%s\n", session, e.Error()) |
|
|
|
} |
|
|
|
return |
|
|
|
break //stop search handler further |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if !bypassSession { // no point to write session for preflight |
|
|
|
e := session.Write() //finish this session to DB |
|
|
|
if e != nil { |
|
|
|
log.Warnf("Failed to Save Session %+v \n reason \n%s\n", session, e.Error()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//Catch for all UnHandled Request |
|
|
|
e := session.Write() //finish this session to DB |
|
|
|
if e != nil { |
|
|
|
log.Warnf("Failed to Save Session %+v \n reason \n%s\n", session, e.Error()) |
|
|
|
if !handled { |
|
|
|
if config.Debug { |
|
|
|
apiV1DumpRequest(w, r, &session) |
|
|
|
} else { |
|
|
|
apiV1EmptyResponse(w, r, &session) |
|
|
|
} |
|
|
|
} |
|
|
|
if config.Debug { |
|
|
|
apiV1DumpRequest(w, r, &session) |
|
|
|
} else { |
|
|
|
apiV1EmptyResponse(w, r, &session) |
|
|
|
} |
|
|
|
|
|
|
|
func apiV1NoNeedSession(r *http.Request) bool { |
|
|
|
if r.Method == "OPTIONS" { |
|
|
|
return true |
|
|
|
} |
|
|
|
|
|
|
|
path := r.URL.Path[len(apiV1Prefix):] //strip API prefix |
|
|
|
|
|
|
|
if r.Method == "GET" { |
|
|
|
if strings.HasPrefix(path, "avatar/") || |
|
|
|
strings.HasPrefix(path, "upload-original/") || |
|
|
|
strings.HasPrefix(path, "upload-as-image/") || |
|
|
|
strings.HasPrefix(path, "upload-as-analysis/") || |
|
|
|
strings.HasPrefix(path, "upload-as-thumbnail/") || |
|
|
|
strings.HasPrefix(path, "upload-as-pdf/") { |
|
|
|
return true |
|
|
|
} |
|
|
|
} |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
|
func apiV1InitSession(r *http.Request) (session loan.Session) { |
|
|
|
session.MarkEmpty() |
|
|
|
|
|
|
|
//track browser, and take session from cookie |
|
|
|
cookieSession, e := apiV1InitSessionByBrowserId(r) |
|
|
|
cookieSession, e := apiV1InitSessionByCookie(r) |
|
|
|
if e == nil { |
|
|
|
session = cookieSession |
|
|
|
} |
|
|
|
@@ -255,8 +283,8 @@ func setupCrossOriginResponse(w *http.ResponseWriter, r *http.Request) { |
|
|
|
method := r.Header.Get("Access-Control-Request-Method") |
|
|
|
(*w).Header().Set("Access-Control-Allow-Origin", origin) //for that specific origin |
|
|
|
(*w).Header().Set("Access-Control-Allow-Credentials", "true") |
|
|
|
(*w).Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, "+method) |
|
|
|
(*w).Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, Cookie, Biukop-Session, Biukop-Session-Token, Biukop-Session-Expire, "+requestedHeaders) |
|
|
|
(*w).Header().Set("Access-Control-Allow-Methods", removeDupHeaderOptions("POST, GET, OPTIONS, PUT, DELETE, "+method)) |
|
|
|
(*w).Header().Set("Access-Control-Allow-Headers", removeDupHeaderOptions("Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, Cookie, Biukop-Session, Biukop-Session-Token, Biukop-Session-Expire, "+requestedHeaders)) |
|
|
|
} |
|
|
|
|
|
|
|
func apiV1GetMachineId(r *http.Request) string { |
|
|
|
@@ -275,11 +303,35 @@ func apiV1GetMachineId(r *http.Request) string { |
|
|
|
return mid |
|
|
|
} |
|
|
|
|
|
|
|
func apiV1GetCORSHeaders(r *http.Request) (ret string) { |
|
|
|
requestedHeaders := r.Header.Get("Access-control-Request-Headers") |
|
|
|
ret = "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, Cookie, Biukop-Session, Biukop-Session-Token, Biukop-Session-Expire," + requestedHeaders |
|
|
|
return removeDupHeaderOptions(ret) |
|
|
|
} |
|
|
|
|
|
|
|
func removeDupHeaderOptions(inStr string) (out string) { |
|
|
|
headers := map[string]struct{}{} |
|
|
|
strings.ReplaceAll(inStr, " ", "") // remove space |
|
|
|
headerArray := strings.Split(inStr, ",") // split |
|
|
|
for _, v := range headerArray { |
|
|
|
headers[v] = struct{}{} // same key will overwrite each other |
|
|
|
} |
|
|
|
out = "" |
|
|
|
for k, _ := range headers { |
|
|
|
if out != "" { |
|
|
|
out += ", " |
|
|
|
} |
|
|
|
out += k |
|
|
|
} |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
func apiV1GetMachineIdFromSession(ss *loan.Session) string { |
|
|
|
return ss.GetStr("Biukop-Mid") |
|
|
|
} |
|
|
|
func apiV1InitSessionByBrowserId(r *http.Request) (session loan.Session, e error) { |
|
|
|
func apiV1InitSessionByCookie(r *http.Request) (session loan.Session, e error) { |
|
|
|
var sid string |
|
|
|
session.MarkEmpty() |
|
|
|
mid := apiV1GetMachineId(r) |
|
|
|
inCookie, e := r.Cookie("Biukop-Session") |
|
|
|
if e == nil { |
|
|
|
@@ -297,29 +349,60 @@ func apiV1InitSessionByBrowserId(r *http.Request) (session loan.Session, e error |
|
|
|
} |
|
|
|
|
|
|
|
func apiV1AddTrackingCookie(w http.ResponseWriter, r *http.Request, session *loan.Session) { |
|
|
|
//set session header too. |
|
|
|
w.Header().Add("Access-Control-Expose-Headers", "Biukop-Session") |
|
|
|
if strings.ToUpper(r.Method) == "OPTION" { |
|
|
|
return |
|
|
|
} |
|
|
|
w.Header().Add("Access-Control-Expose-Headers", apiV1GetCORSHeaders(r)) |
|
|
|
apiV1AddTrackingSession(w, r, session) |
|
|
|
apiV1AddTrackingMachineId(w, r, session) |
|
|
|
} |
|
|
|
|
|
|
|
func apiV1AddTrackingSession(w http.ResponseWriter, r *http.Request, session *loan.Session) { |
|
|
|
sessionId := "" |
|
|
|
if session == nil { |
|
|
|
log.Warn("non-exist session, empty Id sent", session) |
|
|
|
w.Header().Add("Biukop-Session", "") |
|
|
|
} else { |
|
|
|
w.Header().Add("Biukop-Session", session.Id) |
|
|
|
if session.Id == "" { |
|
|
|
log.Warn("empty session, empty Id sent", session) |
|
|
|
} else { |
|
|
|
w.Header().Add("Biukop-Session", session.Id) |
|
|
|
sessionId = session.Id |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
//add tracking cookie |
|
|
|
expiration := time.Now().Add(365 * 24 * time.Hour) |
|
|
|
cookie := http.Cookie{ |
|
|
|
Name: "Biukop-Session", |
|
|
|
Value: sessionId, // may be "" |
|
|
|
Expires: time.Now().Add(365 * 24 * time.Hour), |
|
|
|
Path: "/", |
|
|
|
Secure: true, |
|
|
|
SameSite: http.SameSiteNoneMode} |
|
|
|
http.SetCookie(w, &cookie) |
|
|
|
|
|
|
|
} |
|
|
|
func apiV1AddTrackingMachineId(w http.ResponseWriter, r *http.Request, session *loan.Session) { |
|
|
|
mid := apiV1GetMachineId(r) |
|
|
|
cookie := http.Cookie{Name: "Biukop-Mid", Value: mid, Expires: expiration, Path: "/", Secure: true, SameSite: http.SameSiteNoneMode} |
|
|
|
expiration := time.Now().Add(365 * 24 * time.Hour) |
|
|
|
|
|
|
|
w.Header().Add("Biukop-Mid", mid) |
|
|
|
|
|
|
|
cookie := http.Cookie{ |
|
|
|
Name: "Biukop-Mid", |
|
|
|
Value: mid, |
|
|
|
Expires: expiration, |
|
|
|
Path: "/", |
|
|
|
Secure: true, |
|
|
|
SameSite: http.SameSiteNoneMode} |
|
|
|
http.SetCookie(w, &cookie) |
|
|
|
|
|
|
|
if session != nil { |
|
|
|
cookie = http.Cookie{Name: "Biukop-Session", Value: session.Id, Expires: expiration, Path: "/", Secure: true, SameSite: http.SameSiteNoneMode} |
|
|
|
http.SetCookie(w, &cookie) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func apiV1InitSessionByHttpHeader(r *http.Request) (ss loan.Session, e error) { |
|
|
|
sid := r.Header.Get("Biukop-Session") |
|
|
|
ss.MarkEmpty() |
|
|
|
sid := apiV1GetSessionIdFromRequest(r) |
|
|
|
|
|
|
|
//make sure session id is given |
|
|
|
if sid != "" { |
|
|
|
e = ss.Retrieve(r) |
|
|
|
@@ -332,13 +415,20 @@ func apiV1InitSessionByHttpHeader(r *http.Request) (ss loan.Session, e error) { |
|
|
|
e = errors.New("session not found: " + sid) |
|
|
|
} |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
func apiV1ErrorCheck(e error) { |
|
|
|
if nil != e { |
|
|
|
panic(e.Error()) //TODO: detailed error check, truck all caller |
|
|
|
func apiV1GetSessionIdFromRequest(r *http.Request) string { |
|
|
|
sid := "" |
|
|
|
inCookie, e := r.Cookie("Biukop-Session") |
|
|
|
if e == nil { |
|
|
|
sid = inCookie.Value |
|
|
|
} |
|
|
|
|
|
|
|
headerSid := r.Header.Get("Biukop-Session") |
|
|
|
if headerSid != "" { |
|
|
|
sid = headerSid |
|
|
|
} |
|
|
|
return sid |
|
|
|
} |
|
|
|
|
|
|
|
func apiV1Server500Error(w http.ResponseWriter, r *http.Request) { |