Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 141 additions & 40 deletions db-connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"net/http"
"net/url"
"os"
"regexp"
"strconv"

"crypto/sha256"
Expand Down Expand Up @@ -5089,7 +5090,7 @@ func GetOpenApiDatastore(ctx context.Context, id string) (ParsedOpenApi, error)
}
}

// Can we diff here? Otherwise we may miss items hmm
// Can we diff here? Otherwise we may miss items hmm
// Check if we recently cached the ID. Don't run updates more often than once a day for an app
checkCacheId := fmt.Sprintf("openapi_updatecheck_%s", id)
if _, err := GetCache(ctx, checkCacheId); err != nil {
Expand Down Expand Up @@ -5738,8 +5739,9 @@ func FindUser(ctx context.Context, username string) ([]User, error) {
return newUsers, nil
}

func GetUser(ctx context.Context, username string) (*User, error) {
func GetUser(ctx context.Context, username string, returnEncrypted ...bool) (*User, error) {
curUser := &User{}
uuidRegex := regexp.MustCompile(`^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`)

parsedKey := strings.ToLower(username)
cacheKey := fmt.Sprintf("user_%s", parsedKey)
Expand All @@ -5749,6 +5751,21 @@ func GetUser(ctx context.Context, username string) (*User, error) {
cacheData := []byte(cache.([]uint8))
err = json.Unmarshal(cacheData, &curUser)
if err == nil {
// uuid or not
if len(returnEncrypted) == 0 || !returnEncrypted[0] {
if len(curUser.ApiKey) > 0 && !uuidRegex.MatchString(curUser.ApiKey) {
decryptedApiKey, decErr := HandleKeyDecryption([]byte(curUser.ApiKey), "apikey")
if decErr == nil {
curUser.ApiKey = string(decryptedApiKey)
}
}
if len(curUser.Session) > 0 && !uuidRegex.MatchString(curUser.Session) {
decryptedSession, decErr := HandleKeyDecryption([]byte(curUser.Session), "session")
if decErr == nil {
curUser.Session = string(decryptedSession)
}
}
}
return curUser, nil
}
} else {
Expand Down Expand Up @@ -5815,6 +5832,19 @@ func GetUser(ctx context.Context, username string) (*User, error) {
data, err := json.Marshal(curUser)
if err != nil {
log.Printf("[WARNING] Failed marshalling user: %s", err)
// uuid check
if len(returnEncrypted) == 0 || !returnEncrypted[0] {
if len(curUser.ApiKey) > 0 && !uuidRegex.MatchString(curUser.ApiKey) {
if decrypted, decErr := HandleKeyDecryption([]byte(curUser.ApiKey), "apikey"); decErr == nil {
curUser.ApiKey = string(decrypted)
}
}
if len(curUser.Session) > 0 && !uuidRegex.MatchString(curUser.Session) {
if decrypted, decErr := HandleKeyDecryption([]byte(curUser.Session), "session"); decErr == nil {
curUser.Session = string(decrypted)
}
}
}
return curUser, nil
}

Expand All @@ -5824,6 +5854,21 @@ func GetUser(ctx context.Context, username string) (*User, error) {
}
}

if len(returnEncrypted) == 0 || !returnEncrypted[0] {
if len(curUser.ApiKey) > 0 && !uuidRegex.MatchString(curUser.ApiKey) {
decryptedApiKey, err := HandleKeyDecryption([]byte(curUser.ApiKey), "apikey")
if err == nil {
curUser.ApiKey = string(decryptedApiKey)
}
}
if len(curUser.Session) > 0 && !uuidRegex.MatchString(curUser.Session) {
decryptedSession, err := HandleKeyDecryption([]byte(curUser.Session), "session")
if err == nil {
curUser.Session = string(decryptedSession)
}
}
}

return curUser, nil
}

Expand Down Expand Up @@ -6231,7 +6276,7 @@ func fixUserOrg(ctx context.Context, user *User) *User {
if !strings.Contains(err.Error(), "doesn't exist") {
log.Printf("[WARNING] Error getting org %s in fixUserOrg: %s", orgId, err)
}

return
}

Expand Down Expand Up @@ -9748,17 +9793,34 @@ func GetSessionNew(ctx context.Context, sessionId string) (User, error) {
}
}

// Query for the specific API-key in users
sessionsToSearch := []string{sessionId}
encryptedSession, encErr := HandleKeyEncryption([]byte(sessionId), "session", true)
if encErr == nil {
sessionsToSearch = append([]string{string(encryptedSession)}, sessionsToSearch...)
} else {
log.Printf("[WARNING] Failed encrypting session: %s", encErr)
}

nameKey := "Users"
var users []User
if project.DbType == "opensearch" {
shouldClauses := make([]map[string]interface{}, len(sessionsToSearch))
for i, sess := range sessionsToSearch {
shouldClauses[i] = map[string]interface{}{
"match": map[string]interface{}{
"session": sess,
},
}
}

var buf bytes.Buffer
query := map[string]interface{}{
"from": 0,
"size": 1000,
"query": map[string]interface{}{
"match": map[string]interface{}{
"session": sessionId,
"bool": map[string]interface{}{
"should": shouldClauses,
"minimum_should_match": 1,
},
},
}
Expand All @@ -9780,7 +9842,7 @@ func GetSessionNew(ctx context.Context, sessionId string) (User, error) {
return User{}, nil
}

log.Printf("[ERROR] Error getting response from Opensearch (get api keys): %s", err)
log.Printf("[ERROR] Error getting response from Opensearch (get session): %s", err)
return User{}, err
}

Expand Down Expand Up @@ -9823,27 +9885,37 @@ func GetSessionNew(ctx context.Context, sessionId string) (User, error) {

users = []User{}
for _, hit := range wrapped.Hits.Hits {
if hit.Source.Session != sessionId {
// Check if session matches any of our search keys
matched := false
for _, sess := range sessionsToSearch {
if hit.Source.Session == sess {
matched = true
break
}
}
if !matched {
continue
}

users = append(users, hit.Source)
}

} else {
//log.Printf("[DEBUG] Searching for session %s", sessionId)
q := datastore.NewQuery(nameKey).Filter("session =", sessionId).Limit(1)
_, err := project.Dbclient.GetAll(ctx, q, &users)
if err != nil && len(users) == 0 {
if !strings.Contains(err.Error(), `cannot load field`) {
log.Printf("[WARNING] Error getting session: %s", err)
return User{}, err
for _, sess := range sessionsToSearch {
q := datastore.NewQuery(nameKey).Filter("session =", sess).Limit(1)
_, err := project.Dbclient.GetAll(ctx, q, &users)
if err != nil && len(users) == 0 {
if !strings.Contains(err.Error(), `cannot load field`) {
continue
}
}
if len(users) > 0 {
break
}
}
}

if len(users) == 0 {
return User{}, errors.New("No users found for this apikey (1)")
return User{}, errors.New("No users found for this session")
}

if project.CacheDb {
Expand All @@ -9863,17 +9935,34 @@ func GetSessionNew(ctx context.Context, sessionId string) (User, error) {
}

func GetApikey(ctx context.Context, apikey string) (User, error) {
// Query for the specific API-key in users
// Build list of keys to search: encrypted (new) + plain (backwards compat)
keysToSearch := []string{apikey}
encryptedKey, encErr := HandleKeyEncryption([]byte(apikey), "apikey", true)
if encErr == nil {
keysToSearch = append([]string{string(encryptedKey)}, keysToSearch...)
}

nameKey := "Users"
var users []User
if project.DbType == "opensearch" {
// Build OR query for both encrypted and plain apikey
shouldClauses := make([]map[string]interface{}, len(keysToSearch))
for i, key := range keysToSearch {
shouldClauses[i] = map[string]interface{}{
"match": map[string]interface{}{
"apikey": key,
},
}
}

var buf bytes.Buffer
query := map[string]interface{}{
"from": 0,
"size": 1000,
"query": map[string]interface{}{
"match": map[string]interface{}{
"apikey": apikey,
"bool": map[string]interface{}{
"should": shouldClauses,
"minimum_should_match": 1,
},
},
}
Expand Down Expand Up @@ -9938,20 +10027,32 @@ func GetApikey(ctx context.Context, apikey string) (User, error) {

users = []User{}
for _, hit := range wrapped.Hits.Hits {
if hit.Source.ApiKey != apikey {
// Check if apikey matches any of our search keys
matched := false
for _, key := range keysToSearch {
if hit.Source.ApiKey == key {
matched = true
break
}
}
if !matched {
continue
}

users = append(users, hit.Source)
}

} else {
q := datastore.NewQuery(nameKey).Filter("apikey =", apikey).Limit(1)
_, err := project.Dbclient.GetAll(ctx, q, &users)
if err != nil && len(users) == 0 {
if !strings.Contains(err.Error(), `cannot load field`) {
log.Printf("[WARNING] Error getting apikey: %s", err)
return User{}, err
// Datastore: try encrypted first, then plain (no IN filter support)
for _, key := range keysToSearch {
q := datastore.NewQuery(nameKey).Filter("apikey =", key).Limit(1)
_, err := project.Dbclient.GetAll(ctx, q, &users)
if err != nil && len(users) == 0 {
if !strings.Contains(err.Error(), `cannot load field`) {
continue
}
}
if len(users) > 0 {
break
}
}
}
Expand Down Expand Up @@ -13975,7 +14076,7 @@ func GetDatastoreKey(ctx context.Context, id string, category string) (*CacheKey

category = strings.ReplaceAll(strings.ToLower(category), " ", "_")
if len(category) > 0 && category != "default" {
// FIXME: If they key itself is 'test_protected' and category
// FIXME: If they key itself is 'test_protected' and category
// is 'protected' this breaks... Keeping it for now.
if !strings.HasSuffix(id, fmt.Sprintf("_%s", category)) {
id = fmt.Sprintf("%s_%s", id, category)
Expand Down Expand Up @@ -14235,18 +14336,18 @@ func RunInit(dbclient datastore.Client, storageClient storage.Client, gceProject
} else {
//log.Printf("\n\n[INFO] Should check for SSO during setup - finding main org\n\n")
/*
orgs, err := GetAllOrgs(ctx)
if err == nil {
for _, org := range orgs {
if len(org.ManagerOrgs) == 0 && len(org.SSOConfig.SSOEntrypoint) > 0 {
log.Printf("[INFO] Set initial SSO url for logins to %s", org.SSOConfig.SSOEntrypoint)
SSOUrl = org.SSOConfig.SSOEntrypoint
break
orgs, err := GetAllOrgs(ctx)
if err == nil {
for _, org := range orgs {
if len(org.ManagerOrgs) == 0 && len(org.SSOConfig.SSOEntrypoint) > 0 {
log.Printf("[INFO] Set initial SSO url for logins to %s", org.SSOConfig.SSOEntrypoint)
SSOUrl = org.SSOConfig.SSOEntrypoint
break
}
}
} else {
log.Printf("[WARNING] Error loading orgs: %s", err)
}
} else {
log.Printf("[WARNING] Error loading orgs: %s", err)
}
*/
}
} else {
Expand Down Expand Up @@ -14966,7 +15067,7 @@ func GetAllCacheKeys(ctx context.Context, orgId string, category string, max int
"size": max,
"sort": map[string]interface{}{
"edited": map[string]interface{}{
"order": "desc",
"order": "desc",
"unmapped_type": "date",
},
},
Expand Down
Loading
Loading