diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4cebe746..0dd4a3d5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -205,6 +205,7 @@ jobs: HONEYCOMB_API_KEY: ${{ secrets.HONEYCOMB_API_KEY }} SENTRY_DSN: ${{ secrets.SENTRY_DSN }} SEGMENT_API_KEY: ${{ secrets.SEGMENT_API_KEY }} + INTERCOM_HMAC_KEY: ${{ secrets.INTERCOM_HMAC_KEY }} run: GOOS=linux GOARCH=amd64 make build - uses: actions/upload-artifact@v3 @@ -244,6 +245,7 @@ jobs: HONEYCOMB_API_KEY: ${{ secrets.HONEYCOMB_API_KEY }} SENTRY_DSN: ${{ secrets.SENTRY_DSN }} SEGMENT_API_KEY: ${{ secrets.SEGMENT_API_KEY }} + INTERCOM_HMAC_KEY: ${{ secrets.INTERCOM_HMAC_KEY }} run: GOOS=linux GOARCH=arm64 make build - uses: actions/upload-artifact@v3 diff --git a/Makefile b/Makefile index fb775f74..f536431a 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,8 @@ LDFLAGS := "-s -w \ -X github.com/hoophq/hoop/common/version.buildDate=${DATE} \ -X github.com/hoophq/hoop/common/monitoring.honeycombApiKey=${HONEYCOMB_API_KEY} \ -X github.com/hoophq/hoop/common/monitoring.sentryDSN=${SENTRY_DSN} \ --X github.com/hoophq/hoop/gateway/analytics.segmentApiKey=${SEGMENT_API_KEY}" +-X github.com/hoophq/hoop/gateway/analytics.segmentApiKey=${SEGMENT_API_KEY} \ +-X github.com/hoophq/hoop/gateway/analytics.intercomHmacKey=${INTERCOM_HMAC_KEY}" postgrest-link: echo https://github.com/PostgREST/postgrest/releases/download/v11.2.2/postgrest-v11.2.2-${POSTREST_ARCH_SUFFIX} diff --git a/gateway/analytics/intercom.go b/gateway/analytics/intercom.go new file mode 100644 index 00000000..d29d6e06 --- /dev/null +++ b/gateway/analytics/intercom.go @@ -0,0 +1,21 @@ +package analytics + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + "fmt" +) + +// https://www.intercom.com/help/en/articles/183-set-up-identity-verification-for-web-and-mobile +func GenerateIntercomHmacDigest(email string) (string, error) { + key := []byte(intercomHmacKey) + message := []byte(email) + hash := hmac.New(sha256.New, key) + if _, err := hash.Write(message); err != nil { + return "", fmt.Errorf("failed generating hmac signature for %v, hmac-key-length=%v, reason=%v", + email, len(intercomHmacKey), err) + } + sha := hash.Sum(nil) + return hex.EncodeToString(sha), nil +} diff --git a/gateway/analytics/runtime.go b/gateway/analytics/runtime.go index 278deec9..9820bc41 100644 --- a/gateway/analytics/runtime.go +++ b/gateway/analytics/runtime.go @@ -1,3 +1,6 @@ package analytics -var segmentApiKey string +var ( + segmentApiKey string + intercomHmacKey string +) diff --git a/gateway/api/openapi/types.go b/gateway/api/openapi/types.go index 8bfc5d01..976b6a8e 100644 --- a/gateway/api/openapi/types.go +++ b/gateway/api/openapi/types.go @@ -101,7 +101,8 @@ type UserInfo struct { // Enable or disable Webapp users management // * on - Enable the users management view on Webapp // * on - Disable the users management view on Webapp - WebAppUsersManagement string `json:"webapp_users_management" enums:"on,off" default:"on"` + WebAppUsersManagement string `json:"webapp_users_management" enums:"on,off" default:"on"` + IntercomUserHmacDigest string `json:"intercom_hmac_digest"` } type ServiceAccountStatusType string diff --git a/gateway/api/user/user.go b/gateway/api/user/user.go index dd914d6e..eb16449d 100644 --- a/gateway/api/user/user.go +++ b/gateway/api/user/user.go @@ -446,6 +446,11 @@ func GetUserInfo(c *gin.Context) { case ctx.IsAuditorUser(): roleName = openapi.RoleAuditorType } + + intercomUserHash, err := analytics.GenerateIntercomHmacDigest(ctx.UserEmail) + if err != nil { + log.Warn(err) + } userInfoData := openapi.UserInfo{ User: openapi.User{ ID: ctx.UserID, @@ -458,16 +463,19 @@ func GetUserInfo(c *gin.Context) { SlackID: ctx.SlackID, Groups: groupList, }, - IsAdmin: ctx.IsAdminUser(), // DEPRECATED in flavor of role (admin) - IsMultitenant: isOrgMultiTenant, // DEPRECATED is flavor of tenancy_type - TenancyType: tenancyType, - OrgID: ctx.OrgID, - OrgName: ctx.OrgName, - OrgLicense: ctx.OrgLicense, - FeatureAskAI: askAIFeatureStatus, - WebAppUsersManagement: appconfig.Get().WebappUsersManagement(), + IsAdmin: ctx.IsAdminUser(), // DEPRECATED in flavor of role (admin) + IsMultitenant: isOrgMultiTenant, // DEPRECATED is flavor of tenancy_type + TenancyType: tenancyType, + OrgID: ctx.OrgID, + OrgName: ctx.OrgName, + OrgLicense: ctx.OrgLicense, + FeatureAskAI: askAIFeatureStatus, + WebAppUsersManagement: appconfig.Get().WebappUsersManagement(), + IntercomUserHmacDigest: intercomUserHash, } if ctx.IsAnonymous() { + intercomUserHash, _ := analytics.GenerateIntercomHmacDigest(ctx.UserAnonEmail) + userInfoData.IntercomUserHmacDigest = intercomUserHash userInfoData.Verified = false userInfoData.Email = ctx.UserAnonEmail userInfoData.Name = ctx.UserAnonProfile diff --git a/webapp/src/webapp/events.cljs b/webapp/src/webapp/events.cljs index b78e6557..6128601d 100644 --- a/webapp/src/webapp/events.cljs +++ b/webapp/src/webapp/events.cljs @@ -116,7 +116,10 @@ [{:keys [db]} [_ user]] (js/window.Intercom "boot" - (clj->js {:app_id "ryuapdmp" + (clj->js {:api_base "https://api-iam.intercom.io" + :app_id "ryuapdmp" :name (:name user) - :email (:email user)})) + :email (:email user) + :user_id (:email user) + :user_hash (:intercom_hmac_digest user)})) {}))