WO-FL-009. The files family reaches the CMS File access grant store: a plugin grants one file to a member or an address, lists what a file has handed out, and revokes what it gave. The response carries the signed unlock link, so a seller can deliver a file to somebody with no account. Nothing on the wire names the calling plugin: the host stamps plugin:<name> on what this family writes and refuses a revoke of anything else. ADR 0008. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
80 lines
2.6 KiB
Go
80 lines
2.6 KiB
Go
package caps
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
abiv1 "git.dev.alexdunmow.com/block/pluginsdk/abi/v1"
|
|
"git.dev.alexdunmow.com/block/pluginsdk/plugin"
|
|
"github.com/google/uuid"
|
|
"google.golang.org/protobuf/types/known/timestamppb"
|
|
)
|
|
|
|
// filesStub implements plugin.FileGrants over the files.* capability calls.
|
|
// The grant's source is the host's to decide, so nothing here names the plugin.
|
|
type filesStub struct{ base }
|
|
|
|
var _ plugin.FileGrants = (*filesStub)(nil)
|
|
|
|
func (s *filesStub) GrantFileAccess(ctx context.Context, params plugin.FileGrantParams) (plugin.FileGrant, error) {
|
|
req := &abiv1.FilesGrantAccessRequest{
|
|
AttachmentKind: params.AttachmentKind,
|
|
AttachmentId: params.AttachmentID.String(),
|
|
Email: params.Email,
|
|
}
|
|
if params.PublicUserID != uuid.Nil {
|
|
req.PublicUserId = params.PublicUserID.String()
|
|
}
|
|
if !params.ExpiresAt.IsZero() {
|
|
req.ExpiresAt = timestamppb.New(params.ExpiresAt)
|
|
}
|
|
resp := &abiv1.FilesGrantAccessResponse{}
|
|
if err := s.invoke(ctx, "grant_access", req, resp); err != nil {
|
|
return plugin.FileGrant{}, err
|
|
}
|
|
return fileGrantFromABI(resp.GetGrant()), nil
|
|
}
|
|
|
|
func (s *filesStub) RevokeFileAccess(ctx context.Context, grantID uuid.UUID) error {
|
|
req := &abiv1.FilesRevokeAccessRequest{GrantId: grantID.String()}
|
|
return s.invoke(ctx, "revoke_access", req, &abiv1.FilesRevokeAccessResponse{})
|
|
}
|
|
|
|
func (s *filesStub) ListFileGrants(ctx context.Context, attachmentKind string, attachmentID uuid.UUID) ([]plugin.FileGrant, error) {
|
|
req := &abiv1.FilesListGrantsRequest{AttachmentKind: attachmentKind, AttachmentId: attachmentID.String()}
|
|
resp := &abiv1.FilesListGrantsResponse{}
|
|
if err := s.invoke(ctx, "list_grants", req, resp); err != nil {
|
|
return nil, err
|
|
}
|
|
grants := make([]plugin.FileGrant, 0, len(resp.GetGrants()))
|
|
for _, grant := range resp.GetGrants() {
|
|
grants = append(grants, fileGrantFromABI(grant))
|
|
}
|
|
return grants, nil
|
|
}
|
|
|
|
func fileGrantFromABI(grant *abiv1.FileAccessGrant) plugin.FileGrant {
|
|
if grant == nil {
|
|
return plugin.FileGrant{}
|
|
}
|
|
return plugin.FileGrant{
|
|
GrantID: parseUUID(grant.GetGrantId()),
|
|
AttachmentKind: grant.GetAttachmentKind(),
|
|
AttachmentID: parseUUID(grant.GetAttachmentId()),
|
|
PublicUserID: parseUUID(grant.GetPublicUserId()),
|
|
Email: grant.GetEmail(),
|
|
Source: grant.GetSource(),
|
|
ExpiresAt: abiTime(grant.GetExpiresAt()),
|
|
RevokedAt: abiTime(grant.GetRevokedAt()),
|
|
CreatedAt: abiTime(grant.GetCreatedAt()),
|
|
UnlockURL: grant.GetUnlockUrl(),
|
|
}
|
|
}
|
|
|
|
func abiTime(stamp *timestamppb.Timestamp) time.Time {
|
|
if stamp == nil {
|
|
return time.Time{}
|
|
}
|
|
return stamp.AsTime()
|
|
}
|