From c77a67960ae03c8d7ed36258dc88090a886e5264 Mon Sep 17 00:00:00 2001 From: stremovsky Date: Mon, 16 Dec 2019 17:44:35 +0200 Subject: [PATCH] adding sessions api --- API.md | 13 ++++------ src/qldb.go | 2 +- src/sessions_api.go | 63 +++++++++++++++++++++++++++++++++++++++++++-- src/sessions_db.go | 35 ++++++++++++------------- 4 files changed, 83 insertions(+), 30 deletions(-) diff --git a/API.md b/API.md index 5c235d6..bbd38b9 100644 --- a/API.md +++ b/API.md @@ -165,9 +165,9 @@ This API is used to create new user app record and if the request is successful | Resource / HTTP method | POST (create) | GET (read) | PUT (update) | DELETE (delete) | | ---------------------------- | ------------------ | -------------- | -------------- | --------------- | -| /v1/session/token/{token} | Create new session | Get sessions | Error | Error | +| /v1/session/token/{token} | Create new session | Get sessions | Error | Error | | /v1/session/session/:session | Error | Get session | Error?? | Error?? | -| /v1/session/clientip/:ip | Error | Get sessions | Error | Error | + ## Create user session record @@ -183,6 +183,9 @@ user ip, mobile device info, user agent, etc... You can send the data as JSON POST or as regular POST parameters when working with this API. +Additional parameter is **expiration** that specifies TTL for this session record. + + ## Get user session record ### `GET /v1/session/session/:session` @@ -198,12 +201,6 @@ This API returns session data. This API returns an array of sessions of the same user. -## Get session records by ip address. -### `GET /v1/session/clientip/:ipaddress` - -### Explanation - -This API returns an array of user sessions by IP address. These sessions can be of different people. --- diff --git a/src/qldb.go b/src/qldb.go index 5eaf859..ffe7093 100644 --- a/src/qldb.go +++ b/src/qldb.go @@ -810,7 +810,7 @@ func initSessions(db *sql.DB) error { CREATE TABLE IF NOT EXISTS sessions ( token STRING, session STRING, - meta STRING, + data STRING, when int, endtime int ); diff --git a/src/sessions_api.go b/src/sessions_api.go index 2d41a5f..45ff368 100644 --- a/src/sessions_api.go +++ b/src/sessions_api.go @@ -1,13 +1,72 @@ package main import ( + "encoding/json" + "fmt" "net/http" + "reflect" "github.com/julienschmidt/httprouter" ) func (e mainEnv) newSession(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - token := ps.ByName("token") - event := audit("create new session", token, "token", token) + address := ps.ByName("address") + mode := ps.ByName("mode") + event := audit("create new session", address, mode, address) defer func() { event.submit(e.db) }() + + if e.enforceAuth(w, r, event) == false { + return + } + userTOKEN := "" + if mode == "token" { + if enforceUUID(w, address, event) == false { + return + } + userBson, _ := e.db.lookupUserRecord(address) + if userBson == nil { + // if token not found, exit from here + return + } + userTOKEN = address + } else { + // TODO: decode url in code! + userBson, _ := e.db.lookupUserRecordByIndex(mode, address, e.conf) + if userBson != nil { + userTOKEN = userBson["token"].(string) + event.Record = userTOKEN + } + } + expiration := "" + records, err := getJSONPostData(r) + if err != nil { + returnError(w, r, "failed to decode request body", 405, err, event) + return + } + if len(records) == 0 { + returnError(w, r, "empty body", 405, nil, event) + return + } + if value, ok := records["expiration"]; ok { + if reflect.TypeOf(value) == reflect.TypeOf("string") { + expiration = value.(string) + } else { + returnError(w, r, "failed to parse expiration field", 405, err, event) + return + } + } + jsonData, err := json.Marshal(records) + if err != nil { + returnError(w, r, "internal error", 405, err, event) + return + } + sessionID, err := e.db.createSessionRecord(userTOKEN, expiration, jsonData) + if err != nil { + returnError(w, r, "internal error", 405, err, event) + return + } + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(200) + fmt.Fprintf(w, `{"status":"ok","session":"%s"}`, sessionID) + return } diff --git a/src/sessions_db.go b/src/sessions_db.go index 0a49fbb..43a6812 100644 --- a/src/sessions_db.go +++ b/src/sessions_db.go @@ -1,7 +1,6 @@ package main import ( - "crypto/sha256" "encoding/base64" "errors" "time" @@ -12,18 +11,19 @@ import ( type sessionEvent struct { When int32 - Meta []byte + Data string } -func (dbobj dbcon) generateUserSession(userTOKEN string, clientip string, expiration string, meta []byte) (string, error) { - if len(expiration) == 0 { - return "", errors.New("failed to parse expiration") +func (dbobj dbcon) createSessionRecord(userTOKEN string, expiration string, data []byte) (string, error) { + var endtime int32 = 0 + var err error + if len(expiration) > 0 { + endtime, err = parseExpiration(expiration) + if err != nil { + return "", err + } } - endtime, err := parseExpiration(expiration) - if err != nil { - return "", err - } - encodedStr, err := dbobj.userEncrypt(userTOKEN, meta) + encodedStr, err := dbobj.userEncrypt(userTOKEN, data) if err != nil { return "", err } @@ -32,15 +32,12 @@ func (dbobj dbcon) generateUserSession(userTOKEN string, clientip string, expira return "", err } bdoc := bson.M{} + now := int32(time.Now().Unix()) bdoc["token"] = userTOKEN bdoc["session"] = tokenUUID bdoc["endtime"] = endtime - bdoc["meta"] = encodedStr - if len(clientip) > 0 { - idxString := append(dbobj.hash, []byte(clientip)...) - idxStringHash := sha256.Sum256(idxString) - bdoc["clientipidx"] = base64.StdEncoding.EncodeToString(idxStringHash[:]) - } + bdoc["when"] = now + bdoc["data"] = encodedStr _, err = dbobj.createRecord(TblName.Sessions, bdoc) if err != nil { return "", err @@ -59,7 +56,7 @@ func (dbobj dbcon) getUserSession(sessionUUID string) ([]byte, error) { return nil, errors.New("session expired") } userTOKEN := record["token"].(string) - encData0 := record["meta"].(string) + encData0 := record["data"].(string) decrypted, err := dbobj.userDecrypt(userTOKEN, encData0) if err != nil { return nil, err @@ -92,10 +89,10 @@ func (dbobj dbcon) getUserSessionByToken(userTOKEN string) ([]*sessionEvent, int var results []*sessionEvent for _, element := range records { - encData0 := element["meta"].(string) + encData0 := element["data"].(string) encData, _ := base64.StdEncoding.DecodeString(encData0) decrypted, _ := decrypt(dbobj.masterKey, recordKey, encData) - sEvent := sessionEvent{0, decrypted} + sEvent := sessionEvent{0, string(decrypted)} results = append(results, &sEvent) }