Use stable files API URLs for vendor logo fields
CommonThirdParty.logoUrl and TrustCenterReference.logoUrl were
returning expiring S3 presigned URLs, which break if cached or
shared past their TTL.
Replace with stable /api/files/v1/{id} application URLs.
file.Service now generates these via baseurl; a new filesign
package owns presigning for the files/v1 HTTP handler that
does the internal redirect.
Signed-off-by: Ludovic Vielle <ludovic@probo.com>
This commit is contained in:
@@ -17,51 +17,42 @@ package file
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
|
|
||||||
"go.gearno.de/kit/pg"
|
"go.gearno.de/kit/pg"
|
||||||
|
"go.probo.inc/probo/pkg/baseurl"
|
||||||
"go.probo.inc/probo/pkg/coredata"
|
"go.probo.inc/probo/pkg/coredata"
|
||||||
"go.probo.inc/probo/pkg/filemanager"
|
|
||||||
"go.probo.inc/probo/pkg/gid"
|
"go.probo.inc/probo/pkg/gid"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
pg *pg.Client
|
pg *pg.Client
|
||||||
fileManager *filemanager.Service
|
baseURL *baseurl.BaseURL
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(pgClient *pg.Client, fileManager *filemanager.Service) *Service {
|
func NewService(pgClient *pg.Client, baseURL *baseurl.BaseURL) *Service {
|
||||||
return &Service{
|
return &Service{
|
||||||
pg: pgClient,
|
pg: pgClient,
|
||||||
fileManager: fileManager,
|
baseURL: baseURL,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetPublicFileURL(
|
func (s *Service) GenerateFileURL(ctx context.Context, fileID gid.GID) (string, error) {
|
||||||
ctx context.Context,
|
|
||||||
fileID gid.GID,
|
|
||||||
expiresIn time.Duration,
|
|
||||||
) (string, error) {
|
|
||||||
file := &coredata.File{}
|
file := &coredata.File{}
|
||||||
|
|
||||||
err := s.pg.WithConn(
|
err := s.pg.WithConn(ctx, func(ctx context.Context, conn pg.Querier) error {
|
||||||
ctx,
|
|
||||||
func(ctx context.Context, conn pg.Querier) error {
|
|
||||||
if err := file.LoadPublicByID(ctx, conn, fileID); err != nil {
|
if err := file.LoadPublicByID(ctx, conn, fileID); err != nil {
|
||||||
return fmt.Errorf("cannot load public file: %w", err)
|
return fmt.Errorf("cannot load public file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
})
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
presignedURL, err := s.fileManager.GenerateFileUrl(ctx, file, expiresIn)
|
url, err := s.baseURL.AppendPath("/api/files/v1/" + fileID.String()).String()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("cannot generate file URL: %w", err)
|
return "", fmt.Errorf("cannot build file URL: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return presignedURL, nil
|
return url, nil
|
||||||
}
|
}
|
||||||
|
|||||||
62
pkg/filesign/service.go
Normal file
62
pkg/filesign/service.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
package filesign
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.gearno.de/kit/pg"
|
||||||
|
"go.probo.inc/probo/pkg/coredata"
|
||||||
|
"go.probo.inc/probo/pkg/filemanager"
|
||||||
|
"go.probo.inc/probo/pkg/gid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
pg *pg.Client
|
||||||
|
fileManager *filemanager.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(pgClient *pg.Client, fileManager *filemanager.Service) *Service {
|
||||||
|
return &Service{
|
||||||
|
pg: pgClient,
|
||||||
|
fileManager: fileManager,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GeneratePresignedFileURL returns a short-lived S3 presigned URL for a PUBLIC file.
|
||||||
|
// Prefer file.Service.GenerateFileURL in most cases — it returns a stable, cacheable
|
||||||
|
// application URL. Only use this when a direct S3 URL with a controlled TTL is required
|
||||||
|
// (e.g. the /api/files/v1 HTTP handler that issues the presign-on-redirect).
|
||||||
|
func (s *Service) GeneratePresignedFileURL(
|
||||||
|
ctx context.Context,
|
||||||
|
fileID gid.GID,
|
||||||
|
expiresIn time.Duration,
|
||||||
|
) (string, error) {
|
||||||
|
file := &coredata.File{}
|
||||||
|
|
||||||
|
err := s.pg.WithConn(ctx, func(ctx context.Context, conn pg.Querier) error {
|
||||||
|
if err := file.LoadPublicByID(ctx, conn, fileID); err != nil {
|
||||||
|
return fmt.Errorf("cannot load public file: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.fileManager.GenerateFileUrl(ctx, file, expiresIn)
|
||||||
|
}
|
||||||
@@ -27,6 +27,7 @@ import (
|
|||||||
"go.probo.inc/probo/pkg/coredata"
|
"go.probo.inc/probo/pkg/coredata"
|
||||||
"go.probo.inc/probo/pkg/crypto/cipher"
|
"go.probo.inc/probo/pkg/crypto/cipher"
|
||||||
"go.probo.inc/probo/pkg/esign"
|
"go.probo.inc/probo/pkg/esign"
|
||||||
|
"go.probo.inc/probo/pkg/file"
|
||||||
"go.probo.inc/probo/pkg/filemanager"
|
"go.probo.inc/probo/pkg/filemanager"
|
||||||
"go.probo.inc/probo/pkg/filevalidation"
|
"go.probo.inc/probo/pkg/filevalidation"
|
||||||
"go.probo.inc/probo/pkg/gid"
|
"go.probo.inc/probo/pkg/gid"
|
||||||
@@ -79,6 +80,7 @@ type (
|
|||||||
html2pdfConverter *html2pdf.Converter
|
html2pdfConverter *html2pdf.Converter
|
||||||
acmeService *certmanager.ACMEService
|
acmeService *certmanager.ACMEService
|
||||||
fileManager *filemanager.Service
|
fileManager *filemanager.Service
|
||||||
|
file *file.Service
|
||||||
logger *log.Logger
|
logger *log.Logger
|
||||||
slack *slack.Service
|
slack *slack.Service
|
||||||
esign *esign.Service
|
esign *esign.Service
|
||||||
@@ -144,6 +146,7 @@ func NewService(
|
|||||||
esignService *esign.Service,
|
esignService *esign.Service,
|
||||||
connectorRegistry *connector.ConnectorRegistry,
|
connectorRegistry *connector.ConnectorRegistry,
|
||||||
invitationTokenValidity time.Duration,
|
invitationTokenValidity time.Duration,
|
||||||
|
fileService *file.Service,
|
||||||
) (*Service, error) {
|
) (*Service, error) {
|
||||||
if bucket == "" {
|
if bucket == "" {
|
||||||
return nil, fmt.Errorf("bucket is required")
|
return nil, fmt.Errorf("bucket is required")
|
||||||
@@ -163,6 +166,7 @@ func NewService(
|
|||||||
html2pdfConverter: html2pdfConverter,
|
html2pdfConverter: html2pdfConverter,
|
||||||
acmeService: acmeService,
|
acmeService: acmeService,
|
||||||
fileManager: fileManagerService,
|
fileManager: fileManagerService,
|
||||||
|
file: fileService,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
slack: slackService,
|
slack: slackService,
|
||||||
esign: esignService,
|
esign: esignService,
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"mime"
|
"mime"
|
||||||
"net/url"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -293,49 +292,20 @@ func (s TrustCenterReferenceService) Delete(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s TrustCenterReferenceService) GenerateLogoURL(
|
func (s TrustCenterReferenceService) GenerateLogoURL(
|
||||||
ctx context.Context, scope coredata.Scoper,
|
ctx context.Context,
|
||||||
|
scope coredata.Scoper,
|
||||||
referenceID gid.GID,
|
referenceID gid.GID,
|
||||||
duration time.Duration,
|
|
||||||
) (string, error) {
|
) (string, error) {
|
||||||
reference := &coredata.TrustCenterReference{}
|
reference := &coredata.TrustCenterReference{}
|
||||||
file := &coredata.File{}
|
|
||||||
|
|
||||||
err := s.svc.pg.WithTx(ctx, func(ctx context.Context, tx pg.Tx) error {
|
err := s.svc.pg.WithTx(ctx, func(ctx context.Context, tx pg.Tx) error {
|
||||||
err := reference.LoadByID(ctx, tx, scope, referenceID)
|
return reference.LoadByID(ctx, tx, scope, referenceID)
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("cannot load trust center reference: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = file.LoadByID(ctx, tx, scope, reference.LogoFileID)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("cannot load logo file: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil
|
return "", fmt.Errorf("cannot load trust center reference: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
presignClient := s3.NewPresignClient(s.svc.s3)
|
return s.svc.file.GenerateFileURL(ctx, reference.LogoFileID)
|
||||||
|
|
||||||
encodedFilename := url.PathEscape(file.FileName)
|
|
||||||
contentDisposition := fmt.Sprintf("inline; filename=\"%s\"; filename*=UTF-8''%s",
|
|
||||||
encodedFilename, encodedFilename)
|
|
||||||
|
|
||||||
presignedReq, err := presignClient.PresignGetObject(ctx, &s3.GetObjectInput{
|
|
||||||
Bucket: new(s.svc.bucket),
|
|
||||||
Key: new(file.FileKey),
|
|
||||||
ResponseCacheControl: new("max-age=3600, public"),
|
|
||||||
ResponseContentDisposition: new(contentDisposition),
|
|
||||||
}, func(opts *s3.PresignOptions) {
|
|
||||||
opts.Expires = duration
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("cannot presign GetObject request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return presignedReq.URL, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s TrustCenterReferenceService) uploadLogoFile(
|
func (s TrustCenterReferenceService) uploadLogoFile(
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ import (
|
|||||||
"go.probo.inc/probo/pkg/evidencedescriber"
|
"go.probo.inc/probo/pkg/evidencedescriber"
|
||||||
"go.probo.inc/probo/pkg/file"
|
"go.probo.inc/probo/pkg/file"
|
||||||
"go.probo.inc/probo/pkg/filemanager"
|
"go.probo.inc/probo/pkg/filemanager"
|
||||||
|
"go.probo.inc/probo/pkg/filesign"
|
||||||
"go.probo.inc/probo/pkg/geoloc"
|
"go.probo.inc/probo/pkg/geoloc"
|
||||||
"go.probo.inc/probo/pkg/html2pdf"
|
"go.probo.inc/probo/pkg/html2pdf"
|
||||||
"go.probo.inc/probo/pkg/iam"
|
"go.probo.inc/probo/pkg/iam"
|
||||||
@@ -504,6 +505,9 @@ func (impl *Implm) Run(
|
|||||||
|
|
||||||
cookieBannerService := cookiebanner.NewService(pgClient, impl.cfg.Branding)
|
cookieBannerService := cookiebanner.NewService(pgClient, impl.cfg.Branding)
|
||||||
|
|
||||||
|
fileService := file.NewService(pgClient, baseURL)
|
||||||
|
filesignService := filesign.NewService(pgClient, fileManagerService)
|
||||||
|
|
||||||
proboService, err := probo.NewService(
|
proboService, err := probo.NewService(
|
||||||
ctx,
|
ctx,
|
||||||
encryptionKey,
|
encryptionKey,
|
||||||
@@ -527,6 +531,7 @@ func (impl *Implm) Run(
|
|||||||
esignService,
|
esignService,
|
||||||
defaultConnectorRegistry,
|
defaultConnectorRegistry,
|
||||||
time.Duration(impl.cfg.Auth.InvitationConfirmationTokenValidity)*time.Second,
|
time.Duration(impl.cfg.Auth.InvitationConfirmationTokenValidity)*time.Second,
|
||||||
|
fileService,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot create probo service: %w", err)
|
return fmt.Errorf("cannot create probo service: %w", err)
|
||||||
@@ -544,10 +549,9 @@ func (impl *Implm) Run(
|
|||||||
fileManagerService,
|
fileManagerService,
|
||||||
l,
|
l,
|
||||||
slackService,
|
slackService,
|
||||||
|
fileService,
|
||||||
)
|
)
|
||||||
|
|
||||||
fileService := file.NewService(pgClient, fileManagerService)
|
|
||||||
|
|
||||||
accessReviewService := accessreview.NewService(
|
accessReviewService := accessreview.NewService(
|
||||||
pgClient,
|
pgClient,
|
||||||
encryptionKey,
|
encryptionKey,
|
||||||
@@ -564,7 +568,7 @@ func (impl *Implm) Run(
|
|||||||
AllowedOrigins: impl.cfg.Api.Cors.AllowedOrigins,
|
AllowedOrigins: impl.cfg.Api.Cors.AllowedOrigins,
|
||||||
ExtraHeaderFields: impl.cfg.Api.ExtraHeaderFields,
|
ExtraHeaderFields: impl.cfg.Api.ExtraHeaderFields,
|
||||||
Probo: proboService,
|
Probo: proboService,
|
||||||
File: fileService,
|
FileSign: filesignService,
|
||||||
IAM: iamService,
|
IAM: iamService,
|
||||||
Trust: trustService,
|
Trust: trustService,
|
||||||
ESign: esignService,
|
ESign: esignService,
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import (
|
|||||||
"go.probo.inc/probo/pkg/connector/provider"
|
"go.probo.inc/probo/pkg/connector/provider"
|
||||||
"go.probo.inc/probo/pkg/cookiebanner"
|
"go.probo.inc/probo/pkg/cookiebanner"
|
||||||
"go.probo.inc/probo/pkg/esign"
|
"go.probo.inc/probo/pkg/esign"
|
||||||
"go.probo.inc/probo/pkg/file"
|
"go.probo.inc/probo/pkg/filesign"
|
||||||
"go.probo.inc/probo/pkg/geoloc"
|
"go.probo.inc/probo/pkg/geoloc"
|
||||||
"go.probo.inc/probo/pkg/iam"
|
"go.probo.inc/probo/pkg/iam"
|
||||||
"go.probo.inc/probo/pkg/mailman"
|
"go.probo.inc/probo/pkg/mailman"
|
||||||
@@ -55,7 +55,7 @@ type (
|
|||||||
BaseURL *baseurl.BaseURL
|
BaseURL *baseurl.BaseURL
|
||||||
AllowedOrigins []string
|
AllowedOrigins []string
|
||||||
Probo *probo.Service
|
Probo *probo.Service
|
||||||
File *file.Service
|
FileSign *filesign.Service
|
||||||
IAM *iam.Service
|
IAM *iam.Service
|
||||||
Trust *trust.Service
|
Trust *trust.Service
|
||||||
ESign *esign.Service
|
ESign *esign.Service
|
||||||
@@ -207,7 +207,7 @@ func NewServer(cfg Config) (*Server, error) {
|
|||||||
),
|
),
|
||||||
filesHandler: files_v1.NewMux(
|
filesHandler: files_v1.NewMux(
|
||||||
cfg.Logger.Named("files.v1"),
|
cfg.Logger.Named("files.v1"),
|
||||||
cfg.File,
|
cfg.FileSign,
|
||||||
),
|
),
|
||||||
mcpHandler: mcp_v1.NewMux(
|
mcpHandler: mcp_v1.NewMux(
|
||||||
cfg.Logger.Named("mcp.v1"),
|
cfg.Logger.Named("mcp.v1"),
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ package console_v1
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
|
||||||
|
|
||||||
"go.gearno.de/kit/log"
|
"go.gearno.de/kit/log"
|
||||||
"go.probo.inc/probo/pkg/probo"
|
"go.probo.inc/probo/pkg/probo"
|
||||||
@@ -26,7 +25,7 @@ func (r *commonThirdPartyResolver) LogoURL(ctx context.Context, obj *types.Commo
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
logoURL, err := r.thirdParty.GenerateLogoURL(ctx, *obj.LogoFileID, 1*time.Hour)
|
logoURL, err := r.thirdParty.GenerateLogoURL(ctx, *obj.LogoFileID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.ErrorCtx(ctx, "cannot generate common third party logo URL", log.Error(err))
|
r.logger.ErrorCtx(ctx, "cannot generate common third party logo URL", log.Error(err))
|
||||||
return nil, gqlutils.Internal(ctx)
|
return nil, gqlutils.Internal(ctx)
|
||||||
|
|||||||
@@ -1183,7 +1183,7 @@ func (r *trustCenterReferenceResolver) LogoURL(ctx context.Context, obj *types.T
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
fileURL, err := r.probo.TrustCenterReferences.GenerateLogoURL(ctx, scope, obj.ID, 1*time.Hour)
|
fileURL, err := r.probo.TrustCenterReferences.GenerateLogoURL(ctx, scope, obj.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.ErrorCtx(ctx, "cannot generate logo URL", log.Error(err))
|
r.logger.ErrorCtx(ctx, "cannot generate logo URL", log.Error(err))
|
||||||
return "", gqlutils.Internal(ctx)
|
return "", gqlutils.Internal(ctx)
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import (
|
|||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"go.gearno.de/kit/log"
|
"go.gearno.de/kit/log"
|
||||||
"go.probo.inc/probo/pkg/coredata"
|
"go.probo.inc/probo/pkg/coredata"
|
||||||
"go.probo.inc/probo/pkg/file"
|
"go.probo.inc/probo/pkg/filesign"
|
||||||
"go.probo.inc/probo/pkg/gid"
|
"go.probo.inc/probo/pkg/gid"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,10 +30,10 @@ const presignedURLExpiry = 1 * time.Hour
|
|||||||
|
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
logger *log.Logger
|
logger *log.Logger
|
||||||
fileSvc *file.Service
|
fileSvc *filesign.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMux(logger *log.Logger, fileSvc *file.Service) *chi.Mux {
|
func NewMux(logger *log.Logger, fileSvc *filesign.Service) *chi.Mux {
|
||||||
h := &Handler{
|
h := &Handler{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
fileSvc: fileSvc,
|
fileSvc: fileSvc,
|
||||||
@@ -55,7 +55,7 @@ func (h *Handler) handleGetPublicFile(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
presignedURL, err := h.fileSvc.GetPublicFileURL(r.Context(), fileID, presignedURLExpiry)
|
presignedURL, err := h.fileSvc.GeneratePresignedFileURL(r.Context(), fileID, presignedURLExpiry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
|
|||||||
@@ -975,7 +975,7 @@ func (r *trustCenterReferenceResolver) LogoURL(ctx context.Context, obj *types.T
|
|||||||
scope := coredata.NewScopeFromObjectID(obj.ID)
|
scope := coredata.NewScopeFromObjectID(obj.ID)
|
||||||
trustService := r.trust
|
trustService := r.trust
|
||||||
|
|
||||||
logoURL, err := trustService.TrustCenterReferences.GenerateLogoURL(ctx, scope, obj.ID, 1*time.Hour)
|
logoURL, err := trustService.TrustCenterReferences.GenerateLogoURL(ctx, scope, obj.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.ErrorCtx(ctx, "cannot generate logo URL", log.Error(err))
|
r.logger.ErrorCtx(ctx, "cannot generate logo URL", log.Error(err))
|
||||||
return "", gqlutils.Internal(ctx)
|
return "", gqlutils.Internal(ctx)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import (
|
|||||||
"go.probo.inc/probo/pkg/connector/provider"
|
"go.probo.inc/probo/pkg/connector/provider"
|
||||||
"go.probo.inc/probo/pkg/cookiebanner"
|
"go.probo.inc/probo/pkg/cookiebanner"
|
||||||
"go.probo.inc/probo/pkg/esign"
|
"go.probo.inc/probo/pkg/esign"
|
||||||
"go.probo.inc/probo/pkg/file"
|
"go.probo.inc/probo/pkg/filesign"
|
||||||
"go.probo.inc/probo/pkg/geoloc"
|
"go.probo.inc/probo/pkg/geoloc"
|
||||||
"go.probo.inc/probo/pkg/iam"
|
"go.probo.inc/probo/pkg/iam"
|
||||||
"go.probo.inc/probo/pkg/iam/oauth2server"
|
"go.probo.inc/probo/pkg/iam/oauth2server"
|
||||||
@@ -54,7 +54,7 @@ type Config struct {
|
|||||||
AllowedOrigins []string
|
AllowedOrigins []string
|
||||||
ExtraHeaderFields map[string]string
|
ExtraHeaderFields map[string]string
|
||||||
Probo *probo.Service
|
Probo *probo.Service
|
||||||
File *file.Service
|
FileSign *filesign.Service
|
||||||
IAM *iam.Service
|
IAM *iam.Service
|
||||||
Trust *trust.Service
|
Trust *trust.Service
|
||||||
ESign *esign.Service
|
ESign *esign.Service
|
||||||
@@ -92,7 +92,7 @@ func NewServer(cfg Config) (*Server, error) {
|
|||||||
BaseURL: cfg.BaseURL,
|
BaseURL: cfg.BaseURL,
|
||||||
AllowedOrigins: cfg.AllowedOrigins,
|
AllowedOrigins: cfg.AllowedOrigins,
|
||||||
Probo: cfg.Probo,
|
Probo: cfg.Probo,
|
||||||
File: cfg.File,
|
FileSign: cfg.FileSign,
|
||||||
IAM: cfg.IAM,
|
IAM: cfg.IAM,
|
||||||
Trust: cfg.Trust,
|
Trust: cfg.Trust,
|
||||||
ESign: cfg.ESign,
|
ESign: cfg.ESign,
|
||||||
|
|||||||
4
pkg/thirdparty/service.go
vendored
4
pkg/thirdparty/service.go
vendored
@@ -17,7 +17,6 @@ package thirdparty
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
|
|
||||||
"go.gearno.de/kit/pg"
|
"go.gearno.de/kit/pg"
|
||||||
"go.probo.inc/probo/pkg/coredata"
|
"go.probo.inc/probo/pkg/coredata"
|
||||||
@@ -46,9 +45,8 @@ func NewService(pgClient *pg.Client, fileSvc *file.Service, vetter Vetter) *Serv
|
|||||||
func (s *Service) GenerateLogoURL(
|
func (s *Service) GenerateLogoURL(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
logoFileID gid.GID,
|
logoFileID gid.GID,
|
||||||
expiresIn time.Duration,
|
|
||||||
) (*string, error) {
|
) (*string, error) {
|
||||||
url, err := s.file.GetPublicFileURL(ctx, logoFileID, expiresIn)
|
url, err := s.file.GenerateFileURL(ctx, logoFileID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("cannot generate logo URL: %w", err)
|
return nil, fmt.Errorf("cannot generate logo URL: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import (
|
|||||||
"go.probo.inc/probo/packages/emails"
|
"go.probo.inc/probo/packages/emails"
|
||||||
"go.probo.inc/probo/pkg/coredata"
|
"go.probo.inc/probo/pkg/coredata"
|
||||||
"go.probo.inc/probo/pkg/esign"
|
"go.probo.inc/probo/pkg/esign"
|
||||||
|
"go.probo.inc/probo/pkg/file"
|
||||||
"go.probo.inc/probo/pkg/filemanager"
|
"go.probo.inc/probo/pkg/filemanager"
|
||||||
"go.probo.inc/probo/pkg/gid"
|
"go.probo.inc/probo/pkg/gid"
|
||||||
"go.probo.inc/probo/pkg/html2pdf"
|
"go.probo.inc/probo/pkg/html2pdf"
|
||||||
@@ -46,6 +47,7 @@ type (
|
|||||||
esign *esign.Service
|
esign *esign.Service
|
||||||
html2pdfConverter *html2pdf.Converter
|
html2pdfConverter *html2pdf.Converter
|
||||||
fileManager *filemanager.Service
|
fileManager *filemanager.Service
|
||||||
|
file *file.Service
|
||||||
logger *log.Logger
|
logger *log.Logger
|
||||||
slack *slack.Service
|
slack *slack.Service
|
||||||
TrustCenters *TrustCenterService
|
TrustCenters *TrustCenterService
|
||||||
@@ -75,6 +77,7 @@ func NewService(
|
|||||||
fileManagerService *filemanager.Service,
|
fileManagerService *filemanager.Service,
|
||||||
logger *log.Logger,
|
logger *log.Logger,
|
||||||
slack *slack.Service,
|
slack *slack.Service,
|
||||||
|
fileService *file.Service,
|
||||||
) *Service {
|
) *Service {
|
||||||
svc := &Service{
|
svc := &Service{
|
||||||
pg: pgClient,
|
pg: pgClient,
|
||||||
@@ -86,6 +89,7 @@ func NewService(
|
|||||||
esign: esignSvc,
|
esign: esignSvc,
|
||||||
html2pdfConverter: html2pdfConverter,
|
html2pdfConverter: html2pdfConverter,
|
||||||
fileManager: fileManagerService,
|
fileManager: fileManagerService,
|
||||||
|
file: fileService,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
slack: slack,
|
slack: slack,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,10 +17,7 @@ package trust
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
|
||||||
"go.gearno.de/kit/pg"
|
"go.gearno.de/kit/pg"
|
||||||
"go.probo.inc/probo/pkg/coredata"
|
"go.probo.inc/probo/pkg/coredata"
|
||||||
"go.probo.inc/probo/pkg/gid"
|
"go.probo.inc/probo/pkg/gid"
|
||||||
@@ -58,47 +55,17 @@ func (s TrustCenterReferenceService) GenerateLogoURL(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
scope coredata.Scoper,
|
scope coredata.Scoper,
|
||||||
referenceID gid.GID,
|
referenceID gid.GID,
|
||||||
duration time.Duration,
|
|
||||||
) (string, error) {
|
) (string, error) {
|
||||||
reference := &coredata.TrustCenterReference{}
|
reference := &coredata.TrustCenterReference{}
|
||||||
file := &coredata.File{}
|
|
||||||
|
|
||||||
err := s.svc.pg.WithTx(ctx, func(ctx context.Context, tx pg.Tx) error {
|
err := s.svc.pg.WithTx(ctx, func(ctx context.Context, tx pg.Tx) error {
|
||||||
err := reference.LoadByID(ctx, tx, scope, referenceID)
|
return reference.LoadByID(ctx, tx, scope, referenceID)
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("cannot load trust center reference: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = file.LoadByID(ctx, tx, scope, reference.LogoFileID)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("cannot load logo file: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil
|
return "", fmt.Errorf("cannot load trust center reference: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
presignClient := s3.NewPresignClient(s.svc.s3)
|
return s.svc.file.GenerateFileURL(ctx, reference.LogoFileID)
|
||||||
|
|
||||||
encodedFilename := url.PathEscape(file.FileName)
|
|
||||||
contentDisposition := fmt.Sprintf("inline; filename=\"%s\"; filename*=UTF-8''%s",
|
|
||||||
encodedFilename, encodedFilename)
|
|
||||||
|
|
||||||
presignedReq, err := presignClient.PresignGetObject(ctx, &s3.GetObjectInput{
|
|
||||||
Bucket: new(s.svc.bucket),
|
|
||||||
Key: new(file.FileKey),
|
|
||||||
ResponseCacheControl: new("max-age=3600, public"),
|
|
||||||
ResponseContentDisposition: new(contentDisposition),
|
|
||||||
}, func(opts *s3.PresignOptions) {
|
|
||||||
opts.Expires = duration
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("cannot presign GetObject request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return presignedReq.URL, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s TrustCenterReferenceService) Get(
|
func (s TrustCenterReferenceService) Get(
|
||||||
|
|||||||
Reference in New Issue
Block a user