From 836f16d74d7aa0db55ed80b6af27a6e68971be4a Mon Sep 17 00:00:00 2001 From: yuli Date: Thu, 26 Dec 2024 23:13:11 +0200 Subject: [PATCH] refactor code - adding new utils module --- src/agreements_api.go | 167 +++++++++++++++++----------------- src/audit_api.go | 116 ++++++++++++++++++++--- src/bunker.go | 55 +++++++---- src/captcha.go | 18 ++-- src/conf.go | 4 +- src/expiration_api.go | 59 ++++++------ src/go.mod | 5 +- src/init_test.go | 2 +- src/lbasis_api.go | 43 ++++----- src/pactivities_api.go | 61 +++++++------ src/pactivities_db.go | 5 +- src/requests_api.go | 99 ++++++++++---------- src/service.go | 13 +-- src/sessions_api.go | 69 +++++++------- src/sessions_db.go | 3 +- src/sharedrecords_api.go | 27 +++--- src/sharedrecords_db.go | 7 +- src/storage/mysql-storage.go | 4 +- src/storage/pgsql-storage.go | 4 +- src/storage/sqlite-storage.go | 4 +- src/storage/storage.go | 2 +- src/userapps_api.go | 73 +++++++-------- src/users_api.go | 157 ++++++++++++++++---------------- src/users_db.go | 43 ++++----- src/utils_test.go | 17 ++-- src/xtokens_db.go | 11 ++- 26 files changed, 601 insertions(+), 467 deletions(-) diff --git a/src/agreements_api.go b/src/agreements_api.go index 44e8660..36af39c 100644 --- a/src/agreements_api.go +++ b/src/agreements_api.go @@ -7,6 +7,7 @@ import ( "reflect" "github.com/julienschmidt/httprouter" + "github.com/securitybunker/databunker/src/utils" //"go.mongodb.org/mongo-driver/bson" ) @@ -17,42 +18,42 @@ func (e mainEnv) agreementAccept(w http.ResponseWriter, r *http.Request, ps http event := audit("accept agreement by "+brief, identity, mode, identity) defer func() { event.submit(e.db, e.conf) }() - if validateMode(mode) == false { - returnError(w, r, "bad mode", 405, nil, event) + if utils.ValidateMode(mode) == false { + ReturnError(w, r, "bad mode", 405, nil, event) return } - brief = normalizeBrief(brief) - if isValidBrief(brief) == false { - returnError(w, r, "bad brief format", 405, nil, event) + brief = utils.NormalizeBrief(brief) + if utils.CheckValidBrief(brief) == false { + ReturnError(w, r, "bad brief format", 405, nil, event) return } exists, err := e.db.checkLegalBasis(brief) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } if exists == false { - returnError(w, r, "not found", 404, nil, event) + ReturnError(w, r, "not found", 404, nil, event) return } userTOKEN := "" if mode == "token" { - if enforceUUID(w, identity, event) == false { + if EnforceUUID(w, identity, event) == false { return } userBson, err := e.db.lookupUserRecord(identity) if err != nil || userBson == nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } - if e.enforceAuth(w, r, event) == "" { + if e.EnforceAuth(w, r, event) == "" { return } userTOKEN = identity } else { userBson, err := e.db.lookupUserRecordByIndex(mode, identity, e.conf) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } if userBson != nil { @@ -60,33 +61,33 @@ func (e mainEnv) agreementAccept(w http.ResponseWriter, r *http.Request, ps http event.Record = userTOKEN } else { if mode == "login" { - returnError(w, r, "internal error", 405, nil, event) + ReturnError(w, r, "internal error", 405, nil, event) return } // else user not found - we allow to save consent for unlinked users! } } - records, err := getJSONPostMap(r) + records, err := utils.GetJSONPostMap(r) if err != nil { - returnError(w, r, "failed to decode request body", 405, err, event) + ReturnError(w, r, "failed to decode request body", 405, err, event) return } starttime := int32(0) expiration := int32(0) - referencecode := getStringValue(records["referencecode"]) - lastmodifiedby := getStringValue(records["lastmodifiedby"]) - agreementmethod := getStringValue(records["agreementmethod"]) - status := getStringValue(records["status"]) + referencecode := utils.GetStringValue(records["referencecode"]) + lastmodifiedby := utils.GetStringValue(records["lastmodifiedby"]) + agreementmethod := utils.GetStringValue(records["agreementmethod"]) + status := utils.GetStringValue(records["status"]) if len(status) == 0 { status = "yes" } else { - status = normalizeConsentStatus(status) + status = utils.NormalizeConsentStatus(status) } if value, ok := records["expiration"]; ok { switch records["expiration"].(type) { case string: - expiration, _ = parseExpiration(value.(string)) + expiration, _ = utils.ParseExpiration(value.(string)) case float64: expiration = int32(value.(float64)) } @@ -94,16 +95,16 @@ func (e mainEnv) agreementAccept(w http.ResponseWriter, r *http.Request, ps http if value, ok := records["starttime"]; ok { switch records["starttime"].(type) { case string: - starttime, _ = parseExpiration(value.(string)) + starttime, _ = utils.ParseExpiration(value.(string)) case float64: starttime = int32(value.(float64)) } } switch mode { case "email": - identity = normalizeEmail(identity) + identity = utils.NormalizeEmail(identity) case "phone": - identity = normalizePhone(identity, e.conf.Sms.DefaultCountry) + identity = utils.NormalizePhone(identity, e.conf.Sms.DefaultCountry) } log.Printf("Processing agreement, status: %s\n", status) e.db.acceptAgreement(userTOKEN, mode, identity, brief, status, agreementmethod, @@ -131,37 +132,37 @@ func (e mainEnv) agreementWithdraw(w http.ResponseWriter, r *http.Request, ps ht event := audit("withdraw agreement by "+brief, identity, mode, identity) defer func() { event.submit(e.db, e.conf) }() - if validateMode(mode) == false { - returnError(w, r, "bad mode", 405, nil, event) + if utils.ValidateMode(mode) == false { + ReturnError(w, r, "bad mode", 405, nil, event) return } - brief = normalizeBrief(brief) - if isValidBrief(brief) == false { - returnError(w, r, "bad brief format", 405, nil, event) + brief = utils.NormalizeBrief(brief) + if utils.CheckValidBrief(brief) == false { + ReturnError(w, r, "bad brief format", 405, nil, event) return } lbasis, err := e.db.getLegalBasis(brief) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } if lbasis == nil { - returnError(w, r, "not found", 405, nil, event) + ReturnError(w, r, "not found", 405, nil, event) return } userTOKEN := "" authResult := "" if mode == "token" { - if enforceUUID(w, identity, event) == false { + if EnforceUUID(w, identity, event) == false { return } userBson, _ := e.db.lookupUserRecord(identity) if userBson == nil { - returnError(w, r, "internal error", 405, nil, event) + ReturnError(w, r, "internal error", 405, nil, event) return } - authResult = e.enforceAuth(w, r, event) + authResult = e.EnforceAuth(w, r, event) if authResult == "" { return } @@ -174,18 +175,18 @@ func (e mainEnv) agreementWithdraw(w http.ResponseWriter, r *http.Request, ps ht event.Record = userTOKEN } else { if mode == "login" { - returnError(w, r, "internal error", 405, nil, event) + ReturnError(w, r, "internal error", 405, nil, event) return } // else user not found - we allow to save consent for unlinked users! } } - records, err := getJSONPostMap(r) + records, err := utils.GetJSONPostMap(r) if err != nil { - returnError(w, r, "failed to decode request body", 405, err, event) + ReturnError(w, r, "failed to decode request body", 405, err, event) return } - lastmodifiedby := getStringValue(records["lastmodifiedby"]) + lastmodifiedby := utils.GetStringValue(records["lastmodifiedby"]) selfService := false if value, ok := lbasis["usercontrol"]; ok { if reflect.TypeOf(value).Kind() == reflect.Bool { @@ -200,7 +201,7 @@ func (e mainEnv) agreementWithdraw(w http.ResponseWriter, r *http.Request, ps ht if selfService == false { // user can change consent only for briefs defined in self-service if len(authResult) == 0 { - if e.enforceAdmin(w, r, event) == "" { + if e.EnforceAdmin(w, r, event) == "" { return } } @@ -209,7 +210,7 @@ func (e mainEnv) agreementWithdraw(w http.ResponseWriter, r *http.Request, ps ht if authResult == "login" && selfService == false { rtoken, rstatus, err := e.db.saveUserRequest("agreement-withdraw", userTOKEN, "", brief, nil, e.conf) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -219,9 +220,9 @@ func (e mainEnv) agreementWithdraw(w http.ResponseWriter, r *http.Request, ps ht } switch mode { case "email": - identity = normalizeEmail(identity) + identity = utils.NormalizeEmail(identity) case "phone": - identity = normalizePhone(identity, e.conf.Sms.DefaultCountry) + identity = utils.NormalizePhone(identity, e.conf.Sms.DefaultCountry) } e.db.withdrawAgreement(userTOKEN, brief, mode, identity, lastmodifiedby) w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -237,21 +238,21 @@ func (e mainEnv) agreementWithdraw(w http.ResponseWriter, r *http.Request, ps ht func (e mainEnv) agreementRevokeAll(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { brief := ps.ByName("brief") - if e.enforceAdmin(w, r, nil) == "" { + if e.EnforceAdmin(w, r, nil) == "" { return } - brief = normalizeBrief(brief) - if isValidBrief(brief) == false { - returnError(w, r, "bad brief format", 405, nil, nil) + brief = utils.NormalizeBrief(brief) + if utils.CheckValidBrief(brief) == false { + ReturnError(w, r, "bad brief format", 405, nil, nil) return } exists, err := e.db.checkLegalBasis(brief) if err != nil { - returnError(w, r, "internal error", 405, nil, nil) + ReturnError(w, r, "internal error", 405, nil, nil) return } if exists == false { - returnError(w, r, "not found", 405, nil, nil) + ReturnError(w, r, "not found", 405, nil, nil) return } e.db.revokeLegalBasis(brief) @@ -266,22 +267,22 @@ func (e mainEnv) getUserAgreements(w http.ResponseWriter, r *http.Request, ps ht event := audit("privacy agreements for "+mode, identity, mode, identity) defer func() { event.submit(e.db, e.conf) }() - if validateMode(mode) == false { - returnError(w, r, "bad mode", 405, nil, event) + if utils.ValidateMode(mode) == false { + ReturnError(w, r, "bad mode", 405, nil, event) return } userTOKEN := "" if mode == "token" { - if enforceUUID(w, identity, event) == false { + if EnforceUUID(w, identity, event) == false { return } userBson, _ := e.db.lookupUserRecord(identity) if userBson == nil { - returnError(w, r, "internal error", 405, nil, event) + ReturnError(w, r, "internal error", 405, nil, event) return } - if e.enforceAuth(w, r, event) == "" { + if e.EnforceAuth(w, r, event) == "" { return } userTOKEN = identity @@ -291,12 +292,12 @@ func (e mainEnv) getUserAgreements(w http.ResponseWriter, r *http.Request, ps ht if userBson != nil { userTOKEN = userBson["token"].(string) event.Record = userTOKEN - if e.enforceAuth(w, r, event) == "" { + if e.EnforceAuth(w, r, event) == "" { return } } else { if mode == "login" { - returnError(w, r, "internal error", 405, nil, event) + ReturnError(w, r, "internal error", 405, nil, event) return } // else user not found - we allow to save consent for unlinked users! @@ -304,7 +305,7 @@ func (e mainEnv) getUserAgreements(w http.ResponseWriter, r *http.Request, ps ht } } // make sure that user is logged in here, unless he wants to cancel emails - if e.enforceAuth(w, r, event) == "" { + if e.EnforceAuth(w, r, event) == "" { return } var resultJSON []byte @@ -316,7 +317,7 @@ func (e mainEnv) getUserAgreements(w http.ResponseWriter, r *http.Request, ps ht resultJSON, numRecords, err = e.db.listAgreementRecordsByIdentity(identity) } if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -332,35 +333,35 @@ func (e mainEnv) getUserAgreement(w http.ResponseWriter, r *http.Request, ps htt event := audit("privacy agreements for "+mode, identity, mode, identity) defer func() { event.submit(e.db, e.conf) }() - if validateMode(mode) == false { - returnError(w, r, "bad mode", 405, nil, event) + if utils.ValidateMode(mode) == false { + ReturnError(w, r, "bad mode", 405, nil, event) return } - brief = normalizeBrief(brief) - if isValidBrief(brief) == false { - returnError(w, r, "bad brief format", 405, nil, event) + brief = utils.NormalizeBrief(brief) + if utils.CheckValidBrief(brief) == false { + ReturnError(w, r, "bad brief format", 405, nil, event) return } exists, err := e.db.checkLegalBasis(brief) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } if exists == false { - returnError(w, r, "not found", 404, nil, event) + ReturnError(w, r, "not found", 404, nil, event) return } userTOKEN := "" if mode == "token" { - if enforceUUID(w, identity, event) == false { + if EnforceUUID(w, identity, event) == false { return } userBson, _ := e.db.lookupUserRecord(identity) if userBson == nil { - returnError(w, r, "internal error", 405, nil, event) + ReturnError(w, r, "internal error", 405, nil, event) return } - if e.enforceAuth(w, r, event) == "" { + if e.EnforceAuth(w, r, event) == "" { return } userTOKEN = identity @@ -370,29 +371,29 @@ func (e mainEnv) getUserAgreement(w http.ResponseWriter, r *http.Request, ps htt if userBson != nil { userTOKEN = userBson["token"].(string) event.Record = userTOKEN - if e.enforceAuth(w, r, event) == "" { + if e.EnforceAuth(w, r, event) == "" { return } } else { if mode == "login" { - returnError(w, r, "internal error", 405, nil, event) + ReturnError(w, r, "internal error", 405, nil, event) return } // else user not found - we allow to save consent for unlinked users! } } // make sure that user is logged in here, unless he wants to cancel emails - if e.enforceAuth(w, r, event) == "" { + if e.EnforceAuth(w, r, event) == "" { return } var resultJSON []byte resultJSON, err = e.db.viewAgreementRecord(userTOKEN, brief) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } if resultJSON == nil { - returnError(w, r, "not found", 405, err, event) + ReturnError(w, r, "not found", 405, err, event) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -409,19 +410,19 @@ func (e mainEnv) consentUserRecord(w http.ResponseWriter, r *http.Request, ps ht event := audit("consent record for "+brief, identity, mode, identity) defer func() { event.submit(e.db, e.conf) }() - if validateMode(mode) == false { - returnError(w, r, "bad mode", 405, nil, event) + if utils.ValidateMode(mode) == false { + ReturnError(w, r, "bad mode", 405, nil, event) return } - brief = normalizeBrief(brief) - if isValidBrief(brief) == false { - returnError(w, r, "bad brief format", 405, nil, event) + brief = utils.NormalizeBrief(brief) + if utils.CheckValidBrief(brief) == false { + ReturnError(w, r, "bad brief format", 405, nil, event) return } userTOKEN := identity var userBson bson.M if mode == "token" { - if enforceUUID(w, identity, event) == false { + if EnforceUUID(w, identity, event) == false { return } userBson, _ = e.db.lookupUserRecord(identity) @@ -433,20 +434,20 @@ func (e mainEnv) consentUserRecord(w http.ResponseWriter, r *http.Request, ps ht } } if userBson == nil { - returnError(w, r, "internal error", 405, nil, event) + ReturnError(w, r, "internal error", 405, nil, event) return } // make sure that user is logged in here, unless he wants to cancel emails - if e.enforceAuth(w, r, event) == "" { + if e.EnforceAuth(w, r, event) == "" { return } resultJSON, err := e.db.viewConsentRecord(userTOKEN, brief) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } if resultJSON == nil { - returnError(w, r, "not found", 405, nil, event) + ReturnError(w, r, "not found", 405, nil, event) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -461,7 +462,7 @@ func (e mainEnv) consentFilterRecords(w http.ResponseWriter, r *http.Request, ps brief := ps.ByName("brief") event := audit("consent get all for "+brief, brief, "brief", brief) defer func() { event.submit(e.db, e.conf) }() - if e.enforceAuth(w, r, event) == "" { + if e.EnforceAuth(w, r, event) == "" { return } var offset int32 @@ -475,7 +476,7 @@ func (e mainEnv) consentFilterRecords(w http.ResponseWriter, r *http.Request, ps } resultJSON, numRecords, err := e.db.filterConsentRecords(brief, offset, limit) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } log.Printf("Total count of rows: %d\n", numRecords) diff --git a/src/audit_api.go b/src/audit_api.go index 45c0e3e..73e23ef 100644 --- a/src/audit_api.go +++ b/src/audit_api.go @@ -6,30 +6,122 @@ import ( "net/http" "github.com/julienschmidt/httprouter" + "github.com/securitybunker/databunker/src/utils" ) +func ReturnError(w http.ResponseWriter, r *http.Request, message string, code int, err error, event *auditEvent) { + log.Printf("[%d] %s %s -> Return error\n", code, r.Method, r.URL.Path) + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(code) + fmt.Fprintf(w, `{"status":"error","message":%q}`, message) + if event != nil { + event.Status = "error" + event.Msg = message + if err != nil { + event.Debug = err.Error() + log.Printf("Generate error response: %s, Error: %s\n", message, err.Error()) + } else { + log.Printf("Generate error response: %s\n", message) + } + } + //http.Error(w, http.StatusText(405), 405) +} + +func EnforceUUID(w http.ResponseWriter, uuidCode string, event *auditEvent) bool { + if utils.CheckValidUUID(uuidCode) == false { + //fmt.Printf("405 bad uuid in : %s\n", uuidCode) + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(405) + fmt.Fprintf(w, `{"status":"error","message":"bad uuid"}`) + if event != nil { + event.Status = "error" + event.Msg = "bad uuid" + } + return false + } + return true +} + +func (e mainEnv) EnforceAuth(w http.ResponseWriter, r *http.Request, event *auditEvent) string { + /* + for key, value := range r.Header { + fmt.Printf("%s => %s\n", key, value) + } + */ + if token, ok := r.Header["X-Bunker-Token"]; ok { + authResult, err := e.db.checkUserAuthXToken(token[0]) + //fmt.Printf("error in auth? error %s - %s\n", err, token[0]) + if err == nil { + if event != nil { + event.Identity = authResult.name + if authResult.ttype == "login" && authResult.token == event.Record { + return authResult.ttype + } + } + if len(authResult.ttype) > 0 && authResult.ttype != "login" { + return authResult.ttype + } + } + /* + if e.db.checkXtoken(token[0]) == true { + if event != nil { + event.Identity = "admin" + } + return true + } + */ + } + log.Printf("403 Access denied\n") + w.WriteHeader(http.StatusForbidden) + w.Write([]byte("Access denied")) + if event != nil { + event.Status = "error" + event.Msg = "access denied" + } + return "" +} + +func (e mainEnv) EnforceAdmin(w http.ResponseWriter, r *http.Request, event *auditEvent) string { + if token, ok := r.Header["X-Bunker-Token"]; ok { + authResult, err := e.db.checkUserAuthXToken(token[0]) + //fmt.Printf("error in auth? error %s - %s\n", err, token[0]) + if err == nil { + if event != nil { + event.Identity = authResult.name + } + if len(authResult.ttype) > 0 && authResult.ttype != "login" { + return authResult.ttype + } + } + } + log.Printf("403 Access denied\n") + w.WriteHeader(http.StatusForbidden) + w.Write([]byte("Access denied")) + return "" +} + func (e mainEnv) getAuditEvents(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { userTOKEN := ps.ByName("token") event := audit("view audit events", userTOKEN, "token", userTOKEN) defer func() { event.submit(e.db, e.conf) }() - if enforceUUID(w, userTOKEN, event) == false { + if EnforceUUID(w, userTOKEN, event) == false { return } - if e.enforceAuth(w, r, event) == "" { + if e.EnforceAuth(w, r, event) == "" { return } var offset int32 var limit int32 = 10 args := r.URL.Query() if value, ok := args["offset"]; ok { - offset = atoi(value[0]) + offset = utils.Atoi(value[0]) } if value, ok := args["limit"]; ok { - limit = atoi(value[0]) + limit = utils.Atoi(value[0]) } resultJSON, counter, err := e.db.getAuditEvents(userTOKEN, offset, limit) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } //fmt.Printf("Total count of events: %d\n", counter) @@ -40,21 +132,21 @@ func (e mainEnv) getAuditEvents(w http.ResponseWriter, r *http.Request, ps httpr } func (e mainEnv) getAdminAuditEvents(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - if e.enforceAdmin(w, r, nil) == "" { + if e.EnforceAdmin(w, r, nil) == "" { return } var offset int32 var limit int32 = 10 args := r.URL.Query() if value, ok := args["offset"]; ok { - offset = atoi(value[0]) + offset = utils.Atoi(value[0]) } if value, ok := args["limit"]; ok { - limit = atoi(value[0]) + limit = utils.Atoi(value[0]) } resultJSON, counter, err := e.db.getAdminAuditEvents(offset, limit) if err != nil { - returnError(w, r, "internal error", 405, err, nil) + ReturnError(w, r, "internal error", 405, err, nil) return } //fmt.Printf("Total count of events: %d\n", counter) @@ -69,17 +161,17 @@ func (e mainEnv) getAuditEvent(w http.ResponseWriter, r *http.Request, ps httpro event := audit("view audit event", atoken, "token", atoken) defer func() { event.submit(e.db, e.conf) }() //fmt.Println("error code") - if enforceUUID(w, atoken, event) == false { + if EnforceUUID(w, atoken, event) == false { return } userTOKEN, resultJSON, err := e.db.getAuditEvent(atoken) log.Printf("extracted user token: %s", userTOKEN) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } event.Record = userTOKEN - if e.enforceAuth(w, r, event) == "" { + if e.EnforceAuth(w, r, event) == "" { return } w.Header().Set("Content-Type", "application/json; charset=utf-8") diff --git a/src/bunker.go b/src/bunker.go index 9112e10..ec4d666 100644 --- a/src/bunker.go +++ b/src/bunker.go @@ -9,16 +9,20 @@ import ( "log" "math/rand" "net/http" + "os" "strings" "time" "github.com/gobuffalo/packr" "github.com/julienschmidt/httprouter" + "github.com/kelseyhightower/envconfig" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/securitybunker/databunker/src/autocontext" "github.com/securitybunker/databunker/src/storage" + "github.com/securitybunker/databunker/src/utils" "go.mongodb.org/mongo-driver/bson" + "gopkg.in/yaml.v2" ) var version string @@ -105,16 +109,6 @@ type mainEnv struct { stopChan chan struct{} } -// userJSON used to parse user POST -type userJSON struct { - jsonData []byte - loginIdx string - emailIdx string - phoneIdx string - customIdx string - token string -} - type tokenAuthResult struct { ttype string name string @@ -151,7 +145,7 @@ func (e mainEnv) metrics(w http.ResponseWriter, r *http.Request, ps httprouter.P // backupDB API call. func (e mainEnv) backupDB(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - if e.enforceAuth(w, r, nil) == "" { + if e.EnforceAuth(w, r, nil) == "" { return } w.WriteHeader(200) @@ -169,6 +163,33 @@ func (e mainEnv) checkStatus(w http.ResponseWriter, r *http.Request, ps httprout } } +// ReadConfFile() read configuration file. +func ReadConfFile(cfg *Config, filepath *string) error { + confFile := "databunker.yaml" + if filepath != nil { + if len(*filepath) > 0 { + confFile = *filepath + } + } + log.Printf("Loading configuration file: %s\n", confFile) + f, err := os.Open(confFile) + if err != nil { + return err + } + decoder := yaml.NewDecoder(f) + err = decoder.Decode(cfg) + if err != nil { + return err + } + return nil +} + +// readEnv() process environment variables. +func ReadEnv(cfg *Config) error { + err := envconfig.Process("", cfg) + return err +} + // setupRouter() setup HTTP Router object. func (e mainEnv) setupRouter() *httprouter.Router { box := packr.NewBox("../ui") @@ -335,7 +356,7 @@ func (e mainEnv) setupRouter() *httprouter.Router { // dbCleanup() is used to run cron jobs. func (e mainEnv) dbCleanupDo() { log.Printf("db cleanup timeout\n") - exp, _ := parseExpiration0(e.conf.Policy.MaxAuditRetentionPeriod) + exp, _ := utils.ParseExpiration0(e.conf.Policy.MaxAuditRetentionPeriod) if exp > 0 { e.db.store.DeleteExpired0(storage.TblName.Audit, exp) } @@ -364,13 +385,13 @@ func (e mainEnv) dbCleanup() { // helper function to load user details by idex name func (e mainEnv) loadUserToken(w http.ResponseWriter, r *http.Request, mode string, identity string, event *auditEvent) string { var err error - if validateMode(mode) == false { - returnError(w, r, "bad mode", 405, nil, event) + if utils.ValidateMode(mode) == false { + ReturnError(w, r, "bad mode", 405, nil, event) return "" } var userBson bson.M if mode == "token" { - if enforceUUID(w, identity, event) == false { + if EnforceUUID(w, identity, event) == false { return "" } userBson, err = e.db.lookupUserRecord(identity) @@ -378,7 +399,7 @@ func (e mainEnv) loadUserToken(w http.ResponseWriter, r *http.Request, mode stri userBson, err = e.db.lookupUserRecordByIndex(mode, identity, e.conf) } if userBson == nil || err != nil { - returnError(w, r, "internal error", 405, nil, event) + ReturnError(w, r, "internal error", 405, nil, event) return "" } event.Record = userBson["token"].(string) @@ -470,6 +491,6 @@ func (e mainEnv) reqMiddleware(handler http.Handler) http.Handler { // main application function func main() { rand.Seed(time.Now().UnixNano()) - lockMemory() + utils.LockMemory() loadService() } diff --git a/src/captcha.go b/src/captcha.go index b7e53f6..ecaf90e 100644 --- a/src/captcha.go +++ b/src/captcha.go @@ -6,14 +6,16 @@ import ( "encoding/hex" "errors" "fmt" - "github.com/afocus/captcha" - "github.com/gobuffalo/packr" - "github.com/julienschmidt/httprouter" "image/png" "log" "net/http" "regexp" "time" + + "github.com/afocus/captcha" + "github.com/gobuffalo/packr" + "github.com/julienschmidt/httprouter" + "github.com/securitybunker/databunker/src/utils" ) var ( @@ -26,19 +28,19 @@ func (e mainEnv) showCaptcha(w http.ResponseWriter, r *http.Request, ps httprout code := ps.ByName("code") if len(code) == 0 { err := errors.New("Bad code") - returnError(w, r, "bad code", 405, err, nil) + ReturnError(w, r, "bad code", 405, err, nil) return } s, err := decryptCaptcha(code) if err != nil { - returnError(w, r, err.Error(), 405, err, nil) + ReturnError(w, r, err.Error(), 405, err, nil) return } log.Printf("Decoded captcha: %s", s) //box := packr.NewBox("../ui") //comic, err := box.Find("site/fonts/comic.ttf") //if err != nil { - // returnError(w, r, err.Error(), 405, err, nil) + // ReturnError(w, r, err.Error(), 405, err, nil) // return //} cap := captcha.New() @@ -62,7 +64,7 @@ func initCaptcha(h [16]byte) { } func generateCaptcha() (string, error) { - code := randNum(6) + code := utils.RandNum(6) //log.Printf("Generate captcha code: %d", code) now := int32(time.Now().Unix()) s := fmt.Sprintf("%d:%d", code, now) @@ -112,7 +114,7 @@ func decryptCaptcha(data string) (string, error) { return "", errors.New("Failed to parse captcha") } code := match[1] - t := atoi(match[2]) + t := utils.Atoi(match[2]) // check if time expired now := int32(time.Now().Unix()) if now > (t + 120) { diff --git a/src/conf.go b/src/conf.go index 77c19d4..47c7540 100644 --- a/src/conf.go +++ b/src/conf.go @@ -23,7 +23,7 @@ func (e mainEnv) initContext(r *http.Request) { func (e mainEnv) cookieSettings(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { resultJSON, scriptsJSON, _, err := e.db.getLegalBasisCookieConf() if err != nil { - returnError(w, r, "internal error", 405, err, nil) + ReturnError(w, r, "internal error", 405, err, nil) return } resultUIConfJSON, _ := json.Marshal(e.conf.UI) @@ -34,7 +34,7 @@ func (e mainEnv) cookieSettings(w http.ResponseWriter, r *http.Request, ps httpr } func (e mainEnv) configurationDump(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - if e.enforceAuth(w, r, nil) == "" { + if e.EnforceAuth(w, r, nil) == "" { return } resultJSON, _ := json.Marshal(e.conf) diff --git a/src/expiration_api.go b/src/expiration_api.go index 7f35b9b..030a063 100644 --- a/src/expiration_api.go +++ b/src/expiration_api.go @@ -7,6 +7,7 @@ import ( uuid "github.com/hashicorp/go-uuid" "github.com/julienschmidt/httprouter" "github.com/securitybunker/databunker/src/storage" + "github.com/securitybunker/databunker/src/utils" "go.mongodb.org/mongo-driver/bson" ) @@ -16,7 +17,7 @@ func (e mainEnv) expUsers() error { userTOKEN := rec["token"].(string) resultJSON, userBSON, _ := e.db.getUser(userTOKEN) if resultJSON != nil { - email := getStringValue(userBSON["email"]) + email := utils.GetStringValue(userBSON["email"]) if len(email) > 0 { e.globalUserDelete(email) } @@ -33,13 +34,13 @@ func (e mainEnv) expGetStatus(w http.ResponseWriter, r *http.Request, ps httprou event := audit("get expiration status by "+mode, identity, mode, identity) defer func() { event.submit(e.db, e.conf) }() var err error - if validateMode(mode) == false { - returnError(w, r, "bad mode", 405, nil, event) + if utils.ValidateMode(mode) == false { + ReturnError(w, r, "bad mode", 405, nil, event) return } var userBson bson.M if mode == "token" { - if enforceUUID(w, identity, event) == false { + if EnforceUUID(w, identity, event) == false { return } userBson, err = e.db.lookupUserRecord(identity) @@ -47,14 +48,14 @@ func (e mainEnv) expGetStatus(w http.ResponseWriter, r *http.Request, ps httprou userBson, err = e.db.lookupUserRecordByIndex(mode, identity, e.conf) } if userBson == nil || err != nil { - returnError(w, r, "internal error", 405, nil, event) + ReturnError(w, r, "internal error", 405, nil, event) return } userTOKEN := userBson["token"].(string) event.Record = userTOKEN - expirationDate := getIntValue(userBson["endtime"]) - expirationStatus := getStringValue(userBson["expstatus"]) - expirationToken := getStringValue(userBson["exptoken"]) + expirationDate := utils.GetIntValue(userBson["endtime"]) + expirationStatus := utils.GetStringValue(userBson["expstatus"]) + expirationToken := utils.GetStringValue(userBson["exptoken"]) finalJSON := fmt.Sprintf(`{"status":"ok","exptime":%d,"expstatus":"%s","exptoken":"%s"}`, expirationDate, expirationStatus, expirationToken) w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -68,14 +69,14 @@ func (e mainEnv) expCancel(w http.ResponseWriter, r *http.Request, ps httprouter mode := ps.ByName("mode") event := audit("clear user expiration by "+mode, identity, mode, identity) defer func() { event.submit(e.db, e.conf) }() - if validateMode(mode) == false { - returnError(w, r, "bad mode", 405, nil, event) + if utils.ValidateMode(mode) == false { + ReturnError(w, r, "bad mode", 405, nil, event) return } userTOKEN := identity var userBson bson.M if mode == "token" { - if enforceUUID(w, identity, event) == false { + if EnforceUUID(w, identity, event) == false { return } userBson, err = e.db.lookupUserRecord(identity) @@ -87,13 +88,13 @@ func (e mainEnv) expCancel(w http.ResponseWriter, r *http.Request, ps httprouter } } if userBson == nil || err != nil { - returnError(w, r, "internal error", 405, nil, event) + ReturnError(w, r, "internal error", 405, nil, event) return } status := "" err = e.db.updateUserExpStatus(userTOKEN, status) if err != nil { - returnError(w, r, "internal error", 405, nil, event) + ReturnError(w, r, "internal error", 405, nil, event) return } finalJSON := `{"status":"ok"}` @@ -107,12 +108,12 @@ func (e mainEnv) expRetainData(w http.ResponseWriter, r *http.Request, ps httpro mode := "exptoken" event := audit("retain user data by exptoken", identity, mode, identity) defer func() { event.submit(e.db, e.conf) }() - if enforceUUID(w, identity, event) == false { + if EnforceUUID(w, identity, event) == false { return } userBson, err := e.db.lookupUserRecordByIndex(mode, identity, e.conf) if userBson == nil || err != nil { - returnError(w, r, "internal error", 405, nil, event) + ReturnError(w, r, "internal error", 405, nil, event) return } userTOKEN := userBson["token"].(string) @@ -120,7 +121,7 @@ func (e mainEnv) expRetainData(w http.ResponseWriter, r *http.Request, ps httpro status := "retain" err = e.db.updateUserExpStatus(userTOKEN, status) if err != nil { - returnError(w, r, "internal error", 405, nil, event) + ReturnError(w, r, "internal error", 405, nil, event) return } w.WriteHeader(200) @@ -132,22 +133,22 @@ func (e mainEnv) expDeleteData(w http.ResponseWriter, r *http.Request, ps httpro mode := "exptoken" event := audit("delete user data by exptoken", identity, mode, identity) defer func() { event.submit(e.db, e.conf) }() - if enforceUUID(w, identity, event) == false { + if EnforceUUID(w, identity, event) == false { return } userJSON, userTOKEN, userBSON, err := e.db.getUserByIndex(identity, mode, e.conf) if userJSON == nil || err != nil { - returnError(w, r, "internal error", 405, nil, event) + ReturnError(w, r, "internal error", 405, nil, event) return } event.Record = userTOKEN - email := getStringValue(userBSON["email"]) + email := utils.GetStringValue(userBSON["email"]) if len(email) > 0 { e.globalUserDelete(email) } _, err = e.db.deleteUserRecord(userJSON, userTOKEN, e.conf) if err != nil { - returnError(w, r, "internal error", 405, nil, event) + ReturnError(w, r, "internal error", 405, nil, event) return } e.db.updateUserExpStatus(userTOKEN, "expired") @@ -162,32 +163,32 @@ func (e mainEnv) expStart(w http.ResponseWriter, r *http.Request, ps httprouter. event := audit("initiate user record expiration by "+mode, identity, mode, identity) defer func() { event.submit(e.db, e.conf) }() - if e.enforceAdmin(w, r, event) == "" { + if e.EnforceAdmin(w, r, event) == "" { return } userTOKEN := e.loadUserToken(w, r, mode, identity, event) if userTOKEN == "" { return } - records, err := getJSONPostMap(r) + records, err := utils.GetJSONPostMap(r) if err != nil { - returnError(w, r, "failed to decode request body", 405, err, event) + ReturnError(w, r, "failed to decode request body", 405, err, event) return } - expirationStr := getStringValue(records["expiration"]) - expiration := setExpiration(e.conf.Policy.MaxUserRetentionPeriod, expirationStr) - endtime, _ := parseExpiration(expiration) - status := getStringValue(records["status"]) + expirationStr := utils.GetStringValue(records["expiration"]) + expiration := utils.SetExpiration(e.conf.Policy.MaxUserRetentionPeriod, expirationStr) + endtime, _ := utils.ParseExpiration(expiration) + status := utils.GetStringValue(records["status"]) if len(status) == 0 { status = "wait" } expToken, err := uuid.GenerateUUID() if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) } err = e.db.initiateUserExpiration(userTOKEN, endtime, status, expToken) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } finalJSON := fmt.Sprintf(`{"status":"ok","exptoken":"%s"}`, expToken) diff --git a/src/go.mod b/src/go.mod index 50d59b2..2c875af 100644 --- a/src/go.mod +++ b/src/go.mod @@ -6,6 +6,8 @@ toolchain go1.23.3 replace github.com/securitybunker/databunker/src/storage => ./storage +replace github.com/securitybunker/databunker/src/utils => ./utils + require ( github.com/afocus/captcha v0.0.0-20191010092841-4bd1f21c8868 github.com/evanphx/json-patch v5.9.0+incompatible @@ -50,13 +52,14 @@ require ( github.com/prometheus/procfs v0.15.1 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect + github.com/securitybunker/databunker/src/utils v0.0.0-20241226201542-d0c5d1a19645 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 // indirect golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect golang.org/x/image v0.23.0 // indirect golang.org/x/mod v0.22.0 // indirect - google.golang.org/protobuf v1.36.0 // indirect + google.golang.org/protobuf v1.36.1 // indirect modernc.org/gc/v3 v3.0.0-20241213165251-3bc300f6d0c9 // indirect modernc.org/libc v1.61.4 // indirect modernc.org/mathutil v1.6.0 // indirect diff --git a/src/init_test.go b/src/init_test.go index 30bc309..1e1382c 100644 --- a/src/init_test.go +++ b/src/init_test.go @@ -16,7 +16,7 @@ func init() { rootToken = myRootToken var cfg Config cfile := "../databunker.yaml" - err = readConfFile(&cfg, &cfile) + err = ReadConfFile(&cfg, &cfile) cfg.SelfService.AppRecordChange = []string{"testapp", "super"} if err != nil { cfg.SelfService.ForgetMe = false diff --git a/src/lbasis_api.go b/src/lbasis_api.go index 3635fc0..0d592bb 100644 --- a/src/lbasis_api.go +++ b/src/lbasis_api.go @@ -7,37 +7,38 @@ import ( "reflect" "github.com/julienschmidt/httprouter" + "github.com/securitybunker/databunker/src/utils" //"go.mongodb.org/mongo-driver/bson" ) func (e mainEnv) createLegalBasis(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { brief := ps.ByName("brief") - if e.enforceAdmin(w, r, nil) == "" { + if e.EnforceAdmin(w, r, nil) == "" { return } - brief = normalizeBrief(brief) - if isValidBrief(brief) == false { - returnError(w, r, "bad brief format", 405, nil, nil) + brief = utils.NormalizeBrief(brief) + if utils.CheckValidBrief(brief) == false { + ReturnError(w, r, "bad brief format", 405, nil, nil) return } - records, err := getJSONPostMap(r) + records, err := utils.GetJSONPostMap(r) if err != nil { - returnError(w, r, "failed to decode request body", 405, err, nil) + ReturnError(w, r, "failed to decode request body", 405, err, nil) return } - newbrief := getStringValue(records["brief"]) + newbrief := utils.GetStringValue(records["brief"]) if len(newbrief) > 0 && newbrief != brief { - if isValidBrief(newbrief) == false { - returnError(w, r, "bad brief format", 405, nil, nil) + if utils.CheckValidBrief(newbrief) == false { + ReturnError(w, r, "bad brief format", 405, nil, nil) return } } - status := getStringValue(records["status"]) - module := getStringValue(records["module"]) - fulldesc := getStringValue(records["fulldesc"]) - shortdesc := getStringValue(records["shortdesc"]) - basistype := getStringValue(records["basistype"]) - requiredmsg := getStringValue(records["requiredmsg"]) + status := utils.GetStringValue(records["status"]) + module := utils.GetStringValue(records["module"]) + fulldesc := utils.GetStringValue(records["fulldesc"]) + shortdesc := utils.GetStringValue(records["shortdesc"]) + basistype := utils.GetStringValue(records["basistype"]) + requiredmsg := utils.GetStringValue(records["requiredmsg"]) usercontrol := false requiredflag := false if status != "disabled" { @@ -82,12 +83,12 @@ func (e mainEnv) createLegalBasis(w http.ResponseWriter, r *http.Request, ps htt func (e mainEnv) deleteLegalBasis(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { brief := ps.ByName("brief") - if e.enforceAdmin(w, r, nil) == "" { + if e.EnforceAdmin(w, r, nil) == "" { return } - brief = normalizeBrief(brief) - if isValidBrief(brief) == false { - returnError(w, r, "bad brief format", 405, nil, nil) + brief = utils.NormalizeBrief(brief) + if utils.CheckValidBrief(brief) == false { + ReturnError(w, r, "bad brief format", 405, nil, nil) return } e.db.unlinkProcessingActivityBrief(brief) @@ -98,12 +99,12 @@ func (e mainEnv) deleteLegalBasis(w http.ResponseWriter, r *http.Request, ps htt } func (e mainEnv) listLegalBasisRecords(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - if e.enforceAdmin(w, r, nil) == "" { + if e.EnforceAdmin(w, r, nil) == "" { return } resultJSON, numRecords, err := e.db.getLegalBasisRecords() if err != nil { - returnError(w, r, "internal error", 405, err, nil) + ReturnError(w, r, "internal error", 405, err, nil) return } log.Printf("Total count of rows: %d\n", numRecords) diff --git a/src/pactivities_api.go b/src/pactivities_api.go index 1693236..1b91cb2 100644 --- a/src/pactivities_api.go +++ b/src/pactivities_api.go @@ -7,22 +7,23 @@ import ( "reflect" "github.com/julienschmidt/httprouter" + "github.com/securitybunker/databunker/src/utils" //"go.mongodb.org/mongo-driver/bson" ) func (e mainEnv) pactivityCreate(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { activity := ps.ByName("activity") - if e.enforceAdmin(w, r, nil) == "" { + if e.EnforceAdmin(w, r, nil) == "" { return } - activity = normalizeBrief(activity) - if isValidBrief(activity) == false { - returnError(w, r, "bad activity format", 405, nil, nil) + activity = utils.NormalizeBrief(activity) + if utils.CheckValidBrief(activity) == false { + ReturnError(w, r, "bad activity format", 405, nil, nil) return } - records, err := getJSONPostMap(r) + records, err := utils.GetJSONPostMap(r) if err != nil { - returnError(w, r, "failed to decode request body", 405, err, nil) + ReturnError(w, r, "failed to decode request body", 405, err, nil) return } defer func() { @@ -70,12 +71,12 @@ func (e mainEnv) pactivityCreate(w http.ResponseWriter, r *http.Request, ps http func (e mainEnv) pactivityDelete(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { activity := ps.ByName("activity") - if e.enforceAdmin(w, r, nil) == "" { + if e.EnforceAdmin(w, r, nil) == "" { return } - activity = normalizeBrief(activity) - if isValidBrief(activity) == false { - returnError(w, r, "bad activity format", 405, nil, nil) + activity = utils.NormalizeBrief(activity) + if utils.CheckValidBrief(activity) == false { + ReturnError(w, r, "bad activity format", 405, nil, nil) return } e.db.deleteProcessingActivity(activity) @@ -87,31 +88,31 @@ func (e mainEnv) pactivityDelete(w http.ResponseWriter, r *http.Request, ps http func (e mainEnv) pactivityLink(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { activity := ps.ByName("activity") brief := ps.ByName("brief") - if e.enforceAdmin(w, r, nil) == "" { + if e.EnforceAdmin(w, r, nil) == "" { return } - activity = normalizeBrief(activity) - if isValidBrief(activity) == false { - returnError(w, r, "bad activity format", 405, nil, nil) + activity = utils.NormalizeBrief(activity) + if utils.CheckValidBrief(activity) == false { + ReturnError(w, r, "bad activity format", 405, nil, nil) return } - brief = normalizeBrief(brief) - if isValidBrief(brief) == false { - returnError(w, r, "bad brief format", 405, nil, nil) + brief = utils.NormalizeBrief(brief) + if utils.CheckValidBrief(brief) == false { + ReturnError(w, r, "bad brief format", 405, nil, nil) return } exists, err := e.db.checkLegalBasis(brief) if err != nil { - returnError(w, r, "internal error", 405, nil, nil) + ReturnError(w, r, "internal error", 405, nil, nil) return } if exists == false { - returnError(w, r, "not found", 405, nil, nil) + ReturnError(w, r, "not found", 405, nil, nil) return } _, err = e.db.linkProcessingActivity(activity, brief) if err != nil { - returnError(w, r, "internal error", 405, err, nil) + ReturnError(w, r, "internal error", 405, err, nil) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -122,22 +123,22 @@ func (e mainEnv) pactivityLink(w http.ResponseWriter, r *http.Request, ps httpro func (e mainEnv) pactivityUnlink(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { activity := ps.ByName("activity") brief := ps.ByName("brief") - if e.enforceAdmin(w, r, nil) == "" { + if e.EnforceAdmin(w, r, nil) == "" { return } - activity = normalizeBrief(activity) - if isValidBrief(activity) == false { - returnError(w, r, "bad activity format", 405, nil, nil) + activity = utils.NormalizeBrief(activity) + if utils.CheckValidBrief(activity) == false { + ReturnError(w, r, "bad activity format", 405, nil, nil) return } - brief = normalizeBrief(brief) - if isValidBrief(brief) == false { - returnError(w, r, "bad brief format", 405, nil, nil) + brief = utils.NormalizeBrief(brief) + if utils.CheckValidBrief(brief) == false { + ReturnError(w, r, "bad brief format", 405, nil, nil) return } _, err := e.db.unlinkProcessingActivity(activity, brief) if err != nil { - returnError(w, r, "internal error", 405, err, nil) + ReturnError(w, r, "internal error", 405, err, nil) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -146,12 +147,12 @@ func (e mainEnv) pactivityUnlink(w http.ResponseWriter, r *http.Request, ps http } func (e mainEnv) pactivityList(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - if e.enforceAdmin(w, r, nil) == "" { + if e.EnforceAdmin(w, r, nil) == "" { return } resultJSON, numRecords, err := e.db.listProcessingActivities() if err != nil { - returnError(w, r, "internal error", 405, err, nil) + ReturnError(w, r, "internal error", 405, err, nil) return } log.Printf("Total count of rows: %d\n", numRecords) diff --git a/src/pactivities_db.go b/src/pactivities_db.go index 42d2531..e60e3bb 100644 --- a/src/pactivities_db.go +++ b/src/pactivities_db.go @@ -9,6 +9,7 @@ import ( "time" "github.com/securitybunker/databunker/src/storage" + "github.com/securitybunker/databunker/src/utils" "go.mongodb.org/mongo-driver/bson" ) @@ -75,7 +76,7 @@ func (dbobj dbcon) linkProcessingActivity(activity string, brief string) (bool, } } briefs := strings.Split(legalbasis, ",") - if contains(briefs, brief) == true { + if utils.SliceContains(briefs, brief) == true { // nothing to do here return false, nil } @@ -106,7 +107,7 @@ func (dbobj dbcon) unlinkProcessingActivity(activity string, brief string) (bool } } briefs := strings.Split(legalbasis, ",") - if contains(briefs, brief) == false { + if utils.SliceContains(briefs, brief) == false { // nothing to do here return false, nil } diff --git a/src/requests_api.go b/src/requests_api.go index 7d12b3a..376ea61 100644 --- a/src/requests_api.go +++ b/src/requests_api.go @@ -7,11 +7,12 @@ import ( "strings" "github.com/julienschmidt/httprouter" + "github.com/securitybunker/databunker/src/utils" ) // This function retrieves all requests that require admin approval. This function supports result pager. func (e mainEnv) getUserRequests(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - if e.enforceAuth(w, r, nil) == "" { + if e.EnforceAuth(w, r, nil) == "" { return } var offset int32 @@ -19,17 +20,17 @@ func (e mainEnv) getUserRequests(w http.ResponseWriter, r *http.Request, ps http status := "open" args := r.URL.Query() if value, ok := args["offset"]; ok { - offset = atoi(value[0]) + offset = utils.Atoi(value[0]) } if value, ok := args["limit"]; ok { - limit = atoi(value[0]) + limit = utils.Atoi(value[0]) } if value, ok := args["status"]; ok { status = value[0] } resultJSON, counter, err := e.db.getRequests(status, offset, limit) if err != nil { - returnError(w, r, "internal error", 405, err, nil) + ReturnError(w, r, "internal error", 405, err, nil) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -45,7 +46,7 @@ func (e mainEnv) getCustomUserRequests(w http.ResponseWriter, r *http.Request, p event := audit("get user privacy requests", identity, mode, identity) defer func() { event.submit(e.db, e.conf) }() - if e.enforceAuth(w, r, event) == "" { + if e.EnforceAuth(w, r, event) == "" { return } userTOKEN := e.loadUserToken(w, r, mode, identity, event) @@ -56,14 +57,14 @@ func (e mainEnv) getCustomUserRequests(w http.ResponseWriter, r *http.Request, p var limit int32 = 10 args := r.URL.Query() if value, ok := args["offset"]; ok { - offset = atoi(value[0]) + offset = utils.Atoi(value[0]) } if value, ok := args["limit"]; ok { - limit = atoi(value[0]) + limit = utils.Atoi(value[0]) } resultJSON, counter, err := e.db.getUserRequests(userTOKEN, offset, limit) if err != nil { - returnError(w, r, "internal error", 405, err, nil) + ReturnError(w, r, "internal error", 405, err, nil) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -77,30 +78,30 @@ func (e mainEnv) getUserRequest(w http.ResponseWriter, r *http.Request, ps httpr event := audit("get user request by request token", request, "request", request) defer func() { event.submit(e.db, e.conf) }() - if enforceUUID(w, request, event) == false { + if EnforceUUID(w, request, event) == false { return } requestInfo, err := e.db.getRequest(request) if err != nil { - returnError(w, r, "internal error", 405, err, nil) + ReturnError(w, r, "internal error", 405, err, nil) return } if len(requestInfo) == 0 { - returnError(w, r, "not found", 405, err, event) + ReturnError(w, r, "not found", 405, err, event) return } var resultJSON []byte - action := getStringValue(requestInfo["action"]) - userTOKEN := getStringValue(requestInfo["token"]) + action := utils.GetStringValue(requestInfo["action"]) + userTOKEN := utils.GetStringValue(requestInfo["token"]) if len(userTOKEN) != 0 { event.Record = userTOKEN } - if e.enforceAdmin(w, r, event) == "" { + if e.EnforceAdmin(w, r, event) == "" { return } - change := getStringValue(requestInfo["change"]) - appName := getStringValue(requestInfo["app"]) - brief := getStringValue(requestInfo["brief"]) + change := utils.GetStringValue(requestInfo["change"]) + appName := utils.GetStringValue(requestInfo["app"]) + brief := utils.GetStringValue(requestInfo["brief"]) if strings.HasPrefix(action, "plugin") { brief = "" } @@ -112,11 +113,11 @@ func (e mainEnv) getUserRequest(w http.ResponseWriter, r *http.Request, ps httpr resultJSON, err = e.db.getUserJSON(userTOKEN) } if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } if resultJSON == nil { - returnError(w, r, "not found", 405, err, event) + ReturnError(w, r, "not found", 405, err, event) return } //fmt.Printf("Full json: %s\n", resultJSON) @@ -145,49 +146,49 @@ func (e mainEnv) approveUserRequest(w http.ResponseWriter, r *http.Request, ps h event := audit("approve user request", request, "request", request) defer func() { event.submit(e.db, e.conf) }() - if enforceUUID(w, request, event) == false { + if EnforceUUID(w, request, event) == false { return } - authResult := e.enforceAdmin(w, r, event) + authResult := e.EnforceAdmin(w, r, event) if authResult == "" { return } - records, err := getJSONPostMap(r) + records, err := utils.GetJSONPostMap(r) if err != nil { - returnError(w, r, "failed to decode request body", 405, err, event) + ReturnError(w, r, "failed to decode request body", 405, err, event) return } - reason := getStringValue(records["reason"]) + reason := utils.GetStringValue(records["reason"]) requestInfo, err := e.db.getRequest(request) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } if len(requestInfo) == 0 { - returnError(w, r, "not found", 405, err, event) + ReturnError(w, r, "not found", 405, err, event) return } - userTOKEN := getStringValue(requestInfo["token"]) + userTOKEN := utils.GetStringValue(requestInfo["token"]) if len(userTOKEN) != 0 { event.Record = userTOKEN } - action := getStringValue(requestInfo["action"]) - status := getStringValue(requestInfo["status"]) + action := utils.GetStringValue(requestInfo["action"]) + status := utils.GetStringValue(requestInfo["status"]) if status != "open" { - returnError(w, r, "wrong status: "+status, 405, err, event) + ReturnError(w, r, "wrong status: "+status, 405, err, event) return } userJSON, userBSON, err := e.db.getUser(userTOKEN) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } if userJSON == nil { - returnError(w, r, "not found", 405, err, event) + ReturnError(w, r, "not found", 405, err, event) return } if action == "forget-me" { - email := getStringValue(userBSON["email"]) + email := utils.GetStringValue(userBSON["email"]) if len(email) > 0 { e.globalUserDelete(email) } @@ -198,7 +199,7 @@ func (e mainEnv) approveUserRequest(w http.ResponseWriter, r *http.Request, ps h event.Msg = "failed to delete" } if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } notifyURL := e.conf.Notification.NotificationURL @@ -206,21 +207,21 @@ func (e mainEnv) approveUserRequest(w http.ResponseWriter, r *http.Request, ps h } else if action == "change-profile" { oldJSON, newJSON, lookupErr, err := e.db.updateUserRecord(requestInfo["change"].([]uint8), userTOKEN, userBSON, event, e.conf) if lookupErr { - returnError(w, r, "internal error", 405, errors.New("not found"), event) + ReturnError(w, r, "internal error", 405, errors.New("not found"), event) return } if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } - returnUUID(w, userTOKEN) + utils.ReturnUUID(w, userTOKEN) notifyURL := e.conf.Notification.NotificationURL notifyProfileChange(notifyURL, oldJSON, newJSON, "token", userTOKEN) } else if action == "change-app-data" { app := requestInfo["app"].(string) _, err = e.db.updateAppRecord(requestInfo["change"].([]uint8), userTOKEN, app, event, e.conf) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } } else if action == "agreement-withdraw" { @@ -243,43 +244,43 @@ func (e mainEnv) cancelUserRequest(w http.ResponseWriter, r *http.Request, ps ht event := audit("cancel user request", request, "request", request) defer func() { event.submit(e.db, e.conf) }() - if enforceUUID(w, request, event) == false { + if EnforceUUID(w, request, event) == false { return } - records, err := getJSONPostMap(r) + records, err := utils.GetJSONPostMap(r) if err != nil { - returnError(w, r, "failed to decode request body", 405, err, event) + ReturnError(w, r, "failed to decode request body", 405, err, event) return } - reason := getStringValue(records["reason"]) + reason := utils.GetStringValue(records["reason"]) requestInfo, err := e.db.getRequest(request) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } if len(requestInfo) == 0 { - returnError(w, r, "not found", 405, err, event) + ReturnError(w, r, "not found", 405, err, event) return } - userTOKEN := getStringValue(requestInfo["token"]) + userTOKEN := utils.GetStringValue(requestInfo["token"]) if len(userTOKEN) != 0 { event.Record = userTOKEN } - authResult := e.enforceAuth(w, r, event) + authResult := e.EnforceAuth(w, r, event) if authResult == "" { return } if requestInfo["status"].(string) != "open" { - returnError(w, r, "wrong status: "+requestInfo["status"].(string), 405, err, event) + ReturnError(w, r, "wrong status: "+requestInfo["status"].(string), 405, err, event) return } resultJSON, err := e.db.getUserJSON(userTOKEN) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } if resultJSON == nil { - returnError(w, r, "not found", 405, err, event) + ReturnError(w, r, "not found", 405, err, event) return } if len(reason) == 0 && authResult == "login" { diff --git a/src/service.go b/src/service.go index f9da007..1e7dd00 100644 --- a/src/service.go +++ b/src/service.go @@ -15,6 +15,7 @@ import ( "time" "github.com/securitybunker/databunker/src/storage" + "github.com/securitybunker/databunker/src/utils" ) func loadService() { @@ -34,14 +35,14 @@ func loadService() { } log.Printf("Databunker version: %s\n", version) var cfg Config - readEnv(&cfg) - readConfFile(&cfg, confPtr) + ReadEnv(&cfg) + ReadConfFile(&cfg, confPtr) customRootToken := "" if *demoPtr { customRootToken = "DEMO" } else { - customRootToken = getArgEnvFileVariable("DATABUNKER_ROOTTOKEN", rootTokenKeyPtr) + customRootToken = utils.GetArgEnvFileVariable("DATABUNKER_ROOTTOKEN", rootTokenKeyPtr) } if *initPtr || *demoPtr { if storage.DBExists(dbPtr) == true { @@ -63,7 +64,7 @@ func loadService() { log.Println(`Run "databunker -init" for the first time to generate keys and init database.`) os.Exit(0) } - masterKeyStr := getArgEnvFileVariable("DATABUNKER_MASTERKEY", masterKeyPtr) + masterKeyStr := utils.GetArgEnvFileVariable("DATABUNKER_MASTERKEY", masterKeyPtr) if *startPtr == false { log.Println(`'databunker -start' command is missing.`) os.Exit(0) @@ -149,7 +150,7 @@ func decodeMasterkey(masterKeyStr string) ([]byte, error) { if len(masterKeyStr) != 48 { return nil, errors.New("Master key length is wrong") } - if isValidHex(masterKeyStr) == false { + if utils.CheckValidHex(masterKeyStr) == false { return nil, errors.New("Master key is not valid hex string") } masterKey, err := hex.DecodeString(masterKeyStr) @@ -163,7 +164,7 @@ func setupDB(dbPtr *string, masterKeyPtr *string, customRootToken string) (*dbco log.Println("Databunker init") var masterKey []byte var err error - masterKeyString := getArgEnvFileVariable("DATABUNKER_MASTERKEY", masterKeyPtr) + masterKeyString := utils.GetArgEnvFileVariable("DATABUNKER_MASTERKEY", masterKeyPtr) if len(masterKeyString) > 0 { masterKey, err = decodeMasterkey(masterKeyString) if err != nil { diff --git a/src/sessions_api.go b/src/sessions_api.go index 8fffdcc..5a625f4 100644 --- a/src/sessions_api.go +++ b/src/sessions_api.go @@ -10,6 +10,7 @@ import ( uuid "github.com/hashicorp/go-uuid" "github.com/julienschmidt/httprouter" "github.com/securitybunker/databunker/src/storage" + "github.com/securitybunker/databunker/src/utils" "go.mongodb.org/mongo-driver/bson" ) @@ -21,30 +22,30 @@ func (e mainEnv) createSession(w http.ResponseWriter, r *http.Request, ps httpro event.submit(e.db, e.conf) } }() - if enforceUUID(w, session, event) == false { - //returnError(w, r, "bad session format", nil, event) + if EnforceUUID(w, session, event) == false { + //ReturnError(w, r, "bad session format", nil, event) return } - if e.enforceAdmin(w, r, event) == "" { + if e.EnforceAdmin(w, r, event) == "" { return } - records, err := getJSONPostMap(r) + records, err := utils.GetJSONPostMap(r) if err != nil { - returnError(w, r, "failed to decode request body", 405, err, event) + ReturnError(w, r, "failed to decode request body", 405, err, event) return } if len(records) == 0 { - returnError(w, r, "empty body", 405, nil, event) + ReturnError(w, r, "empty body", 405, nil, event) return } - expirationStr := getStringValue(records["expiration"]) - expiration := setExpiration(e.conf.Policy.MaxSessionRetentionPeriod, expirationStr) + expirationStr := utils.GetStringValue(records["expiration"]) + expiration := utils.SetExpiration(e.conf.Policy.MaxSessionRetentionPeriod, expirationStr) log.Printf("Record expiration: %s", expiration) - userToken := getStringValue(records["token"]) - userLogin := getStringValue(records["login"]) - userEmail := getStringValue(records["email"]) - userPhone := getStringValue(records["phone"]) - userCustomIdx := getStringValue(records["custom"]) + userToken := utils.GetStringValue(records["token"]) + userLogin := utils.GetStringValue(records["login"]) + userEmail := utils.GetStringValue(records["email"]) + userPhone := utils.GetStringValue(records["phone"]) + userCustomIdx := utils.GetStringValue(records["custom"]) var userBson bson.M if len(userLogin) > 0 { @@ -59,7 +60,7 @@ func (e mainEnv) createSession(w http.ResponseWriter, r *http.Request, ps httpro userBson, err = e.db.lookupUserRecord(userToken) } if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } userTOKEN := "" @@ -70,12 +71,12 @@ func (e mainEnv) createSession(w http.ResponseWriter, r *http.Request, ps httpro } jsonData, err := json.Marshal(records) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } session, err = e.db.createSessionRecord(session, userTOKEN, expiration, jsonData) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -87,11 +88,11 @@ func (e mainEnv) deleteSession(w http.ResponseWriter, r *http.Request, ps httpro session := ps.ByName("session") event := audit("delete session", session, "session", session) defer func() { event.submit(e.db, e.conf) }() - if enforceUUID(w, session, event) == false { - //returnError(w, r, "bad session format", nil, event) + if EnforceUUID(w, session, event) == false { + //ReturnError(w, r, "bad session format", nil, event) return } - if e.enforceAdmin(w, r, event) == "" { + if e.EnforceAdmin(w, r, event) == "" { return } e.db.deleteSession(session) @@ -111,34 +112,34 @@ func (e mainEnv) newUserSession(w http.ResponseWriter, r *http.Request, ps httpr if userTOKEN == "" { return } - if e.enforceAuth(w, r, event) == "" { + if e.EnforceAuth(w, r, event) == "" { return } - records, err := getJSONPostMap(r) + records, err := utils.GetJSONPostMap(r) if err != nil { - returnError(w, r, "failed to decode request body", 405, err, event) + ReturnError(w, r, "failed to decode request body", 405, err, event) return } if len(records) == 0 { - returnError(w, r, "empty body", 405, nil, event) + ReturnError(w, r, "empty body", 405, nil, event) return } - expirationStr := getStringValue(records["expiration"]) - expiration := setExpiration(e.conf.Policy.MaxSessionRetentionPeriod, expirationStr) + expirationStr := utils.GetStringValue(records["expiration"]) + expiration := utils.SetExpiration(e.conf.Policy.MaxSessionRetentionPeriod, expirationStr) log.Printf("Record expiration: %s", expiration) jsonData, err := json.Marshal(records) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } sessionUUID, err := uuid.GenerateUUID() if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } sessionID, err := e.db.createSessionRecord(sessionUUID, userTOKEN, expiration, jsonData) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -156,7 +157,7 @@ func (e mainEnv) getUserSessions(w http.ResponseWriter, r *http.Request, ps http if userTOKEN == "" { return } - if e.enforceAuth(w, r, event) == "" { + if e.EnforceAuth(w, r, event) == "" { return } e.db.store.DeleteExpired(storage.TblName.Sessions, "token", userTOKEN) @@ -164,14 +165,14 @@ func (e mainEnv) getUserSessions(w http.ResponseWriter, r *http.Request, ps http var offset int32 var limit int32 = 10 if value, ok := args["offset"]; ok { - offset = atoi(value[0]) + offset = utils.Atoi(value[0]) } if value, ok := args["limit"]; ok { - limit = atoi(value[0]) + limit = utils.Atoi(value[0]) } records, count, err := e.db.getUserSessionsByToken(userTOKEN, offset, limit) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } data := strings.Join(records, ",") @@ -194,11 +195,11 @@ func (e mainEnv) getSession(w http.ResponseWriter, r *http.Request, ps httproute e.db.store.DeleteExpired(storage.TblName.Sessions, "token", userTOKEN) } if err != nil { - returnError(w, r, err.Error(), 405, err, event) + ReturnError(w, r, err.Error(), 405, err, event) return } - if e.enforceAuth(w, r, event) == "" { + if e.EnforceAuth(w, r, event) == "" { return } w.Header().Set("Content-Type", "application/json; charset=utf-8") diff --git a/src/sessions_db.go b/src/sessions_db.go index cddefbe..3a50eb6 100644 --- a/src/sessions_db.go +++ b/src/sessions_db.go @@ -7,6 +7,7 @@ import ( "time" "github.com/securitybunker/databunker/src/storage" + "github.com/securitybunker/databunker/src/utils" "go.mongodb.org/mongo-driver/bson" ) @@ -20,7 +21,7 @@ func (dbobj dbcon) createSessionRecord(sessionUUID string, userTOKEN string, exp var err error now := int32(time.Now().Unix()) if len(expiration) > 0 { - endtime, err = parseExpiration(expiration) + endtime, err = utils.ParseExpiration(expiration) if err != nil { return "", err } diff --git a/src/sharedrecords_api.go b/src/sharedrecords_api.go index 1dea957..ca7d3c9 100644 --- a/src/sharedrecords_api.go +++ b/src/sharedrecords_api.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/julienschmidt/httprouter" + "github.com/securitybunker/databunker/src/utils" "github.com/tidwall/gjson" ) @@ -22,12 +23,12 @@ func (e mainEnv) newSharedRecord(w http.ResponseWriter, r *http.Request, ps http if userTOKEN == "" { return } - if e.enforceAuth(w, r, event) == "" { + if e.EnforceAuth(w, r, event) == "" { return } - records, err := getJSONPostMap(r) + records, err := utils.GetJSONPostMap(r) if err != nil { - returnError(w, r, "failed to decode request body", 405, err, event) + ReturnError(w, r, "failed to decode request body", 405, err, event) return } fields := "" @@ -52,21 +53,21 @@ func (e mainEnv) newSharedRecord(w http.ResponseWriter, r *http.Request, ps http } if value, ok := records["expiration"]; ok { if reflect.TypeOf(value) == reflect.TypeOf("string") { - expiration = setExpiration(e.conf.Policy.MaxShareableRecordRetentionPeriod, value.(string)) + expiration = utils.SetExpiration(e.conf.Policy.MaxShareableRecordRetentionPeriod, value.(string)) } else { - returnError(w, r, "failed to parse expiration field", 405, err, event) + ReturnError(w, r, "failed to parse expiration field", 405, err, event) return } } if value, ok := records["app"]; ok { if reflect.TypeOf(value) == reflect.TypeOf("string") { appName = strings.ToLower(value.(string)) - if len(appName) > 0 && isValidApp(appName) == false { - returnError(w, r, "unknown app name", 405, nil, event) + if len(appName) > 0 && utils.CheckValidApp(appName) == false { + ReturnError(w, r, "unknown app name", 405, nil, event) } } else { // type is different - returnError(w, r, "failed to parse app field", 405, nil, event) + ReturnError(w, r, "failed to parse app field", 405, nil, event) } } if len(expiration) == 0 { @@ -75,7 +76,7 @@ func (e mainEnv) newSharedRecord(w http.ResponseWriter, r *http.Request, ps http } recordUUID, err := e.db.saveSharedRecord(userTOKEN, fields, expiration, session, appName, partner, e.conf) if err != nil { - returnError(w, r, err.Error(), 405, err, event) + ReturnError(w, r, err.Error(), 405, err, event) return } event.Record = userTOKEN @@ -90,7 +91,7 @@ func (e mainEnv) getRecord(w http.ResponseWriter, r *http.Request, ps httprouter event := audit("get shareable record by token", record, "record", record) defer func() { event.submit(e.db, e.conf) }() - if enforceUUID(w, record, event) == false { + if EnforceUUID(w, record, event) == false { return } recordInfo, err := e.db.getSharedRecord(record) @@ -114,18 +115,18 @@ func (e mainEnv) getRecord(w http.ResponseWriter, r *http.Request, ps httprouter resultJSON, err = e.db.getUserJSON(recordInfo.token) } if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } if resultJSON == nil { - returnError(w, r, "not found", 405, err, event) + ReturnError(w, r, "not found", 405, err, event) return } log.Printf("Full json: %s\n", resultJSON) if len(recordInfo.fields) > 0 { raw := make(map[string]interface{}) //var newJSON json - allFields := parseFields(recordInfo.fields) + allFields := utils.ParseFields(recordInfo.fields) for _, f := range allFields { if f == "token" { raw["token"] = recordInfo.token diff --git a/src/sharedrecords_db.go b/src/sharedrecords_db.go index 02403be..5a0de0e 100644 --- a/src/sharedrecords_db.go +++ b/src/sharedrecords_db.go @@ -8,11 +8,12 @@ import ( uuid "github.com/hashicorp/go-uuid" "github.com/securitybunker/databunker/src/storage" + "github.com/securitybunker/databunker/src/utils" "go.mongodb.org/mongo-driver/bson" ) func (dbobj dbcon) saveSharedRecord(userTOKEN string, fields string, expiration string, session string, appName string, partner string, conf Config) (string, error) { - if isValidUUID(userTOKEN) == false { + if utils.CheckValidUUID(userTOKEN) == false { return "", errors.New("bad uuid") } if len(expiration) == 0 { @@ -26,7 +27,7 @@ func (dbobj dbcon) saveSharedRecord(userTOKEN string, fields string, expiration } log.Printf("Expiration is : %s\n", expiration) - start, err := parseExpiration(expiration) + start, err := utils.ParseExpiration(expiration) if err != nil { return "", err } @@ -67,7 +68,7 @@ func (dbobj dbcon) saveSharedRecord(userTOKEN string, fields string, expiration func (dbobj dbcon) getSharedRecord(recordUUID string) (checkRecordResult, error) { var result checkRecordResult - //if isValidUUID(recordUUID) == false { + //if utils.CheckValidUUID(recordUUID) == false { // return result, errors.New("failed to authenticate") //} record, err := dbobj.store.GetRecord(storage.TblName.Sharedrecords, "record", recordUUID) diff --git a/src/storage/mysql-storage.go b/src/storage/mysql-storage.go index 57b3ed9..149b7af 100644 --- a/src/storage/mysql-storage.go +++ b/src/storage/mysql-storage.go @@ -861,7 +861,7 @@ func (dbobj MySQLDB) GetAllTables() ([]string, error) { // ValidateNewApp function check if app name can be part of the table name func (dbobj MySQLDB) ValidateNewApp(appName string) bool { - if contains(allTables, appName) == true { + if SliceContains(allTables, appName) == true { return true } return true @@ -891,7 +891,7 @@ func (dbobj MySQLDB) execQueries(queries []string) error { // CreateNewAppTable creates a new app table and creates indexes for it. func (dbobj MySQLDB) CreateNewAppTable(appName string) { - if contains(allTables, appName) == false { + if SliceContains(allTables, appName) == false { // it is a new app, create an index log.Printf("This is a new app, creating table & index for: %s\n", appName) queries := []string{ diff --git a/src/storage/pgsql-storage.go b/src/storage/pgsql-storage.go index e00178a..d726e99 100644 --- a/src/storage/pgsql-storage.go +++ b/src/storage/pgsql-storage.go @@ -865,7 +865,7 @@ func (dbobj PGSQLDB) GetAllTables() ([]string, error) { // ValidateNewApp function check if app name can be part of the table name func (dbobj PGSQLDB) ValidateNewApp(appName string) bool { - if contains(allTables, appName) == true { + if SliceContains(allTables, appName) == true { return true } if len(allTables) >= 100 { @@ -898,7 +898,7 @@ func (dbobj PGSQLDB) execQueries(queries []string) error { // CreateNewAppTable creates a new app table and creates indexes for it. func (dbobj PGSQLDB) CreateNewAppTable(appName string) { - if contains(allTables, appName) == false { + if SliceContains(allTables, appName) == false { // it is a new app, create an index log.Printf("This is a new app, creating table & index for: %s\n", appName) queries := []string{ diff --git a/src/storage/sqlite-storage.go b/src/storage/sqlite-storage.go index feaaf9f..3bca350 100644 --- a/src/storage/sqlite-storage.go +++ b/src/storage/sqlite-storage.go @@ -849,7 +849,7 @@ func (dbobj SQLiteDB) GetAllTables() ([]string, error) { // ValidateNewApp function check if app name can be part of the table name func (dbobj SQLiteDB) ValidateNewApp(appName string) bool { - if contains(knownApps, appName) == true { + if SliceContains(knownApps, appName) == true { return true } return true @@ -875,7 +875,7 @@ func (dbobj SQLiteDB) execQueries(queries []string) error { // CreateNewAppTable creates a new app table and creates indexes for it. func (dbobj SQLiteDB) CreateNewAppTable(appName string) { - if contains(knownApps, appName) == false { + if SliceContains(knownApps, appName) == false { // it is a new app, create an index log.Printf("This is a new app, creating table & index for: %s\n", appName) queries := []string{"CREATE TABLE IF NOT EXISTS " + appName + ` ( diff --git a/src/storage/storage.go b/src/storage/storage.go index 694b863..acb008a 100644 --- a/src/storage/storage.go +++ b/src/storage/storage.go @@ -143,7 +143,7 @@ func CreateTestDB() string { return db.CreateTestDB() } -func contains(slice []string, item string) bool { +func SliceContains(slice []string, item string) bool { set := make(map[string]struct{}, len(slice)) for _, s := range slice { set[s] = struct{}{} diff --git a/src/userapps_api.go b/src/userapps_api.go index 406f3b0..9c9f157 100644 --- a/src/userapps_api.go +++ b/src/userapps_api.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/julienschmidt/httprouter" + "github.com/securitybunker/databunker/src/utils" ) func (e mainEnv) userappNew(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { @@ -20,38 +21,38 @@ func (e mainEnv) userappNew(w http.ResponseWriter, r *http.Request, ps httproute if userTOKEN == "" { return } - if e.enforceAuth(w, r, event) == "" { + if e.EnforceAuth(w, r, event) == "" { return } - if isValidApp(appName) == false { - returnError(w, r, "bad appname", 405, nil, event) + if utils.CheckValidApp(appName) == false { + ReturnError(w, r, "bad appname", 405, nil, event) return } if e.db.store.ValidateNewApp("app_"+appName) == false { - returnError(w, r, "db limitation", 405, nil, event) + ReturnError(w, r, "db limitation", 405, nil, event) return } - data, err := getJSONPostMap(r) + data, err := utils.GetJSONPostMap(r) if err != nil { - returnError(w, r, "failed to decode request body", 405, err, event) + ReturnError(w, r, "failed to decode request body", 405, err, event) return } if len(data) == 0 { - returnError(w, r, "empty body", 405, nil, event) + ReturnError(w, r, "empty body", 405, nil, event) return } jsonData, err := json.Marshal(data) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } _, err = e.db.createAppRecord(jsonData, userTOKEN, appName, event, e.conf) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } - returnUUID(w, userTOKEN) + utils.ReturnUUID(w, userTOKEN) return } @@ -65,58 +66,58 @@ func (e mainEnv) userappChange(w http.ResponseWriter, r *http.Request, ps httpro if userTOKEN == "" { return } - authResult := e.enforceAuth(w, r, event) + authResult := e.EnforceAuth(w, r, event) if authResult == "" { return } - if isValidApp(appName) == false { - returnError(w, r, "bad appname", 405, nil, event) + if utils.CheckValidApp(appName) == false { + ReturnError(w, r, "bad appname", 405, nil, event) return } - jsonData, err := getJSONPostData(r) + jsonData, err := utils.GetJSONPostData(r) if err != nil { - returnError(w, r, "failed to decode request body", 405, err, event) + ReturnError(w, r, "failed to decode request body", 405, err, event) return } if jsonData == nil { - returnError(w, r, "empty body", 405, nil, event) + ReturnError(w, r, "empty body", 405, nil, event) return } // make sure userapp exists resultJSON, err := e.db.getUserApp(userTOKEN, appName, e.conf) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } if resultJSON == nil { - returnError(w, r, "not found", 405, nil, event) + ReturnError(w, r, "not found", 405, nil, event) return } if authResult != "login" { _, err = e.db.updateAppRecord(jsonData, userTOKEN, appName, event, e.conf) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } - returnUUID(w, userTOKEN) + utils.ReturnUUID(w, userTOKEN) return } if e.conf.SelfService.AppRecordChange != nil { for _, name := range e.conf.SelfService.AppRecordChange { - if stringPatternMatch(strings.ToLower(name), appName) { + if utils.StringPatternMatch(strings.ToLower(name), appName) { _, err = e.db.updateAppRecord(jsonData, userTOKEN, appName, event, e.conf) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } - returnUUID(w, userTOKEN) + utils.ReturnUUID(w, userTOKEN) return } } } rtoken, rstatus, err := e.db.saveUserRequest("change-app-data", userTOKEN, appName, "", jsonData, e.conf) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -133,12 +134,12 @@ func (e mainEnv) userappList(w http.ResponseWriter, r *http.Request, ps httprout if userTOKEN == "" { return } - if e.enforceAuth(w, r, event) == "" { + if e.EnforceAuth(w, r, event) == "" { return } result, err := e.db.listUserApps(userTOKEN, e.conf) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -156,20 +157,20 @@ func (e mainEnv) userappGet(w http.ResponseWriter, r *http.Request, ps httproute if userTOKEN == "" { return } - if e.enforceAuth(w, r, event) == "" { + if e.EnforceAuth(w, r, event) == "" { return } - if isValidApp(appName) == false { - returnError(w, r, "bad appname", 405, nil, event) + if utils.CheckValidApp(appName) == false { + ReturnError(w, r, "bad appname", 405, nil, event) return } resultJSON, err := e.db.getUserApp(userTOKEN, appName, e.conf) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } if resultJSON == nil { - returnError(w, r, "not found", 405, nil, event) + ReturnError(w, r, "not found", 405, nil, event) return } finalJSON := fmt.Sprintf(`{"status":"ok","token":"%s","data":%s}`, userTOKEN, resultJSON) @@ -188,11 +189,11 @@ func (e mainEnv) userappDelete(w http.ResponseWriter, r *http.Request, ps httpro if userTOKEN == "" { return } - if e.enforceAuth(w, r, event) == "" { + if e.EnforceAuth(w, r, event) == "" { return } - if isValidApp(appName) == false { - returnError(w, r, "bad appname", 405, nil, event) + if utils.CheckValidApp(appName) == false { + ReturnError(w, r, "bad appname", 405, nil, event) return } @@ -205,12 +206,12 @@ func (e mainEnv) userappDelete(w http.ResponseWriter, r *http.Request, ps httpro } func (e mainEnv) appList(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - if e.enforceAuth(w, r, nil) == "" { + if e.EnforceAuth(w, r, nil) == "" { return } result, err := e.db.listAllApps(e.conf) if err != nil { - returnError(w, r, "internal error", 405, err, nil) + ReturnError(w, r, "internal error", 405, err, nil) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") diff --git a/src/users_api.go b/src/users_api.go index 7e9194c..9a8be3a 100644 --- a/src/users_api.go +++ b/src/users_api.go @@ -8,6 +8,7 @@ import ( "github.com/julienschmidt/httprouter" "github.com/securitybunker/databunker/src/storage" + "github.com/securitybunker/databunker/src/utils" "go.mongodb.org/mongo-driver/bson" ) @@ -17,98 +18,98 @@ func (e mainEnv) userCreate(w http.ResponseWriter, r *http.Request, ps httproute if e.conf.Generic.CreateUserWithoutAccessToken == false { // anonymous user can not create user record, check token - if e.enforceAuth(w, r, event) == "" { + if e.EnforceAuth(w, r, event) == "" { log.Println("Failed to create user, access denied, try to configure Create_user_without_access_token") return } } - userJSON, err := getUserJSON(r, e.conf.Sms.DefaultCountry) + userJSON, err := utils.GetUserJSONStruct(r, e.conf.Sms.DefaultCountry) if err != nil { - returnError(w, r, "failed to decode request body", 405, err, event) + ReturnError(w, r, "failed to decode request body", 405, err, event) return } - if len(userJSON.jsonData) == 0 { - returnError(w, r, "empty request body", 405, nil, event) + if len(userJSON.JsonData) == 0 { + ReturnError(w, r, "empty request body", 405, nil, event) return } - err = validateUserRecord(userJSON.jsonData) + err = validateUserRecord(userJSON.JsonData) if err != nil { - returnError(w, r, "user schema error: "+err.Error(), 405, err, event) + ReturnError(w, r, "user schema error: "+err.Error(), 405, err, event) return } // make sure that login, email and phone are unique - if len(userJSON.loginIdx) > 0 { - otherUserBson, err := e.db.lookupUserRecordByIndex("login", userJSON.loginIdx, e.conf) + if len(userJSON.LoginIdx) > 0 { + otherUserBson, err := e.db.lookupUserRecordByIndex("login", userJSON.LoginIdx, e.conf) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } if otherUserBson != nil { - returnError(w, r, "duplicate index: login", 405, nil, event) + ReturnError(w, r, "duplicate index: login", 405, nil, event) return } } - if len(userJSON.emailIdx) > 0 { - otherUserBson, err := e.db.lookupUserRecordByIndex("email", userJSON.emailIdx, e.conf) + if len(userJSON.EmailIdx) > 0 { + otherUserBson, err := e.db.lookupUserRecordByIndex("email", userJSON.EmailIdx, e.conf) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } if otherUserBson != nil { - returnError(w, r, "duplicate index: email", 405, nil, event) + ReturnError(w, r, "duplicate index: email", 405, nil, event) return } } - if len(userJSON.phoneIdx) > 0 { - otherUserBson, err := e.db.lookupUserRecordByIndex("phone", userJSON.phoneIdx, e.conf) + if len(userJSON.PhoneIdx) > 0 { + otherUserBson, err := e.db.lookupUserRecordByIndex("phone", userJSON.PhoneIdx, e.conf) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } if otherUserBson != nil { - returnError(w, r, "duplicate index: phone", 405, nil, event) + ReturnError(w, r, "duplicate index: phone", 405, nil, event) return } } - if len(userJSON.customIdx) > 0 { - otherUserBson, err := e.db.lookupUserRecordByIndex("custom", userJSON.customIdx, e.conf) + if len(userJSON.CustomIdx) > 0 { + otherUserBson, err := e.db.lookupUserRecordByIndex("custom", userJSON.CustomIdx, e.conf) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } if otherUserBson != nil { - returnError(w, r, "duplicate index: custom", 405, nil, event) + ReturnError(w, r, "duplicate index: custom", 405, nil, event) return } } - if len(userJSON.loginIdx) == 0 && - len(userJSON.emailIdx) == 0 && - len(userJSON.phoneIdx) == 0 && - len(userJSON.customIdx) == 0 { - returnError(w, r, "failed to create user, all user lookup fields are missing", 405, err, event) + if len(userJSON.LoginIdx) == 0 && + len(userJSON.EmailIdx) == 0 && + len(userJSON.PhoneIdx) == 0 && + len(userJSON.CustomIdx) == 0 { + ReturnError(w, r, "failed to create user, all user lookup fields are missing", 405, err, event) return } userTOKEN, err := e.db.createUserRecord(userJSON, event) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } encPhoneIdx := "" - if len(userJSON.emailIdx) > 0 { - encEmailIdx, _ := basicStringEncrypt(userJSON.emailIdx, e.db.masterKey, e.db.GetCode()) + if len(userJSON.EmailIdx) > 0 { + encEmailIdx, _ := basicStringEncrypt(userJSON.EmailIdx, e.db.masterKey, e.db.GetCode()) e.db.linkAgreementRecords(userTOKEN, encEmailIdx) } - if len(userJSON.phoneIdx) > 0 { - encPhoneIdx, _ = basicStringEncrypt(userJSON.phoneIdx, e.db.masterKey, e.db.GetCode()) + if len(userJSON.PhoneIdx) > 0 { + encPhoneIdx, _ = basicStringEncrypt(userJSON.PhoneIdx, e.db.masterKey, e.db.GetCode()) e.db.linkAgreementRecords(userTOKEN, encPhoneIdx) } - if len(userJSON.emailIdx) > 0 && len(userJSON.phoneIdx) > 0 { + if len(userJSON.EmailIdx) > 0 && len(userJSON.PhoneIdx) > 0 { // delete duplicate consent records for user records, _ := e.db.store.GetList(storage.TblName.Agreements, "token", userTOKEN, 0, 0, "") var briefCodes []string for _, val := range records { - if contains(briefCodes, val["brief"].(string)) == true { + if utils.SliceContains(briefCodes, val["brief"].(string)) == true { e.db.store.DeleteRecord2(storage.TblName.Agreements, "token", userTOKEN, "who", encPhoneIdx) } else { briefCodes = append(briefCodes, val["brief"].(string)) @@ -116,9 +117,9 @@ func (e mainEnv) userCreate(w http.ResponseWriter, r *http.Request, ps httproute } } event.Record = userTOKEN - returnUUID(w, userTOKEN) + utils.ReturnUUID(w, userTOKEN) notifyURL := e.conf.Notification.NotificationURL - notifyProfileNew(notifyURL, userJSON.jsonData, "token", userTOKEN) + notifyProfileNew(notifyURL, userJSON.JsonData, "token", userTOKEN) } func (e mainEnv) userGet(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { @@ -129,14 +130,14 @@ func (e mainEnv) userGet(w http.ResponseWriter, r *http.Request, ps httprouter.P event := audit("get user record by "+mode, identity, mode, identity) defer func() { event.submit(e.db, e.conf) }() - if validateMode(mode) == false { - returnError(w, r, "bad mode", 405, nil, event) + if utils.ValidateMode(mode) == false { + ReturnError(w, r, "bad mode", 405, nil, event) return } userTOKEN := "" authResult := "" if mode == "token" { - if enforceUUID(w, identity, event) == false { + if EnforceUUID(w, identity, event) == false { return } resultJSON, err = e.db.getUserJSON(identity) @@ -146,15 +147,15 @@ func (e mainEnv) userGet(w http.ResponseWriter, r *http.Request, ps httprouter.P event.Record = userTOKEN } if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } - authResult = e.enforceAuth(w, r, event) + authResult = e.EnforceAuth(w, r, event) if authResult == "" { return } if resultJSON == nil { - returnError(w, r, "record not found", 405, nil, event) + ReturnError(w, r, "record not found", 405, nil, event) return } finalJSON := fmt.Sprintf(`{"status":"ok","token":"%s","data":%s}`, userTOKEN, resultJSON) @@ -166,21 +167,21 @@ func (e mainEnv) userGet(w http.ResponseWriter, r *http.Request, ps httprouter.P } func (e mainEnv) userList(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - if e.enforceAdmin(w, r, nil) == "" { + if e.EnforceAdmin(w, r, nil) == "" { return } if e.conf.Generic.ListUsers == false { - returnError(w, r, "access denied", 403, nil, nil) + ReturnError(w, r, "access denied", 403, nil, nil) return } var offset int32 = 0 var limit int32 = 10 args := r.URL.Query() if value, ok := args["offset"]; ok { - offset = atoi(value[0]) + offset = utils.Atoi(value[0]) } if value, ok := args["limit"]; ok { - limit = atoi(value[0]) + limit = utils.Atoi(value[0]) } resultJSON, counter, _ := e.db.getUsers(offset, limit) log.Printf("Total count of events: %d\n", counter) @@ -201,25 +202,25 @@ func (e mainEnv) userChange(w http.ResponseWriter, r *http.Request, ps httproute event := audit("change user record by "+mode, identity, mode, identity) defer func() { event.submit(e.db, e.conf) }() - if validateMode(mode) == false { - returnError(w, r, "bad index", 405, nil, event) + if utils.ValidateMode(mode) == false { + ReturnError(w, r, "bad index", 405, nil, event) return } - jsonData, err := getJSONPostData(r) + jsonData, err := utils.GetJSONPostData(r) if err != nil { - returnError(w, r, "failed to decode request body", 405, err, event) + ReturnError(w, r, "failed to decode request body", 405, err, event) return } if jsonData == nil { - returnError(w, r, "empty request body", 405, nil, event) + ReturnError(w, r, "empty request body", 405, nil, event) return } userTOKEN := "" var userJSON []byte var userBSON bson.M if mode == "token" { - if enforceUUID(w, identity, event) == false { + if EnforceUUID(w, identity, event) == false { return } userTOKEN = identity @@ -229,14 +230,14 @@ func (e mainEnv) userChange(w http.ResponseWriter, r *http.Request, ps httproute event.Record = userTOKEN } if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } if userJSON == nil { - returnError(w, r, "user record not found", 405, nil, event) + ReturnError(w, r, "user record not found", 405, nil, event) return } - authResult := e.enforceAuth(w, r, event) + authResult := e.EnforceAuth(w, r, event) if authResult == "" { return } @@ -244,7 +245,7 @@ func (e mainEnv) userChange(w http.ResponseWriter, r *http.Request, ps httproute if UserSchemaEnabled() { adminRecordChanged, err = e.db.validateUserRecordChange(userJSON, jsonData, userTOKEN, authResult) if err != nil { - returnError(w, r, "schema validation error: "+err.Error(), 405, err, event) + ReturnError(w, r, "schema validation error: "+err.Error(), 405, err, event) return } } @@ -253,7 +254,7 @@ func (e mainEnv) userChange(w http.ResponseWriter, r *http.Request, ps httproute if e.conf.SelfService.UserRecordChange == false || adminRecordChanged == true { rtoken, rstatus, err := e.db.saveUserRequest("change-profile", userTOKEN, "", "", jsonData, e.conf) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -264,14 +265,14 @@ func (e mainEnv) userChange(w http.ResponseWriter, r *http.Request, ps httproute } oldJSON, newJSON, lookupErr, err := e.db.updateUserRecord(jsonData, userTOKEN, userBSON, event, e.conf) if lookupErr { - returnError(w, r, "record not found", 405, errors.New("record not found"), event) + ReturnError(w, r, "record not found", 405, errors.New("record not found"), event) return } if err != nil { - returnError(w, r, "error updating user", 405, err, event) + ReturnError(w, r, "error updating user", 405, err, event) return } - returnUUID(w, userTOKEN) + utils.ReturnUUID(w, userTOKEN) notifyURL := e.conf.Notification.NotificationURL notifyProfileChange(notifyURL, oldJSON, newJSON, "token", userTOKEN) } @@ -283,8 +284,8 @@ func (e mainEnv) userDelete(w http.ResponseWriter, r *http.Request, ps httproute event := audit("delete user record by "+mode, identity, mode, identity) defer func() { event.submit(e.db, e.conf) }() - if validateMode(mode) == false { - returnError(w, r, "bad mode", 405, nil, event) + if utils.ValidateMode(mode) == false { + ReturnError(w, r, "bad mode", 405, nil, event) return } var err error @@ -292,7 +293,7 @@ func (e mainEnv) userDelete(w http.ResponseWriter, r *http.Request, ps httproute var userJSON []byte userTOKEN := identity if mode == "token" { - if enforceUUID(w, identity, event) == false { + if EnforceUUID(w, identity, event) == false { return } userJSON, userBSON, err = e.db.getUser(identity) @@ -301,10 +302,10 @@ func (e mainEnv) userDelete(w http.ResponseWriter, r *http.Request, ps httproute event.Record = userTOKEN } if err != nil { - returnError(w, r, "internal error", 405, nil, event) + ReturnError(w, r, "internal error", 405, nil, event) return } - authResult := e.enforceAuth(w, r, event) + authResult := e.EnforceAuth(w, r, event) if authResult == "" { return } @@ -315,7 +316,7 @@ func (e mainEnv) userDelete(w http.ResponseWriter, r *http.Request, ps httproute w.WriteHeader(200) fmt.Fprintf(w, `{"status":"ok","result":"done"}`) } - returnError(w, r, "record not found", 405, nil, event) + ReturnError(w, r, "record not found", 405, nil, event) return } @@ -324,7 +325,7 @@ func (e mainEnv) userDelete(w http.ResponseWriter, r *http.Request, ps httproute if e.conf.SelfService.ForgetMe == false { rtoken, rstatus, err := e.db.saveUserRequest("forget-me", userTOKEN, "", "", nil, e.conf) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -333,14 +334,14 @@ func (e mainEnv) userDelete(w http.ResponseWriter, r *http.Request, ps httproute return } } - email := getStringValue(userBSON["email"]) + email := utils.GetStringValue(userBSON["email"]) if len(email) > 0 { e.globalUserDelete(email) } //fmt.Printf("deleting user %s\n", userTOKEN) _, err = e.db.deleteUserRecord(userJSON, userTOKEN, e.conf) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -366,12 +367,12 @@ func (e mainEnv) userPrelogin(w http.ResponseWriter, r *http.Request, ps httprou return } if mode != "phone" && mode != "email" { - returnError(w, r, "bad mode", 405, nil, event) + ReturnError(w, r, "bad mode", 405, nil, event) return } userBson, err := e.db.lookupUserRecordByIndex(mode, identity, e.conf) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } if userBson != nil { @@ -394,7 +395,7 @@ func (e mainEnv) userPrelogin(w http.ResponseWriter, r *http.Request, ps httprou //notifyURL := e.conf.Notification.NotificationURL //notifyBadLogin(notifyURL, mode, identity) e.pluginUserLookup(identity) - //returnError(w, r, "record not found", 405, errors.New("record not found"), event) + //ReturnError(w, r, "record not found", 405, errors.New("record not found"), event) captcha, _ := generateCaptcha() w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(403) @@ -409,20 +410,20 @@ func (e mainEnv) userPrelogin(w http.ResponseWriter, r *http.Request, ps httprou } func (e mainEnv) userLogin(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - tmp := atoi(ps.ByName("tmp")) + tmp := utils.Atoi(ps.ByName("tmp")) identity := ps.ByName("identity") mode := ps.ByName("mode") event := audit("user login by "+mode, identity, mode, identity) defer func() { event.submit(e.db, e.conf) }() if mode != "phone" && mode != "email" { - returnError(w, r, "bad mode", 405, nil, event) + ReturnError(w, r, "bad mode", 405, nil, event) return } userBson, err := e.db.lookupUserRecordByIndex(mode, identity, e.conf) if userBson == nil || err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } @@ -438,7 +439,7 @@ func (e mainEnv) userLogin(w http.ResponseWriter, r *http.Request, ps httprouter xtoken, hashedToken, err := e.db.generateUserLoginXtoken(userTOKEN) //fmt.Printf("generate user access token: %s\n", xtoken) if err != nil { - returnError(w, r, "internal error", 405, err, event) + ReturnError(w, r, "internal error", 405, err, event) return } event.Msg = "generated: " + hashedToken @@ -447,5 +448,5 @@ func (e mainEnv) userLogin(w http.ResponseWriter, r *http.Request, ps httprouter fmt.Fprintf(w, `{"status":"ok","xtoken":"%s","token":"%s"}`, xtoken, userTOKEN) return } - returnError(w, r, "internal error", 405, nil, event) + ReturnError(w, r, "internal error", 405, nil, event) } diff --git a/src/users_db.go b/src/users_db.go index 65afce4..943e6c2 100644 --- a/src/users_db.go +++ b/src/users_db.go @@ -12,10 +12,11 @@ import ( jsonpatch "github.com/evanphx/json-patch" uuid "github.com/hashicorp/go-uuid" "github.com/securitybunker/databunker/src/storage" + "github.com/securitybunker/databunker/src/utils" "go.mongodb.org/mongo-driver/bson" ) -func (dbobj dbcon) createUserRecord(parsedData userJSON, event *auditEvent) (string, error) { +func (dbobj dbcon) createUserRecord(parsedData utils.UserJSONStruct, event *auditEvent) (string, error) { var userTOKEN string //var bdoc interface{} bdoc := bson.M{} @@ -28,7 +29,7 @@ func (dbobj dbcon) createUserRecord(parsedData userJSON, event *auditEvent) (str return "", err } //err = bson.UnmarshalExtJSON(jsonData, false, &bdoc) - encoded, err := encrypt(dbobj.masterKey, userKeyBinary, parsedData.jsonData) + encoded, err := encrypt(dbobj.masterKey, userKeyBinary, parsedData.JsonData) if err != nil { return "", err } @@ -43,17 +44,17 @@ func (dbobj dbcon) createUserRecord(parsedData userJSON, event *auditEvent) (str // the index search field is hashed here, to be not-reversible // I use original md5(master_key) as a kind of salt here, // so no additional configuration field is needed here. - if len(parsedData.loginIdx) > 0 { - bdoc["loginidx"] = hashString(dbobj.hash, parsedData.loginIdx) + if len(parsedData.LoginIdx) > 0 { + bdoc["loginidx"] = utils.HashString(dbobj.hash, parsedData.LoginIdx) } - if len(parsedData.emailIdx) > 0 { - bdoc["emailidx"] = hashString(dbobj.hash, parsedData.emailIdx) + if len(parsedData.EmailIdx) > 0 { + bdoc["emailidx"] = utils.HashString(dbobj.hash, parsedData.EmailIdx) } - if len(parsedData.phoneIdx) > 0 { - bdoc["phoneidx"] = hashString(dbobj.hash, parsedData.phoneIdx) + if len(parsedData.PhoneIdx) > 0 { + bdoc["phoneidx"] = utils.HashString(dbobj.hash, parsedData.PhoneIdx) } - if len(parsedData.customIdx) > 0 { - bdoc["customidx"] = hashString(dbobj.hash, parsedData.customIdx) + if len(parsedData.CustomIdx) > 0 { + bdoc["customidx"] = utils.HashString(dbobj.hash, parsedData.CustomIdx) } if event != nil { event.After = encodedStr @@ -93,7 +94,7 @@ func (dbobj dbcon) updateUserExpStatus(userTOKEN string, status string) error { } func (dbobj dbcon) generateTempLoginCode(userTOKEN string) int32 { - rnd := randNum(6) + rnd := utils.RandNum(6) log.Printf("Random: %d\n", rnd) bdoc := bson.M{} bdoc["tempcode"] = rnd @@ -185,7 +186,7 @@ func (dbobj dbcon) updateUserRecordDo(jsonDataPatch []byte, userTOKEN string, ol } oldEmail := "" if _, ok := raw2["email"]; ok { - oldEmail = normalizeEmail(raw2["email"].(string)) + oldEmail = utils.NormalizeEmail(raw2["email"].(string)) } // merge //log.Printf("old json: %s\n", decrypted) @@ -221,21 +222,21 @@ func (dbobj dbcon) updateUserRecordDo(jsonDataPatch []byte, userTOKEN string, ol actionCode := 1 newIdxFinalValue := "" if newIdxValue, ok3 := raw[idx]; ok3 { - newIdxFinalValue = getIndexString(newIdxValue) + newIdxFinalValue = utils.GetIndexString(newIdxValue) //log.Println("newIdxFinalValue0", newIdxFinalValue) if len(newIdxFinalValue) > 0 { if idx == "email" { - newIdxFinalValue = normalizeEmail(newIdxFinalValue) + newIdxFinalValue = utils.NormalizeEmail(newIdxFinalValue) newEmail = newIdxFinalValue } else if idx == "phone" { - newIdxFinalValue = normalizePhone(newIdxFinalValue, conf.Sms.DefaultCountry) + newIdxFinalValue = utils.NormalizePhone(newIdxFinalValue, conf.Sms.DefaultCountry) } } //log.Println("newIdxFinalValue", newIdxFinalValue) } if idxOldValue, ok := oldUserBson[idx+"idx"]; ok { if len(newIdxFinalValue) > 0 && len(idxOldValue.(string)) >= 0 { - idxStringHashHex := hashString(dbobj.hash, newIdxFinalValue) + idxStringHashHex := utils.HashString(dbobj.hash, newIdxFinalValue) if idxStringHashHex == idxOldValue.(string) { //log.Println("Index value NOT changed!") actionCode = 0 @@ -255,7 +256,7 @@ func (dbobj dbcon) updateUserRecordDo(jsonDataPatch []byte, userTOKEN string, ol return nil, nil, true, fmt.Errorf("duplicate %s index", idx) } //log.Printf("Adding index3? %s\n", raw[idx]) - bdoc[idx+"idx"] = hashString(dbobj.hash, newIdxFinalValue) + bdoc[idx+"idx"] = utils.HashString(dbobj.hash, newIdxFinalValue) } else if len(newIdxFinalValue) == 0 { bdel = append(bdel, idx+"idx") } @@ -301,9 +302,9 @@ func (dbobj dbcon) lookupUserRecord(userTOKEN string) (bson.M, error) { func (dbobj dbcon) lookupUserRecordByIndex(indexName string, indexValue string, conf Config) (bson.M, error) { if indexName == "email" { - indexValue = normalizeEmail(indexValue) + indexValue = utils.NormalizeEmail(indexValue) } else if indexName == "phone" { - indexValue = normalizePhone(indexValue, conf.Sms.DefaultCountry) + indexValue = utils.NormalizePhone(indexValue, conf.Sms.DefaultCountry) } if len(indexValue) == 0 { return nil, nil @@ -311,7 +312,7 @@ func (dbobj dbcon) lookupUserRecordByIndex(indexName string, indexValue string, if indexName == "exptoken" { return dbobj.store.GetRecord(storage.TblName.Users, "exptoken", indexValue) } - idxStringHashHex := hashString(dbobj.hash, indexValue) + idxStringHashHex := utils.HashString(dbobj.hash, indexValue) //log.Printf("Loading by %s, value: %s\n", indexName, indexValue) return dbobj.store.GetRecord(storage.TblName.Users, indexName+"idx", idxStringHashHex) } @@ -416,7 +417,7 @@ func (dbobj dbcon) getUsers(offset int32, limit int32) ([]byte, int64, error) { } rec["private"] = raw2 } - expstatus := getStringValue(element["expstatus"]) + expstatus := utils.GetStringValue(element["expstatus"]) if len(expstatus) > 0 { rec["endtime"] = element["endtime"] rec["expstatus"] = expstatus diff --git a/src/utils_test.go b/src/utils_test.go index 9538a2a..1c600aa 100644 --- a/src/utils_test.go +++ b/src/utils_test.go @@ -10,6 +10,7 @@ import ( "testing" uuid "github.com/hashicorp/go-uuid" + "github.com/securitybunker/databunker/src/utils" ) func TestUtilUUID(t *testing.T) { @@ -18,7 +19,7 @@ func TestUtilUUID(t *testing.T) { t.Logf("Checking[%d]: %s\n", id, recordUUID) if err != nil { t.Fatalf("Failed to generate UUID %s: %s ", recordUUID, err) - } else if isValidUUID(recordUUID) == false { + } else if utils.CheckValidUUID(recordUUID) == false { t.Fatalf("Failed to validate UUID: %s ", recordUUID) } } @@ -27,13 +28,13 @@ func TestUtilUUID(t *testing.T) { func TestUtilAppNames(t *testing.T) { goodApps := []string{"penn", "teller", "a123", "good_app"} for _, value := range goodApps { - if isValidApp(value) == false { + if utils.CheckValidApp(value) == false { t.Fatalf("Failed to validate good app name: %s ", value) } } badApps := []string{"P1", "4as", "_a", "a.a", "a a", "a!b"} for _, value := range badApps { - if isValidApp(value) == true { + if utils.CheckValidApp(value) == true { t.Fatalf("Failed to validate bad app name: %s ", value) } } @@ -51,7 +52,7 @@ func TestUtilStringPatternMatch(t *testing.T) { {"pattern": "*test", "name": "123test", "result": true}, } for _, value := range goodJsons { - if stringPatternMatch(value["pattern"].(string), value["name"].(string)) != value["result"].(bool) { + if utils.StringPatternMatch(value["pattern"].(string), value["name"].(string)) != value["result"].(bool) { t.Fatalf("Failed in %s match %s\n", value["pattern"].(string), value["name"].(string)) } } @@ -67,11 +68,11 @@ func TestUtilGetJSONPost(t *testing.T) { for _, value := range goodJsons { request := httptest.NewRequest("POST", "/user", strings.NewReader(value)) request.Header.Set("Content-Type", "application/json") - result, err := getUserJSON(request, "IL") + result, err := utils.GetUserJSONStruct(request, "IL") if err != nil { t.Fatalf("Failed to parse json: %s, err: %s\n", value, err) } - if len(result.loginIdx) == 0 { + if len(result.LoginIdx) == 0 { t.Fatalf("Failed to parse login index from json: %s ", value) } } @@ -83,11 +84,11 @@ func TestUtilGetJSONPost(t *testing.T) { for _, value := range badJsons { request := httptest.NewRequest("POST", "/user", strings.NewReader(value)) request.Header.Set("Content-Type", "application/json") - result, err := getUserJSON(request, "IL") + result, err := utils.GetUserJSONStruct(request, "IL") if err != nil { t.Fatalf("Failed to parse json: %s, err: %s\n", value, err) } - if len(result.loginIdx) != 0 { + if len(result.LoginIdx) != 0 { t.Fatalf("Failed to parse login index from json: %s ", value) } } diff --git a/src/xtokens_db.go b/src/xtokens_db.go index c7256be..b5ed8b1 100644 --- a/src/xtokens_db.go +++ b/src/xtokens_db.go @@ -6,6 +6,7 @@ import ( uuid "github.com/hashicorp/go-uuid" "github.com/securitybunker/databunker/src/storage" + "github.com/securitybunker/databunker/src/utils" "go.mongodb.org/mongo-driver/bson" ) @@ -28,7 +29,7 @@ func (dbobj dbcon) createRootXtoken(customRootXtoken string) (string, error) { return "already-initialized", nil } if len(customRootXtoken) > 0 { - if customRootXtoken != "DEMO" && !isValidUUID(customRootXtoken) { + if customRootXtoken != "DEMO" && !utils.CheckValidUUID(customRootXtoken) { return "", errors.New("bad root token format") } rootToken = customRootXtoken @@ -39,7 +40,7 @@ func (dbobj dbcon) createRootXtoken(customRootXtoken string) (string, error) { } } bdoc := bson.M{} - bdoc["xtoken"] = hashString(dbobj.hash, rootToken) + bdoc["xtoken"] = utils.HashString(dbobj.hash, rootToken) bdoc["type"] = "root" bdoc["token"] = "" _, err = dbobj.store.CreateRecord(storage.TblName.Xtokens, &bdoc) @@ -60,7 +61,7 @@ func (dbobj dbcon) generateUserLoginXtoken(userTOKEN string) (string, string, er if err != nil { return "", "", err } - hashedToken := hashString(dbobj.hash, tokenUUID) + hashedToken := utils.HashString(dbobj.hash, tokenUUID) // by default login token for 30 minutes only expired := int32(time.Now().Unix()) + 10*60 bdoc := bson.M{} @@ -74,10 +75,10 @@ func (dbobj dbcon) generateUserLoginXtoken(userTOKEN string) (string, string, er func (dbobj dbcon) checkUserAuthXToken(xtokenUUID string) (tokenAuthResult, error) { result := tokenAuthResult{} - if xtokenUUID != "DEMO" && isValidUUID(xtokenUUID) == false { + if xtokenUUID != "DEMO" && utils.CheckValidUUID(xtokenUUID) == false { return result, errors.New("failed to authenticate") } - xtokenHashed := hashString(dbobj.hash, xtokenUUID) + xtokenHashed := utils.HashString(dbobj.hash, xtokenUUID) if len(rootXTOKEN) > 0 && rootXTOKEN == xtokenHashed { //log.Println("It is a root token") result.ttype = "root"