Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
filippo.io/edwards25519 v1.1.0
github.com/aws/aws-sdk-go-v2 v0.17.0
github.com/code-payments/code-vm-indexer v1.2.0
github.com/code-payments/ocp-protobuf-api v1.7.1-0.20260401115005-c2265cbd04b0
github.com/code-payments/ocp-protobuf-api v1.8.1
github.com/emirpasic/gods v1.12.0
github.com/envoyproxy/protoc-gen-validate v1.2.1
github.com/golang/protobuf v1.5.4
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/code-payments/code-vm-indexer v1.2.0 h1:rSHpBMiT9BKgmKcXg/VIoi/h0t7jNxGx07Qz59m+6Q0=
github.com/code-payments/code-vm-indexer v1.2.0/go.mod h1:vn91YN2qNqb+gGJeZe2+l+TNxVmEEiRHXXnIn2Y40h8=
github.com/code-payments/ocp-protobuf-api v1.7.1-0.20260401115005-c2265cbd04b0 h1:zQdbkGJKttqckZ8GH66fx0g6D6UB/WHT7z5MNiBHMIE=
github.com/code-payments/ocp-protobuf-api v1.7.1-0.20260401115005-c2265cbd04b0/go.mod h1:tw6BooY5a8l6CtSZnKOruyKII0W04n89pcM4BizrgG8=
github.com/code-payments/ocp-protobuf-api v1.8.1 h1:IaCVADbbTUtZwf0Rk8Pf8PygsancuOXc+A3CcTG/74w=
github.com/code-payments/ocp-protobuf-api v1.8.1/go.mod h1:tw6BooY5a8l6CtSZnKOruyKII0W04n89pcM4BizrgG8=
github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6 h1:NmTXa/uVnDyp0TY5MKi197+3HWcnYWfnHGyaFthlnGw=
github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
Expand Down
25 changes: 25 additions & 0 deletions ocp/integration/moderation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package integration

import (
"context"

"github.com/code-payments/ocp-server/ocp/common"
)

// Moderation is an OCP integration enabling custom moderation rules
type Moderation interface {
// ValidateAttestation validates a moderation attestation for a piece of moderated content
ValidateAttestation(ctx context.Context, owner *common.Account, rawAttestation []byte, content any) (bool, error)
}

type allowEverythingModerationIntegration struct {
}

// NewAllowEverythingModerationIntegration returns a default Moderation integration that allows everything
func NewAllowEverythingModerationIntegration() Moderation {
return &allowEverythingModerationIntegration{}
}

func (i *allowEverythingModerationIntegration) ValidateAttestation(_ context.Context, _ *common.Account, _ []byte, _ any) (bool, error) {
return true, nil
}
8 changes: 8 additions & 0 deletions ocp/rpc/currency/icon.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ func (s *currencyServer) UpdateIcon(ctx context.Context, req *currencypb.UpdateI
return &currencypb.UpdateIconResponse{Result: currencypb.UpdateIconResponse_DENIED}, nil
}

isModerated, err := s.moderation.ValidateAttestation(ctx, ownerAccount, req.ModerationAttestation.RawValue, req.Icon)
if err != nil {
log.With(zap.Error(err)).Warn("failed to validate moderation attestation")
return nil, status.Error(codes.Internal, "")
} else if !isModerated {
return &currencypb.UpdateIconResponse{Result: currencypb.UpdateIconResponse_DENIED}, nil
}

processed, ext, contentType, err := processIcon(req.Icon)
if err == errInvalidIcon {
return &currencypb.UpdateIconResponse{Result: currencypb.UpdateIconResponse_INVALID_ICON}, nil
Expand Down
50 changes: 48 additions & 2 deletions ocp/rpc/currency/launch.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@ func (s *currencyServer) Launch(ctx context.Context, req *currencypb.LaunchReque
return &currencypb.LaunchResponse{Result: currencypb.LaunchResponse_DENIED}, nil
}

isModerated, err := s.moderation.ValidateAttestation(ctx, ownerAccount, req.NameModerationAttestation.RawValue, req.Name)
if err != nil {
log.With(zap.Error(err)).Warn("failed to validate name moderation attestation")
return nil, status.Error(codes.Internal, "")
} else if !isModerated {
return &currencypb.LaunchResponse{Result: currencypb.LaunchResponse_DENIED}, nil
}

symbol := strings.TrimSpace(req.Symbol)
if len(symbol) == 0 {
symbol = strings.ToUpper(strings.Map(
Expand All @@ -77,15 +85,53 @@ func (s *currencyServer) Launch(ctx context.Context, req *currencypb.LaunchReque
if len(symbol) > currencycreator.MaxCurrencyConfigAccountSymbolLength {
symbol = symbol[0:currencycreator.MaxCurrencyConfigAccountSymbolLength]
}
} else if symbol != req.Symbol {
return &currencypb.LaunchResponse{Result: currencypb.LaunchResponse_DENIED}, nil
} else {
if symbol != req.Symbol {
return &currencypb.LaunchResponse{Result: currencypb.LaunchResponse_DENIED}, nil
}
if req.SymbolModerationAttestation == nil {
return &currencypb.LaunchResponse{Result: currencypb.LaunchResponse_DENIED}, nil
}
isModerated, err := s.moderation.ValidateAttestation(ctx, ownerAccount, req.SymbolModerationAttestation.RawValue, req.Symbol)
if err != nil {
log.With(zap.Error(err)).Warn("failed to validate symbol moderation attestation")
return nil, status.Error(codes.Internal, "")
} else if !isModerated {
return &currencypb.LaunchResponse{Result: currencypb.LaunchResponse_DENIED}, nil
}
}

description := strings.TrimSpace(req.Description)
if description != req.Description {
return &currencypb.LaunchResponse{Result: currencypb.LaunchResponse_DENIED}, nil
}
if len(req.Description) > 0 {
if req.DescriptionModerationAttestation == nil {
return &currencypb.LaunchResponse{Result: currencypb.LaunchResponse_DENIED}, nil
}
isModerated, err := s.moderation.ValidateAttestation(ctx, ownerAccount, req.DescriptionModerationAttestation.RawValue, req.Description)
if err != nil {
log.With(zap.Error(err)).Warn("failed to validate description moderation attestation")
return nil, status.Error(codes.Internal, "")
} else if !isModerated {
return &currencypb.LaunchResponse{Result: currencypb.LaunchResponse_DENIED}, nil
}
}

var processedIcon []byte
var iconExt, iconContentType string
if len(req.Icon) > 0 {
if req.IconModerationAttestation == nil {
return &currencypb.LaunchResponse{Result: currencypb.LaunchResponse_DENIED}, nil
}
isModerated, err := s.moderation.ValidateAttestation(ctx, ownerAccount, req.IconModerationAttestation.RawValue, req.Icon)
if err != nil {
log.With(zap.Error(err)).Warn("failed to validate icon moderation attestation")
return nil, status.Error(codes.Internal, "")
} else if !isModerated {
return &currencypb.LaunchResponse{Result: currencypb.LaunchResponse_DENIED}, nil
}

processedIcon, iconExt, iconContentType, err = processIcon(req.Icon)
if err == errInvalidIcon {
return &currencypb.LaunchResponse{Result: currencypb.LaunchResponse_INVALID_ICON}, nil
Expand Down
8 changes: 8 additions & 0 deletions ocp/rpc/currency/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@ func (s *currencyServer) UpdateMetadata(ctx context.Context, req *currencypb.Upd
}

if req.NewDescription != nil {
isModerated, err := s.moderation.ValidateAttestation(ctx, ownerAccount, req.NewDescription.ModerationAttestation.RawValue, req.NewDescription.Value)
if err != nil {
log.With(zap.Error(err)).Warn("failed to validate description moderation attestation")
return nil, status.Error(codes.Internal, "")
} else if !isModerated {
return &currencypb.UpdateMetadataResponse{Result: currencypb.UpdateMetadataResponse_DENIED}, nil
}

metadataRecord.Description = req.NewDescription.Value
}

Expand Down
4 changes: 4 additions & 0 deletions ocp/rpc/currency/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
auth_util "github.com/code-payments/ocp-server/ocp/auth"
currency_util "github.com/code-payments/ocp-server/ocp/currency"
ocp_data "github.com/code-payments/ocp-server/ocp/data"
"github.com/code-payments/ocp-server/ocp/integration"
)

type currencyServer struct {
Expand All @@ -24,6 +25,7 @@ type currencyServer struct {
auth *auth_util.RPCSignatureVerifier

antispamGuard *antispam.Guard
moderation integration.Moderation

s3Client *s3.Client

Expand All @@ -40,6 +42,7 @@ func NewCurrencyServer(
data ocp_data.Provider,
mintDataProvider *currency_util.MintDataProvider,
antispamGuard *antispam.Guard,
moderation integration.Moderation,
s3Client *s3.Client,
configProvider ConfigProvider,
) currencypb.CurrencyServer {
Expand All @@ -56,6 +59,7 @@ func NewCurrencyServer(
auth: auth_util.NewRPCSignatureVerifier(log, data),

antispamGuard: antispamGuard,
moderation: moderation,

s3Client: s3Client,

Expand Down
Loading