Add trust center front
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
99
pkg/trust/audit_service.go
Normal file
99
pkg/trust/audit_service.go
Normal file
@@ -0,0 +1,99 @@
|
||||
// Copyright (c) 2025 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 trust
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/getprobo/probo/pkg/coredata"
|
||||
"github.com/getprobo/probo/pkg/gid"
|
||||
"github.com/getprobo/probo/pkg/page"
|
||||
"go.gearno.de/kit/pg"
|
||||
)
|
||||
|
||||
type AuditService struct {
|
||||
svc *TenantService
|
||||
}
|
||||
|
||||
func (s AuditService) Get(
|
||||
ctx context.Context,
|
||||
auditID gid.GID,
|
||||
) (*coredata.Audit, error) {
|
||||
audit := &coredata.Audit{}
|
||||
|
||||
err := s.svc.pg.WithConn(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
return audit.LoadByID(ctx, conn, s.svc.scope, auditID)
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return audit, nil
|
||||
}
|
||||
|
||||
func (s AuditService) ListForOrganizationId(
|
||||
ctx context.Context,
|
||||
organizationID gid.GID,
|
||||
cursor *page.Cursor[coredata.AuditOrderField],
|
||||
) (*page.Page[*coredata.Audit, coredata.AuditOrderField], error) {
|
||||
var audits coredata.Audits
|
||||
|
||||
err := s.svc.pg.WithConn(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
filter := coredata.NewAuditTrustCenterFilter()
|
||||
err := audits.LoadByOrganizationID(ctx, conn, s.svc.scope, organizationID, cursor, filter)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot load audits: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return page.NewPage(audits, cursor), nil
|
||||
}
|
||||
|
||||
func (s AuditService) GenerateReportURL(
|
||||
ctx context.Context,
|
||||
auditID gid.GID,
|
||||
expiresIn time.Duration,
|
||||
) (*string, error) {
|
||||
audit, err := s.Get(ctx, auditID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot get audit: %w", err)
|
||||
}
|
||||
|
||||
if audit.ReportID == nil {
|
||||
return nil, fmt.Errorf("audit has no report")
|
||||
}
|
||||
|
||||
url, err := s.svc.Reports.GenerateDownloadURL(ctx, *audit.ReportID, expiresIn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot generate report download URL: %w", err)
|
||||
}
|
||||
|
||||
return url, nil
|
||||
}
|
||||
219
pkg/trust/document_service.go
Normal file
219
pkg/trust/document_service.go
Normal file
@@ -0,0 +1,219 @@
|
||||
// Copyright (c) 2025 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 trust
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/getprobo/probo/pkg/coredata"
|
||||
"github.com/getprobo/probo/pkg/docgen"
|
||||
"github.com/getprobo/probo/pkg/gid"
|
||||
"github.com/getprobo/probo/pkg/html2pdf"
|
||||
"github.com/getprobo/probo/pkg/page"
|
||||
"go.gearno.de/kit/pg"
|
||||
)
|
||||
|
||||
type (
|
||||
DocumentService struct {
|
||||
svc *TenantService
|
||||
html2pdfConverter *html2pdf.Converter
|
||||
}
|
||||
)
|
||||
|
||||
// ListVersions lists all versions of a document
|
||||
func (s *DocumentService) ListVersions(
|
||||
ctx context.Context,
|
||||
documentID gid.GID,
|
||||
cursor *page.Cursor[coredata.DocumentVersionOrderField],
|
||||
) (*page.Page[*coredata.DocumentVersion, coredata.DocumentVersionOrderField], error) {
|
||||
var documentVersions coredata.DocumentVersions
|
||||
|
||||
err := s.svc.pg.WithConn(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
return documentVersions.LoadByDocumentID(ctx, conn, s.svc.scope, documentID, cursor)
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return page.NewPage(documentVersions, cursor), nil
|
||||
}
|
||||
|
||||
func (s *DocumentService) ListForOrganizationId(
|
||||
ctx context.Context,
|
||||
organizationID gid.GID,
|
||||
cursor *page.Cursor[coredata.DocumentOrderField],
|
||||
) (*page.Page[*coredata.Document, coredata.DocumentOrderField], error) {
|
||||
var documents coredata.Documents
|
||||
|
||||
err := s.svc.pg.WithConn(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
filter := coredata.NewDocumentTrustCenterFilter()
|
||||
err := documents.LoadByOrganizationID(ctx, conn, s.svc.scope, organizationID, cursor, filter)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot load documents: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return page.NewPage(documents, cursor), nil
|
||||
}
|
||||
|
||||
func (s *DocumentService) ExportPDF(
|
||||
ctx context.Context,
|
||||
documentVersionID gid.GID,
|
||||
) ([]byte, error) {
|
||||
document := &coredata.Document{}
|
||||
version := &coredata.DocumentVersion{}
|
||||
owner := &coredata.People{}
|
||||
publishedBy := &coredata.People{}
|
||||
signatures := coredata.DocumentVersionSignatures{}
|
||||
peopleMap := make(map[gid.GID]*coredata.People)
|
||||
|
||||
err := s.svc.pg.WithConn(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
if err := version.LoadByID(ctx, conn, s.svc.scope, documentVersionID); err != nil {
|
||||
return fmt.Errorf("cannot load document version: %w", err)
|
||||
}
|
||||
|
||||
if err := document.LoadByID(ctx, conn, s.svc.scope, version.DocumentID); err != nil {
|
||||
return fmt.Errorf("cannot load document: %w", err)
|
||||
}
|
||||
|
||||
if !document.ShowOnTrustCenter {
|
||||
return fmt.Errorf("document not visible on trust center")
|
||||
}
|
||||
|
||||
if version.PublishedBy != nil {
|
||||
if err := publishedBy.LoadByID(ctx, conn, s.svc.scope, *version.PublishedBy); err != nil {
|
||||
return fmt.Errorf("cannot load published by person: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
cursor := page.NewCursor(
|
||||
100,
|
||||
nil,
|
||||
page.Head,
|
||||
page.OrderBy[coredata.DocumentVersionSignatureOrderField]{
|
||||
Field: coredata.DocumentVersionSignatureOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionAsc,
|
||||
},
|
||||
)
|
||||
|
||||
if err := signatures.LoadByDocumentVersionID(ctx, conn, s.svc.scope, documentVersionID, cursor); err != nil {
|
||||
return fmt.Errorf("cannot load document version signatures: %w", err)
|
||||
}
|
||||
|
||||
if err := owner.LoadByID(ctx, conn, s.svc.scope, document.OwnerID); err != nil {
|
||||
return fmt.Errorf("cannot load document owner: %w", err)
|
||||
}
|
||||
|
||||
// TODO: refactor this to use a single query
|
||||
for _, sig := range signatures {
|
||||
if _, ok := peopleMap[sig.SignedBy]; !ok {
|
||||
people := &coredata.People{}
|
||||
if err := people.LoadByID(ctx, conn, s.svc.scope, sig.SignedBy); err != nil {
|
||||
return fmt.Errorf("cannot load people %q: %w", sig.SignedBy, err)
|
||||
}
|
||||
peopleMap[sig.SignedBy] = people
|
||||
}
|
||||
|
||||
if _, ok := peopleMap[sig.RequestedBy]; !ok {
|
||||
people := &coredata.People{}
|
||||
if err := people.LoadByID(ctx, conn, s.svc.scope, sig.RequestedBy); err != nil {
|
||||
return fmt.Errorf("cannot load people %q: %w", sig.RequestedBy, err)
|
||||
}
|
||||
peopleMap[sig.RequestedBy] = people
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
classification := docgen.ClassificationInternal
|
||||
switch document.DocumentType {
|
||||
case coredata.DocumentTypePolicy:
|
||||
classification = docgen.ClassificationConfidential
|
||||
case coredata.DocumentTypeISMS:
|
||||
classification = docgen.ClassificationSecret
|
||||
}
|
||||
|
||||
docData := docgen.DocumentData{
|
||||
Title: version.Title,
|
||||
Content: version.Content,
|
||||
Version: version.VersionNumber,
|
||||
Classification: classification,
|
||||
Approver: owner.FullName,
|
||||
Description: version.Changelog,
|
||||
PublishedAt: version.PublishedAt,
|
||||
PublishedBy: publishedBy.FullName,
|
||||
Signatures: make([]docgen.SignatureData, len(signatures)),
|
||||
}
|
||||
|
||||
for i, sig := range signatures {
|
||||
docData.Signatures[i] = docgen.SignatureData{
|
||||
SignedBy: peopleMap[sig.SignedBy].FullName,
|
||||
SignedAt: sig.SignedAt,
|
||||
State: sig.State,
|
||||
RequestedAt: sig.RequestedAt,
|
||||
RequestedBy: peopleMap[sig.RequestedBy].FullName,
|
||||
}
|
||||
}
|
||||
|
||||
htmlContent, err := docgen.RenderHTML(docData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot generate HTML: %w", err)
|
||||
}
|
||||
|
||||
cfg := html2pdf.RenderConfig{
|
||||
PageFormat: html2pdf.PageFormatA4,
|
||||
Orientation: html2pdf.OrientationPortrait,
|
||||
MarginTop: html2pdf.NewMarginInches(1.0),
|
||||
MarginBottom: html2pdf.NewMarginInches(1.0),
|
||||
MarginLeft: html2pdf.NewMarginInches(1.0),
|
||||
MarginRight: html2pdf.NewMarginInches(1.0),
|
||||
PrintBackground: true,
|
||||
Scale: 1.0,
|
||||
}
|
||||
|
||||
pdfReader, err := s.html2pdfConverter.GeneratePDF(ctx, htmlContent, cfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot generate PDF: %w", err)
|
||||
}
|
||||
|
||||
pdfData, err := io.ReadAll(pdfReader)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot read PDF data: %w", err)
|
||||
}
|
||||
return pdfData, nil
|
||||
}
|
||||
51
pkg/trust/framework_service.go
Normal file
51
pkg/trust/framework_service.go
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2025 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 trust
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"fmt"
|
||||
|
||||
"github.com/getprobo/probo/pkg/coredata"
|
||||
"github.com/getprobo/probo/pkg/gid"
|
||||
"go.gearno.de/kit/pg"
|
||||
)
|
||||
|
||||
type FrameworkService struct {
|
||||
svc *TenantService
|
||||
}
|
||||
|
||||
func (s FrameworkService) Get(
|
||||
ctx context.Context,
|
||||
frameworkID gid.GID,
|
||||
) (*coredata.Framework, error) {
|
||||
framework := &coredata.Framework{}
|
||||
|
||||
err := s.svc.pg.WithConn(ctx, func(conn pg.Conn) error {
|
||||
err := framework.LoadByID(ctx, conn, s.svc.scope, frameworkID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot load framework: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return framework, nil
|
||||
}
|
||||
97
pkg/trust/organization_service.go
Normal file
97
pkg/trust/organization_service.go
Normal file
@@ -0,0 +1,97 @@
|
||||
// Copyright (c) 2025 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 trust
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
"github.com/getprobo/probo/pkg/coredata"
|
||||
"github.com/getprobo/probo/pkg/gid"
|
||||
"go.gearno.de/kit/pg"
|
||||
)
|
||||
|
||||
type OrganizationService struct {
|
||||
svc *TenantService
|
||||
}
|
||||
|
||||
func (s OrganizationService) Get(
|
||||
ctx context.Context,
|
||||
organizationID gid.GID,
|
||||
) (*coredata.Organization, error) {
|
||||
organization := &coredata.Organization{}
|
||||
|
||||
err := s.svc.pg.WithConn(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
err := organization.LoadByID(
|
||||
ctx,
|
||||
conn,
|
||||
s.svc.scope,
|
||||
organizationID,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot load organization: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return organization, nil
|
||||
}
|
||||
|
||||
func (s OrganizationService) GenerateLogoURL(
|
||||
ctx context.Context,
|
||||
organizationID gid.GID,
|
||||
expiresIn time.Duration,
|
||||
) (*string, error) {
|
||||
organization, err := s.Get(ctx, organizationID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot get organization: %w", err)
|
||||
}
|
||||
|
||||
if organization.LogoObjectKey == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
presignClient := s3.NewPresignClient(s.svc.s3)
|
||||
|
||||
encodedFilename := url.QueryEscape(organization.Name)
|
||||
contentDisposition := fmt.Sprintf("attachment; filename=\"%s\"; filename*=UTF-8''%s",
|
||||
encodedFilename, encodedFilename)
|
||||
|
||||
presignedReq, err := presignClient.PresignGetObject(ctx, &s3.GetObjectInput{
|
||||
Bucket: aws.String(s.svc.bucket),
|
||||
Key: aws.String(organization.LogoObjectKey),
|
||||
ResponseCacheControl: aws.String("max-age=3600, public"),
|
||||
ResponseContentDisposition: aws.String(contentDisposition),
|
||||
}, func(opts *s3.PresignOptions) {
|
||||
opts.Expires = expiresIn
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot presign GetObject request: %w", err)
|
||||
}
|
||||
|
||||
return &presignedReq.URL, nil
|
||||
}
|
||||
84
pkg/trust/report_service.go
Normal file
84
pkg/trust/report_service.go
Normal file
@@ -0,0 +1,84 @@
|
||||
// Copyright (c) 2025 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 trust
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
"github.com/getprobo/probo/pkg/coredata"
|
||||
"github.com/getprobo/probo/pkg/gid"
|
||||
"go.gearno.de/kit/pg"
|
||||
)
|
||||
|
||||
type ReportService struct {
|
||||
svc *TenantService
|
||||
}
|
||||
|
||||
func (s ReportService) Get(
|
||||
ctx context.Context,
|
||||
reportID gid.GID,
|
||||
) (*coredata.Report, error) {
|
||||
report := &coredata.Report{}
|
||||
|
||||
err := s.svc.pg.WithConn(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
err := report.LoadByID(ctx, conn, s.svc.scope, reportID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot load report: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return report, nil
|
||||
}
|
||||
|
||||
func (s ReportService) GenerateDownloadURL(
|
||||
ctx context.Context,
|
||||
reportID gid.GID,
|
||||
expiresIn time.Duration,
|
||||
) (*string, error) {
|
||||
report, err := s.Get(ctx, reportID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot get report: %w", err)
|
||||
}
|
||||
|
||||
presignClient := s3.NewPresignClient(s.svc.s3)
|
||||
|
||||
presignedReq, err := presignClient.PresignGetObject(ctx, &s3.GetObjectInput{
|
||||
Bucket: aws.String(s.svc.bucket),
|
||||
Key: aws.String(report.ObjectKey),
|
||||
ResponseCacheControl: aws.String("max-age=3600, public"),
|
||||
ResponseContentType: aws.String(report.MimeType),
|
||||
ResponseContentDisposition: aws.String(fmt.Sprintf("attachment; filename=\"%s\"", report.Filename)),
|
||||
}, func(opts *s3.PresignOptions) {
|
||||
opts.Expires = expiresIn
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot presign GetObject request: %w", err)
|
||||
}
|
||||
|
||||
return &presignedReq.URL, nil
|
||||
}
|
||||
108
pkg/trust/service.go
Normal file
108
pkg/trust/service.go
Normal file
@@ -0,0 +1,108 @@
|
||||
// Copyright (c) 2025 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 trust
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
"github.com/getprobo/probo/pkg/coredata"
|
||||
"github.com/getprobo/probo/pkg/crypto/cipher"
|
||||
"github.com/getprobo/probo/pkg/gid"
|
||||
"github.com/getprobo/probo/pkg/html2pdf"
|
||||
"github.com/getprobo/probo/pkg/probo"
|
||||
"github.com/getprobo/probo/pkg/usrmgr"
|
||||
"go.gearno.de/kit/pg"
|
||||
)
|
||||
|
||||
type (
|
||||
Service struct {
|
||||
pg *pg.Client
|
||||
s3 *s3.Client
|
||||
bucket string
|
||||
proboSvc *probo.Service
|
||||
encryptionKey cipher.EncryptionKey
|
||||
tokenSecret string
|
||||
usrmgr *usrmgr.Service
|
||||
html2pdfConverter *html2pdf.Converter
|
||||
}
|
||||
|
||||
TenantService struct {
|
||||
pg *pg.Client
|
||||
s3 *s3.Client
|
||||
bucket string
|
||||
scope coredata.Scoper
|
||||
proboSvc *probo.Service
|
||||
encryptionKey cipher.EncryptionKey
|
||||
tokenSecret string
|
||||
usrmgr *usrmgr.Service
|
||||
html2pdfConverter *html2pdf.Converter
|
||||
TrustCenters *TrustCenterService
|
||||
Documents *DocumentService
|
||||
Audits *AuditService
|
||||
Vendors *VendorService
|
||||
Frameworks *FrameworkService
|
||||
TrustCenterAccesses *TrustCenterAccessService
|
||||
Reports *ReportService
|
||||
Organizations *OrganizationService
|
||||
}
|
||||
)
|
||||
|
||||
func NewService(
|
||||
pgClient *pg.Client,
|
||||
s3Client *s3.Client,
|
||||
bucket string,
|
||||
encryptionKey cipher.EncryptionKey,
|
||||
tokenSecret string,
|
||||
usrmgr *usrmgr.Service,
|
||||
html2pdfConverter *html2pdf.Converter,
|
||||
) *Service {
|
||||
return &Service{
|
||||
pg: pgClient,
|
||||
s3: s3Client,
|
||||
bucket: bucket,
|
||||
encryptionKey: encryptionKey,
|
||||
tokenSecret: tokenSecret,
|
||||
usrmgr: usrmgr,
|
||||
html2pdfConverter: html2pdfConverter,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) GetEncryptionKey() cipher.EncryptionKey {
|
||||
return s.encryptionKey
|
||||
}
|
||||
|
||||
func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService {
|
||||
tenantService := &TenantService{
|
||||
pg: s.pg,
|
||||
s3: s.s3,
|
||||
bucket: s.bucket,
|
||||
scope: coredata.NewScope(tenantID),
|
||||
proboSvc: s.proboSvc,
|
||||
encryptionKey: s.encryptionKey,
|
||||
tokenSecret: s.tokenSecret,
|
||||
usrmgr: s.usrmgr,
|
||||
html2pdfConverter: s.html2pdfConverter,
|
||||
}
|
||||
|
||||
tenantService.TrustCenters = &TrustCenterService{svc: tenantService}
|
||||
tenantService.Documents = &DocumentService{svc: tenantService, html2pdfConverter: s.html2pdfConverter}
|
||||
tenantService.Audits = &AuditService{svc: tenantService}
|
||||
tenantService.Vendors = &VendorService{svc: tenantService}
|
||||
tenantService.Frameworks = &FrameworkService{svc: tenantService}
|
||||
tenantService.TrustCenterAccesses = &TrustCenterAccessService{svc: tenantService, usrmgr: s.usrmgr}
|
||||
tenantService.Reports = &ReportService{svc: tenantService}
|
||||
tenantService.Organizations = &OrganizationService{svc: tenantService}
|
||||
|
||||
return tenantService
|
||||
}
|
||||
89
pkg/trust/trust_center_access_service.go
Normal file
89
pkg/trust/trust_center_access_service.go
Normal file
@@ -0,0 +1,89 @@
|
||||
// Copyright (c) 2025 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 trust
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/getprobo/probo/pkg/coredata"
|
||||
"github.com/getprobo/probo/pkg/gid"
|
||||
"github.com/getprobo/probo/pkg/probo"
|
||||
"github.com/getprobo/probo/pkg/statelesstoken"
|
||||
"github.com/getprobo/probo/pkg/usrmgr"
|
||||
"go.gearno.de/kit/pg"
|
||||
)
|
||||
|
||||
type (
|
||||
TrustCenterAccessService struct {
|
||||
svc *TenantService
|
||||
usrmgr *usrmgr.Service
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
TokenTypeTrustCenterAccess = "trust_center_access"
|
||||
)
|
||||
|
||||
func (s TrustCenterAccessService) ValidateToken(
|
||||
ctx context.Context,
|
||||
tokenString string,
|
||||
) (*probo.TrustCenterAccessData, error) {
|
||||
token, err := statelesstoken.ValidateToken[probo.TrustCenterAccessData](
|
||||
s.svc.tokenSecret,
|
||||
TokenTypeTrustCenterAccess,
|
||||
tokenString,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot validate trust center access token: %w", err)
|
||||
}
|
||||
|
||||
access := &coredata.TrustCenterAccess{}
|
||||
err = s.svc.pg.WithConn(ctx, func(conn pg.Conn) error {
|
||||
err := access.LoadByTrustCenterIDAndEmail(ctx, conn, s.svc.scope, token.Data.TrustCenterID, token.Data.Email)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot load trust center access: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !access.Active {
|
||||
return nil, fmt.Errorf("access has been revoked")
|
||||
}
|
||||
|
||||
return &token.Data, nil
|
||||
}
|
||||
|
||||
func (s TrustCenterAccessService) IsAccessActive(
|
||||
ctx context.Context,
|
||||
trustCenterID gid.GID,
|
||||
email string,
|
||||
) (bool, error) {
|
||||
access := &coredata.TrustCenterAccess{}
|
||||
err := s.svc.pg.WithConn(ctx, func(conn pg.Conn) error {
|
||||
return access.LoadByTrustCenterIDAndEmail(ctx, conn, s.svc.scope, trustCenterID, email)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("cannot load trust center access: %w", err)
|
||||
}
|
||||
|
||||
return access.Active, nil
|
||||
}
|
||||
53
pkg/trust/trust_center_service.go
Normal file
53
pkg/trust/trust_center_service.go
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2025 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 trust
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"fmt"
|
||||
|
||||
"github.com/getprobo/probo/pkg/coredata"
|
||||
"go.gearno.de/kit/pg"
|
||||
)
|
||||
|
||||
type TrustCenterService struct {
|
||||
svc *TenantService
|
||||
}
|
||||
|
||||
func (s TrustCenterService) GetBySlug(
|
||||
ctx context.Context,
|
||||
slug string,
|
||||
) (*coredata.TrustCenter, error) {
|
||||
trustCenter := &coredata.TrustCenter{}
|
||||
|
||||
err := s.svc.pg.WithConn(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
err := trustCenter.LoadBySlug(ctx, conn, slug)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot load trust center: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return trustCenter, nil
|
||||
}
|
||||
81
pkg/trust/vendor_service.go
Normal file
81
pkg/trust/vendor_service.go
Normal file
@@ -0,0 +1,81 @@
|
||||
// Copyright (c) 2025 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 trust
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/getprobo/probo/pkg/coredata"
|
||||
"github.com/getprobo/probo/pkg/gid"
|
||||
"github.com/getprobo/probo/pkg/page"
|
||||
"go.gearno.de/kit/pg"
|
||||
)
|
||||
|
||||
type VendorService struct {
|
||||
svc *TenantService
|
||||
}
|
||||
|
||||
func (s VendorService) Get(
|
||||
ctx context.Context,
|
||||
vendorID gid.GID,
|
||||
) (*coredata.Vendor, error) {
|
||||
vendor := &coredata.Vendor{}
|
||||
|
||||
err := s.svc.pg.WithConn(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
err := vendor.LoadByID(ctx, conn, s.svc.scope, vendorID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot load vendor: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return vendor, nil
|
||||
}
|
||||
|
||||
func (s VendorService) ListForOrganizationId(
|
||||
ctx context.Context,
|
||||
organizationID gid.GID,
|
||||
cursor *page.Cursor[coredata.VendorOrderField],
|
||||
) (*page.Page[*coredata.Vendor, coredata.VendorOrderField], error) {
|
||||
var vendors coredata.Vendors
|
||||
|
||||
err := s.svc.pg.WithConn(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
filter := coredata.NewVendorTrustCenterFilter()
|
||||
err := vendors.LoadByOrganizationID(ctx, conn, s.svc.scope, organizationID, cursor, filter)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot load vendors: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return page.NewPage(vendors, cursor), nil
|
||||
}
|
||||
Reference in New Issue
Block a user