Documentation
¶
Index ¶
- Constants
- Variables
- func HighestFlaggedCategory(result *Result) moderationpb.FlaggedCategory
- func NewIntegration(attestor *commonpb.PublicKey, acceptUnknownKind bool) ocp_integration.Moderation
- func ValidateAttestation(attestation *moderationpb.ModerationAttestation, attestor *commonpb.PublicKey, ...) error
- type Client
- type Integration
- type Result
- type Server
Constants ¶
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 ¶
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") )
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
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 (*Server) ModerateImage ¶
func (s *Server) ModerateImage(ctx context.Context, req *moderationpb.ModerateImageRequest) (*moderationpb.ModerateImageResponse, error)
func (*Server) ModerateText ¶
func (s *Server) ModerateText(ctx context.Context, req *moderationpb.ModerateTextRequest) (*moderationpb.ModerateTextResponse, error)
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).