moonspoof

    Unicode Spoof and Homoglyph Detection for MoonBit (UTS #39)

    unicode
    uts39
    security
    spoof
    confusable
    homoglyph
    identifier
    Download zip
    Version
    0.2.0
    License
    Apache-2.0
    Last updated
    6 days ago
    Downloads
    42

    No dependencies

    #MoonSpoof

    Unicode Spoof and Homoglyph Detection for MoonBit, implementing selected Unicode Technical Standard #39 mechanisms.

    #Key Features

    • Unicode 16.0 NFD, full default folding, default-ignorable removal and stable confusable keys.
    • Complete Unicode Script/Script_Extensions properties and resolved script sets, alongside legacy script diagnostics and restriction estimates.
    • Optional literal Identifier_Status filtering with typed codepoint/index evidence, separate from existing profile defaults and application syntax.
    • Opt-in decimal-system mixing detection with scalar conflict evidence.
    • Multi-script restriction level classification (Single Script, Highly Restrictive, Moderately Restrictive).
    • Detection of invisible zero-width formatting characters and bidirectional control codes.
    • Stable hash-indexed batch collision grouping using the same keys as pair matching.

    #Usage

    Install with moon add Sidney-sunny/moonspoof and import "Sidney-sunny/moonspoof" @moonspoof in your package. Source development uses the compiler pinned in .moon-version (0.10.18). See third-party notices when redistributing generated data or engine artifacts.

    ///|
    let authentic = "paypal"

    ///|
    let candidate = "p\u0430ypal" // Cyrillic Small Letter A

    ///|
    let is_confusable = @moonspoof.are_confusable(authentic, candidate)

    ///|
    let skeleton = @moonspoof.skeleton(candidate)

    ///|
    let report = @moonspoof.analyze_identifier(candidate)

    Default profiles do not enforce Identifier_Status or decimal mixing checks, and bidi skeleton reordering is not implemented. See the complete script API contracts. Fullwidth folding and key stabilization are application extensions.

    For complete documentation, see the Documentation and API Specification.

    ScriptSet

    ALL is distinct from an empty intersection and from the Unknown property.

    analyze_identifier

    analyze_scripts

    are_confusable

    fn are_confusable(a : String, b : String) -> Bool

    are_confusable_ignore_case

    fn are_confusable_ignore_case(a : String, b : String) -> Bool

    find_confusable_groups

    find_confusable_groups_ignore_case

    fn find_confusable_groups_ignore_case(names : Array[String]) -> Array[
    ConfusableGroup
    ]

    get_decimal_systems

    fn get_decimal_systems(input : String) -> Array[Int]

    get_decimal_zero

    fn get_decimal_zero(cp : Int) -> Int?

    get_identifier_status

    get_library_version

    fn get_library_version() -> String

    Release identity for persisted metadata and integration diagnostics.

    get_restriction_level

    get_script_extensions

    fn get_script_extensions(cp : Int) -> Array[String]

    get_unicode_script

    fn get_unicode_script(cp : Int) -> String

    get_unicode_version

    has_bidi_controls

    fn has_bidi_controls(input : String) -> Bool

    has_bidi_override

    fn has_bidi_override(input : String) -> Bool

    has_invisible_characters

    fn has_invisible_characters(input : String) -> Bool

    has_mixed_numbers

    fn has_mixed_numbers(input : String) -> Bool

    is_allowed_identifier

    fn is_allowed_identifier(input : String, profile? :
    IdentifierProfile
    ) -> Bool

    is_mixed_script

    fn is_mixed_script(input : String) -> Bool

    is_mixed_script_resolved

    fn is_mixed_script_resolved(input : String) -> Bool

    is_single_script

    fn is_single_script(input : String) -> Bool

    resolve_script_set

    fn resolve_script_set(input : String) ->
    ScriptSet

    skeleton

    fn skeleton(input : String) -> String

    skeleton_case_folded

    fn skeleton_case_folded(input : String) -> String

    validate_identifier

    fn validate_identifier(input : String, profile? :
    IdentifierProfile
    ) -> Result[Unit, String]

    validate_identifier_status

    fn validate_identifier_status(input : String) -> Result[Unit,
    IdentifierStatusError
    ]

    validate_number_systems

    fn validate_number_systems(input : String) -> Result[Unit,
    MixedNumberIssue
    ]