From 6ecaab322331bb4101d9a9bf20c86d642f263bb4 Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 12:20:36 -0800 Subject: [PATCH 01/51] fix: request sent to dbx --- backend/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/main.go b/backend/main.go index 505749b..082a6ee 100644 --- a/backend/main.go +++ b/backend/main.go @@ -127,6 +127,7 @@ func queryDatabricksForRecipient(email string) (bool, error) { return false, fmt.Errorf("error creating request: %w", err) } req.Header.Set("Authorization", "Bearer "+databricksPAT) + fmt.Println("Request: ", req) client := &http.Client{} resp, err := client.Do(req) From 07cc6b999d5a70bcabf64214ed8767ddb5e0ab8c Mon Sep 17 00:00:00 2001 From: alldoami Date: Mon, 3 Feb 2025 20:22:48 +0000 Subject: [PATCH 02/51] chore: Updated [rdev] values.yaml image tags to sha-6ecaab3 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index 3921669..36b9d96 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-0b28772 + tag: sha-6ecaab3 replicaCount: 1 \ No newline at end of file From 8ff7c30d4f239678e74aae85bbc63a462d6864d2 Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 12:24:44 -0800 Subject: [PATCH 03/51] rdev --- cli/main.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cli/main.go b/cli/main.go index 35e88d0..379ecf0 100644 --- a/cli/main.go +++ b/cli/main.go @@ -25,7 +25,8 @@ func main() { } // Send the token to the backend - backendURL := "https://delta-share.prod-sci-general.prod.czi.team/verify-token" + // backendURL := "https://delta-share.prod-sci-general.prod.czi.team/verify-token" + backendURL := "https://electric-osprey.dev-sci-general.dev.czi.team/verify-token" reqBody := map[string]string{"token": token.IDToken} reqBodyJSON, _ := json.Marshal(reqBody) From 760f745578d5b50c7ea68a2b447cc8a1e60f9e73 Mon Sep 17 00:00:00 2001 From: alldoami Date: Mon, 3 Feb 2025 20:26:55 +0000 Subject: [PATCH 04/51] chore: Updated [rdev] values.yaml image tags to sha-b112d09 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index 36b9d96..d2b41bc 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-6ecaab3 + tag: sha-b112d09 replicaCount: 1 \ No newline at end of file From 6818695ddfa3bea48e318c5cb8ac2f4ba1d67890 Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 12:36:38 -0800 Subject: [PATCH 05/51] try --- backend/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/main.go b/backend/main.go index 082a6ee..e0aefd9 100644 --- a/backend/main.go +++ b/backend/main.go @@ -143,7 +143,7 @@ func queryDatabricksForRecipient(email string) (bool, error) { // Parse the response var recipientsResponse RecipientsResponse if err := json.NewDecoder(resp.Body).Decode(&recipientsResponse); err != nil { - return false, fmt.Errorf("error parsing response: %w", err) + return false, fmt.Errorf("allison error parsing response: %w", err) } // Check if the email matches any recipient From 054ddf8d03cf9193d63528706838d97d135e39c3 Mon Sep 17 00:00:00 2001 From: alldoami Date: Mon, 3 Feb 2025 20:38:51 +0000 Subject: [PATCH 06/51] chore: Updated [rdev] values.yaml image tags to sha-a9bd0cb --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index d2b41bc..246b4ea 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-b112d09 + tag: sha-a9bd0cb replicaCount: 1 \ No newline at end of file From 67f68f8f97ae4657456c27c062e05235ae1492c5 Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 12:43:59 -0800 Subject: [PATCH 07/51] print request --- backend/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/main.go b/backend/main.go index e0aefd9..5528c9b 100644 --- a/backend/main.go +++ b/backend/main.go @@ -127,7 +127,7 @@ func queryDatabricksForRecipient(email string) (bool, error) { return false, fmt.Errorf("error creating request: %w", err) } req.Header.Set("Authorization", "Bearer "+databricksPAT) - fmt.Println("Request: ", req) + fmt.Printf("Request: %v\n", req) client := &http.Client{} resp, err := client.Do(req) @@ -143,7 +143,7 @@ func queryDatabricksForRecipient(email string) (bool, error) { // Parse the response var recipientsResponse RecipientsResponse if err := json.NewDecoder(resp.Body).Decode(&recipientsResponse); err != nil { - return false, fmt.Errorf("allison error parsing response: %w", err) + return false, fmt.Errorf("error parsing response: %w", err) } // Check if the email matches any recipient From ac06a88e4dabe6aefe2fdc688aa692387b851a0c Mon Sep 17 00:00:00 2001 From: alldoami Date: Mon, 3 Feb 2025 20:46:05 +0000 Subject: [PATCH 08/51] chore: Updated [rdev] values.yaml image tags to sha-67f68f8 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index 246b4ea..12619dd 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-a9bd0cb + tag: sha-67f68f8 replicaCount: 1 \ No newline at end of file From 6de5df81c159a71acb21e3916f3cf88adbf99e9d Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 13:46:58 -0800 Subject: [PATCH 09/51] update --- backend/main.go | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/backend/main.go b/backend/main.go index 5528c9b..0590135 100644 --- a/backend/main.go +++ b/backend/main.go @@ -20,7 +20,6 @@ type TokenRequest struct { type Recipient struct { Name string `json:"name"` } - type RecipientsResponse struct { Recipients []Recipient `json:"recipients"` } @@ -119,15 +118,17 @@ func validateCognitoToken(token string) (string, error) { return email, nil } -// Query the Databricks API to check for Delta Share recipient +// queryDatabricksForRecipient checks if a recipient exists based on the provided email. func queryDatabricksForRecipient(email string) (bool, error) { + url := fmt.Sprintf("%s/%s", databricksURL+"/api/2.1/unity-catalog/recipients", email) + // Make the API request - req, err := http.NewRequest("GET", databricksURL, nil) + req, err := http.NewRequest("GET", url, nil) if err != nil { return false, fmt.Errorf("error creating request: %w", err) } req.Header.Set("Authorization", "Bearer "+databricksPAT) - fmt.Printf("Request: %v\n", req) + req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, err := client.Do(req) @@ -136,22 +137,12 @@ func queryDatabricksForRecipient(email string) (bool, error) { } defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return false, fmt.Errorf("received status code %d from Databricks", resp.StatusCode) - } - - // Parse the response - var recipientsResponse RecipientsResponse - if err := json.NewDecoder(resp.Body).Decode(&recipientsResponse); err != nil { - return false, fmt.Errorf("error parsing response: %w", err) + // Handle HTTP response status codes + if resp.StatusCode == http.StatusOK { + return true, nil + } else if resp.StatusCode == http.StatusNotFound { + return false, nil + } else { + return false, fmt.Errorf("unexpected response: %d", resp.StatusCode) } - - // Check if the email matches any recipient - for _, recipient := range recipientsResponse.Recipients { - if recipient.Name == strings.Split(email, "@")[0] { - return true, nil - } - } - - return false, nil } From be160d301572d52d6a168448c01c656c76e1f6b2 Mon Sep 17 00:00:00 2001 From: alldoami Date: Mon, 3 Feb 2025 21:49:14 +0000 Subject: [PATCH 10/51] chore: Updated [rdev] values.yaml image tags to sha-5e154cf --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index 12619dd..3707153 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-67f68f8 + tag: sha-5e154cf replicaCount: 1 \ No newline at end of file From af07cd333eb5ee7d7f68084e4876f1c24f38c49b Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 13:49:32 -0800 Subject: [PATCH 11/51] fix --- backend/main.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/backend/main.go b/backend/main.go index 0590135..d1a12fd 100644 --- a/backend/main.go +++ b/backend/main.go @@ -120,7 +120,10 @@ func validateCognitoToken(token string) (string, error) { // queryDatabricksForRecipient checks if a recipient exists based on the provided email. func queryDatabricksForRecipient(email string) (bool, error) { - url := fmt.Sprintf("%s/%s", databricksURL+"/api/2.1/unity-catalog/recipients", email) + // We cannot use email as the recipient name because name cannot include period, space, or forward-slash + // All recipient names in Databricks should be the username of the email address + recipientName := strings.Split(email, "@")[0] + url := fmt.Sprintf("%s/%s", databricksURL+"/api/2.1/unity-catalog/recipients", recipientName) // Make the API request req, err := http.NewRequest("GET", url, nil) From 9e2b1ab8e8625ee3ad9df1e260c86d505768987f Mon Sep 17 00:00:00 2001 From: alldoami Date: Mon, 3 Feb 2025 21:54:22 +0000 Subject: [PATCH 12/51] chore: Updated [rdev] values.yaml image tags to sha-1d5830e --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index 3707153..efbb7da 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-5e154cf + tag: sha-1d5830e replicaCount: 1 \ No newline at end of file From f9d9dbc540a1dc40f141436f607b494ffdcfbb55 Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 14:35:16 -0800 Subject: [PATCH 13/51] token rotation --- backend/main.go | 274 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 190 insertions(+), 84 deletions(-) diff --git a/backend/main.go b/backend/main.go index d1a12fd..37dbde5 100644 --- a/backend/main.go +++ b/backend/main.go @@ -8,84 +8,46 @@ import ( "net/http" "os" "strings" + "time" "github.com/gofiber/fiber/v2" ) -// Structs for request/response +var ( + databricksPAT = os.Getenv("DATABRICKS_PAT") + cognitoIssuer = os.Getenv("COGNITO_ISSUER") + databricksURL = os.Getenv("DATABRICKS_URL") + databricksAPIBase = fmt.Sprintf("https://%s/api/2.1/unity-catalog/recipients", databricksURL) +) + +// TokenRequest represents the request body for verifying a token type TokenRequest struct { Token string `json:"token"` } -type Recipient struct { - Name string `json:"name"` +// RecipientResponse represents recipient details +type RecipientResponse struct { + Name string `json:"name"` + ActivationLink string `json:"activation_link"` + TokenInfo struct { + ActivationURL string `json:"activation_url"` + ExpirationTime int64 `json:"expiration_time"` + Token string `json:"token"` + } `json:"token_info"` } -type RecipientsResponse struct { - Recipients []Recipient `json:"recipients"` -} - -// Environment Variables stored using argus set secrets -var ( - databricksPAT = os.Getenv("DATABRICKS_PAT") - databricksURL = os.Getenv("DATABRICKS_URL") - cognitoIssuer = os.Getenv("COGNITO_ISSUER") -) - -func main() { - app := fiber.New() - - // Health Check Endpoint - app.Get("/health", func(c *fiber.Ctx) error { - return c.Status(http.StatusOK).JSON(fiber.Map{ - "status": "healthy", - }) - }) - - // Token Verification Endpoint - app.Post("/verify-token", func(c *fiber.Ctx) error { - var tokenRequest TokenRequest - - // Parse the incoming JSON body - if err := c.BodyParser(&tokenRequest); err != nil { - return c.Status(http.StatusBadRequest).JSON(fiber.Map{ - "error": "Invalid request body", - }) - } - // Decode and Validate the Cognito Token - email, err := validateCognitoToken(tokenRequest.Token) - if err != nil { - return c.Status(http.StatusUnauthorized).JSON(fiber.Map{ - "error": "Invalid token: " + err.Error(), - }) - } - - // Query Databricks API for Delta Share recipient - isRecipient, err := queryDatabricksForRecipient(email) - if err != nil { - return c.Status(http.StatusInternalServerError).JSON(fiber.Map{ - "error": "Error querying Databricks: " + err.Error(), - }) - } - - if !isRecipient { - return c.Status(http.StatusForbidden).JSON(fiber.Map{ - "error": fmt.Sprintf("User %s is not a Delta Share recipient", email), - }) - } - - // Return Success Response - return c.Status(http.StatusOK).JSON(fiber.Map{ - "message": fmt.Sprintf("User %s is a Delta Share recipient", email), - "databricks_url": databricksURL, - }) - }) +// RecipientRequest represents the request body for creating a recipient +type RecipientRequest struct { + Name string `json:"name"` + AuthenticationType string `json:"authentication_type"` +} - // Start the Fiber app - log.Fatal(app.Listen(":8080")) +// TokenRotationResponse represents the response when rotating a token +type TokenRotationResponse struct { + Token string `json:"token"` + ActivationLink string `json:"activation_link"` } -// Validate and Decode Cognito Token func validateCognitoToken(token string) (string, error) { parts := strings.Split(token, ".") if len(parts) != 3 { @@ -118,34 +80,178 @@ func validateCognitoToken(token string) (string, error) { return email, nil } -// queryDatabricksForRecipient checks if a recipient exists based on the provided email. -func queryDatabricksForRecipient(email string) (bool, error) { - // We cannot use email as the recipient name because name cannot include period, space, or forward-slash - // All recipient names in Databricks should be the username of the email address +// queryRecipient checks if a recipient exists and returns its token info. +func queryRecipient(email string) (*RecipientResponse, error) { recipientName := strings.Split(email, "@")[0] - url := fmt.Sprintf("%s/%s", databricksURL+"/api/2.1/unity-catalog/recipients", recipientName) + url := fmt.Sprintf("%s/%s", databricksAPIBase, recipientName) - // Make the API request - req, err := http.NewRequest("GET", url, nil) + resp, err := makeRequest("GET", url, nil) if err != nil { - return false, fmt.Errorf("error creating request: %w", err) + return nil, err } - req.Header.Set("Authorization", "Bearer "+databricksPAT) - req.Header.Set("Content-Type", "application/json") - client := &http.Client{} - resp, err := client.Do(req) + if resp.StatusCode == http.StatusOK { + var recipient RecipientResponse + if err := json.NewDecoder(resp.Body).Decode(&recipient); err != nil { + return nil, fmt.Errorf("error parsing recipient response: %w", err) + } + return &recipient, nil + } else if resp.StatusCode == http.StatusNotFound { + return nil, nil + } else { + return nil, fmt.Errorf("unexpected response: %d", resp.StatusCode) + } +} + +// createRecipient creates a new recipient with token authentication and returns the token. +func createRecipient(email string) (string, error) { + recipientName := strings.Split(email, "@")[0] + url := databricksAPIBase + + payload := RecipientRequest{ + Name: recipientName, + AuthenticationType: "TOKEN", + } + + resp, err := makeRequest("POST", url, payload) if err != nil { - return false, fmt.Errorf("error making request: %w", err) + return "", err + } + + if resp.StatusCode == http.StatusCreated { + var recipient RecipientResponse + if err := json.NewDecoder(resp.Body).Decode(&recipient); err != nil { + return "", fmt.Errorf("error parsing recipient response: %w", err) + } + fmt.Printf("Recipient '%s' created successfully. Activation link: %s\n", recipientName, recipient.ActivationLink) + return recipient.TokenInfo.Token, nil + } + + return "", fmt.Errorf("failed to create recipient: %d", resp.StatusCode) +} + +func rotateToken(email string) (string, error) { + recipientName := strings.Split(email, "@")[0] + url := fmt.Sprintf("%s/%s/rotate-token", databricksAPIBase, recipientName) + + resp, err := makeRequest("PUT", url, nil) + if err != nil { + return "", err } - defer resp.Body.Close() - // Handle HTTP response status codes if resp.StatusCode == http.StatusOK { - return true, nil - } else if resp.StatusCode == http.StatusNotFound { - return false, nil + var rotationResponse TokenRotationResponse + if err := json.NewDecoder(resp.Body).Decode(&rotationResponse); err != nil { + return "", fmt.Errorf("error parsing token rotation response: %w", err) + } + fmt.Printf("Token rotated successfully. New activation link: %s\n", rotationResponse.ActivationLink) + return rotationResponse.Token, nil + } + + return "", fmt.Errorf("failed to rotate token: %d", resp.StatusCode) +} + +// makeRequest is a helper function to send HTTP requests +func makeRequest(method, url string, payload interface{}) (*http.Response, error) { + client := &http.Client{} + + var req *http.Request + var err error + + if payload != nil { + jsonData, _ := json.Marshal(payload) + req, err = http.NewRequest(method, url, strings.NewReader(string(jsonData))) } else { - return false, fmt.Errorf("unexpected response: %d", resp.StatusCode) + req, err = http.NewRequest(method, url, nil) } + + if err != nil { + return nil, fmt.Errorf("error creating request: %w", err) + } + + req.Header.Set("Authorization", "Bearer "+databricksPAT) + req.Header.Set("Content-Type", "application/json") + + return client.Do(req) +} + +func main() { + app := fiber.New() + + // Health Check Endpoint + app.Get("/health", func(c *fiber.Ctx) error { + return c.Status(http.StatusOK).JSON(fiber.Map{ + "status": "healthy", + }) + }) + + // Token Verification & Databricks Recipient Handling + app.Post("/verify-token", func(c *fiber.Ctx) error { + var tokenRequest TokenRequest + + // Parse the incoming JSON body + if err := c.BodyParser(&tokenRequest); err != nil { + return c.Status(http.StatusBadRequest).JSON(fiber.Map{ + "error": "Invalid request body", + }) + } + + // Decode and Validate the Cognito Token + email, err := validateCognitoToken(tokenRequest.Token) + if err != nil { + return c.Status(http.StatusUnauthorized).JSON(fiber.Map{ + "error": "Invalid token: " + err.Error(), + }) + } + + // Query Databricks API for Delta Share recipient + recipient, err := queryRecipient(email) + if err != nil { + return c.Status(http.StatusInternalServerError).JSON(fiber.Map{ + "error": "Error querying Databricks: " + err.Error(), + }) + } + + // If recipient does not exist, create one + if recipient == nil { + fmt.Printf("Recipient for email '%s' does not exist. Creating...\n", email) + token, err := createRecipient(email) + if err != nil { + return c.Status(http.StatusInternalServerError).JSON(fiber.Map{ + "error": "Error creating recipient: " + err.Error(), + }) + } + return c.Status(http.StatusOK).JSON(fiber.Map{ + "message": fmt.Sprintf("New recipient created for %s", email), + "token": token, + }) + } + + // Recipient exists but token is expired, so rotate it + expirationTime := recipient.TokenInfo.ExpirationTime + currentTime := time.Now().Unix() + + if expirationTime < currentTime { + fmt.Printf("Token for recipient '%s' has expired. Rotating...\n", recipient.Name) + newToken, err := rotateToken(email) + if err != nil { + return c.Status(http.StatusInternalServerError).JSON(fiber.Map{ + "error": "Error rotating token: " + err.Error(), + }) + } + return c.Status(http.StatusOK).JSON(fiber.Map{ + "message": fmt.Sprintf("Token for %s rotated", email), + "token": newToken, + }) + } + + // Token is still valid + return c.Status(http.StatusOK).JSON(fiber.Map{ + "message": fmt.Sprintf("Token for %s is still valid", email), + "token": recipient.TokenInfo.Token, + }) + }) + + // Start the Fiber app + log.Fatal(app.Listen(":8080")) } From 45c1b1e5fec86811fba7733c65e22b32d2301ae2 Mon Sep 17 00:00:00 2001 From: alldoami Date: Mon, 3 Feb 2025 22:38:05 +0000 Subject: [PATCH 14/51] chore: Updated [rdev] values.yaml image tags to sha-e718e4f --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index efbb7da..cc127d4 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-1d5830e + tag: sha-e718e4f replicaCount: 1 \ No newline at end of file From d1d0dd677f0b99f8df8df425063daa4089bdf6e0 Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 14:52:00 -0800 Subject: [PATCH 15/51] remove https --- backend/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/main.go b/backend/main.go index 37dbde5..5da989a 100644 --- a/backend/main.go +++ b/backend/main.go @@ -17,7 +17,7 @@ var ( databricksPAT = os.Getenv("DATABRICKS_PAT") cognitoIssuer = os.Getenv("COGNITO_ISSUER") databricksURL = os.Getenv("DATABRICKS_URL") - databricksAPIBase = fmt.Sprintf("https://%s/api/2.1/unity-catalog/recipients", databricksURL) + databricksAPIBase = fmt.Sprintf("%s/api/2.1/unity-catalog/recipients", databricksURL) ) // TokenRequest represents the request body for verifying a token From 2357f2ac147175facbc55fdce4d737f378dd3f44 Mon Sep 17 00:00:00 2001 From: alldoami Date: Mon, 3 Feb 2025 22:54:03 +0000 Subject: [PATCH 16/51] chore: Updated [rdev] values.yaml image tags to sha-d1d0dd6 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index cc127d4..efec255 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-e718e4f + tag: sha-d1d0dd6 replicaCount: 1 \ No newline at end of file From ecb2c5b3fdc47afa433f64c03f0671c0164b9293 Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 15:03:53 -0800 Subject: [PATCH 17/51] change to post --- backend/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/main.go b/backend/main.go index 5da989a..c3e72d2 100644 --- a/backend/main.go +++ b/backend/main.go @@ -134,7 +134,7 @@ func rotateToken(email string) (string, error) { recipientName := strings.Split(email, "@")[0] url := fmt.Sprintf("%s/%s/rotate-token", databricksAPIBase, recipientName) - resp, err := makeRequest("PUT", url, nil) + resp, err := makeRequest("POST", url, nil) if err != nil { return "", err } From 73a8b4b659749b06ca11ce32e71cd066b8bd9360 Mon Sep 17 00:00:00 2001 From: alldoami Date: Mon, 3 Feb 2025 23:06:05 +0000 Subject: [PATCH 18/51] chore: Updated [rdev] values.yaml image tags to sha-f160730 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index efec255..b8a9ce8 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-d1d0dd6 + tag: sha-f160730 replicaCount: 1 \ No newline at end of file From 421d4b21876bac191fcbf7a133b6528389181004 Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 15:17:05 -0800 Subject: [PATCH 19/51] print --- backend/main.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/main.go b/backend/main.go index c3e72d2..66d4204 100644 --- a/backend/main.go +++ b/backend/main.go @@ -139,6 +139,8 @@ func rotateToken(email string) (string, error) { return "", err } + fmt.Printf("Response: %v\n", resp) + if resp.StatusCode == http.StatusOK { var rotationResponse TokenRotationResponse if err := json.NewDecoder(resp.Body).Decode(&rotationResponse); err != nil { From d3793b9e43622b55d372cec67838d98427e43d1f Mon Sep 17 00:00:00 2001 From: alldoami Date: Mon, 3 Feb 2025 23:22:59 +0000 Subject: [PATCH 20/51] chore: Updated [rdev] values.yaml image tags to sha-421d4b2 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index b8a9ce8..ec82634 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-f160730 + tag: sha-421d4b2 replicaCount: 1 \ No newline at end of file From 413c013b38980a47c3151cc2f550ccceeb0ffc72 Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 15:29:21 -0800 Subject: [PATCH 21/51] expire in seconds --- backend/main.go | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/backend/main.go b/backend/main.go index 66d4204..3ed8963 100644 --- a/backend/main.go +++ b/backend/main.go @@ -20,12 +20,20 @@ var ( databricksAPIBase = fmt.Sprintf("%s/api/2.1/unity-catalog/recipients", databricksURL) ) +const ( + expirationInSeconds = 604800 // 7 days in seconds +) + // TokenRequest represents the request body for verifying a token type TokenRequest struct { Token string `json:"token"` } -// RecipientResponse represents recipient details +type RecipientRequest struct { + Name string `json:"name"` + AuthenticationType string `json:"authentication_type"` +} + type RecipientResponse struct { Name string `json:"name"` ActivationLink string `json:"activation_link"` @@ -36,13 +44,10 @@ type RecipientResponse struct { } `json:"token_info"` } -// RecipientRequest represents the request body for creating a recipient -type RecipientRequest struct { - Name string `json:"name"` - AuthenticationType string `json:"authentication_type"` +type TokenRotationRequest struct { + ExistingTokenExpireInSeconds int `json:"existing_token_expire_in_seconds"` } -// TokenRotationResponse represents the response when rotating a token type TokenRotationResponse struct { Token string `json:"token"` ActivationLink string `json:"activation_link"` @@ -130,11 +135,18 @@ func createRecipient(email string) (string, error) { return "", fmt.Errorf("failed to create recipient: %d", resp.StatusCode) } -func rotateToken(email string) (string, error) { +// rotateToken rotates the recipient’s token and returns the new token. +func rotateToken(email string, expireInSeconds int) (string, error) { recipientName := strings.Split(email, "@")[0] url := fmt.Sprintf("%s/%s/rotate-token", databricksAPIBase, recipientName) - resp, err := makeRequest("POST", url, nil) + // Prepare the request body + payload := TokenRotationRequest{ + ExistingTokenExpireInSeconds: expireInSeconds, // This will define when the old token expires + } + + resp, err := makeRequest("POST", url, payload) + fmt.Printf("Made the response") if err != nil { return "", err } @@ -235,7 +247,7 @@ func main() { if expirationTime < currentTime { fmt.Printf("Token for recipient '%s' has expired. Rotating...\n", recipient.Name) - newToken, err := rotateToken(email) + newToken, err := rotateToken(email, expirationInSeconds) if err != nil { return c.Status(http.StatusInternalServerError).JSON(fiber.Map{ "error": "Error rotating token: " + err.Error(), From 50a655dbd67eafced0a98fb9a44ca38e82e24efc Mon Sep 17 00:00:00 2001 From: alldoami Date: Mon, 3 Feb 2025 23:32:56 +0000 Subject: [PATCH 22/51] chore: Updated [rdev] values.yaml image tags to sha-413c013 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index ec82634..e0d86c8 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-421d4b2 + tag: sha-413c013 replicaCount: 1 \ No newline at end of file From d1f6421cde726ace125976df0393e7df0de40e21 Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 16:01:33 -0800 Subject: [PATCH 23/51] make changes --- backend/main.go | 36 +++++++++++++++++++----------------- cli/main.go | 25 ++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 18 deletions(-) diff --git a/backend/main.go b/backend/main.go index 3ed8963..90ca10c 100644 --- a/backend/main.go +++ b/backend/main.go @@ -30,8 +30,9 @@ type TokenRequest struct { } type RecipientRequest struct { - Name string `json:"name"` - AuthenticationType string `json:"authentication_type"` + Name string `json:"name"` + AuthenticationType string `json:"authentication_type"` + TokenExpirationTime int `json:"token_expiration_time"` } type RecipientResponse struct { @@ -114,8 +115,9 @@ func createRecipient(email string) (string, error) { url := databricksAPIBase payload := RecipientRequest{ - Name: recipientName, - AuthenticationType: "TOKEN", + Name: recipientName, + AuthenticationType: "TOKEN", + TokenExpirationTime: expirationInSeconds, } resp, err := makeRequest("POST", url, payload) @@ -136,7 +138,7 @@ func createRecipient(email string) (string, error) { } // rotateToken rotates the recipient’s token and returns the new token. -func rotateToken(email string, expireInSeconds int) (string, error) { +func rotateToken(email string, expireInSeconds int) (string, string, error) { recipientName := strings.Split(email, "@")[0] url := fmt.Sprintf("%s/%s/rotate-token", databricksAPIBase, recipientName) @@ -148,21 +150,19 @@ func rotateToken(email string, expireInSeconds int) (string, error) { resp, err := makeRequest("POST", url, payload) fmt.Printf("Made the response") if err != nil { - return "", err + return "", "", err } - fmt.Printf("Response: %v\n", resp) - if resp.StatusCode == http.StatusOK { var rotationResponse TokenRotationResponse if err := json.NewDecoder(resp.Body).Decode(&rotationResponse); err != nil { - return "", fmt.Errorf("error parsing token rotation response: %w", err) + return "", "", fmt.Errorf("error parsing token rotation response: %w", err) } fmt.Printf("Token rotated successfully. New activation link: %s\n", rotationResponse.ActivationLink) - return rotationResponse.Token, nil + return rotationResponse.Token, rotationResponse.ActivationLink, nil } - return "", fmt.Errorf("failed to rotate token: %d", resp.StatusCode) + return "", "", fmt.Errorf("failed to rotate token: %d", resp.StatusCode) } // makeRequest is a helper function to send HTTP requests @@ -247,22 +247,24 @@ func main() { if expirationTime < currentTime { fmt.Printf("Token for recipient '%s' has expired. Rotating...\n", recipient.Name) - newToken, err := rotateToken(email, expirationInSeconds) + newToken, activationLink, err := rotateToken(email, expirationInSeconds) if err != nil { return c.Status(http.StatusInternalServerError).JSON(fiber.Map{ "error": "Error rotating token: " + err.Error(), }) } return c.Status(http.StatusOK).JSON(fiber.Map{ - "message": fmt.Sprintf("Token for %s rotated", email), - "token": newToken, + "message": fmt.Sprintf("Token for %s rotated", email), + "token": newToken, + "activation_link": activationLink, }) } - // Token is still valid + // Recipient exists and token is still valid return c.Status(http.StatusOK).JSON(fiber.Map{ - "message": fmt.Sprintf("Token for %s is still valid", email), - "token": recipient.TokenInfo.Token, + "message": fmt.Sprintf("Token for %s is still valid", email), + "token": recipient.TokenInfo.Token, + "activation_link": recipient.TokenInfo.ActivationURL, }) }) diff --git a/cli/main.go b/cli/main.go index 379ecf0..dd3096e 100644 --- a/cli/main.go +++ b/cli/main.go @@ -43,5 +43,28 @@ func main() { return } - fmt.Println("User successfully verified!") + body, err := io.ReadAll(resp.Body) + if err != nil { + fmt.Println("Error reading response:", err) + return + } + + // Define a struct to parse the JSON response + var response struct { + Message string `json:"message"` + Token string `json:"token"` + ActivationLink string `json:"activation_link"` + } + + // Parse the JSON response + if err := json.Unmarshal(body, &response); err != nil { + fmt.Println("Error parsing response:", err) + return + } + + // Print the success message and activation link + fmt.Println(response.Message) + if response.ActivationLink != "" { + fmt.Println("Activation Link:", response.ActivationLink) + } } From c4f43e28a7a4541d62a7e3cf1f35e7d95a893c35 Mon Sep 17 00:00:00 2001 From: alldoami Date: Tue, 4 Feb 2025 00:03:47 +0000 Subject: [PATCH 24/51] chore: Updated [rdev] values.yaml image tags to sha-2f2d1b8 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index e0d86c8..a29770b 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-413c013 + tag: sha-2f2d1b8 replicaCount: 1 \ No newline at end of file From 0e6d14b01723c577d4736c90bcd85e159c3b328c Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 16:08:14 -0800 Subject: [PATCH 25/51] rotate --- backend/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/main.go b/backend/main.go index 90ca10c..31391b4 100644 --- a/backend/main.go +++ b/backend/main.go @@ -254,7 +254,7 @@ func main() { }) } return c.Status(http.StatusOK).JSON(fiber.Map{ - "message": fmt.Sprintf("Token for %s rotated", email), + "message": fmt.Sprintf("Token for %s rotated. Activation link is: %s", email, activationLink), "token": newToken, "activation_link": activationLink, }) From 0ece7d250a8ec3582acda95e8002f36ee6f86ab5 Mon Sep 17 00:00:00 2001 From: alldoami Date: Tue, 4 Feb 2025 00:10:28 +0000 Subject: [PATCH 26/51] chore: Updated [rdev] values.yaml image tags to sha-0e6d14b --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index a29770b..11dbf02 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-2f2d1b8 + tag: sha-0e6d14b replicaCount: 1 \ No newline at end of file From f91b2300d4b70325b135121e160ae22cbe059675 Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 16:18:30 -0800 Subject: [PATCH 27/51] rotate --- backend/main.go | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/backend/main.go b/backend/main.go index 31391b4..f3abb9d 100644 --- a/backend/main.go +++ b/backend/main.go @@ -50,8 +50,10 @@ type TokenRotationRequest struct { } type TokenRotationResponse struct { - Token string `json:"token"` - ActivationLink string `json:"activation_link"` + Tokens []struct { + ActivationURL string `json:"activation_url"` + ExpirationTime int64 `json:"expiration_time"` + } `json:"tokens"` } func validateCognitoToken(token string) (string, error) { @@ -138,31 +140,31 @@ func createRecipient(email string) (string, error) { } // rotateToken rotates the recipient’s token and returns the new token. -func rotateToken(email string, expireInSeconds int) (string, string, error) { +func rotateToken(email string, expireInSeconds int) (string, error) { recipientName := strings.Split(email, "@")[0] url := fmt.Sprintf("%s/%s/rotate-token", databricksAPIBase, recipientName) // Prepare the request body payload := TokenRotationRequest{ - ExistingTokenExpireInSeconds: expireInSeconds, // This will define when the old token expires + ExistingTokenExpireInSeconds: expireInSeconds, } resp, err := makeRequest("POST", url, payload) - fmt.Printf("Made the response") + if err != nil { - return "", "", err + return "", err } if resp.StatusCode == http.StatusOK { var rotationResponse TokenRotationResponse if err := json.NewDecoder(resp.Body).Decode(&rotationResponse); err != nil { - return "", "", fmt.Errorf("error parsing token rotation response: %w", err) + return "", fmt.Errorf("error parsing token rotation response: %w", err) } - fmt.Printf("Token rotated successfully. New activation link: %s\n", rotationResponse.ActivationLink) - return rotationResponse.Token, rotationResponse.ActivationLink, nil + fmt.Printf("Token rotated successfully. New activation link: %s\n", rotationResponse.Tokens[0].ActivationURL) + return rotationResponse.Tokens[0].ActivationURL, nil } - return "", "", fmt.Errorf("failed to rotate token: %d", resp.StatusCode) + return "", fmt.Errorf("failed to rotate token: %d", resp.StatusCode) } // makeRequest is a helper function to send HTTP requests @@ -247,15 +249,14 @@ func main() { if expirationTime < currentTime { fmt.Printf("Token for recipient '%s' has expired. Rotating...\n", recipient.Name) - newToken, activationLink, err := rotateToken(email, expirationInSeconds) + activationLink, err := rotateToken(email, expirationInSeconds) if err != nil { return c.Status(http.StatusInternalServerError).JSON(fiber.Map{ "error": "Error rotating token: " + err.Error(), }) } return c.Status(http.StatusOK).JSON(fiber.Map{ - "message": fmt.Sprintf("Token for %s rotated. Activation link is: %s", email, activationLink), - "token": newToken, + "message": fmt.Sprintf("Token for %s rotated.", email), "activation_link": activationLink, }) } From 8888650f970350621865fb4b83dd751fd49aa5d3 Mon Sep 17 00:00:00 2001 From: alldoami Date: Tue, 4 Feb 2025 00:21:16 +0000 Subject: [PATCH 28/51] chore: Updated [rdev] values.yaml image tags to sha-6448b75 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index 11dbf02..f2b6e82 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-0e6d14b + tag: sha-6448b75 replicaCount: 1 \ No newline at end of file From 8c34faa06d917fc62d97839933494d23245fba33 Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 16:21:37 -0800 Subject: [PATCH 29/51] new response --- backend/main.go | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/backend/main.go b/backend/main.go index f3abb9d..611cd27 100644 --- a/backend/main.go +++ b/backend/main.go @@ -36,13 +36,11 @@ type RecipientRequest struct { } type RecipientResponse struct { - Name string `json:"name"` - ActivationLink string `json:"activation_link"` - TokenInfo struct { + Name string `json:"name"` + Tokens []struct { ActivationURL string `json:"activation_url"` ExpirationTime int64 `json:"expiration_time"` - Token string `json:"token"` - } `json:"token_info"` + } `json:"tokens"` } type TokenRotationRequest struct { @@ -132,8 +130,8 @@ func createRecipient(email string) (string, error) { if err := json.NewDecoder(resp.Body).Decode(&recipient); err != nil { return "", fmt.Errorf("error parsing recipient response: %w", err) } - fmt.Printf("Recipient '%s' created successfully. Activation link: %s\n", recipientName, recipient.ActivationLink) - return recipient.TokenInfo.Token, nil + fmt.Printf("Recipient '%s' created successfully. Activation link: %s\n", recipientName, recipient.Tokens[0].ActivationURL) + return recipient.Tokens[0].ActivationURL, nil } return "", fmt.Errorf("failed to create recipient: %d", resp.StatusCode) @@ -244,7 +242,7 @@ func main() { } // Recipient exists but token is expired, so rotate it - expirationTime := recipient.TokenInfo.ExpirationTime + expirationTime := recipient.Tokens[0].ExpirationTime currentTime := time.Now().Unix() if expirationTime < currentTime { @@ -264,8 +262,7 @@ func main() { // Recipient exists and token is still valid return c.Status(http.StatusOK).JSON(fiber.Map{ "message": fmt.Sprintf("Token for %s is still valid", email), - "token": recipient.TokenInfo.Token, - "activation_link": recipient.TokenInfo.ActivationURL, + "activation_link": recipient.Tokens[0].ActivationURL, }) }) From 3e571eedeb84929c62997beb1570d862d154e112 Mon Sep 17 00:00:00 2001 From: alldoami Date: Tue, 4 Feb 2025 00:23:50 +0000 Subject: [PATCH 30/51] chore: Updated [rdev] values.yaml image tags to sha-8c34faa --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index f2b6e82..0020209 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-6448b75 + tag: sha-8c34faa replicaCount: 1 \ No newline at end of file From 2fe4525aa49c44044cf6404efcd7ad5228e76961 Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 16:50:36 -0800 Subject: [PATCH 31/51] changes --- backend/main.go | 108 ++++++++++++++++++------------------------------ cli/main.go | 16 ++++--- 2 files changed, 48 insertions(+), 76 deletions(-) diff --git a/backend/main.go b/backend/main.go index 611cd27..1230eb1 100644 --- a/backend/main.go +++ b/backend/main.go @@ -20,11 +20,8 @@ var ( databricksAPIBase = fmt.Sprintf("%s/api/2.1/unity-catalog/recipients", databricksURL) ) -const ( - expirationInSeconds = 604800 // 7 days in seconds -) +const expirationInSeconds = 604800 // 7 days -// TokenRequest represents the request body for verifying a token type TokenRequest struct { Token string `json:"token"` } @@ -36,11 +33,13 @@ type RecipientRequest struct { } type RecipientResponse struct { - Name string `json:"name"` - Tokens []struct { - ActivationURL string `json:"activation_url"` - ExpirationTime int64 `json:"expiration_time"` - } `json:"tokens"` + Name string `json:"name"` + Tokens []TokenDetails `json:"tokens"` +} + +type TokenDetails struct { + ActivationURL string `json:"activation_url"` + ExpirationTime int64 `json:"expiration_time"` } type TokenRotationRequest struct { @@ -48,10 +47,7 @@ type TokenRotationRequest struct { } type TokenRotationResponse struct { - Tokens []struct { - ActivationURL string `json:"activation_url"` - ExpirationTime int64 `json:"expiration_time"` - } `json:"tokens"` + Tokens []TokenDetails `json:"tokens"` } func validateCognitoToken(token string) (string, error) { @@ -60,24 +56,20 @@ func validateCognitoToken(token string) (string, error) { return "", fmt.Errorf("invalid token format") } - // Decode the payload (middle part of the JWT) payloadBytes, err := base64.RawURLEncoding.DecodeString(parts[1]) if err != nil { return "", fmt.Errorf("error decoding token payload: %w", err) } - // Parse the payload as JSON var payload map[string]interface{} if err := json.Unmarshal(payloadBytes, &payload); err != nil { return "", fmt.Errorf("error parsing token payload: %w", err) } - // Ensure the token is issued by your Cognito issuer if payload["iss"] != cognitoIssuer { return "", fmt.Errorf("token issuer is invalid") } - // Extract and return the email email, ok := payload["email"].(string) if !ok { return "", fmt.Errorf("email not found in token") @@ -86,7 +78,7 @@ func validateCognitoToken(token string) (string, error) { return email, nil } -// queryRecipient checks if a recipient exists and returns its token info. +// Query Databricks API for recipient info func queryRecipient(email string) (*RecipientResponse, error) { recipientName := strings.Split(email, "@")[0] url := fmt.Sprintf("%s/%s", databricksAPIBase, recipientName) @@ -95,6 +87,7 @@ func queryRecipient(email string) (*RecipientResponse, error) { if err != nil { return nil, err } + defer resp.Body.Close() if resp.StatusCode == http.StatusOK { var recipient RecipientResponse @@ -104,12 +97,12 @@ func queryRecipient(email string) (*RecipientResponse, error) { return &recipient, nil } else if resp.StatusCode == http.StatusNotFound { return nil, nil - } else { - return nil, fmt.Errorf("unexpected response: %d", resp.StatusCode) } + + return nil, fmt.Errorf("unexpected response: %d", resp.StatusCode) } -// createRecipient creates a new recipient with token authentication and returns the token. +// Create a new recipient in Databricks func createRecipient(email string) (string, error) { recipientName := strings.Split(email, "@")[0] url := databricksAPIBase @@ -124,12 +117,18 @@ func createRecipient(email string) (string, error) { if err != nil { return "", err } + defer resp.Body.Close() if resp.StatusCode == http.StatusCreated { var recipient RecipientResponse if err := json.NewDecoder(resp.Body).Decode(&recipient); err != nil { return "", fmt.Errorf("error parsing recipient response: %w", err) } + + if len(recipient.Tokens) == 0 { + return "", fmt.Errorf("no tokens returned for new recipient") + } + fmt.Printf("Recipient '%s' created successfully. Activation link: %s\n", recipientName, recipient.Tokens[0].ActivationURL) return recipient.Tokens[0].ActivationURL, nil } @@ -137,27 +136,28 @@ func createRecipient(email string) (string, error) { return "", fmt.Errorf("failed to create recipient: %d", resp.StatusCode) } -// rotateToken rotates the recipient’s token and returns the new token. +// Rotate an expired token func rotateToken(email string, expireInSeconds int) (string, error) { recipientName := strings.Split(email, "@")[0] url := fmt.Sprintf("%s/%s/rotate-token", databricksAPIBase, recipientName) - // Prepare the request body - payload := TokenRotationRequest{ - ExistingTokenExpireInSeconds: expireInSeconds, - } - + payload := TokenRotationRequest{ExistingTokenExpireInSeconds: expireInSeconds} resp, err := makeRequest("POST", url, payload) - if err != nil { return "", err } + defer resp.Body.Close() if resp.StatusCode == http.StatusOK { var rotationResponse TokenRotationResponse if err := json.NewDecoder(resp.Body).Decode(&rotationResponse); err != nil { return "", fmt.Errorf("error parsing token rotation response: %w", err) } + + if len(rotationResponse.Tokens) == 0 { + return "", fmt.Errorf("no tokens returned after rotation") + } + fmt.Printf("Token rotated successfully. New activation link: %s\n", rotationResponse.Tokens[0].ActivationURL) return rotationResponse.Tokens[0].ActivationURL, nil } @@ -165,7 +165,7 @@ func rotateToken(email string, expireInSeconds int) (string, error) { return "", fmt.Errorf("failed to rotate token: %d", resp.StatusCode) } -// makeRequest is a helper function to send HTTP requests +// Send HTTP requests func makeRequest(method, url string, payload interface{}) (*http.Response, error) { client := &http.Client{} @@ -192,56 +192,40 @@ func makeRequest(method, url string, payload interface{}) (*http.Response, error func main() { app := fiber.New() - // Health Check Endpoint + // Health Check app.Get("/health", func(c *fiber.Ctx) error { - return c.Status(http.StatusOK).JSON(fiber.Map{ - "status": "healthy", - }) + return c.Status(http.StatusOK).JSON(fiber.Map{"status": "healthy"}) }) // Token Verification & Databricks Recipient Handling app.Post("/verify-token", func(c *fiber.Ctx) error { var tokenRequest TokenRequest - // Parse the incoming JSON body if err := c.BodyParser(&tokenRequest); err != nil { - return c.Status(http.StatusBadRequest).JSON(fiber.Map{ - "error": "Invalid request body", - }) + return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "Invalid request body"}) } - // Decode and Validate the Cognito Token email, err := validateCognitoToken(tokenRequest.Token) if err != nil { - return c.Status(http.StatusUnauthorized).JSON(fiber.Map{ - "error": "Invalid token: " + err.Error(), - }) + return c.Status(http.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid token: " + err.Error()}) } - // Query Databricks API for Delta Share recipient recipient, err := queryRecipient(email) if err != nil { - return c.Status(http.StatusInternalServerError).JSON(fiber.Map{ - "error": "Error querying Databricks: " + err.Error(), - }) + return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "Error querying Databricks: " + err.Error()}) } - // If recipient does not exist, create one + // Create recipient if not found if recipient == nil { fmt.Printf("Recipient for email '%s' does not exist. Creating...\n", email) token, err := createRecipient(email) if err != nil { - return c.Status(http.StatusInternalServerError).JSON(fiber.Map{ - "error": "Error creating recipient: " + err.Error(), - }) + return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "Error creating recipient: " + err.Error()}) } - return c.Status(http.StatusOK).JSON(fiber.Map{ - "message": fmt.Sprintf("New recipient created for %s", email), - "token": token, - }) + return c.Status(http.StatusOK).JSON(fiber.Map{"message": fmt.Sprintf("New recipient created for %s", email), "activation_link": token}) } - // Recipient exists but token is expired, so rotate it + // Check token expiration expirationTime := recipient.Tokens[0].ExpirationTime currentTime := time.Now().Unix() @@ -249,23 +233,13 @@ func main() { fmt.Printf("Token for recipient '%s' has expired. Rotating...\n", recipient.Name) activationLink, err := rotateToken(email, expirationInSeconds) if err != nil { - return c.Status(http.StatusInternalServerError).JSON(fiber.Map{ - "error": "Error rotating token: " + err.Error(), - }) + return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "Error rotating token: " + err.Error()}) } - return c.Status(http.StatusOK).JSON(fiber.Map{ - "message": fmt.Sprintf("Token for %s rotated.", email), - "activation_link": activationLink, - }) + return c.Status(http.StatusOK).JSON(fiber.Map{"message": fmt.Sprintf("Token for %s rotated", email), "activation_link": activationLink}) } - // Recipient exists and token is still valid - return c.Status(http.StatusOK).JSON(fiber.Map{ - "message": fmt.Sprintf("Token for %s is still valid", email), - "activation_link": recipient.Tokens[0].ActivationURL, - }) + return c.Status(http.StatusOK).JSON(fiber.Map{"message": fmt.Sprintf("Token for %s is still valid", email), "activation_link": recipient.Tokens[0].ActivationURL}) }) - // Start the Fiber app log.Fatal(app.Listen(":8080")) } diff --git a/cli/main.go b/cli/main.go index dd3096e..dff2b8f 100644 --- a/cli/main.go +++ b/cli/main.go @@ -37,26 +37,24 @@ func main() { } defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - body, _ := io.ReadAll(resp.Body) - fmt.Printf("Error from backend: %s\n", body) - return - } - body, err := io.ReadAll(resp.Body) if err != nil { fmt.Println("Error reading response:", err) return } - // Define a struct to parse the JSON response + // Handle non-200 responses + if resp.StatusCode != http.StatusOK { + fmt.Printf("Error from backend (Status %d): %s\n", resp.StatusCode, string(body)) + return + } + + // Parse JSON response var response struct { Message string `json:"message"` - Token string `json:"token"` ActivationLink string `json:"activation_link"` } - // Parse the JSON response if err := json.Unmarshal(body, &response); err != nil { fmt.Println("Error parsing response:", err) return From 442b3fae8541f80b73eb54fc5571803235d8822c Mon Sep 17 00:00:00 2001 From: alldoami Date: Tue, 4 Feb 2025 00:52:44 +0000 Subject: [PATCH 32/51] chore: Updated [rdev] values.yaml image tags to sha-2fe4525 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index 0020209..998c8ea 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-8c34faa + tag: sha-2fe4525 replicaCount: 1 \ No newline at end of file From c3e4af716ca836fbaed990f1b7478fe2953a05c3 Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 17:05:52 -0800 Subject: [PATCH 33/51] fix --- backend/main.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/backend/main.go b/backend/main.go index 1230eb1..6e78a64 100644 --- a/backend/main.go +++ b/backend/main.go @@ -33,6 +33,10 @@ type RecipientRequest struct { } type RecipientResponse struct { + Recipients []RecipientDetails `json:"recipients"` +} + +type RecipientDetails struct { Name string `json:"name"` Tokens []TokenDetails `json:"tokens"` } @@ -125,12 +129,12 @@ func createRecipient(email string) (string, error) { return "", fmt.Errorf("error parsing recipient response: %w", err) } - if len(recipient.Tokens) == 0 { + if len(recipient.Recipients) == 0 { return "", fmt.Errorf("no tokens returned for new recipient") } - fmt.Printf("Recipient '%s' created successfully. Activation link: %s\n", recipientName, recipient.Tokens[0].ActivationURL) - return recipient.Tokens[0].ActivationURL, nil + fmt.Printf("Recipient '%s' created successfully. Activation link: %s\n", recipientName, recipient.Recipients[0].Tokens[0].ActivationURL) + return recipient.Recipients[0].Tokens[0].ActivationURL, nil } return "", fmt.Errorf("failed to create recipient: %d", resp.StatusCode) @@ -226,11 +230,11 @@ func main() { } // Check token expiration - expirationTime := recipient.Tokens[0].ExpirationTime + expirationTime := recipient.Recipients[0].Tokens[0].ExpirationTime currentTime := time.Now().Unix() if expirationTime < currentTime { - fmt.Printf("Token for recipient '%s' has expired. Rotating...\n", recipient.Name) + fmt.Printf("Token for recipient '%s' has expired. Rotating...\n", recipient.Recipients[0].Name) activationLink, err := rotateToken(email, expirationInSeconds) if err != nil { return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "Error rotating token: " + err.Error()}) @@ -238,7 +242,7 @@ func main() { return c.Status(http.StatusOK).JSON(fiber.Map{"message": fmt.Sprintf("Token for %s rotated", email), "activation_link": activationLink}) } - return c.Status(http.StatusOK).JSON(fiber.Map{"message": fmt.Sprintf("Token for %s is still valid", email), "activation_link": recipient.Tokens[0].ActivationURL}) + return c.Status(http.StatusOK).JSON(fiber.Map{"message": fmt.Sprintf("Token for %s is still valid", email), "activation_link": recipient.Recipients[0].Tokens[0].ActivationURL}) }) log.Fatal(app.Listen(":8080")) From 6d9698374a67c0d47f0ce0e875993545195ea42d Mon Sep 17 00:00:00 2001 From: alldoami Date: Tue, 4 Feb 2025 01:07:55 +0000 Subject: [PATCH 34/51] chore: Updated [rdev] values.yaml image tags to sha-c3e4af7 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index 998c8ea..c977f0b 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-2fe4525 + tag: sha-c3e4af7 replicaCount: 1 \ No newline at end of file From 9bc9764b43cf152a230a1784eab6d2304b056b8b Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 17:16:07 -0800 Subject: [PATCH 35/51] add print --- backend/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/main.go b/backend/main.go index 6e78a64..c669e85 100644 --- a/backend/main.go +++ b/backend/main.go @@ -230,6 +230,7 @@ func main() { } // Check token expiration + fmt.Printf("Recipient response: %+v\n", recipient) expirationTime := recipient.Recipients[0].Tokens[0].ExpirationTime currentTime := time.Now().Unix() From 6aeed4124c8be0689eadedf60400409bf982b1e8 Mon Sep 17 00:00:00 2001 From: alldoami Date: Tue, 4 Feb 2025 01:18:15 +0000 Subject: [PATCH 36/51] chore: Updated [rdev] values.yaml image tags to sha-9bc9764 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index c977f0b..59b3b33 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-c3e4af7 + tag: sha-9bc9764 replicaCount: 1 \ No newline at end of file From aa034547a745de88d3c243ab37fd96c6cb31b65f Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 17:27:45 -0800 Subject: [PATCH 37/51] remove close --- backend/main.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/backend/main.go b/backend/main.go index c669e85..22d4324 100644 --- a/backend/main.go +++ b/backend/main.go @@ -91,7 +91,6 @@ func queryRecipient(email string) (*RecipientResponse, error) { if err != nil { return nil, err } - defer resp.Body.Close() if resp.StatusCode == http.StatusOK { var recipient RecipientResponse @@ -121,7 +120,6 @@ func createRecipient(email string) (string, error) { if err != nil { return "", err } - defer resp.Body.Close() if resp.StatusCode == http.StatusCreated { var recipient RecipientResponse @@ -150,7 +148,6 @@ func rotateToken(email string, expireInSeconds int) (string, error) { if err != nil { return "", err } - defer resp.Body.Close() if resp.StatusCode == http.StatusOK { var rotationResponse TokenRotationResponse From e433179baf4acde23e7b206dfe63cd52d6c123f2 Mon Sep 17 00:00:00 2001 From: alldoami Date: Tue, 4 Feb 2025 01:29:50 +0000 Subject: [PATCH 38/51] chore: Updated [rdev] values.yaml image tags to sha-aa03454 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index 59b3b33..dff380b 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-9bc9764 + tag: sha-aa03454 replicaCount: 1 \ No newline at end of file From ea3081fb8b3f5a3f55eb9892b1a1cc85ed2735bf Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 17:34:32 -0800 Subject: [PATCH 39/51] comment out --- backend/main.go | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/backend/main.go b/backend/main.go index 22d4324..eb12d2b 100644 --- a/backend/main.go +++ b/backend/main.go @@ -8,7 +8,6 @@ import ( "net/http" "os" "strings" - "time" "github.com/gofiber/fiber/v2" ) @@ -94,6 +93,8 @@ func queryRecipient(email string) (*RecipientResponse, error) { if resp.StatusCode == http.StatusOK { var recipient RecipientResponse + fmt.Printf("Recipient response body: %+v\n", resp.Body) + fmt.Print(json.NewDecoder(resp.Body).Decode(&recipient)) if err := json.NewDecoder(resp.Body).Decode(&recipient); err != nil { return nil, fmt.Errorf("error parsing recipient response: %w", err) } @@ -131,8 +132,9 @@ func createRecipient(email string) (string, error) { return "", fmt.Errorf("no tokens returned for new recipient") } - fmt.Printf("Recipient '%s' created successfully. Activation link: %s\n", recipientName, recipient.Recipients[0].Tokens[0].ActivationURL) - return recipient.Recipients[0].Tokens[0].ActivationURL, nil + // fmt.Printf("Recipient '%s' created successfully. Activation link: %s\n", recipientName, recipient.Recipients[0].Tokens[0].ActivationURL) + // return recipient.Recipients[0].Tokens[0].ActivationURL, nil + return "trying to send activation link", nil } return "", fmt.Errorf("failed to create recipient: %d", resp.StatusCode) @@ -159,8 +161,9 @@ func rotateToken(email string, expireInSeconds int) (string, error) { return "", fmt.Errorf("no tokens returned after rotation") } - fmt.Printf("Token rotated successfully. New activation link: %s\n", rotationResponse.Tokens[0].ActivationURL) - return rotationResponse.Tokens[0].ActivationURL, nil + // fmt.Printf("Token rotated successfully. New activation link: %s\n", rotationResponse.Tokens[0].ActivationURL) + // return rotationResponse.Tokens[0].ActivationURL, nil + return "trying to send activation link", nil } return "", fmt.Errorf("failed to rotate token: %d", resp.StatusCode) @@ -228,19 +231,19 @@ func main() { // Check token expiration fmt.Printf("Recipient response: %+v\n", recipient) - expirationTime := recipient.Recipients[0].Tokens[0].ExpirationTime - currentTime := time.Now().Unix() - - if expirationTime < currentTime { - fmt.Printf("Token for recipient '%s' has expired. Rotating...\n", recipient.Recipients[0].Name) - activationLink, err := rotateToken(email, expirationInSeconds) - if err != nil { - return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "Error rotating token: " + err.Error()}) - } - return c.Status(http.StatusOK).JSON(fiber.Map{"message": fmt.Sprintf("Token for %s rotated", email), "activation_link": activationLink}) - } - - return c.Status(http.StatusOK).JSON(fiber.Map{"message": fmt.Sprintf("Token for %s is still valid", email), "activation_link": recipient.Recipients[0].Tokens[0].ActivationURL}) + // expirationTime := recipient.Recipients[0].Tokens[0].ExpirationTime + // currentTime := time.Now().Unix() + + // if expirationTime < currentTime { + // fmt.Printf("Token for recipient '%s' has expired. Rotating...\n", recipient.Recipients[0].Name) + // activationLink, err := rotateToken(email, expirationInSeconds) + // if err != nil { + // return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "Error rotating token: " + err.Error()}) + // } + // return c.Status(http.StatusOK).JSON(fiber.Map{"message": fmt.Sprintf("Token for %s rotated", email), "activation_link": activationLink}) + // } + + // return c.Status(http.StatusOK).JSON(fiber.Map{"message": fmt.Sprintf("Token for %s is still valid", email), "activation_link": recipient.Recipients[0].Tokens[0].ActivationURL}) }) log.Fatal(app.Listen(":8080")) From 40e1c4e48fb1ab959f47482e07e4502d0d9dc975 Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 17:48:20 -0800 Subject: [PATCH 40/51] new return --- backend/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/main.go b/backend/main.go index eb12d2b..add6f1d 100644 --- a/backend/main.go +++ b/backend/main.go @@ -244,6 +244,7 @@ func main() { // } // return c.Status(http.StatusOK).JSON(fiber.Map{"message": fmt.Sprintf("Token for %s is still valid", email), "activation_link": recipient.Recipients[0].Tokens[0].ActivationURL}) + return c.Status(http.StatusOK).JSON(fiber.Map{"message": fmt.Sprintf("Token for %s is still valid", email), "activation_link": "trying to send activation link"}) }) log.Fatal(app.Listen(":8080")) From accfccc94e2c8210505c5e1d86fe4eb09dffbae6 Mon Sep 17 00:00:00 2001 From: alldoami Date: Tue, 4 Feb 2025 01:50:23 +0000 Subject: [PATCH 41/51] chore: Updated [rdev] values.yaml image tags to sha-40e1c4e --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index dff380b..c4e4e4a 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-aa03454 + tag: sha-40e1c4e replicaCount: 1 \ No newline at end of file From 23c693bf5abee5d22b78685f19554b1540c510e1 Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 21:05:27 -0800 Subject: [PATCH 42/51] add logging --- backend/main.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/backend/main.go b/backend/main.go index add6f1d..1e14cc1 100644 --- a/backend/main.go +++ b/backend/main.go @@ -4,6 +4,7 @@ import ( "encoding/base64" "encoding/json" "fmt" + "io" "log" "net/http" "os" @@ -91,10 +92,15 @@ func queryRecipient(email string) (*RecipientResponse, error) { return nil, err } + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("error reading Databricks response body: %w", err) + } + + fmt.Printf("Databricks Response (Status %d): %s\n", resp.StatusCode, string(body)) + if resp.StatusCode == http.StatusOK { var recipient RecipientResponse - fmt.Printf("Recipient response body: %+v\n", resp.Body) - fmt.Print(json.NewDecoder(resp.Body).Decode(&recipient)) if err := json.NewDecoder(resp.Body).Decode(&recipient); err != nil { return nil, fmt.Errorf("error parsing recipient response: %w", err) } From 49a9fe00abb1dfe35c45d6a16fc004260460e3c6 Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 21:06:37 -0800 Subject: [PATCH 43/51] url log --- backend/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/main.go b/backend/main.go index 1e14cc1..80555ec 100644 --- a/backend/main.go +++ b/backend/main.go @@ -87,6 +87,7 @@ func queryRecipient(email string) (*RecipientResponse, error) { recipientName := strings.Split(email, "@")[0] url := fmt.Sprintf("%s/%s", databricksAPIBase, recipientName) + fmt.Printf("Querying using URL %s\n", url) resp, err := makeRequest("GET", url, nil) if err != nil { return nil, err From 114becbd0c4841998a7656e3b1974e20c62f6be0 Mon Sep 17 00:00:00 2001 From: alldoami Date: Tue, 4 Feb 2025 05:08:40 +0000 Subject: [PATCH 44/51] chore: Updated [rdev] values.yaml image tags to sha-49a9fe0 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index c4e4e4a..6e12499 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-40e1c4e + tag: sha-49a9fe0 replicaCount: 1 \ No newline at end of file From 9ee334a88d70f3ab871b98b608a451866e1baece Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 21:44:44 -0800 Subject: [PATCH 45/51] fixed all --- backend/main.go | 202 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 144 insertions(+), 58 deletions(-) diff --git a/backend/main.go b/backend/main.go index 80555ec..9a77c4e 100644 --- a/backend/main.go +++ b/backend/main.go @@ -33,17 +33,31 @@ type RecipientRequest struct { } type RecipientResponse struct { - Recipients []RecipientDetails `json:"recipients"` -} - -type RecipientDetails struct { - Name string `json:"name"` - Tokens []TokenDetails `json:"tokens"` + Name string `json:"name"` + AuthenticationType string `json:"authentication_type"` + Owner string `json:"owner"` + CreatedAt int64 `json:"created_at"` + UpdatedAt int64 `json:"updated_at"` + FullName string `json:"full_name"` + SecurableType string `json:"securable_type"` + SecurableKind string `json:"securable_kind"` + ID string `json:"id"` + Tokens []TokenDetails `json:"tokens,omitempty"` } type TokenDetails struct { + ID string `json:"id"` ActivationURL string `json:"activation_url"` ExpirationTime int64 `json:"expiration_time"` + CreatedAt int64 `json:"created_at"` + CreatedBy string `json:"created_by"` + UpdatedAt int64 `json:"updated_at"` + UpdatedBy string `json:"updated_by"` +} + +type RecipientDetails struct { + Name string `json:"name"` + Tokens []TokenDetails `json:"tokens"` } type TokenRotationRequest struct { @@ -82,35 +96,39 @@ func validateCognitoToken(token string) (string, error) { return email, nil } -// Query Databricks API for recipient info -func queryRecipient(email string) (*RecipientResponse, error) { +func queryRecipient(email string) (*RecipientResponse, bool, error) { recipientName := strings.Split(email, "@")[0] url := fmt.Sprintf("%s/%s", databricksAPIBase, recipientName) - fmt.Printf("Querying using URL %s\n", url) resp, err := makeRequest("GET", url, nil) if err != nil { - return nil, err + return nil, false, fmt.Errorf("error making request to Databricks: %w", err) } + defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { - return nil, fmt.Errorf("error reading Databricks response body: %w", err) + return nil, false, fmt.Errorf("error reading Databricks response body: %w", err) } + // 🔹 Log full response for debugging fmt.Printf("Databricks Response (Status %d): %s\n", resp.StatusCode, string(body)) if resp.StatusCode == http.StatusOK { var recipient RecipientResponse - if err := json.NewDecoder(resp.Body).Decode(&recipient); err != nil { - return nil, fmt.Errorf("error parsing recipient response: %w", err) + if err := json.Unmarshal(body, &recipient); err != nil { + return nil, false, fmt.Errorf("error parsing recipient response JSON: %w", err) } - return &recipient, nil + + // ✅ Check if `tokens` exists and has at least one entry + hasTokens := len(recipient.Tokens) > 0 + + return &recipient, hasTokens, nil } else if resp.StatusCode == http.StatusNotFound { - return nil, nil + return nil, false, nil // Recipient does not exist } - return nil, fmt.Errorf("unexpected response: %d", resp.StatusCode) + return nil, false, fmt.Errorf("unexpected Databricks response: %d - %s", resp.StatusCode, string(body)) } // Create a new recipient in Databricks @@ -118,6 +136,31 @@ func createRecipient(email string) (string, error) { recipientName := strings.Split(email, "@")[0] url := databricksAPIBase + // ✅ First, check if the recipient already exists + recipient, hasTokens, err := queryRecipient(email) + if err != nil { + return "", fmt.Errorf("error checking recipient existence: %w", err) + } + + // ✅ If recipient already exists and has tokens, return its activation link + if recipient != nil && hasTokens { + fmt.Printf("Recipient '%s' already exists and has a valid token.\n", recipient.Name) + return recipient.Tokens[0].ActivationURL, nil + } + + // ✅ If recipient exists but has no tokens, rotate a new token + if recipient != nil && !hasTokens { + fmt.Printf("Recipient '%s' exists but has no tokens. Rotating a new token...\n", recipient.Name) + activationLink, err := rotateToken(email, expirationInSeconds) + if err != nil { + return "", fmt.Errorf("error rotating token: %w", err) + } + return activationLink, nil + } + + // ✅ If recipient is not found, create a new one + fmt.Printf("Recipient '%s' does not exist. Creating new recipient...\n", recipientName) + payload := RecipientRequest{ Name: recipientName, AuthenticationType: "TOKEN", @@ -126,25 +169,37 @@ func createRecipient(email string) (string, error) { resp, err := makeRequest("POST", url, payload) if err != nil { - return "", err + return "", fmt.Errorf("error making request to create recipient: %w", err) + } + defer resp.Body.Close() + + // Read response body for debugging + body, err := io.ReadAll(resp.Body) + if err != nil { + return "", fmt.Errorf("error reading create-recipient response body: %w", err) } + // 🔹 Log full response for debugging + fmt.Printf("Databricks Create Recipient Response (Status %d): %s\n", resp.StatusCode, string(body)) + + // ✅ Handle successful recipient creation if resp.StatusCode == http.StatusCreated { - var recipient RecipientResponse - if err := json.NewDecoder(resp.Body).Decode(&recipient); err != nil { - return "", fmt.Errorf("error parsing recipient response: %w", err) + var recipientResponse RecipientResponse + if err := json.Unmarshal(body, &recipientResponse); err != nil { + return "", fmt.Errorf("error parsing create-recipient response JSON: %w", err) } - if len(recipient.Recipients) == 0 { - return "", fmt.Errorf("no tokens returned for new recipient") + // ✅ Ensure at least one token exists in the response + if len(recipientResponse.Tokens) == 0 { + return "", fmt.Errorf("create-recipient API returned no tokens") } - // fmt.Printf("Recipient '%s' created successfully. Activation link: %s\n", recipientName, recipient.Recipients[0].Tokens[0].ActivationURL) - // return recipient.Recipients[0].Tokens[0].ActivationURL, nil - return "trying to send activation link", nil + fmt.Printf("Recipient '%s' created successfully. Activation link: %s\n", recipientName, recipientResponse.Tokens[0].ActivationURL) + return recipientResponse.Tokens[0].ActivationURL, nil } - return "", fmt.Errorf("failed to create recipient: %d", resp.StatusCode) + // Handle unexpected responses + return "", fmt.Errorf("failed to create recipient: %d - %s", resp.StatusCode, string(body)) } // Rotate an expired token @@ -152,28 +207,47 @@ func rotateToken(email string, expireInSeconds int) (string, error) { recipientName := strings.Split(email, "@")[0] url := fmt.Sprintf("%s/%s/rotate-token", databricksAPIBase, recipientName) - payload := TokenRotationRequest{ExistingTokenExpireInSeconds: expireInSeconds} + // Prepare the request payload + payload := TokenRotationRequest{ + ExistingTokenExpireInSeconds: expireInSeconds, + } + resp, err := makeRequest("POST", url, payload) if err != nil { - return "", err + return "", fmt.Errorf("error making request to rotate token: %w", err) } + defer resp.Body.Close() + // Read full response body for debugging + body, err := io.ReadAll(resp.Body) + if err != nil { + return "", fmt.Errorf("error reading Databricks rotate-token response body: %w", err) + } + + // 🔹 Log full response for debugging + fmt.Printf("Databricks Rotate Token Response (Status %d): %s\n", resp.StatusCode, string(body)) + + // Check for successful response if resp.StatusCode == http.StatusOK { var rotationResponse TokenRotationResponse - if err := json.NewDecoder(resp.Body).Decode(&rotationResponse); err != nil { - return "", fmt.Errorf("error parsing token rotation response: %w", err) + if err := json.Unmarshal(body, &rotationResponse); err != nil { + return "", fmt.Errorf("error parsing rotate-token response JSON: %w", err) } + // ✅ Ensure at least one token exists in the response if len(rotationResponse.Tokens) == 0 { - return "", fmt.Errorf("no tokens returned after rotation") + return "", fmt.Errorf("rotate-token API returned no tokens") } - // fmt.Printf("Token rotated successfully. New activation link: %s\n", rotationResponse.Tokens[0].ActivationURL) - // return rotationResponse.Tokens[0].ActivationURL, nil - return "trying to send activation link", nil + // ✅ Extract the latest token (assuming last token in the list is the most recent) + latestToken := rotationResponse.Tokens[len(rotationResponse.Tokens)-1] + + fmt.Printf("Token rotated successfully. New activation link: %s\n", latestToken.ActivationURL) + return latestToken.ActivationURL, nil } - return "", fmt.Errorf("failed to rotate token: %d", resp.StatusCode) + // Handle unexpected responses + return "", fmt.Errorf("failed to rotate token: %d - %s", resp.StatusCode, string(body)) } // Send HTTP requests @@ -221,37 +295,49 @@ func main() { return c.Status(http.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid token: " + err.Error()}) } - recipient, err := queryRecipient(email) + // 🔹 Step 1: Check if recipient exists + recipient, hasTokens, err := queryRecipient(email) if err != nil { - return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "Error querying Databricks: " + err.Error()}) + return c.Status(http.StatusInternalServerError).JSON(fiber.Map{ + "error": "Error querying Databricks: " + err.Error(), + }) } - // Create recipient if not found + // 🔹 Step 2: If recipient is missing, create it if recipient == nil { - fmt.Printf("Recipient for email '%s' does not exist. Creating...\n", email) - token, err := createRecipient(email) + fmt.Printf("⚠️ Recipient for email '%s' does not exist. Creating...\n", email) + activationLink, err := createRecipient(email) + if err != nil { + return c.Status(http.StatusInternalServerError).JSON(fiber.Map{ + "error": "Error creating recipient: " + err.Error(), + }) + } + return c.Status(http.StatusOK).JSON(fiber.Map{ + "message": fmt.Sprintf("New recipient created for %s", email), + "activation_link": activationLink, + }) + } + + // 🔹 Step 3: If recipient exists but has no token, rotate a new token + if !hasTokens { + fmt.Printf("⚠️ Recipient '%s' exists but has no tokens. Rotating...\n", recipient.Name) + activationLink, err := rotateToken(email, expirationInSeconds) if err != nil { - return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "Error creating recipient: " + err.Error()}) + return c.Status(http.StatusInternalServerError).JSON(fiber.Map{ + "error": "Error rotating token: " + err.Error(), + }) } - return c.Status(http.StatusOK).JSON(fiber.Map{"message": fmt.Sprintf("New recipient created for %s", email), "activation_link": token}) + return c.Status(http.StatusOK).JSON(fiber.Map{ + "message": fmt.Sprintf("Token for %s rotated", email), + "activation_link": activationLink, + }) } - // Check token expiration - fmt.Printf("Recipient response: %+v\n", recipient) - // expirationTime := recipient.Recipients[0].Tokens[0].ExpirationTime - // currentTime := time.Now().Unix() - - // if expirationTime < currentTime { - // fmt.Printf("Token for recipient '%s' has expired. Rotating...\n", recipient.Recipients[0].Name) - // activationLink, err := rotateToken(email, expirationInSeconds) - // if err != nil { - // return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "Error rotating token: " + err.Error()}) - // } - // return c.Status(http.StatusOK).JSON(fiber.Map{"message": fmt.Sprintf("Token for %s rotated", email), "activation_link": activationLink}) - // } - - // return c.Status(http.StatusOK).JSON(fiber.Map{"message": fmt.Sprintf("Token for %s is still valid", email), "activation_link": recipient.Recipients[0].Tokens[0].ActivationURL}) - return c.Status(http.StatusOK).JSON(fiber.Map{"message": fmt.Sprintf("Token for %s is still valid", email), "activation_link": "trying to send activation link"}) + // 🔹 Step 4: If recipient exists and has a valid token, return it + return c.Status(http.StatusOK).JSON(fiber.Map{ + "message": fmt.Sprintf("Token for %s is still valid", email), + "activation_link": recipient.Tokens[0].ActivationURL, // ✅ Safe to access + }) }) log.Fatal(app.Listen(":8080")) From d06d5455be29e388d96557ae1fbe40d66b10bf7d Mon Sep 17 00:00:00 2001 From: alldoami Date: Tue, 4 Feb 2025 05:46:51 +0000 Subject: [PATCH 46/51] chore: Updated [rdev] values.yaml image tags to sha-9ee334a --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index 6e12499..f38ab98 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-49a9fe0 + tag: sha-9ee334a replicaCount: 1 \ No newline at end of file From 3b5b8361bc8927ca97455b08049c86d2edd2a3b3 Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 22:00:05 -0800 Subject: [PATCH 47/51] remove unnecessary code --- backend/main.go | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/backend/main.go b/backend/main.go index 9a77c4e..12dd6d8 100644 --- a/backend/main.go +++ b/backend/main.go @@ -136,31 +136,6 @@ func createRecipient(email string) (string, error) { recipientName := strings.Split(email, "@")[0] url := databricksAPIBase - // ✅ First, check if the recipient already exists - recipient, hasTokens, err := queryRecipient(email) - if err != nil { - return "", fmt.Errorf("error checking recipient existence: %w", err) - } - - // ✅ If recipient already exists and has tokens, return its activation link - if recipient != nil && hasTokens { - fmt.Printf("Recipient '%s' already exists and has a valid token.\n", recipient.Name) - return recipient.Tokens[0].ActivationURL, nil - } - - // ✅ If recipient exists but has no tokens, rotate a new token - if recipient != nil && !hasTokens { - fmt.Printf("Recipient '%s' exists but has no tokens. Rotating a new token...\n", recipient.Name) - activationLink, err := rotateToken(email, expirationInSeconds) - if err != nil { - return "", fmt.Errorf("error rotating token: %w", err) - } - return activationLink, nil - } - - // ✅ If recipient is not found, create a new one - fmt.Printf("Recipient '%s' does not exist. Creating new recipient...\n", recipientName) - payload := RecipientRequest{ Name: recipientName, AuthenticationType: "TOKEN", @@ -189,11 +164,6 @@ func createRecipient(email string) (string, error) { return "", fmt.Errorf("error parsing create-recipient response JSON: %w", err) } - // ✅ Ensure at least one token exists in the response - if len(recipientResponse.Tokens) == 0 { - return "", fmt.Errorf("create-recipient API returned no tokens") - } - fmt.Printf("Recipient '%s' created successfully. Activation link: %s\n", recipientName, recipientResponse.Tokens[0].ActivationURL) return recipientResponse.Tokens[0].ActivationURL, nil } From 6e7b865fc617f04ca5f1faade1281d33dad1667a Mon Sep 17 00:00:00 2001 From: alldoami Date: Tue, 4 Feb 2025 06:02:12 +0000 Subject: [PATCH 48/51] chore: Updated [rdev] values.yaml image tags to sha-3b5b836 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index f38ab98..ba5f238 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-9ee334a + tag: sha-3b5b836 replicaCount: 1 \ No newline at end of file From a42d98daf972dad780a2b5345b3014dc711c6a5c Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 22:34:53 -0800 Subject: [PATCH 49/51] statusok --- backend/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/main.go b/backend/main.go index 12dd6d8..750a507 100644 --- a/backend/main.go +++ b/backend/main.go @@ -158,7 +158,7 @@ func createRecipient(email string) (string, error) { fmt.Printf("Databricks Create Recipient Response (Status %d): %s\n", resp.StatusCode, string(body)) // ✅ Handle successful recipient creation - if resp.StatusCode == http.StatusCreated { + if resp.StatusCode == http.StatusOK { var recipientResponse RecipientResponse if err := json.Unmarshal(body, &recipientResponse); err != nil { return "", fmt.Errorf("error parsing create-recipient response JSON: %w", err) From 9c52921dcbfde0ff07ea782cab39d507160a4033 Mon Sep 17 00:00:00 2001 From: alldoami Date: Tue, 4 Feb 2025 06:36:58 +0000 Subject: [PATCH 50/51] chore: Updated [rdev] values.yaml image tags to sha-a42d98d --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index ba5f238..7bfd6c8 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,5 +2,5 @@ stack: services: backend: image: - tag: sha-3b5b836 + tag: sha-a42d98d replicaCount: 1 \ No newline at end of file From 3ce68ffdff0af793c2b4b1897585635030ccd31c Mon Sep 17 00:00:00 2001 From: Allison Doami Date: Mon, 3 Feb 2025 22:47:37 -0800 Subject: [PATCH 51/51] revise comment --- backend/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/main.go b/backend/main.go index 750a507..72e1dea 100644 --- a/backend/main.go +++ b/backend/main.go @@ -157,7 +157,7 @@ func createRecipient(email string) (string, error) { // 🔹 Log full response for debugging fmt.Printf("Databricks Create Recipient Response (Status %d): %s\n", resp.StatusCode, string(body)) - // ✅ Handle successful recipient creation + // ✅ Handle successful recipient creation, returns a status 200 if successful if resp.StatusCode == http.StatusOK { var recipientResponse RecipientResponse if err := json.Unmarshal(body, &recipientResponse); err != nil {