From 6e1dbf4f14d2f0080d1d11a7e8b6171c4efecf1c Mon Sep 17 00:00:00 2001 From: yuli Date: Sat, 28 Dec 2024 21:39:51 +0200 Subject: [PATCH] create audit module --- Dockerfile | 2 +- docker-build.sh | 2 +- src/agreements_api.go | 107 ++++++++++++++++++----------------- src/audit_api.go | 56 ++++-------------- src/audit_db.go | 33 ++--------- src/bunker.go | 9 +-- src/captcha.go | 6 +- src/conf.go | 3 +- src/expiration_api.go | 53 ++++++++--------- src/go.mod | 5 +- src/lbasis_api.go | 10 ++-- src/notify.go | 4 +- src/pactivities_api.go | 24 ++++---- src/requests_api.go | 67 +++++++++++----------- src/schema.go | 3 +- src/sessions_api.go | 55 +++++++++--------- src/sharedrecords_api.go | 25 ++++---- src/storage/mysql-storage.go | 3 +- src/storage/pgsql-storage.go | 3 +- src/userapps_api.go | 61 ++++++++++---------- src/userapps_db.go | 5 +- src/users_api.go | 107 ++++++++++++++++++----------------- src/users_db.go | 7 ++- src/utils/checks.go | 42 ++++++++++++++ src/utils/go.mod | 3 + src/utils/utils.go | 6 +- src/utils_test.go | 12 ++-- 27 files changed, 357 insertions(+), 356 deletions(-) create mode 100644 src/utils/checks.go diff --git a/Dockerfile b/Dockerfile index 62ab72b..6228f4c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ FROM golang:alpine AS builder RUN apk update && apk add --no-cache git gcc libc-dev openssl && go install github.com/gobuffalo/packr/packr@latest WORKDIR /go/src/securitybunker/databunker/src/ COPY src/go.mod ./deps -RUN cat ./deps | grep -v storage | grep -v utils > ./go.mod && go mod download +RUN cat ./deps | grep -v storage | grep -v utils | grep -v audit > ./go.mod && go mod download COPY . /go/src/securitybunker/databunker/ WORKDIR /go/src/securitybunker/databunker/ #RUN echo "tidy " && go get -u && go mod tidy && cat ./go.mod diff --git a/docker-build.sh b/docker-build.sh index 7645d58..b53ed7c 100755 --- a/docker-build.sh +++ b/docker-build.sh @@ -1,5 +1,5 @@ #!/bin/sh VERSION=$(cat ./version.txt) -docker build -t securitybunker/databunker:$VERSION . +docker build --progress=plain -t securitybunker/databunker:$VERSION . docker tag securitybunker/databunker:$VERSION securitybunker/databunker:latest diff --git a/src/agreements_api.go b/src/agreements_api.go index 20c247b..8fdb19f 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/audit" "github.com/securitybunker/databunker/src/utils" //"go.mongodb.org/mongo-driver/bson" ) @@ -15,35 +16,35 @@ func (e mainEnv) agreementAccept(w http.ResponseWriter, r *http.Request, ps http identity := ps.ByName("identity") brief := ps.ByName("brief") mode := ps.ByName("mode") - event := audit("accept agreement by "+brief, identity, mode, identity) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("accept agreement by "+brief, identity, mode, identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() if utils.ValidateMode(mode) == false { - ReturnError(w, r, "bad mode", 405, nil, event) + utils.ReturnError(w, r, "bad mode", 405, nil, event) return } brief = utils.NormalizeBrief(brief) if utils.CheckValidBrief(brief) == false { - ReturnError(w, r, "bad brief format", 405, nil, event) + utils.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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } if exists == false { - ReturnError(w, r, "not found", 404, nil, event) + utils.ReturnError(w, r, "not found", 404, nil, event) return } userTOKEN := "" if mode == "token" { - if EnforceUUID(w, identity, event) == false { + if utils.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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } if e.EnforceAuth(w, r, event) == "" { @@ -53,7 +54,7 @@ func (e mainEnv) agreementAccept(w http.ResponseWriter, r *http.Request, ps http } else { userBson, err := e.db.lookupUserRecordByIndex(mode, identity, e.conf) if err != nil { - ReturnError(w, r, "internal error", 405, err, event) + utils.ReturnError(w, r, "internal error", 405, err, event) return } if userBson != nil { @@ -61,7 +62,7 @@ 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) + utils.ReturnError(w, r, "internal error", 405, nil, event) return } // else user not found - we allow to save consent for unlinked users! @@ -70,7 +71,7 @@ func (e mainEnv) agreementAccept(w http.ResponseWriter, r *http.Request, ps http records, err := utils.GetJSONPostMap(r) if err != nil { - ReturnError(w, r, "failed to decode request body", 405, err, event) + utils.ReturnError(w, r, "failed to decode request body", 405, err, event) return } starttime := int32(0) @@ -129,37 +130,37 @@ func (e mainEnv) agreementWithdraw(w http.ResponseWriter, r *http.Request, ps ht identity := ps.ByName("identity") brief := ps.ByName("brief") mode := ps.ByName("mode") - event := audit("withdraw agreement by "+brief, identity, mode, identity) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("withdraw agreement by "+brief, identity, mode, identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() if utils.ValidateMode(mode) == false { - ReturnError(w, r, "bad mode", 405, nil, event) + utils.ReturnError(w, r, "bad mode", 405, nil, event) return } brief = utils.NormalizeBrief(brief) if utils.CheckValidBrief(brief) == false { - ReturnError(w, r, "bad brief format", 405, nil, event) + utils.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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } if lbasis == nil { - ReturnError(w, r, "not found", 405, nil, event) + utils.ReturnError(w, r, "not found", 405, nil, event) return } userTOKEN := "" authResult := "" if mode == "token" { - if EnforceUUID(w, identity, event) == false { + if utils.EnforceUUID(w, identity, event) == false { return } userBson, _ := e.db.lookupUserRecord(identity) if userBson == nil { - ReturnError(w, r, "internal error", 405, nil, event) + utils.ReturnError(w, r, "internal error", 405, nil, event) return } authResult = e.EnforceAuth(w, r, event) @@ -175,7 +176,7 @@ 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) + utils.ReturnError(w, r, "internal error", 405, nil, event) return } // else user not found - we allow to save consent for unlinked users! @@ -183,7 +184,7 @@ func (e mainEnv) agreementWithdraw(w http.ResponseWriter, r *http.Request, ps ht } records, err := utils.GetJSONPostMap(r) if err != nil { - ReturnError(w, r, "failed to decode request body", 405, err, event) + utils.ReturnError(w, r, "failed to decode request body", 405, err, event) return } lastmodifiedby := utils.GetStringValue(records["lastmodifiedby"]) @@ -210,7 +211,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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -243,16 +244,16 @@ func (e mainEnv) agreementRevokeAll(w http.ResponseWriter, r *http.Request, ps h } brief = utils.NormalizeBrief(brief) if utils.CheckValidBrief(brief) == false { - ReturnError(w, r, "bad brief format", 405, nil, nil) + utils.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) + utils.ReturnError(w, r, "internal error", 405, nil, nil) return } if exists == false { - ReturnError(w, r, "not found", 405, nil, nil) + utils.ReturnError(w, r, "not found", 405, nil, nil) return } e.db.revokeLegalBasis(brief) @@ -264,22 +265,22 @@ func (e mainEnv) agreementRevokeAll(w http.ResponseWriter, r *http.Request, ps h func (e mainEnv) getUserAgreements(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { identity := ps.ByName("identity") mode := ps.ByName("mode") - event := audit("privacy agreements for "+mode, identity, mode, identity) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("privacy agreements for "+mode, identity, mode, identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() if utils.ValidateMode(mode) == false { - ReturnError(w, r, "bad mode", 405, nil, event) + utils.ReturnError(w, r, "bad mode", 405, nil, event) return } userTOKEN := "" if mode == "token" { - if EnforceUUID(w, identity, event) == false { + if utils.EnforceUUID(w, identity, event) == false { return } userBson, _ := e.db.lookupUserRecord(identity) if userBson == nil { - ReturnError(w, r, "internal error", 405, nil, event) + utils.ReturnError(w, r, "internal error", 405, nil, event) return } if e.EnforceAuth(w, r, event) == "" { @@ -297,7 +298,7 @@ func (e mainEnv) getUserAgreements(w http.ResponseWriter, r *http.Request, ps ht } } else { if mode == "login" { - ReturnError(w, r, "internal error", 405, nil, event) + utils.ReturnError(w, r, "internal error", 405, nil, event) return } // else user not found - we allow to save consent for unlinked users! @@ -317,7 +318,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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -330,35 +331,35 @@ func (e mainEnv) getUserAgreement(w http.ResponseWriter, r *http.Request, ps htt identity := ps.ByName("identity") brief := ps.ByName("brief") mode := ps.ByName("mode") - event := audit("privacy agreements for "+mode, identity, mode, identity) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("privacy agreements for "+mode, identity, mode, identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() if utils.ValidateMode(mode) == false { - ReturnError(w, r, "bad mode", 405, nil, event) + utils.ReturnError(w, r, "bad mode", 405, nil, event) return } brief = utils.NormalizeBrief(brief) if utils.CheckValidBrief(brief) == false { - ReturnError(w, r, "bad brief format", 405, nil, event) + utils.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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } if exists == false { - ReturnError(w, r, "not found", 404, nil, event) + utils.ReturnError(w, r, "not found", 404, nil, event) return } userTOKEN := "" if mode == "token" { - if EnforceUUID(w, identity, event) == false { + if utils.EnforceUUID(w, identity, event) == false { return } userBson, _ := e.db.lookupUserRecord(identity) if userBson == nil { - ReturnError(w, r, "internal error", 405, nil, event) + utils.ReturnError(w, r, "internal error", 405, nil, event) return } if e.EnforceAuth(w, r, event) == "" { @@ -376,7 +377,7 @@ func (e mainEnv) getUserAgreement(w http.ResponseWriter, r *http.Request, ps htt } } else { if mode == "login" { - ReturnError(w, r, "internal error", 405, nil, event) + utils.ReturnError(w, r, "internal error", 405, nil, event) return } // else user not found - we allow to save consent for unlinked users! @@ -389,11 +390,11 @@ func (e mainEnv) getUserAgreement(w http.ResponseWriter, r *http.Request, ps htt var resultJSON []byte resultJSON, err = e.db.viewAgreementRecord(userTOKEN, brief) if err != nil { - ReturnError(w, r, "internal error", 405, err, event) + utils.ReturnError(w, r, "internal error", 405, err, event) return } if resultJSON == nil { - ReturnError(w, r, "not found", 405, err, event) + utils.ReturnError(w, r, "not found", 405, err, event) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -407,16 +408,16 @@ func (e mainEnv) consentUserRecord(w http.ResponseWriter, r *http.Request, ps ht identity := ps.ByName("identity") brief := ps.ByName("brief") mode := ps.ByName("mode") - event := audit("consent record for "+brief, identity, mode, identity) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("consent record for "+brief, identity, mode, identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() if utils.ValidateMode(mode) == false { - ReturnError(w, r, "bad mode", 405, nil, event) + utils.ReturnError(w, r, "bad mode", 405, nil, event) return } brief = utils.NormalizeBrief(brief) if utils.CheckValidBrief(brief) == false { - ReturnError(w, r, "bad brief format", 405, nil, event) + utils.ReturnError(w, r, "bad brief format", 405, nil, event) return } userTOKEN := identity @@ -434,7 +435,7 @@ func (e mainEnv) consentUserRecord(w http.ResponseWriter, r *http.Request, ps ht } } if userBson == nil { - ReturnError(w, r, "internal error", 405, nil, event) + utils.ReturnError(w, r, "internal error", 405, nil, event) return } // make sure that user is logged in here, unless he wants to cancel emails @@ -443,11 +444,11 @@ func (e mainEnv) consentUserRecord(w http.ResponseWriter, r *http.Request, ps ht } resultJSON, err := e.db.viewConsentRecord(userTOKEN, brief) if err != nil { - ReturnError(w, r, "internal error", 405, err, event) + utils.ReturnError(w, r, "internal error", 405, err, event) return } if resultJSON == nil { - ReturnError(w, r, "not found", 405, nil, event) + utils.ReturnError(w, r, "not found", 405, nil, event) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -460,8 +461,8 @@ func (e mainEnv) consentUserRecord(w http.ResponseWriter, r *http.Request, ps ht /* func (e mainEnv) consentFilterRecords(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { brief := ps.ByName("brief") - event := audit("consent get all for "+brief, brief, "brief", brief) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("consent get all for "+brief, brief, "brief", brief) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() if e.EnforceAuth(w, r, event) == "" { return } @@ -476,7 +477,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) + utils.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 73e23ef..20d5b2f 100644 --- a/src/audit_api.go +++ b/src/audit_api.go @@ -6,43 +6,11 @@ import ( "net/http" "github.com/julienschmidt/httprouter" + "github.com/securitybunker/databunker/src/audit" "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 { +func (e mainEnv) EnforceAuth(w http.ResponseWriter, r *http.Request, event *audit.AuditEvent) string { /* for key, value := range r.Header { fmt.Printf("%s => %s\n", key, value) @@ -81,7 +49,7 @@ func (e mainEnv) EnforceAuth(w http.ResponseWriter, r *http.Request, event *audi return "" } -func (e mainEnv) EnforceAdmin(w http.ResponseWriter, r *http.Request, event *auditEvent) string { +func (e mainEnv) EnforceAdmin(w http.ResponseWriter, r *http.Request, event *audit.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]) @@ -102,9 +70,9 @@ func (e mainEnv) EnforceAdmin(w http.ResponseWriter, r *http.Request, event *aud 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 { + event := audit.CreateAuditEvent("view audit events", userTOKEN, "token", userTOKEN) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() + if utils.EnforceUUID(w, userTOKEN, event) == false { return } if e.EnforceAuth(w, r, event) == "" { @@ -121,7 +89,7 @@ func (e mainEnv) getAuditEvents(w http.ResponseWriter, r *http.Request, ps httpr } resultJSON, counter, err := e.db.getAuditEvents(userTOKEN, offset, limit) if err != nil { - ReturnError(w, r, "internal error", 405, err, event) + utils.ReturnError(w, r, "internal error", 405, err, event) return } //fmt.Printf("Total count of events: %d\n", counter) @@ -146,7 +114,7 @@ func (e mainEnv) getAdminAuditEvents(w http.ResponseWriter, r *http.Request, ps } resultJSON, counter, err := e.db.getAdminAuditEvents(offset, limit) if err != nil { - ReturnError(w, r, "internal error", 405, err, nil) + utils.ReturnError(w, r, "internal error", 405, err, nil) return } //fmt.Printf("Total count of events: %d\n", counter) @@ -158,16 +126,16 @@ func (e mainEnv) getAdminAuditEvents(w http.ResponseWriter, r *http.Request, ps func (e mainEnv) getAuditEvent(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { atoken := ps.ByName("atoken") - event := audit("view audit event", atoken, "token", atoken) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("view audit event", atoken, "token", atoken) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() //fmt.Println("error code") - if EnforceUUID(w, atoken, event) == false { + if utils.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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } event.Record = userTOKEN diff --git a/src/audit_db.go b/src/audit_db.go index 79ef11c..cc2f2ad 100644 --- a/src/audit_db.go +++ b/src/audit_db.go @@ -6,41 +6,18 @@ import ( "fmt" //"log" - "time" uuid "github.com/hashicorp/go-uuid" + "github.com/securitybunker/databunker/src/audit" "github.com/securitybunker/databunker/src/storage" "github.com/securitybunker/databunker/src/utils" "go.mongodb.org/mongo-driver/bson" ) -type auditEvent struct { - When int32 `json:"when"` - Who string `json:"who"` - Mode string `json:"mode"` - Identity string `json:"identity"` - Record string `json:"record"` - App string `json:"app"` - Title string `json:"title"` - Status string `json:"status"` - Msg string `json:"msg"` - Debug string `json:"debug"` - Before string `json:"before"` - After string `json:"after"` - Atoken string `json:"atoken"` -} - -func audit(title string, record string, mode string, identity string) *auditEvent { - //fmt.Printf("/%s : %s\n", title, record) - return &auditEvent{Title: title, Mode: mode, Who: identity, Record: record, Status: "ok", When: int32(time.Now().Unix())} -} - -func auditApp(title string, record string, app string, mode string, identity string) *auditEvent { - //fmt.Printf("/%s : %s : %s\n", title, app, record) - return &auditEvent{Title: title, Mode: mode, Who: identity, Record: record, Status: "ok", When: int32(time.Now().Unix())} -} - -func (event auditEvent) submit(db *dbcon, conf Config) { +func SaveAuditEvent(event *audit.AuditEvent, db *dbcon, conf Config) { + if event == nil { + return + } if conf.Generic.DisableAudit == true { return } diff --git a/src/bunker.go b/src/bunker.go index ec4d666..3897dab 100644 --- a/src/bunker.go +++ b/src/bunker.go @@ -18,6 +18,7 @@ import ( "github.com/kelseyhightower/envconfig" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/securitybunker/databunker/src/audit" "github.com/securitybunker/databunker/src/autocontext" "github.com/securitybunker/databunker/src/storage" "github.com/securitybunker/databunker/src/utils" @@ -383,15 +384,15 @@ 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 { +func (e mainEnv) loadUserToken(w http.ResponseWriter, r *http.Request, mode string, identity string, event *audit.AuditEvent) string { var err error if utils.ValidateMode(mode) == false { - ReturnError(w, r, "bad mode", 405, nil, event) + utils.ReturnError(w, r, "bad mode", 405, nil, event) return "" } var userBson bson.M if mode == "token" { - if EnforceUUID(w, identity, event) == false { + if utils.EnforceUUID(w, identity, event) == false { return "" } userBson, err = e.db.lookupUserRecord(identity) @@ -399,7 +400,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) + utils.ReturnError(w, r, "internal error", 405, nil, event) return "" } event.Record = userBson["token"].(string) diff --git a/src/captcha.go b/src/captcha.go index ecaf90e..8731f28 100644 --- a/src/captcha.go +++ b/src/captcha.go @@ -28,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) + utils.ReturnError(w, r, "bad code", 405, err, nil) return } s, err := decryptCaptcha(code) if err != nil { - ReturnError(w, r, err.Error(), 405, err, nil) + utils.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) + // utils.ReturnError(w, r, err.Error(), 405, err, nil) // return //} cap := captcha.New() diff --git a/src/conf.go b/src/conf.go index 47c7540..5091907 100644 --- a/src/conf.go +++ b/src/conf.go @@ -7,6 +7,7 @@ import ( "github.com/julienschmidt/httprouter" "github.com/securitybunker/databunker/src/autocontext" + "github.com/securitybunker/databunker/src/utils" ) func (e mainEnv) setupConfRouter(router *httprouter.Router) *httprouter.Router { @@ -23,7 +24,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) + utils.ReturnError(w, r, "internal error", 405, err, nil) return } resultUIConfJSON, _ := json.Marshal(e.conf.UI) diff --git a/src/expiration_api.go b/src/expiration_api.go index 030a063..0994d97 100644 --- a/src/expiration_api.go +++ b/src/expiration_api.go @@ -6,6 +6,7 @@ import ( uuid "github.com/hashicorp/go-uuid" "github.com/julienschmidt/httprouter" + "github.com/securitybunker/databunker/src/audit" "github.com/securitybunker/databunker/src/storage" "github.com/securitybunker/databunker/src/utils" "go.mongodb.org/mongo-driver/bson" @@ -31,16 +32,16 @@ func (e mainEnv) expUsers() error { func (e mainEnv) expGetStatus(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { identity := ps.ByName("identity") mode := ps.ByName("mode") - event := audit("get expiration status by "+mode, identity, mode, identity) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("get expiration status by "+mode, identity, mode, identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() var err error if utils.ValidateMode(mode) == false { - ReturnError(w, r, "bad mode", 405, nil, event) + utils.ReturnError(w, r, "bad mode", 405, nil, event) return } var userBson bson.M if mode == "token" { - if EnforceUUID(w, identity, event) == false { + if utils.EnforceUUID(w, identity, event) == false { return } userBson, err = e.db.lookupUserRecord(identity) @@ -48,7 +49,7 @@ 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) + utils.ReturnError(w, r, "internal error", 405, nil, event) return } userTOKEN := userBson["token"].(string) @@ -67,16 +68,16 @@ func (e mainEnv) expCancel(w http.ResponseWriter, r *http.Request, ps httprouter var err error identity := ps.ByName("identity") mode := ps.ByName("mode") - event := audit("clear user expiration by "+mode, identity, mode, identity) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("clear user expiration by "+mode, identity, mode, identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() if utils.ValidateMode(mode) == false { - ReturnError(w, r, "bad mode", 405, nil, event) + utils.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 utils.EnforceUUID(w, identity, event) == false { return } userBson, err = e.db.lookupUserRecord(identity) @@ -88,13 +89,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) + utils.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) + utils.ReturnError(w, r, "internal error", 405, nil, event) return } finalJSON := `{"status":"ok"}` @@ -106,14 +107,14 @@ func (e mainEnv) expCancel(w http.ResponseWriter, r *http.Request, ps httprouter func (e mainEnv) expRetainData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { identity := ps.ByName("exptoken") 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 { + event := audit.CreateAuditEvent("retain user data by exptoken", identity, mode, identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() + if utils.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) + utils.ReturnError(w, r, "internal error", 405, nil, event) return } userTOKEN := userBson["token"].(string) @@ -121,7 +122,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) + utils.ReturnError(w, r, "internal error", 405, nil, event) return } w.WriteHeader(200) @@ -131,14 +132,14 @@ func (e mainEnv) expRetainData(w http.ResponseWriter, r *http.Request, ps httpro func (e mainEnv) expDeleteData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { identity := ps.ByName("exptoken") 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 { + event := audit.CreateAuditEvent("delete user data by exptoken", identity, mode, identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() + if utils.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) + utils.ReturnError(w, r, "internal error", 405, nil, event) return } event.Record = userTOKEN @@ -148,7 +149,7 @@ func (e mainEnv) expDeleteData(w http.ResponseWriter, r *http.Request, ps httpro } _, err = e.db.deleteUserRecord(userJSON, userTOKEN, e.conf) if err != nil { - ReturnError(w, r, "internal error", 405, nil, event) + utils.ReturnError(w, r, "internal error", 405, nil, event) return } e.db.updateUserExpStatus(userTOKEN, "expired") @@ -160,8 +161,8 @@ func (e mainEnv) expStart(w http.ResponseWriter, r *http.Request, ps httprouter. var err error identity := ps.ByName("identity") mode := ps.ByName("mode") - event := audit("initiate user record expiration by "+mode, identity, mode, identity) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("initiate user record expiration by "+mode, identity, mode, identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() if e.EnforceAdmin(w, r, event) == "" { return @@ -172,7 +173,7 @@ func (e mainEnv) expStart(w http.ResponseWriter, r *http.Request, ps httprouter. } records, err := utils.GetJSONPostMap(r) if err != nil { - ReturnError(w, r, "failed to decode request body", 405, err, event) + utils.ReturnError(w, r, "failed to decode request body", 405, err, event) return } expirationStr := utils.GetStringValue(records["expiration"]) @@ -184,11 +185,11 @@ func (e mainEnv) expStart(w http.ResponseWriter, r *http.Request, ps httprouter. } expToken, err := uuid.GenerateUUID() if err != nil { - ReturnError(w, r, "internal error", 405, err, event) + utils.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) + utils.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 40aaead..7b0f7a1 100644 --- a/src/go.mod +++ b/src/go.mod @@ -8,6 +8,8 @@ replace github.com/securitybunker/databunker/src/storage => ./storage replace github.com/securitybunker/databunker/src/utils => ./utils +replace github.com/securitybunker/databunker/src/audit => ./audit + require ( github.com/afocus/captcha v0.0.0-20191010092841-4bd1f21c8868 github.com/evanphx/json-patch v5.9.0+incompatible @@ -18,6 +20,7 @@ require ( github.com/oschwald/geoip2-golang v1.11.0 github.com/prometheus/client_golang v1.20.5 github.com/qri-io/jsonpointer v0.1.1 + github.com/securitybunker/databunker/src/audit v0.0.0 github.com/securitybunker/databunker/src/storage v0.0.0 github.com/securitybunker/databunker/src/utils v0.0.0 github.com/securitybunker/jsonschema v0.2.1-0.20201128224651-d77c1a3cb787 @@ -62,7 +65,7 @@ require ( google.golang.org/protobuf v1.36.1 // indirect modernc.org/gc/v3 v3.0.0-20241223112719-96e2e1e4408d // indirect modernc.org/libc v1.61.5 // indirect - modernc.org/mathutil v1.7.0 // indirect + modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.8.0 // indirect modernc.org/sqlite v1.34.4 // indirect modernc.org/strutil v1.2.0 // indirect diff --git a/src/lbasis_api.go b/src/lbasis_api.go index 0d592bb..4e85fc9 100644 --- a/src/lbasis_api.go +++ b/src/lbasis_api.go @@ -18,18 +18,18 @@ func (e mainEnv) createLegalBasis(w http.ResponseWriter, r *http.Request, ps htt } brief = utils.NormalizeBrief(brief) if utils.CheckValidBrief(brief) == false { - ReturnError(w, r, "bad brief format", 405, nil, nil) + utils.ReturnError(w, r, "bad brief format", 405, nil, nil) return } records, err := utils.GetJSONPostMap(r) if err != nil { - ReturnError(w, r, "failed to decode request body", 405, err, nil) + utils.ReturnError(w, r, "failed to decode request body", 405, err, nil) return } newbrief := utils.GetStringValue(records["brief"]) if len(newbrief) > 0 && newbrief != brief { if utils.CheckValidBrief(newbrief) == false { - ReturnError(w, r, "bad brief format", 405, nil, nil) + utils.ReturnError(w, r, "bad brief format", 405, nil, nil) return } } @@ -88,7 +88,7 @@ func (e mainEnv) deleteLegalBasis(w http.ResponseWriter, r *http.Request, ps htt } brief = utils.NormalizeBrief(brief) if utils.CheckValidBrief(brief) == false { - ReturnError(w, r, "bad brief format", 405, nil, nil) + utils.ReturnError(w, r, "bad brief format", 405, nil, nil) return } e.db.unlinkProcessingActivityBrief(brief) @@ -104,7 +104,7 @@ func (e mainEnv) listLegalBasisRecords(w http.ResponseWriter, r *http.Request, p } resultJSON, numRecords, err := e.db.getLegalBasisRecords() if err != nil { - ReturnError(w, r, "internal error", 405, err, nil) + utils.ReturnError(w, r, "internal error", 405, err, nil) return } log.Printf("Total count of rows: %d\n", numRecords) diff --git a/src/notify.go b/src/notify.go index 44da387..67ca357 100644 --- a/src/notify.go +++ b/src/notify.go @@ -4,7 +4,7 @@ import ( "bytes" "encoding/json" "fmt" - "io/ioutil" + "io" "log" "net/http" @@ -80,7 +80,7 @@ func notify(notifyURL string, host interface{}, requestBody []byte) { return } defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { log.Printf("error in body read: %s", err) return diff --git a/src/pactivities_api.go b/src/pactivities_api.go index 1b91cb2..f43fea2 100644 --- a/src/pactivities_api.go +++ b/src/pactivities_api.go @@ -18,12 +18,12 @@ func (e mainEnv) pactivityCreate(w http.ResponseWriter, r *http.Request, ps http } activity = utils.NormalizeBrief(activity) if utils.CheckValidBrief(activity) == false { - ReturnError(w, r, "bad activity format", 405, nil, nil) + utils.ReturnError(w, r, "bad activity format", 405, nil, nil) return } records, err := utils.GetJSONPostMap(r) if err != nil { - ReturnError(w, r, "failed to decode request body", 405, err, nil) + utils.ReturnError(w, r, "failed to decode request body", 405, err, nil) return } defer func() { @@ -76,7 +76,7 @@ func (e mainEnv) pactivityDelete(w http.ResponseWriter, r *http.Request, ps http } activity = utils.NormalizeBrief(activity) if utils.CheckValidBrief(activity) == false { - ReturnError(w, r, "bad activity format", 405, nil, nil) + utils.ReturnError(w, r, "bad activity format", 405, nil, nil) return } e.db.deleteProcessingActivity(activity) @@ -93,26 +93,26 @@ func (e mainEnv) pactivityLink(w http.ResponseWriter, r *http.Request, ps httpro } activity = utils.NormalizeBrief(activity) if utils.CheckValidBrief(activity) == false { - ReturnError(w, r, "bad activity format", 405, nil, nil) + utils.ReturnError(w, r, "bad activity format", 405, nil, nil) return } brief = utils.NormalizeBrief(brief) if utils.CheckValidBrief(brief) == false { - ReturnError(w, r, "bad brief format", 405, nil, nil) + utils.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) + utils.ReturnError(w, r, "internal error", 405, nil, nil) return } if exists == false { - ReturnError(w, r, "not found", 405, nil, nil) + utils.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) + utils.ReturnError(w, r, "internal error", 405, err, nil) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -128,17 +128,17 @@ func (e mainEnv) pactivityUnlink(w http.ResponseWriter, r *http.Request, ps http } activity = utils.NormalizeBrief(activity) if utils.CheckValidBrief(activity) == false { - ReturnError(w, r, "bad activity format", 405, nil, nil) + utils.ReturnError(w, r, "bad activity format", 405, nil, nil) return } brief = utils.NormalizeBrief(brief) if utils.CheckValidBrief(brief) == false { - ReturnError(w, r, "bad brief format", 405, nil, nil) + utils.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) + utils.ReturnError(w, r, "internal error", 405, err, nil) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -152,7 +152,7 @@ func (e mainEnv) pactivityList(w http.ResponseWriter, r *http.Request, ps httpro } resultJSON, numRecords, err := e.db.listProcessingActivities() if err != nil { - ReturnError(w, r, "internal error", 405, err, nil) + utils.ReturnError(w, r, "internal error", 405, err, nil) return } log.Printf("Total count of rows: %d\n", numRecords) diff --git a/src/requests_api.go b/src/requests_api.go index 376ea61..4c73833 100644 --- a/src/requests_api.go +++ b/src/requests_api.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/julienschmidt/httprouter" + "github.com/securitybunker/databunker/src/audit" "github.com/securitybunker/databunker/src/utils" ) @@ -30,7 +31,7 @@ func (e mainEnv) getUserRequests(w http.ResponseWriter, r *http.Request, ps http } resultJSON, counter, err := e.db.getRequests(status, offset, limit) if err != nil { - ReturnError(w, r, "internal error", 405, err, nil) + utils.ReturnError(w, r, "internal error", 405, err, nil) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -43,8 +44,8 @@ func (e mainEnv) getUserRequests(w http.ResponseWriter, r *http.Request, ps http func (e mainEnv) getCustomUserRequests(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { identity := ps.ByName("identity") mode := ps.ByName("mode") - event := audit("get user privacy requests", identity, mode, identity) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("get user privacy requests", identity, mode, identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() if e.EnforceAuth(w, r, event) == "" { return @@ -64,7 +65,7 @@ func (e mainEnv) getCustomUserRequests(w http.ResponseWriter, r *http.Request, p } resultJSON, counter, err := e.db.getUserRequests(userTOKEN, offset, limit) if err != nil { - ReturnError(w, r, "internal error", 405, err, nil) + utils.ReturnError(w, r, "internal error", 405, err, nil) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -75,19 +76,19 @@ func (e mainEnv) getCustomUserRequests(w http.ResponseWriter, r *http.Request, p func (e mainEnv) getUserRequest(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { request := ps.ByName("request") - event := audit("get user request by request token", request, "request", request) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("get user request by request token", request, "request", request) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() - if EnforceUUID(w, request, event) == false { + if utils.EnforceUUID(w, request, event) == false { return } requestInfo, err := e.db.getRequest(request) if err != nil { - ReturnError(w, r, "internal error", 405, err, nil) + utils.ReturnError(w, r, "internal error", 405, err, nil) return } if len(requestInfo) == 0 { - ReturnError(w, r, "not found", 405, err, event) + utils.ReturnError(w, r, "not found", 405, err, event) return } var resultJSON []byte @@ -113,11 +114,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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } if resultJSON == nil { - ReturnError(w, r, "not found", 405, err, event) + utils.ReturnError(w, r, "not found", 405, err, event) return } //fmt.Printf("Full json: %s\n", resultJSON) @@ -143,10 +144,10 @@ func (e mainEnv) getUserRequest(w http.ResponseWriter, r *http.Request, ps httpr func (e mainEnv) approveUserRequest(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { request := ps.ByName("request") - event := audit("approve user request", request, "request", request) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("approve user request", request, "request", request) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() - if EnforceUUID(w, request, event) == false { + if utils.EnforceUUID(w, request, event) == false { return } authResult := e.EnforceAdmin(w, r, event) @@ -155,17 +156,17 @@ func (e mainEnv) approveUserRequest(w http.ResponseWriter, r *http.Request, ps h } records, err := utils.GetJSONPostMap(r) if err != nil { - ReturnError(w, r, "failed to decode request body", 405, err, event) + utils.ReturnError(w, r, "failed to decode request body", 405, err, event) return } reason := utils.GetStringValue(records["reason"]) requestInfo, err := e.db.getRequest(request) if err != nil { - ReturnError(w, r, "internal error", 405, err, event) + utils.ReturnError(w, r, "internal error", 405, err, event) return } if len(requestInfo) == 0 { - ReturnError(w, r, "not found", 405, err, event) + utils.ReturnError(w, r, "not found", 405, err, event) return } userTOKEN := utils.GetStringValue(requestInfo["token"]) @@ -175,16 +176,16 @@ func (e mainEnv) approveUserRequest(w http.ResponseWriter, r *http.Request, ps h action := utils.GetStringValue(requestInfo["action"]) status := utils.GetStringValue(requestInfo["status"]) if status != "open" { - ReturnError(w, r, "wrong status: "+status, 405, err, event) + utils.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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } if userJSON == nil { - ReturnError(w, r, "not found", 405, err, event) + utils.ReturnError(w, r, "not found", 405, err, event) return } if action == "forget-me" { @@ -199,7 +200,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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } notifyURL := e.conf.Notification.NotificationURL @@ -207,11 +208,11 @@ 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) + utils.ReturnError(w, r, "internal error", 405, errors.New("not found"), event) return } if err != nil { - ReturnError(w, r, "internal error", 405, err, event) + utils.ReturnError(w, r, "internal error", 405, err, event) return } utils.ReturnUUID(w, userTOKEN) @@ -221,7 +222,7 @@ func (e mainEnv) approveUserRequest(w http.ResponseWriter, r *http.Request, ps h 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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } } else if action == "agreement-withdraw" { @@ -241,25 +242,25 @@ func (e mainEnv) approveUserRequest(w http.ResponseWriter, r *http.Request, ps h func (e mainEnv) cancelUserRequest(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { request := ps.ByName("request") - event := audit("cancel user request", request, "request", request) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("cancel user request", request, "request", request) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() - if EnforceUUID(w, request, event) == false { + if utils.EnforceUUID(w, request, event) == false { return } records, err := utils.GetJSONPostMap(r) if err != nil { - ReturnError(w, r, "failed to decode request body", 405, err, event) + utils.ReturnError(w, r, "failed to decode request body", 405, err, event) return } reason := utils.GetStringValue(records["reason"]) requestInfo, err := e.db.getRequest(request) if err != nil { - ReturnError(w, r, "internal error", 405, err, event) + utils.ReturnError(w, r, "internal error", 405, err, event) return } if len(requestInfo) == 0 { - ReturnError(w, r, "not found", 405, err, event) + utils.ReturnError(w, r, "not found", 405, err, event) return } userTOKEN := utils.GetStringValue(requestInfo["token"]) @@ -271,16 +272,16 @@ func (e mainEnv) cancelUserRequest(w http.ResponseWriter, r *http.Request, ps ht return } if requestInfo["status"].(string) != "open" { - ReturnError(w, r, "wrong status: "+requestInfo["status"].(string), 405, err, event) + utils.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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } if resultJSON == nil { - ReturnError(w, r, "not found", 405, err, event) + utils.ReturnError(w, r, "not found", 405, err, event) return } if len(reason) == 0 && authResult == "login" { diff --git a/src/schema.go b/src/schema.go index 42f0351..de81587 100644 --- a/src/schema.go +++ b/src/schema.go @@ -5,7 +5,6 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" "os" "path/filepath" "strconv" @@ -51,7 +50,7 @@ func loadUserSchema(cfg Config, confFile *string) error { if os.IsNotExist(err) { return err } - schemaData, err := ioutil.ReadFile(fileSchema) + schemaData, err := os.ReadFile(fileSchema) if err != nil { return err } diff --git a/src/sessions_api.go b/src/sessions_api.go index 5a625f4..9431895 100644 --- a/src/sessions_api.go +++ b/src/sessions_api.go @@ -9,6 +9,7 @@ import ( uuid "github.com/hashicorp/go-uuid" "github.com/julienschmidt/httprouter" + "github.com/securitybunker/databunker/src/audit" "github.com/securitybunker/databunker/src/storage" "github.com/securitybunker/databunker/src/utils" "go.mongodb.org/mongo-driver/bson" @@ -16,14 +17,14 @@ import ( func (e mainEnv) createSession(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { session := ps.ByName("session") - var event *auditEvent + var event *audit.AuditEvent defer func() { if event != nil { - event.submit(e.db, e.conf) + SaveAuditEvent(event, e.db, e.conf) } }() - if EnforceUUID(w, session, event) == false { - //ReturnError(w, r, "bad session format", nil, event) + if utils.EnforceUUID(w, session, event) == false { + //utils.ReturnError(w, r, "bad session format", nil, event) return } if e.EnforceAdmin(w, r, event) == "" { @@ -31,11 +32,11 @@ func (e mainEnv) createSession(w http.ResponseWriter, r *http.Request, ps httpro } records, err := utils.GetJSONPostMap(r) if err != nil { - ReturnError(w, r, "failed to decode request body", 405, err, event) + utils.ReturnError(w, r, "failed to decode request body", 405, err, event) return } if len(records) == 0 { - ReturnError(w, r, "empty body", 405, nil, event) + utils.ReturnError(w, r, "empty body", 405, nil, event) return } expirationStr := utils.GetStringValue(records["expiration"]) @@ -60,23 +61,23 @@ 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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } userTOKEN := "" if userBson != nil { - event = audit("create session", session, "session", session) + event = audit.CreateAuditEvent("create session", session, "session", session) userTOKEN = userBson["token"].(string) event.Record = userTOKEN } jsonData, err := json.Marshal(records) if err != nil { - ReturnError(w, r, "internal error", 405, err, event) + utils.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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -86,10 +87,10 @@ func (e mainEnv) createSession(w http.ResponseWriter, r *http.Request, ps httpro func (e mainEnv) deleteSession(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { 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) + event := audit.CreateAuditEvent("delete session", session, "session", session) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() + if utils.EnforceUUID(w, session, event) == false { + //utils.ReturnError(w, r, "bad session format", nil, event) return } if e.EnforceAdmin(w, r, event) == "" { @@ -105,8 +106,8 @@ func (e mainEnv) deleteSession(w http.ResponseWriter, r *http.Request, ps httpro func (e mainEnv) newUserSession(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { identity := ps.ByName("identity") mode := ps.ByName("mode") - event := audit("create user session by "+mode, identity, mode, identity) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("create user session by "+mode, identity, mode, identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() userTOKEN := e.loadUserToken(w, r, mode, identity, event) if userTOKEN == "" { @@ -117,11 +118,11 @@ func (e mainEnv) newUserSession(w http.ResponseWriter, r *http.Request, ps httpr } records, err := utils.GetJSONPostMap(r) if err != nil { - ReturnError(w, r, "failed to decode request body", 405, err, event) + utils.ReturnError(w, r, "failed to decode request body", 405, err, event) return } if len(records) == 0 { - ReturnError(w, r, "empty body", 405, nil, event) + utils.ReturnError(w, r, "empty body", 405, nil, event) return } expirationStr := utils.GetStringValue(records["expiration"]) @@ -129,17 +130,17 @@ func (e mainEnv) newUserSession(w http.ResponseWriter, r *http.Request, ps httpr log.Printf("Record expiration: %s", expiration) jsonData, err := json.Marshal(records) if err != nil { - ReturnError(w, r, "internal error", 405, err, event) + utils.ReturnError(w, r, "internal error", 405, err, event) return } sessionUUID, err := uuid.GenerateUUID() if err != nil { - ReturnError(w, r, "internal error", 405, err, event) + utils.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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -150,8 +151,8 @@ func (e mainEnv) newUserSession(w http.ResponseWriter, r *http.Request, ps httpr func (e mainEnv) getUserSessions(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { identity := ps.ByName("identity") mode := ps.ByName("mode") - event := audit("get all user sessions", identity, mode, identity) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("get all user sessions", identity, mode, identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() userTOKEN := e.loadUserToken(w, r, mode, identity, event) if userTOKEN == "" { @@ -172,7 +173,7 @@ func (e mainEnv) getUserSessions(w http.ResponseWriter, r *http.Request, ps http } records, count, err := e.db.getUserSessionsByToken(userTOKEN, offset, limit) if err != nil { - ReturnError(w, r, "internal error", 405, err, event) + utils.ReturnError(w, r, "internal error", 405, err, event) return } data := strings.Join(records, ",") @@ -183,10 +184,10 @@ func (e mainEnv) getUserSessions(w http.ResponseWriter, r *http.Request, ps http func (e mainEnv) getSession(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { session := ps.ByName("session") - event := audit("get session", session, "session", session) + event := audit.CreateAuditEvent("get session", session, "session", session) defer func() { if event != nil { - event.submit(e.db, e.conf) + SaveAuditEvent(event, e.db, e.conf) } }() when, record, userTOKEN, err := e.db.getSession(session) @@ -195,7 +196,7 @@ 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) + utils.ReturnError(w, r, err.Error(), 405, err, event) return } diff --git a/src/sharedrecords_api.go b/src/sharedrecords_api.go index ca7d3c9..7ff7f4a 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/audit" "github.com/securitybunker/databunker/src/utils" "github.com/tidwall/gjson" ) @@ -16,8 +17,8 @@ import ( func (e mainEnv) newSharedRecord(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { identity := ps.ByName("identity") mode := ps.ByName("mode") - event := audit("create shareable record by "+mode, identity, "token", identity) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("create shareable record by "+mode, identity, "token", identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() userTOKEN := e.loadUserToken(w, r, mode, identity, event) if userTOKEN == "" { @@ -28,7 +29,7 @@ func (e mainEnv) newSharedRecord(w http.ResponseWriter, r *http.Request, ps http } records, err := utils.GetJSONPostMap(r) if err != nil { - ReturnError(w, r, "failed to decode request body", 405, err, event) + utils.ReturnError(w, r, "failed to decode request body", 405, err, event) return } fields := "" @@ -55,7 +56,7 @@ func (e mainEnv) newSharedRecord(w http.ResponseWriter, r *http.Request, ps http if reflect.TypeOf(value) == reflect.TypeOf("string") { expiration = utils.SetExpiration(e.conf.Policy.MaxShareableRecordRetentionPeriod, value.(string)) } else { - ReturnError(w, r, "failed to parse expiration field", 405, err, event) + utils.ReturnError(w, r, "failed to parse expiration field", 405, err, event) return } } @@ -63,11 +64,11 @@ func (e mainEnv) newSharedRecord(w http.ResponseWriter, r *http.Request, ps http if reflect.TypeOf(value) == reflect.TypeOf("string") { appName = strings.ToLower(value.(string)) if len(appName) > 0 && utils.CheckValidApp(appName) == false { - ReturnError(w, r, "unknown app name", 405, nil, event) + utils.ReturnError(w, r, "unknown app name", 405, nil, event) } } else { // type is different - ReturnError(w, r, "failed to parse app field", 405, nil, event) + utils.ReturnError(w, r, "failed to parse app field", 405, nil, event) } } if len(expiration) == 0 { @@ -76,7 +77,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) + utils.ReturnError(w, r, err.Error(), 405, err, event) return } event.Record = userTOKEN @@ -88,10 +89,10 @@ func (e mainEnv) newSharedRecord(w http.ResponseWriter, r *http.Request, ps http func (e mainEnv) getRecord(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { record := ps.ByName("record") - event := audit("get shareable record by token", record, "record", record) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("get shareable record by token", record, "record", record) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() - if EnforceUUID(w, record, event) == false { + if utils.EnforceUUID(w, record, event) == false { return } recordInfo, err := e.db.getSharedRecord(record) @@ -115,11 +116,11 @@ 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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } if resultJSON == nil { - ReturnError(w, r, "not found", 405, err, event) + utils.ReturnError(w, r, "not found", 405, err, event) return } log.Printf("Full json: %s\n", resultJSON) diff --git a/src/storage/mysql-storage.go b/src/storage/mysql-storage.go index b552636..570e804 100644 --- a/src/storage/mysql-storage.go +++ b/src/storage/mysql-storage.go @@ -5,7 +5,6 @@ package storage import ( "database/sql" "fmt" - "io/ioutil" "log" "net/http" "os" @@ -42,7 +41,7 @@ func (dbobj MySQLDB) getConnectionString(dbname *string) string { dbnameString = *dbname } if len(os.Getenv("MYSQL_USER_PASS_FILE")) > 0 { - content, err := ioutil.ReadFile(os.Getenv("MYSQL_USER_PASS_FILE")) + content, err := os.ReadFile(os.Getenv("MYSQL_USER_PASS_FILE")) if err != nil { return "" } diff --git a/src/storage/pgsql-storage.go b/src/storage/pgsql-storage.go index 6ffe0f8..d7cf0b6 100644 --- a/src/storage/pgsql-storage.go +++ b/src/storage/pgsql-storage.go @@ -5,7 +5,6 @@ package storage import ( "database/sql" "fmt" - "io/ioutil" "log" "net/http" "os" @@ -42,7 +41,7 @@ func (dbobj PGSQLDB) getConnectionString(dbname *string) string { dbnameString = *dbname } if len(os.Getenv("PGSQL_USER_PASS_FILE")) > 0 { - content, err := ioutil.ReadFile(os.Getenv("PGSQL_USER_PASS_FILE")) + content, err := os.ReadFile(os.Getenv("PGSQL_USER_PASS_FILE")) if err != nil { return "" } diff --git a/src/userapps_api.go b/src/userapps_api.go index 9c9f157..9d93d71 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/audit" "github.com/securitybunker/databunker/src/utils" ) @@ -14,8 +15,8 @@ func (e mainEnv) userappNew(w http.ResponseWriter, r *http.Request, ps httproute appName := strings.ToLower(ps.ByName("appname")) identity := ps.ByName("identity") mode := ps.ByName("mode") - event := auditApp("create user app record by "+mode, identity, appName, mode, identity) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditAppEvent("create user app record by "+mode, identity, appName, mode, identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() userTOKEN := e.loadUserToken(w, r, mode, identity, event) if userTOKEN == "" { @@ -25,31 +26,31 @@ func (e mainEnv) userappNew(w http.ResponseWriter, r *http.Request, ps httproute return } if utils.CheckValidApp(appName) == false { - ReturnError(w, r, "bad appname", 405, nil, event) + utils.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) + utils.ReturnError(w, r, "db limitation", 405, nil, event) return } data, err := utils.GetJSONPostMap(r) if err != nil { - ReturnError(w, r, "failed to decode request body", 405, err, event) + utils.ReturnError(w, r, "failed to decode request body", 405, err, event) return } if len(data) == 0 { - ReturnError(w, r, "empty body", 405, nil, event) + utils.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) + utils.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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } utils.ReturnUUID(w, userTOKEN) @@ -60,8 +61,8 @@ func (e mainEnv) userappChange(w http.ResponseWriter, r *http.Request, ps httpro appName := strings.ToLower(ps.ByName("appname")) identity := ps.ByName("identity") mode := ps.ByName("mode") - event := auditApp("change user app record by "+mode, identity, appName, mode, identity) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditAppEvent("change user app record by "+mode, identity, appName, mode, identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() userTOKEN := e.loadUserToken(w, r, mode, identity, event) if userTOKEN == "" { return @@ -71,32 +72,32 @@ func (e mainEnv) userappChange(w http.ResponseWriter, r *http.Request, ps httpro return } if utils.CheckValidApp(appName) == false { - ReturnError(w, r, "bad appname", 405, nil, event) + utils.ReturnError(w, r, "bad appname", 405, nil, event) return } jsonData, err := utils.GetJSONPostData(r) if err != nil { - ReturnError(w, r, "failed to decode request body", 405, err, event) + utils.ReturnError(w, r, "failed to decode request body", 405, err, event) return } if jsonData == nil { - ReturnError(w, r, "empty body", 405, nil, event) + utils.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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } if resultJSON == nil { - ReturnError(w, r, "not found", 405, nil, event) + utils.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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } utils.ReturnUUID(w, userTOKEN) @@ -107,7 +108,7 @@ func (e mainEnv) userappChange(w http.ResponseWriter, r *http.Request, ps httpro 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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } utils.ReturnUUID(w, userTOKEN) @@ -117,7 +118,7 @@ func (e mainEnv) userappChange(w http.ResponseWriter, r *http.Request, ps httpro } 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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -128,8 +129,8 @@ func (e mainEnv) userappChange(w http.ResponseWriter, r *http.Request, ps httpro func (e mainEnv) userappList(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { identity := ps.ByName("identity") mode := ps.ByName("mode") - event := audit("get user app list by "+mode, identity, mode, identity) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("get user app list by "+mode, identity, mode, identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() userTOKEN := e.loadUserToken(w, r, mode, identity, event) if userTOKEN == "" { return @@ -139,7 +140,7 @@ func (e mainEnv) userappList(w http.ResponseWriter, r *http.Request, ps httprout } result, err := e.db.listUserApps(userTOKEN, e.conf) if err != nil { - ReturnError(w, r, "internal error", 405, err, event) + utils.ReturnError(w, r, "internal error", 405, err, event) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -151,8 +152,8 @@ func (e mainEnv) userappGet(w http.ResponseWriter, r *http.Request, ps httproute appName := strings.ToLower(ps.ByName("appname")) identity := ps.ByName("identity") mode := ps.ByName("mode") - event := auditApp("get user app record by "+mode, identity, appName, mode, identity) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditAppEvent("get user app record by "+mode, identity, appName, mode, identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() userTOKEN := e.loadUserToken(w, r, mode, identity, event) if userTOKEN == "" { return @@ -161,16 +162,16 @@ func (e mainEnv) userappGet(w http.ResponseWriter, r *http.Request, ps httproute return } if utils.CheckValidApp(appName) == false { - ReturnError(w, r, "bad appname", 405, nil, event) + utils.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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } if resultJSON == nil { - ReturnError(w, r, "not found", 405, nil, event) + utils.ReturnError(w, r, "not found", 405, nil, event) return } finalJSON := fmt.Sprintf(`{"status":"ok","token":"%s","data":%s}`, userTOKEN, resultJSON) @@ -183,8 +184,8 @@ func (e mainEnv) userappDelete(w http.ResponseWriter, r *http.Request, ps httpro appName := strings.ToLower(ps.ByName("appname")) identity := ps.ByName("identity") mode := ps.ByName("mode") - event := auditApp("delete user app record by "+mode, identity, appName, mode, identity) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditAppEvent("delete user app record by "+mode, identity, appName, mode, identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() userTOKEN := e.loadUserToken(w, r, mode, identity, event) if userTOKEN == "" { return @@ -193,7 +194,7 @@ func (e mainEnv) userappDelete(w http.ResponseWriter, r *http.Request, ps httpro return } if utils.CheckValidApp(appName) == false { - ReturnError(w, r, "bad appname", 405, nil, event) + utils.ReturnError(w, r, "bad appname", 405, nil, event) return } @@ -211,7 +212,7 @@ func (e mainEnv) appList(w http.ResponseWriter, r *http.Request, ps httprouter.P } result, err := e.db.listAllApps(e.conf) if err != nil { - ReturnError(w, r, "internal error", 405, err, nil) + utils.ReturnError(w, r, "internal error", 405, err, nil) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") diff --git a/src/userapps_db.go b/src/userapps_db.go index 70cb669..c255093 100644 --- a/src/userapps_db.go +++ b/src/userapps_db.go @@ -8,6 +8,7 @@ import ( "strings" jsonpatch "github.com/evanphx/json-patch" + "github.com/securitybunker/databunker/src/audit" "github.com/securitybunker/databunker/src/storage" "github.com/securitybunker/databunker/src/utils" "go.mongodb.org/mongo-driver/bson" @@ -54,7 +55,7 @@ func (dbobj dbcon) deleteUserApps(userTOKEN string, conf Config) { } } -func (dbobj dbcon) createAppRecord(jsonData []byte, userTOKEN string, appName string, event *auditEvent, conf Config) (string, error) { +func (dbobj dbcon) createAppRecord(jsonData []byte, userTOKEN string, appName string, event *audit.AuditEvent, conf Config) (string, error) { appNameFull := "app_" + appName //log.Printf("Going to create app record: %s\n", appName) encodedStr, err := dbobj.userEncrypt(userTOKEN, jsonData) @@ -103,7 +104,7 @@ func (dbobj dbcon) createAppRecord(jsonData []byte, userTOKEN string, appName st return userTOKEN, err } -func (dbobj dbcon) updateAppRecord(jsonDataPatch []byte, userTOKEN string, appName string, event *auditEvent, conf Config) (string, error) { +func (dbobj dbcon) updateAppRecord(jsonDataPatch []byte, userTOKEN string, appName string, event *audit.AuditEvent, conf Config) (string, error) { //_, err = collection.InsertOne(context.TODO(), bson.M{"name": "The Go Language2", "genre": "Coding", "authorId": "4"}) appNameFull := "app_" + appName userBson, err := dbobj.lookupUserRecord(userTOKEN) diff --git a/src/users_api.go b/src/users_api.go index 0a4f82f..c0b10d2 100644 --- a/src/users_api.go +++ b/src/users_api.go @@ -7,14 +7,15 @@ import ( "net/http" "github.com/julienschmidt/httprouter" + "github.com/securitybunker/databunker/src/audit" "github.com/securitybunker/databunker/src/storage" "github.com/securitybunker/databunker/src/utils" "go.mongodb.org/mongo-driver/bson" ) func (e mainEnv) userCreate(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - event := audit("create user record", "", "", "") - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("create user record", "", "", "") + defer func() { SaveAuditEvent(event, e.db, e.conf) }() if e.conf.Generic.CreateUserWithoutAccessToken == false { // anonymous user can not create user record, check token @@ -25,60 +26,60 @@ func (e mainEnv) userCreate(w http.ResponseWriter, r *http.Request, ps httproute } userJSON, err := utils.GetUserJSONStruct(r, e.conf.Sms.DefaultCountry) if err != nil { - ReturnError(w, r, "failed to decode request body", 405, err, event) + utils.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) + utils.ReturnError(w, r, "empty request body", 405, nil, event) return } err = validateUserRecord(userJSON.JsonData) if err != nil { - ReturnError(w, r, "user schema error: "+err.Error(), 405, err, event) + utils.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 err != nil { - ReturnError(w, r, "internal error", 405, err, event) + utils.ReturnError(w, r, "internal error", 405, err, event) return } if otherUserBson != nil { - ReturnError(w, r, "duplicate index: login", 405, nil, event) + utils.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 err != nil { - ReturnError(w, r, "internal error", 405, err, event) + utils.ReturnError(w, r, "internal error", 405, err, event) return } if otherUserBson != nil { - ReturnError(w, r, "duplicate index: email", 405, nil, event) + utils.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 err != nil { - ReturnError(w, r, "internal error", 405, err, event) + utils.ReturnError(w, r, "internal error", 405, err, event) return } if otherUserBson != nil { - ReturnError(w, r, "duplicate index: phone", 405, nil, event) + utils.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 err != nil { - ReturnError(w, r, "internal error", 405, err, event) + utils.ReturnError(w, r, "internal error", 405, err, event) return } if otherUserBson != nil { - ReturnError(w, r, "duplicate index: custom", 405, nil, event) + utils.ReturnError(w, r, "duplicate index: custom", 405, nil, event) return } } @@ -86,13 +87,13 @@ func (e mainEnv) userCreate(w http.ResponseWriter, r *http.Request, ps httproute 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) + utils.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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } encPhoneIdx := "" @@ -127,17 +128,17 @@ func (e mainEnv) userGet(w http.ResponseWriter, r *http.Request, ps httprouter.P var resultJSON []byte identity := ps.ByName("identity") mode := ps.ByName("mode") - event := audit("get user record by "+mode, identity, mode, identity) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("get user record by "+mode, identity, mode, identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() if utils.ValidateMode(mode) == false { - ReturnError(w, r, "bad mode", 405, nil, event) + utils.ReturnError(w, r, "bad mode", 405, nil, event) return } userTOKEN := "" authResult := "" if mode == "token" { - if EnforceUUID(w, identity, event) == false { + if utils.EnforceUUID(w, identity, event) == false { return } resultJSON, err = e.db.getUserJSON(identity) @@ -147,7 +148,7 @@ 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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } authResult = e.EnforceAuth(w, r, event) @@ -155,7 +156,7 @@ func (e mainEnv) userGet(w http.ResponseWriter, r *http.Request, ps httprouter.P return } if resultJSON == nil { - ReturnError(w, r, "record not found", 405, nil, event) + utils.ReturnError(w, r, "record not found", 405, nil, event) return } finalJSON := fmt.Sprintf(`{"status":"ok","token":"%s","data":%s}`, userTOKEN, resultJSON) @@ -171,7 +172,7 @@ func (e mainEnv) userList(w http.ResponseWriter, r *http.Request, ps httprouter. return } if e.conf.Generic.ListUsers == false { - ReturnError(w, r, "access denied", 403, nil, nil) + utils.ReturnError(w, r, "access denied", 403, nil, nil) return } var offset int32 = 0 @@ -199,28 +200,28 @@ func (e mainEnv) userList(w http.ResponseWriter, r *http.Request, ps httprouter. func (e mainEnv) userChange(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { identity := ps.ByName("identity") mode := ps.ByName("mode") - event := audit("change user record by "+mode, identity, mode, identity) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("change user record by "+mode, identity, mode, identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() if utils.ValidateMode(mode) == false { - ReturnError(w, r, "bad index", 405, nil, event) + utils.ReturnError(w, r, "bad index", 405, nil, event) return } jsonData, err := utils.GetJSONPostData(r) if err != nil { - ReturnError(w, r, "failed to decode request body", 405, err, event) + utils.ReturnError(w, r, "failed to decode request body", 405, err, event) return } if jsonData == nil { - ReturnError(w, r, "empty request body", 405, nil, event) + utils.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 utils.EnforceUUID(w, identity, event) == false { return } userTOKEN = identity @@ -230,11 +231,11 @@ 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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } if userJSON == nil { - ReturnError(w, r, "user record not found", 405, nil, event) + utils.ReturnError(w, r, "user record not found", 405, nil, event) return } authResult := e.EnforceAuth(w, r, event) @@ -245,7 +246,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) + utils.ReturnError(w, r, "schema validation error: "+err.Error(), 405, err, event) return } } @@ -254,7 +255,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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -265,11 +266,11 @@ 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) + utils.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) + utils.ReturnError(w, r, "error updating user", 405, err, event) return } utils.ReturnUUID(w, userTOKEN) @@ -281,11 +282,11 @@ func (e mainEnv) userChange(w http.ResponseWriter, r *http.Request, ps httproute func (e mainEnv) userDelete(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { identity := ps.ByName("identity") mode := ps.ByName("mode") - event := audit("delete user record by "+mode, identity, mode, identity) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("delete user record by "+mode, identity, mode, identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() if utils.ValidateMode(mode) == false { - ReturnError(w, r, "bad mode", 405, nil, event) + utils.ReturnError(w, r, "bad mode", 405, nil, event) return } var err error @@ -293,7 +294,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 utils.EnforceUUID(w, identity, event) == false { return } userJSON, userBSON, err = e.db.getUser(identity) @@ -302,7 +303,7 @@ 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) + utils.ReturnError(w, r, "internal error", 405, nil, event) return } authResult := e.EnforceAuth(w, r, event) @@ -316,7 +317,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) + utils.ReturnError(w, r, "record not found", 405, nil, event) return } @@ -325,7 +326,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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -341,7 +342,7 @@ func (e mainEnv) userDelete(w http.ResponseWriter, r *http.Request, ps httproute //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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -356,8 +357,8 @@ func (e mainEnv) userPrelogin(w http.ResponseWriter, r *http.Request, ps httprou code := ps.ByName("code") identity := ps.ByName("identity") mode := ps.ByName("mode") - event := audit("user prelogin by "+mode, identity, mode, identity) - defer func() { event.submit(e.db, e.conf) }() + event := audit.CreateAuditEvent("user prelogin by "+mode, identity, mode, identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() code0, err := decryptCaptcha(captcha) if err != nil || code0 != code { @@ -367,12 +368,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) + utils.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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } if userBson != nil { @@ -395,7 +396,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) + //utils.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) @@ -413,17 +414,17 @@ func (e mainEnv) userLogin(w http.ResponseWriter, r *http.Request, ps httprouter 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) }() + event := audit.CreateAuditEvent("user login by "+mode, identity, mode, identity) + defer func() { SaveAuditEvent(event, e.db, e.conf) }() if mode != "phone" && mode != "email" { - ReturnError(w, r, "bad mode", 405, nil, event) + utils.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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } @@ -439,7 +440,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) + utils.ReturnError(w, r, "internal error", 405, err, event) return } event.Msg = "generated: " + hashedToken @@ -448,5 +449,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) + utils.ReturnError(w, r, "internal error", 405, nil, event) } diff --git a/src/users_db.go b/src/users_db.go index 57acacc..11e8f2f 100644 --- a/src/users_db.go +++ b/src/users_db.go @@ -11,12 +11,13 @@ import ( jsonpatch "github.com/evanphx/json-patch" uuid "github.com/hashicorp/go-uuid" + "github.com/securitybunker/databunker/src/audit" "github.com/securitybunker/databunker/src/storage" "github.com/securitybunker/databunker/src/utils" "go.mongodb.org/mongo-driver/bson" ) -func (dbobj dbcon) createUserRecord(parsedData utils.UserJSONStruct, event *auditEvent) (string, error) { +func (dbobj dbcon) createUserRecord(parsedData utils.UserJSONStruct, event *audit.AuditEvent) (string, error) { var userTOKEN string //var bdoc interface{} bdoc := bson.M{} @@ -139,7 +140,7 @@ func (dbobj dbcon) validateUserRecordChange(oldUserJSON []byte, jsonDataPatch [] return validateUserRecordChange(oldUserJSON, newJSON, authResult) } -func (dbobj dbcon) updateUserRecord(jsonDataPatch []byte, userTOKEN string, userBSON bson.M, event *auditEvent, conf Config) ([]byte, []byte, bool, error) { +func (dbobj dbcon) updateUserRecord(jsonDataPatch []byte, userTOKEN string, userBSON bson.M, event *audit.AuditEvent, conf Config) ([]byte, []byte, bool, error) { oldJSON, newJSON, lookupErr, err := dbobj.updateUserRecordDo(jsonDataPatch, userTOKEN, userBSON, event, conf) if lookupErr == true { return oldJSON, newJSON, lookupErr, err @@ -162,7 +163,7 @@ func (dbobj dbcon) updateUserRecord(jsonDataPatch []byte, userTOKEN string, user return nil, nil, false, err } -func (dbobj dbcon) updateUserRecordDo(jsonDataPatch []byte, userTOKEN string, oldUserBson bson.M, event *auditEvent, conf Config) ([]byte, []byte, bool, error) { +func (dbobj dbcon) updateUserRecordDo(jsonDataPatch []byte, userTOKEN string, oldUserBson bson.M, event *audit.AuditEvent, conf Config) ([]byte, []byte, bool, error) { // get user key userKey := oldUserBson["key"].(string) diff --git a/src/utils/checks.go b/src/utils/checks.go new file mode 100644 index 0000000..6316bf7 --- /dev/null +++ b/src/utils/checks.go @@ -0,0 +1,42 @@ +package utils + +import ( + "fmt" + "log" + "net/http" + + "github.com/securitybunker/databunker/src/audit" +) + +func ReturnError(w http.ResponseWriter, r *http.Request, message string, code int, err error, event *audit.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 *audit.AuditEvent) bool { + if 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 +} diff --git a/src/utils/go.mod b/src/utils/go.mod index 9012b25..3d2a406 100644 --- a/src/utils/go.mod +++ b/src/utils/go.mod @@ -4,7 +4,10 @@ go 1.21 toolchain go1.23.2 +replace github.com/securitybunker/databunker/src/audit => ../audit + require ( + github.com/securitybunker/databunker/src/audit v0.0.0 github.com/ttacon/libphonenumber v1.2.1 golang.org/x/sys v0.28.0 ) diff --git a/src/utils/utils.go b/src/utils/utils.go index bf513c3..d035e9a 100644 --- a/src/utils/utils.go +++ b/src/utils/utils.go @@ -6,7 +6,7 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" + "io" "log" "math/rand" "mime" @@ -387,7 +387,7 @@ func GetJSONPostMap(r *http.Request) (map[string]interface{}, error) { // otherwise data is not parsed! r.Method = "PATCH" } - body0, err := ioutil.ReadAll(r.Body) + body0, err := io.ReadAll(r.Body) if err != nil { return nil, err } @@ -446,7 +446,7 @@ func GetJSONPostData(r *http.Request) ([]byte, error) { // otherwise data is not parsed! r.Method = "PATCH" } - body0, err := ioutil.ReadAll(r.Body) + body0, err := io.ReadAll(r.Body) if err != nil { return nil, err } diff --git a/src/utils_test.go b/src/utils_test.go index 1c600aa..cff06ae 100644 --- a/src/utils_test.go +++ b/src/utils_test.go @@ -2,7 +2,7 @@ package main import ( "fmt" - "io/ioutil" + "io" "log" "net/http" "net/http/httptest" @@ -99,7 +99,7 @@ func TestUtilSMS(t *testing.T) { rw.Header().Set("Content-Type", "application/json") rw.WriteHeader(200) defer req.Body.Close() - bodyBytes, _ := ioutil.ReadAll(req.Body) + bodyBytes, _ := io.ReadAll(req.Body) log.Printf("body: %s\n", string(bodyBytes)) if string(bodyBytes) != "Body=Data+Bunker+code+1234&From=from1234&To=4444" { t.Fatalf("bad request: %s", string(bodyBytes)) @@ -119,7 +119,7 @@ func TestUtilNotifyConsentChange(t *testing.T) { rw.Header().Set("Content-Type", "application/json") rw.WriteHeader(200) defer req.Body.Close() - bodyBytes, _ := ioutil.ReadAll(req.Body) + bodyBytes, _ := io.ReadAll(req.Body) log.Printf("body: %s\n", string(bodyBytes)) if string(bodyBytes) != `{"action":"consentchange","brief":"brief","identity":"user3@user3.com","mode":"email","status":"no"}` { q <- fmt.Sprintf("bad request in notifyConsentChange: %s", string(bodyBytes)) @@ -142,7 +142,7 @@ func TestUtilNotifyProfileNew(t *testing.T) { rw.Header().Set("Content-Type", "application/json") rw.WriteHeader(200) defer req.Body.Close() - bodyBytes, _ := ioutil.ReadAll(req.Body) + bodyBytes, _ := io.ReadAll(req.Body) log.Printf("body: %s\n", string(bodyBytes)) if string(bodyBytes) != `{"action":"profilenew","identity":"user3@user3.com","mode":"email","profile":{"name":"alex"}}` { q <- fmt.Sprintf("bad request in notifyConsentChange: %s", string(bodyBytes)) @@ -166,7 +166,7 @@ func TestUtilNotifyForgetMe(t *testing.T) { rw.Header().Set("Content-Type", "application/json") rw.WriteHeader(200) defer req.Body.Close() - bodyBytes, _ := ioutil.ReadAll(req.Body) + bodyBytes, _ := io.ReadAll(req.Body) log.Printf("body: %s\n", string(bodyBytes)) if string(bodyBytes) != `{"action":"forgetme","identity":"user3@user3.com","mode":"email","profile":{"name":"alex"}}` { q <- fmt.Sprintf("bad request in notifyConsentChange: %s", string(bodyBytes)) @@ -190,7 +190,7 @@ func TestUtilNotifyProfileChange(t *testing.T) { rw.Header().Set("Content-Type", "application/json") rw.WriteHeader(200) defer req.Body.Close() - bodyBytes, _ := ioutil.ReadAll(req.Body) + bodyBytes, _ := io.ReadAll(req.Body) log.Printf("body: %s\n", string(bodyBytes)) if string(bodyBytes) != `{"action":"profilechange","identity":"user3@user3.com","mode":"email","old":{"name":"alex2"},"profile":{"name":"alex3"}}` { q <- fmt.Sprintf("bad request in notifyConsentChange: %s", string(bodyBytes))