121 lines
4.6 KiB
Go
121 lines
4.6 KiB
Go
package v1
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/golang-jwt/jwt/v5"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func setupEmailOAuthAuthorizationRouter() *gin.Engine {
|
|
gin.SetMode(gin.TestMode)
|
|
r := gin.New()
|
|
r.RedirectTrailingSlash = false
|
|
googleHandler := NewGoogleChannelHandler(nil, nil, nil, nil)
|
|
microsoftHandler := NewMicrosoftChannelHandler(nil, nil, nil, nil)
|
|
r.POST("/api/v1/accounts/:account_id/google/authorization", googleHandler.ChatwootAuthorization)
|
|
r.POST("/api/v1/accounts/:account_id/microsoft/authorization", microsoftHandler.ChatwootAuthorization)
|
|
return r
|
|
}
|
|
|
|
func TestGoogleAuthorization_ReturnsChatwootPayload(t *testing.T) {
|
|
t.Setenv("GOOGLE_OAUTH_CLIENT_ID", "google-client")
|
|
t.Setenv("GOOGLE_OAUTH_CLIENT_SECRET", "google-secret")
|
|
t.Setenv("FRONTEND_URL", "https://app.example.test/")
|
|
|
|
r := setupEmailOAuthAuthorizationRouter()
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest(http.MethodPost, "/api/v1/accounts/42/google/authorization", strings.NewReader(`{"email":"agent@example.test"}`))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
r.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
var resp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
assert.Equal(t, true, resp["success"])
|
|
|
|
parsed, err := url.Parse(resp["url"].(string))
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "https://accounts.google.com/o/oauth2/auth", parsed.Scheme+"://"+parsed.Host+parsed.Path)
|
|
query := parsed.Query()
|
|
assert.Equal(t, "google-client", query.Get("client_id"))
|
|
assert.Equal(t, "https://app.example.test/google/callback", query.Get("redirect_uri"))
|
|
assert.Equal(t, "email profile https://mail.google.com/", query.Get("scope"))
|
|
assert.Equal(t, "code", query.Get("response_type"))
|
|
assert.Equal(t, "consent", query.Get("prompt"))
|
|
assert.Equal(t, "offline", query.Get("access_type"))
|
|
assertSignedAccountState(t, query.Get("state"), "google-secret", 42)
|
|
}
|
|
|
|
func TestMicrosoftAuthorization_ReturnsChatwootPayload(t *testing.T) {
|
|
t.Setenv("AZURE_APP_ID", "azure-client")
|
|
t.Setenv("AZURE_APP_SECRET", "azure-secret")
|
|
t.Setenv("FRONTEND_URL", "https://app.example.test")
|
|
|
|
r := setupEmailOAuthAuthorizationRouter()
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest(http.MethodPost, "/api/v1/accounts/42/microsoft/authorization", nil)
|
|
r.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
var resp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
assert.Equal(t, true, resp["success"])
|
|
|
|
parsed, err := url.Parse(resp["url"].(string))
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "https://login.microsoftonline.com/common/oauth2/v2.0/authorize", parsed.Scheme+"://"+parsed.Host+parsed.Path)
|
|
query := parsed.Query()
|
|
assert.Equal(t, "azure-client", query.Get("client_id"))
|
|
assert.Equal(t, "https://app.example.test/microsoft/callback", query.Get("redirect_uri"))
|
|
assert.Equal(t, "offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send openid profile email", query.Get("scope"))
|
|
assert.Equal(t, "code", query.Get("response_type"))
|
|
assert.Empty(t, query.Get("prompt"))
|
|
assertSignedAccountState(t, query.Get("state"), "azure-secret", 42)
|
|
}
|
|
|
|
func TestEmailOAuthAuthorization_BadAccountID(t *testing.T) {
|
|
r := setupEmailOAuthAuthorizationRouter()
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest(http.MethodPost, "/api/v1/accounts/abc/google/authorization", nil)
|
|
r.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
|
var resp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
errBody := resp["error"].(map[string]interface{})
|
|
assert.Contains(t, errBody["message"], "invalid account_id")
|
|
}
|
|
|
|
func TestEmailOAuthAuthorization_NotConfigured(t *testing.T) {
|
|
t.Setenv("GOOGLE_OAUTH_CLIENT_ID", "")
|
|
t.Setenv("GOOGLE_OAUTH_CLIENT_SECRET", "")
|
|
r := setupEmailOAuthAuthorizationRouter()
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest(http.MethodPost, "/api/v1/accounts/42/google/authorization", nil)
|
|
r.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusUnprocessableEntity, w.Code)
|
|
var resp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
assert.Equal(t, false, resp["success"])
|
|
}
|
|
|
|
func assertSignedAccountState(t *testing.T, state string, secret string, accountID float64) {
|
|
t.Helper()
|
|
claims := jwt.MapClaims{}
|
|
token, err := jwt.ParseWithClaims(state, claims, func(token *jwt.Token) (any, error) {
|
|
return []byte(secret), nil
|
|
})
|
|
require.NoError(t, err)
|
|
require.True(t, token.Valid)
|
|
assert.Equal(t, accountID, claims["sub"])
|
|
}
|