moderation

package
v1.39.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 13, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Index

Constants

View Source
const CategoryGibberish = "gibberish"

CategoryGibberish is the category the generic text classifier and the group title classifier score text under when it has no plausible meaning. It is named here because a caller moderating a name ignores it (see Result.Ignoring); no other category is singled out that way.

Variables

View Source
var (
	ErrInvalidAttestation  = errors.New("invalid attestation")
	ErrInvalidSignature    = errors.New("invalid attestation signature")
	ErrInvalidAttestor     = errors.New("attestor public key mismatch")
	ErrInvalidContentHash  = errors.New("content hash mismatch")
	ErrExpiredAttestation  = errors.New("attestation is expired")
	ErrContentKindMismatch = errors.New("content was moderated as a different kind")
)
View Source
var ErrUnsupportedLanguage = errors.New("unsupported language")

ErrUnsupportedLanguage is returned when the moderation service does not support the language of the provided text.

Functions

func HighestFlaggedCategory added in v1.19.0

func HighestFlaggedCategory(result *Result) moderationpb.FlaggedCategory

HighestFlaggedCategory maps a moderation Result's flagged categories onto the proto FlaggedCategory vocabulary, returning the highest-scoring one that maps to a well-defined category (falling back to OTHER). It is the shared mapping used both by this service's responses and by callers that surface a moderation verdict elsewhere (e.g. a blob's rejection metadata).

func NewIntegration

func NewIntegration(attestor *commonpb.PublicKey, acceptUnknownKind bool) ocp_integration.Moderation

NewIntegration returns OCP's moderation integration, which accepts content whose attestation attestor signed for the kind OCP uses it as. acceptUnknownKind also accepts an attestation naming no kind, from a legacy client, for any kind; it is for the transition only (see ValidateAttestation).

func ValidateAttestation

func ValidateAttestation(attestation *moderationpb.ModerationAttestation, attestor *commonpb.PublicKey, kind moderationpb.ContentKind, content any, acceptUnknownKind bool) error

ValidateAttestation validates a moderation attestation against the expected attestor public key and content, used as kind. Content must be a string (for text) or []byte (for images).

The attestation must name kind: each kind is moderated under its own checks, so content moderated as one kind (e.g. a currency description, which skips a name's impersonation checks) must not pass where another is used (e.g. as the currency's name). kind is the caller's, decided by where the content is used, never by the client; it must not be UNKNOWN_CONTENT_KIND.

acceptUnknownKind admits an attestation naming no kind, from a legacy client's request, for any kind. That is safe because a legacy request gets the checks every kind once shared, under which any text short enough to be a currency name was checked as one. It exists for the transition only: once legacy clients are gone, pass false, and after maxAttestationAge no legacy attestation remains valid anyway.

Types

type Client

type Client interface {
	// ClassifyText classifies the provided text for moderation. The result
	// indicates whether the text was flagged and includes per-category scores.
	// This is the generic classification that should be applied to all text.
	// For usecase-specific moderation, an additional call must be made.
	ClassifyText(ctx context.Context, text string) (*Result, error)

	// ClassifyImage classifies the provided image data for moderation. The
	// result indicates whether the image was flagged and includes per-category
	// scores.
	ClassifyImage(ctx context.Context, data []byte) (*Result, error)

	// ClassifyCurrencyName checks whether a currency name infringes on
	// existing trademarks, impersonates known brands, or is otherwise
	// misleading. The result includes per-category scores for areas like
	// cryptocurrency, financial_service, impersonation, etc.
	ClassifyCurrencyName(ctx context.Context, name string) (*Result, error)

	// ClassifyUsername checks a user-chosen username on two independent axes:
	// who the handle claims to be, and what it says.
	//
	// A handle is unique and globally addressable, so holding one is a claim to
	// be its subject. It is scored for squatting a brand, token, exchange,
	// financial service, government body, public figure, or the Flipcash
	// platform itself, and for reading as an official support or staff role
	// rather than as a person. This is the reverse of ClassifyDisplayName,
	// which deliberately allows any name: a display name is not unique, so it
	// claims nothing.
	//
	// A handle is also text other users see when they pay, message, or search
	// for its holder, so it is scored for harmful content under the same
	// categories ClassifyDisplayName uses. Overlapping ClassifyText there is
	// deliberate: a handle is at most 30 characters with no whitespace, rarely
	// enough for the general classifier to identify a language, so it often
	// declines with ErrUnsupportedLanguage and leaves this the only classifier
	// that saw the handle.
	//
	// The result includes per-category scores for areas like impersonation,
	// official_role, hate, sexual, etc.
	ClassifyUsername(ctx context.Context, username string) (*Result, error)

	// ClassifyDisplayName checks whether a user-chosen display name abuses the
	// name field to advertise, solicit, or expose others to harmful content.
	// The result includes per-category scores for areas like solicitation,
	// contact_info, hate, etc.
	//
	// It deliberately does not score impersonation: users are free to call
	// themselves whatever they like, including the name of a real person or
	// brand. Nor does it score gibberish, and neither does ClassifyUsername: a
	// random-looking name or handle is a user's to choose, and a meaningless
	// one harms no one, so both are judged only on what they spell. ClassifyText
	// still scores gibberish when run on the same name, and a caller moderating
	// a name sets that one verdict aside with Result.Ignoring. It is also
	// distinct from ClassifyText, which is tuned for prose and has little to
	// work with in a one- or two-word name.
	ClassifyDisplayName(ctx context.Context, name string) (*Result, error)

	// ClassifyGroupTitle checks whether a user-chosen group chat title abuses
	// the title to advertise, solicit, or expose others to harmful content. It
	// is the group counterpart of ClassifyDisplayName and scores the same
	// categories (solicitation, contact_info, hate, etc.), but is tuned for what
	// a title is: a label for a shared room, seen by everyone in the group and
	// everyone considering joining it, that names a topic, a community, or an
	// occasion rather than a person. It is the one name-like classifier that
	// also scores gibberish, because a title with no plausible meaning is a
	// room nobody can find rather than a name somebody chose.
	//
	// Like ClassifyDisplayName it does not score impersonation: a group may be
	// titled after any brand, person, or topic. It is also distinct from
	// ClassifyText, which has little to work with in a short title.
	ClassifyGroupTitle(ctx context.Context, title string) (*Result, error)
}

type Integration

type Integration struct {
	// contains filtered or unexported fields
}

func (*Integration) ValidateAttestation

func (i *Integration) ValidateAttestation(_ context.Context, _ *ocp_common.Account, rawAttestation []byte, kind ocp_integration.ModeratedContentKind, content any) (bool, error)

type Result

type Result struct {
	// Is the piece of data flaggged as unsafe?
	Flagged bool

	// Categories that caused the data to be flagged
	FlaggedCategories []string

	// Various category scores applied to the piece of data
	CategoryScores map[string]float64
}

func (*Result) Ignoring added in v1.32.0

func (r *Result) Ignoring(categories ...string) *Result

Ignoring returns r's verdict with the named categories no longer counted toward it: they are dropped from FlaggedCategories and Flagged is recomputed from what remains, while CategoryScores is kept whole so an ignored category still reads for logging. A result that flagged none of them is returned as is, verdict included, and a nil r yields nil, so a classifier that declined (ErrUnsupportedLanguage) needs no special case. r itself is never modified.

It exists for a caller that runs the generic text classifier on input one of its categories does not apply to and cannot ask the classifier to leave that category out: a display name or username is a user's to make meaningless, so the gibberish class that is right for prose, and for a group title, is wrong for them.

type Server

type Server struct {
	moderationpb.UnimplementedModerationServer
	// contains filtered or unexported fields
}

func NewServer

func NewServer(log *zap.Logger, authz auth.Authorizer, client Client, attestor model.KeyPair) *Server

func (*Server) ModerateText

ModerateText moderates text under the checks of the kind the request names (req.Kind) and signs that kind into the attestation, so the attestation is valid only where content of that kind is used (see ValidateAttestation).

A request naming no kind comes from a legacy client and gets the checks every kind once shared (moderateLegacyText).

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL