diff --git a/pkg/coredata/slack_message.go b/pkg/coredata/slack_message.go index b987eac6b..8d99d8d48 100644 --- a/pkg/coredata/slack_message.go +++ b/pkg/coredata/slack_message.go @@ -92,6 +92,8 @@ INSERT INTO slack_messages ( requester_email, metadata, initial_slack_message_id, + message_ts, + channel_id, created_at, updated_at ) @@ -104,6 +106,8 @@ VALUES ( @requester_email, @metadata, @initial_slack_message_id, + @message_ts, + @channel_id, @created_at, @updated_at ) @@ -118,6 +122,8 @@ VALUES ( "requester_email": s.RequesterEmail, "metadata": s.Metadata, "initial_slack_message_id": s.InitialSlackMessageID, + "message_ts": s.MessageTS, + "channel_id": s.ChannelID, "created_at": s.CreatedAt, "updated_at": s.UpdatedAt, } diff --git a/pkg/probo/service.go b/pkg/probo/service.go index 28bc68371..762768b99 100644 --- a/pkg/probo/service.go +++ b/pkg/probo/service.go @@ -33,6 +33,7 @@ import ( "go.probo.inc/probo/pkg/filevalidation" "go.probo.inc/probo/pkg/gid" "go.probo.inc/probo/pkg/html2pdf" + "go.probo.inc/probo/pkg/slack" ) const ( @@ -68,6 +69,7 @@ type ( auth *auth.Service authz *authz.Service logger *log.Logger + slack *slack.Service } TenantService struct { @@ -113,6 +115,7 @@ type ( ProcessingActivities *ProcessingActivityService Files *FileService CustomDomains *CustomDomainService + Slack *slack.TenantService } ) @@ -132,6 +135,7 @@ func NewService( authService *auth.Service, authzService *authz.Service, logger *log.Logger, + slackService *slack.Service, ) (*Service, error) { if bucket == "" { return nil, fmt.Errorf("bucket is required") @@ -152,6 +156,7 @@ func NewService( auth: authService, authz: authzService, logger: logger, + slack: slackService, } return svc, nil @@ -169,6 +174,7 @@ func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService { trustConfig: s.trustConfig, agent: agents.NewAgent(nil, s.agentConfig), fileManager: s.fileManager, + Slack: s.slack.WithTenant(tenantID), } tenantService.Frameworks = &FrameworkService{ diff --git a/pkg/probo/trust_center_access_service.go b/pkg/probo/trust_center_access_service.go index 5372c3be1..c9e4e63e3 100644 --- a/pkg/probo/trust_center_access_service.go +++ b/pkg/probo/trust_center_access_service.go @@ -273,6 +273,8 @@ func (s TrustCenterAccessService) Update( now := time.Now() var access *coredata.TrustCenterAccess + var trustCenterAcessActivated bool + var shouldUpdateSlackMessage bool err := s.svc.pg.WithTx( ctx, func(tx pg.Conn) error { @@ -282,7 +284,7 @@ func (s TrustCenterAccessService) Update( return fmt.Errorf("cannot load trust center access: %w", err) } - shouldSendEmail := req.Active != nil && *req.Active && !access.Active + trustCenterAcessActivated = req.Active != nil && *req.Active && !access.Active if req.Name != nil { access.Name = *req.Name } @@ -339,12 +341,18 @@ func (s TrustCenterAccessService) Update( } } - if shouldSendEmail { + if trustCenterAcessActivated { if err := s.sendAccessEmail(ctx, tx, access); err != nil { return fmt.Errorf("cannot send access email: %w", err) } } + shouldUpdateSlackMessage = trustCenterAcessActivated || + len(req.DocumentAccesses) > 0 || + len(req.ReportAccesses) > 0 || + len(req.TrustCenterFileAccesses) > 0 || + req.Name != nil + return nil }, ) @@ -353,6 +361,12 @@ func (s TrustCenterAccessService) Update( return nil, err } + if shouldUpdateSlackMessage { + if err := s.svc.Slack.GetSlackMessageService().QueueSlackAccessMessageUpdate(ctx, access.Email, access.TrustCenterID); err != nil { + return nil, fmt.Errorf("cannot queue slack access message update: %w", err) + } + } + return access, nil } diff --git a/pkg/probod/probod.go b/pkg/probod/probod.go index d1c9177c7..5339d1738 100644 --- a/pkg/probod/probod.go +++ b/pkg/probod/probod.go @@ -342,6 +342,15 @@ func (impl *Implm) Run( return fmt.Errorf("cannot initialize ACME service: %w", err) } + slackService := slack.NewService( + pgClient, + impl.cfg.GetSlackSigningSecret(), + impl.cfg.BaseURL.String(), + impl.cfg.EncryptionKey, + impl.cfg.Auth.Cookie.Secret, + l.Named("slack"), + ) + proboService, err := probo.NewService( ctx, impl.cfg.EncryptionKey, @@ -358,6 +367,7 @@ func (impl *Implm) Run( authService, authzService, l.Named("probo"), + slackService, ) if err != nil { return fmt.Errorf("cannot create probo service: %w", err) @@ -370,7 +380,6 @@ func (impl *Implm) Run( impl.cfg.BaseURL.String(), impl.cfg.EncryptionKey, impl.cfg.TrustAuth.TokenSecret, - impl.cfg.GetSlackSigningSecret(), authService, html2pdfConverter, fileManagerService, @@ -380,6 +389,7 @@ func (impl *Implm) Run( TokenDuration: time.Duration(impl.cfg.TrustAuth.TokenDuration) * time.Hour, TokenType: impl.cfg.TrustAuth.TokenType, }, + slackService, ) serverHandler, err := server.NewServer( @@ -390,6 +400,7 @@ func (impl *Implm) Run( Auth: authService, Authz: authzService, Trust: trustService, + Slack: slackService, SAML: samlService, ConnectorRegistry: defaultConnectorRegistry, Agent: agent, diff --git a/pkg/server/api/api.go b/pkg/server/api/api.go index 14119ddfb..c64b117c0 100644 --- a/pkg/server/api/api.go +++ b/pkg/server/api/api.go @@ -31,7 +31,9 @@ import ( "go.probo.inc/probo/pkg/saferedirect" console_v1 "go.probo.inc/probo/pkg/server/api/console/v1" mcp_v1 "go.probo.inc/probo/pkg/server/api/mcp/v1" + slack_v1 "go.probo.inc/probo/pkg/server/api/slack/v1" trust_v1 "go.probo.inc/probo/pkg/server/api/trust/v1" + "go.probo.inc/probo/pkg/slack" "go.probo.inc/probo/pkg/trust" ) @@ -62,6 +64,7 @@ type ( Auth *auth.Service Authz *authz.Service Trust *trust.Service + Slack *slack.Service SAML *auth.SAMLService ConsoleAuth ConsoleAuthConfig TrustAuth TrustAuthConfig @@ -83,6 +86,7 @@ type ( trustAPIHandler http.Handler consoleAPIHandler http.Handler mcpAPIHandler http.Handler + slackAPIHandler http.Handler } ) @@ -157,6 +161,7 @@ func NewServer(cfg Config) (*Server, error) { TokenType: cfg.TrustAuth.TokenType, CookieSecure: cfg.TrustAuth.CookieSecure, }, + cfg.Slack, ) consoleAPIHandler := console_v1.NewMux( @@ -189,11 +194,18 @@ func NewServer(cfg Config) (*Server, error) { }, ) + slackAPIHandler := slack_v1.NewMux( + cfg.Logger.Named("slack.v1"), + cfg.Slack, + cfg.Trust, + ) + return &Server{ cfg: cfg, trustAPIHandler: trustAPIHandler, consoleAPIHandler: consoleAPIHandler, mcpAPIHandler: mcpAPIHandler, + slackAPIHandler: slackAPIHandler, }, nil } @@ -229,6 +241,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { router.Mount("/console/v1", s.consoleAPIHandler) router.Mount("/trust/v1", s.trustAPIHandler) router.Mount("/mcp/v1", s.mcpAPIHandler) + router.Mount("/slack/v1", s.slackAPIHandler) router.ServeHTTP(w, r) } diff --git a/pkg/server/api/slack/v1/resolver.go b/pkg/server/api/slack/v1/resolver.go new file mode 100644 index 000000000..230d515ae --- /dev/null +++ b/pkg/server/api/slack/v1/resolver.go @@ -0,0 +1,26 @@ +package slack_v1 + +import ( + "github.com/go-chi/chi/v5" + "go.gearno.de/kit/log" + "go.probo.inc/probo/pkg/slack" + "go.probo.inc/probo/pkg/trust" +) + +func NewMux( + logger *log.Logger, + slackSvc *slack.Service, + trustSvc *trust.Service, +) *chi.Mux { + r := chi.NewMux() + logger.Info("Registering Slack interactive endpoint") + + r.Post("/interactive", SlackHandler( + slackSvc, + slackSvc.GetSlackSigningSecret(), + logger, + trustSvc, + )) + + return r +} diff --git a/pkg/server/api/trust/v1/slack_handler.go b/pkg/server/api/slack/v1/slack_handler.go similarity index 94% rename from pkg/server/api/trust/v1/slack_handler.go rename to pkg/server/api/slack/v1/slack_handler.go index 249d57441..f9d5fd4d6 100644 --- a/pkg/server/api/trust/v1/slack_handler.go +++ b/pkg/server/api/slack/v1/slack_handler.go @@ -12,7 +12,7 @@ // OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -package trust_v1 +package slack_v1 import ( "bytes" @@ -57,7 +57,7 @@ const ( StatusReject = "reject" ) -func slackHandler(trustSvc *trust.Service, slackSigningSecret string, logger *log.Logger) http.HandlerFunc { +func SlackHandler(slackSvc *slack.Service, slackSigningSecret string, logger *log.Logger, trustSvc *trust.Service) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() @@ -132,7 +132,7 @@ func slackHandler(trustSvc *trust.Service, slackSigningSecret string, logger *lo return } - initialSlackMessage, err := trustSvc.GetInitialSlackMessageByChannelAndTS(ctx, slackPayload.Container.ChannelID, slackPayload.Container.MessageTS) + initialSlackMessage, err := slackSvc.GetInitialSlackMessageByChannelAndTS(ctx, slackPayload.Container.ChannelID, slackPayload.Container.MessageTS) if err != nil { logger.ErrorCtx(ctx, "cannot load slack message", log.Error(err)) httpserver.RenderJSON(w, http.StatusInternalServerError, SlackInteractiveResponse{Success: false, Message: "internal server error"}) @@ -168,7 +168,7 @@ func slackHandler(trustSvc *trust.Service, slackSigningSecret string, logger *lo return } - documentIDs, reportIDs, fileIDs, err = tenantSvc.SlackMessages.GetSlackMessageDocumentIDs(ctx, currentMessageId) + documentIDs, reportIDs, fileIDs, err = slackSvc.WithTenant(initialSlackMessage.OrganizationID.TenantID()).GetSlackMessageService().GetSlackMessageDocumentIDs(ctx, currentMessageId) if err != nil { logger.ErrorCtx(ctx, "cannot load slack message document ids", log.Error(err)) httpserver.RenderJSON(w, http.StatusInternalServerError, SlackInteractiveResponse{Success: false, Message: "internal server error"}) @@ -261,7 +261,7 @@ func slackHandler(trustSvc *trust.Service, slackSigningSecret string, logger *lo return } - if err := tenantSvc.SlackMessages.UpdateSlackAccessMessage( + if err := slackSvc.WithTenant(initialSlackMessage.OrganizationID.TenantID()).GetSlackMessageService().UpdateSlackAccessMessage( ctx, initialSlackMessage.ID, slackPayload.ResponseURL, diff --git a/pkg/server/api/trust/v1/resolver.go b/pkg/server/api/trust/v1/resolver.go index b3c1f1b87..75ac52477 100644 --- a/pkg/server/api/trust/v1/resolver.go +++ b/pkg/server/api/trust/v1/resolver.go @@ -34,10 +34,12 @@ import ( "go.probo.inc/probo/pkg/gid" "go.probo.inc/probo/pkg/probo" console_v1 "go.probo.inc/probo/pkg/server/api/console/v1" + slack_v1 "go.probo.inc/probo/pkg/server/api/slack/v1" "go.probo.inc/probo/pkg/server/api/trust/v1/schema" "go.probo.inc/probo/pkg/server/api/trust/v1/trustauth" "go.probo.inc/probo/pkg/server/gqlutils" "go.probo.inc/probo/pkg/server/session" + "go.probo.inc/probo/pkg/slack" "go.probo.inc/probo/pkg/statelesstoken" "go.probo.inc/probo/pkg/trust" ) @@ -103,6 +105,9 @@ func NewMux( trustSvc *trust.Service, authCfg console_v1.AuthConfig, trustAuthCfg TrustAuthConfig, + + // TODO: Remove this after successful migration to /slack/v1. + slackSvc *slack.Service, ) *chi.Mux { r := chi.NewMux() @@ -111,7 +116,9 @@ func NewMux( r.Post("/auth/authenticate", authTokenHandler(trustSvc, trustAuthCfg)) r.Delete("/auth/logout", trustCenterLogoutHandler(authCfg, trustAuthCfg)) - r.Post("/slack", slackHandler(trustSvc, trustSvc.GetSlackSigningSecret(), logger)) + // Backward compatibility: support old /trust/v1/slack endpoint + // TODO: Remove this after successful migration to /slack/v1 and then make SlackHandler PRIVATE in slack_v1 package. + r.Post("/slack", slack_v1.SlackHandler(slackSvc, slackSvc.GetSlackSigningSecret(), logger, trustSvc)) return r } diff --git a/pkg/server/server.go b/pkg/server/server.go index 3ff09e3e3..1eca612d4 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -38,6 +38,7 @@ import ( authz_server "go.probo.inc/probo/pkg/server/authz" "go.probo.inc/probo/pkg/server/trust" "go.probo.inc/probo/pkg/server/web" + "go.probo.inc/probo/pkg/slack" trust_pkg "go.probo.inc/probo/pkg/trust" ) @@ -48,6 +49,7 @@ type Config struct { Auth *auth.Service Authz *authz.Service Trust *trust_pkg.Service + Slack *slack.Service SAML *auth.SAMLService ConsoleAuth api.ConsoleAuthConfig TrustAuth api.TrustAuthConfig @@ -80,6 +82,7 @@ func NewServer(cfg Config) (*Server, error) { Auth: cfg.Auth, Authz: cfg.Authz, Trust: cfg.Trust, + Slack: cfg.Slack, SAML: cfg.SAML, ConsoleAuth: cfg.ConsoleAuth, TrustAuth: cfg.TrustAuth, diff --git a/pkg/slack/connector_config.go b/pkg/slack/connector_config.go new file mode 100644 index 000000000..f0f9d0aa6 --- /dev/null +++ b/pkg/slack/connector_config.go @@ -0,0 +1,31 @@ +package slack + +import ( + "encoding/json" + "strings" + "text/template" +) + +var ( + accessRequestTemplate = template.Must( + template.New("access-request.json.tmpl"). + Funcs(template.FuncMap{ + "jsonEscape": func(s string) string { + b, _ := json.Marshal(s) + return string(b[1 : len(b)-1]) + }, + "buildAcceptAllValue": func(docIDs, repIDs []string) string { + value := map[string][]string{ + "document_ids": docIDs, + "report_ids": repIDs, + } + b, _ := json.Marshal(value) + s := string(b) + s = strings.ReplaceAll(s, `\`, `\\`) + s = strings.ReplaceAll(s, `"`, `\"`) + return s + }, + }). + ParseFS(Templates, "templates/access-request.json.tmpl"), + ) +) diff --git a/pkg/slack/service.go b/pkg/slack/service.go new file mode 100644 index 000000000..958fb8902 --- /dev/null +++ b/pkg/slack/service.go @@ -0,0 +1,95 @@ +package slack + +import ( + "context" + "fmt" + + "go.gearno.de/kit/log" + "go.gearno.de/kit/pg" + "go.probo.inc/probo/pkg/coredata" + "go.probo.inc/probo/pkg/crypto/cipher" + "go.probo.inc/probo/pkg/gid" +) + +type Service struct { + pg *pg.Client + logger *log.Logger + slackSigningSecret string + baseURL string + encryptionKey cipher.EncryptionKey + tokenSecret string +} + +type TenantService struct { + pg *pg.Client + scope coredata.Scoper + logger *log.Logger + baseURL string + encryptionKey cipher.EncryptionKey + tokenSecret string +} + +func NewService( + pg *pg.Client, + slackSigningSecret string, + baseURL string, + encryptionKey cipher.EncryptionKey, + tokenSecret string, + logger *log.Logger, +) *Service { + return &Service{ + pg: pg, + logger: logger, + slackSigningSecret: slackSigningSecret, + baseURL: baseURL, + encryptionKey: encryptionKey, + tokenSecret: tokenSecret, + } +} + +func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService { + tenantService := &TenantService{ + pg: s.pg, + scope: coredata.NewScope(tenantID), + logger: s.logger, + baseURL: s.baseURL, + encryptionKey: s.encryptionKey, + tokenSecret: s.tokenSecret, + } + + return tenantService +} + +func (s *TenantService) GetSlackClient() *Client { + return NewClient(s.logger) +} + +func (s *TenantService) GetSlackMessageService() *SlackMessageService { + return &SlackMessageService{svc: s} +} + +func (s *Service) GetSlackSigningSecret() string { + return s.slackSigningSecret +} + +func (s *Service) GetInitialSlackMessageByChannelAndTS( + ctx context.Context, + channelID string, + messageTS string, +) (*coredata.SlackMessage, error) { + var slackMessage coredata.SlackMessage + + err := s.pg.WithConn(ctx, func(conn pg.Conn) error { + if err := slackMessage.LoadInitialByChannelAndTS(ctx, conn, coredata.NewNoScope(), channelID, messageTS); err != nil { + return fmt.Errorf("cannot load slack message: %w", err) + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &slackMessage, nil +} diff --git a/pkg/trust/slack_message_service.go b/pkg/slack/slack_message_service.go similarity index 80% rename from pkg/trust/slack_message_service.go rename to pkg/slack/slack_message_service.go index 5f1668cf8..9d4c39650 100644 --- a/pkg/trust/slack_message_service.go +++ b/pkg/slack/slack_message_service.go @@ -12,7 +12,7 @@ // OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -package trust +package slack import ( "bytes" @@ -26,7 +26,6 @@ import ( "go.probo.inc/probo/pkg/baseurl" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/gid" - "go.probo.inc/probo/pkg/slack" ) const ( @@ -35,8 +34,7 @@ const ( type ( SlackMessageService struct { - svc *TenantService - slackClient *slack.Client + svc *TenantService } SlackMessageDocument struct { @@ -74,28 +72,6 @@ func (m SlackMessageMetadata) toMap() map[string]any { } } -func (s *Service) GetInitialSlackMessageByChannelAndTS( - ctx context.Context, - channelID string, - messageTS string, -) (*coredata.SlackMessage, error) { - var slackMessage coredata.SlackMessage - - err := s.pg.WithConn(ctx, func(conn pg.Conn) error { - if err := slackMessage.LoadInitialByChannelAndTS(ctx, conn, coredata.NewNoScope(), channelID, messageTS); err != nil { - return fmt.Errorf("cannot load slack message: %w", err) - } - - return nil - }) - - if err != nil { - return nil, err - } - - return &slackMessage, nil -} - func (s *SlackMessageService) GetSlackMessageDocumentIDs( ctx context.Context, slackMessageID gid.GID, @@ -132,7 +108,6 @@ func (s *SlackMessageService) UpdateSlackAccessMessage( if err := slackMessage.LoadById(ctx, tx, s.svc.scope, slackMessageID); err != nil { return fmt.Errorf("cannot load slack message: %w", err) } - var trustCenter coredata.TrustCenter if err := trustCenter.LoadByOrganizationID(ctx, tx, s.svc.scope, slackMessage.OrganizationID); err != nil { return fmt.Errorf("cannot load trust center: %w", err) @@ -189,7 +164,7 @@ func (s *SlackMessageService) UpdateSlackAccessMessage( return fmt.Errorf("cannot insert slack message: %w", err) } - if err := s.slackClient.UpdateInteractiveMessage(ctx, responseURL, updatedBody); err != nil { + if err := s.svc.GetSlackClient().UpdateInteractiveMessage(ctx, responseURL, updatedBody); err != nil { return fmt.Errorf("cannot update Slack message: %w", err) } @@ -310,6 +285,102 @@ func (s *SlackMessageService) QueueSlackNotification( }) } +func (s *SlackMessageService) QueueSlackAccessMessageUpdate( + ctx context.Context, + requesterEmail string, + trustCenterID gid.GID, +) error { + return s.svc.pg.WithTx(ctx, func(tx pg.Conn) error { + var trustCenter coredata.TrustCenter + if err := trustCenter.LoadByID(ctx, tx, s.svc.scope, trustCenterID); err != nil { + return fmt.Errorf("cannot load trust center: %w", err) + } + + var trustCenterAccess coredata.TrustCenterAccess + if err := trustCenterAccess.LoadByTrustCenterIDAndEmail(ctx, tx, s.svc.scope, trustCenterID, requesterEmail); err != nil { + return fmt.Errorf("cannot load trust center access: %w", err) + } + + var existingMessage coredata.SlackMessage + err := existingMessage.LoadLatestByRequesterEmailAndType( + ctx, + tx, + s.svc.scope, + trustCenter.OrganizationID, + requesterEmail, + coredata.SlackMessageTypeTrustCenterAccessRequest, + time.Time{}, + ) + if err != nil { + var notFoundErr coredata.ErrSlackMessageNotFound + if errors.Is(err, notFoundErr) { + return nil + } + return fmt.Errorf("cannot load existing slack message: %w", err) + } + + if existingMessage.MessageTS == nil || existingMessage.ChannelID == nil { + return nil + } + + if existingMessage.ID != existingMessage.InitialSlackMessageID { + var originalMessage coredata.SlackMessage + if err := originalMessage.LoadById(ctx, tx, s.svc.scope, existingMessage.InitialSlackMessageID); err != nil { + return nil + } + existingMessage = originalMessage + } + + documents, reports, files, err := s.loadDocumentsReportsAndFilesFromAccesses(ctx, tx, trustCenterAccess.ID) + if err != nil { + return fmt.Errorf("cannot load documents, reports and files: %w", err) + } + + newSlackMessageID := gid.New(s.svc.scope.GetTenantID(), coredata.SlackMessageEntityType) + + updatedBody, err := s.buildAccessRequestMessage( + newSlackMessageID, + trustCenterAccess.Name, + requesterEmail, + trustCenter.OrganizationID, + documents, + reports, + files, + ) + if err != nil { + return fmt.Errorf("cannot build access request message: %w", err) + } + + metadata := SlackMessageMetadata{ + Documents: documents, + Reports: reports, + Files: files, + } + + now := time.Now() + newSlackMessage := &coredata.SlackMessage{ + ID: newSlackMessageID, + OrganizationID: existingMessage.OrganizationID, + Type: existingMessage.Type, + Body: updatedBody, + MessageTS: existingMessage.MessageTS, + ChannelID: existingMessage.ChannelID, + RequesterEmail: existingMessage.RequesterEmail, + Metadata: metadata.toMap(), + InitialSlackMessageID: existingMessage.InitialSlackMessageID, + CreatedAt: now, + UpdatedAt: now, + SentAt: nil, + } + + if err := newSlackMessage.Insert(ctx, tx, s.svc.scope); err != nil { + return fmt.Errorf("cannot insert slack message: %w", err) + } + + return nil + }) +} + func (s *SlackMessageService) loadDocumentsReportsAndFilesFromAccesses( ctx context.Context, conn pg.Conn, diff --git a/pkg/trust/templates.go b/pkg/slack/templates.go similarity index 98% rename from pkg/trust/templates.go rename to pkg/slack/templates.go index 50d69af4d..905130387 100644 --- a/pkg/trust/templates.go +++ b/pkg/slack/templates.go @@ -12,7 +12,7 @@ // OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -package trust +package slack import ( "embed" diff --git a/pkg/trust/templates/access-request.json.tmpl b/pkg/slack/templates/access-request.json.tmpl similarity index 100% rename from pkg/trust/templates/access-request.json.tmpl rename to pkg/slack/templates/access-request.json.tmpl diff --git a/pkg/trust/service.go b/pkg/trust/service.go index 5960d4696..dacced9ea 100644 --- a/pkg/trust/service.go +++ b/pkg/trust/service.go @@ -18,6 +18,8 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/service/s3" + "go.gearno.de/kit/log" + "go.gearno.de/kit/pg" "go.probo.inc/probo/pkg/auth" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/crypto/cipher" @@ -26,8 +28,6 @@ import ( "go.probo.inc/probo/pkg/html2pdf" "go.probo.inc/probo/pkg/probo" "go.probo.inc/probo/pkg/slack" - "go.gearno.de/kit/log" - "go.gearno.de/kit/pg" ) type ( @@ -38,19 +38,19 @@ type ( } Service struct { - pg *pg.Client - s3 *s3.Client - bucket string - proboSvc *probo.Service - encryptionKey cipher.EncryptionKey - tokenSecret string - slackSigningSecret string - baseURL string - auth *auth.Service - html2pdfConverter *html2pdf.Converter - fileManager *filemanager.Service - logger *log.Logger - trustConfig TrustConfig + pg *pg.Client + s3 *s3.Client + bucket string + proboSvc *probo.Service + encryptionKey cipher.EncryptionKey + tokenSecret string + baseURL string + auth *auth.Service + html2pdfConverter *html2pdf.Converter + fileManager *filemanager.Service + logger *log.Logger + trustConfig TrustConfig + slack *slack.Service } TenantService struct { @@ -77,7 +77,7 @@ type ( TrustCenterFiles *TrustCenterFileService Reports *ReportService Organizations *OrganizationService - SlackMessages *SlackMessageService + slack *slack.TenantService } ) @@ -88,26 +88,26 @@ func NewService( baseURL string, encryptionKey cipher.EncryptionKey, tokenSecret string, - slackSigningSecret string, auth *auth.Service, html2pdfConverter *html2pdf.Converter, fileManagerService *filemanager.Service, logger *log.Logger, trustConfig TrustConfig, + slack *slack.Service, ) *Service { return &Service{ - pg: pgClient, - s3: s3Client, - bucket: bucket, - encryptionKey: encryptionKey, - tokenSecret: tokenSecret, - slackSigningSecret: slackSigningSecret, - baseURL: baseURL, - auth: auth, - html2pdfConverter: html2pdfConverter, - fileManager: fileManagerService, - logger: logger, - trustConfig: trustConfig, + pg: pgClient, + s3: s3Client, + bucket: bucket, + encryptionKey: encryptionKey, + tokenSecret: tokenSecret, + baseURL: baseURL, + auth: auth, + html2pdfConverter: html2pdfConverter, + fileManager: fileManagerService, + logger: logger, + trustConfig: trustConfig, + slack: slack, } } @@ -126,10 +126,9 @@ func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService { fileManager: s.fileManager, logger: s.logger, trustConfig: s.trustConfig, + slack: s.slack.WithTenant(tenantID), } - slackClient := slack.NewClient(s.logger) - tenantService.TrustCenters = &TrustCenterService{svc: tenantService} tenantService.Documents = &DocumentService{svc: tenantService, html2pdfConverter: s.html2pdfConverter} tenantService.Audits = &AuditService{svc: tenantService} @@ -140,7 +139,6 @@ func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService { tenantService.TrustCenterFiles = &TrustCenterFileService{svc: tenantService} tenantService.Reports = &ReportService{svc: tenantService} tenantService.Organizations = &OrganizationService{svc: tenantService} - tenantService.SlackMessages = &SlackMessageService{svc: tenantService, slackClient: slackClient} return tenantService } @@ -148,7 +146,3 @@ func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService { func (s *Service) GetTokenSecret() string { return s.tokenSecret } - -func (s *Service) GetSlackSigningSecret() string { - return s.slackSigningSecret -} diff --git a/pkg/trust/trust_center_access_service.go b/pkg/trust/trust_center_access_service.go index 74b321593..389ff9b81 100644 --- a/pkg/trust/trust_center_access_service.go +++ b/pkg/trust/trust_center_access_service.go @@ -21,8 +21,6 @@ import ( "fmt" "net/mail" "net/url" - "strings" - "text/template" "time" "go.gearno.de/kit/log" @@ -35,30 +33,6 @@ import ( "go.probo.inc/probo/pkg/statelesstoken" ) -var ( - accessRequestTemplate = template.Must( - template.New("access-request.json.tmpl"). - Funcs(template.FuncMap{ - "jsonEscape": func(s string) string { - b, _ := json.Marshal(s) - return string(b[1 : len(b)-1]) - }, - "buildAcceptAllValue": func(docIDs, repIDs []string) string { - value := map[string][]string{ - "document_ids": docIDs, - "report_ids": repIDs, - } - b, _ := json.Marshal(value) - s := string(b) - s = strings.ReplaceAll(s, `\`, `\\`) - s = strings.ReplaceAll(s, `"`, `\"`) - return s - }, - }). - ParseFS(Templates, "templates/access-request.json.tmpl"), - ) -) - type ( TrustCenterAccessService struct { svc *TenantService @@ -258,7 +232,8 @@ func (s TrustCenterAccessService) Request( return nil, err } - if err := s.svc.SlackMessages.QueueSlackNotification(ctx, access.Email, req.TrustCenterID); err != nil { + slackMessageService := s.svc.slack.GetSlackMessageService() + if err := slackMessageService.QueueSlackNotification(ctx, access.Email, req.TrustCenterID); err != nil { s.logger.ErrorCtx(ctx, "cannot queue slack notification", log.Error(err)) }