Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
a7c93f7
feat: add Blaspable Eloquent model trait for automatic profanity dete…
deemonic Feb 12, 2026
78b4d1e
refactor: remove legacy v3 source code
deemonic Feb 12, 2026
882f22c
feat: add v4 core engine with driver-based architecture
deemonic Feb 12, 2026
0242d3d
feat: add v4 Laravel integration layer
deemonic Feb 12, 2026
5b64f05
chore: update config and autoload for v4 namespace
deemonic Feb 12, 2026
fc5daa1
test: update test suite for v4 API
deemonic Feb 12, 2026
0b56eae
docs: rewrite README for v4
deemonic Feb 12, 2026
cf7ecbe
feat: add middleware alias, Blade directive, and Str/Stringable macros
deemonic Feb 12, 2026
853c6d5
refactor: flatten Laravel/ namespace into root package namespace
deemonic Feb 13, 2026
a0e0b2f
feat: add phonetic detection driver using metaphone + Levenshtein
deemonic Feb 13, 2026
62d83b9
docs: document phonetic driver in README
deemonic Feb 13, 2026
0b19ab4
feat: add pipeline driver to chain multiple detection drivers
deemonic Feb 13, 2026
9639506
feat: add non-English severity maps and result caching
deemonic Feb 13, 2026
1a2dd69
fix: add high severity tiers and sync severity maps with profanities …
deemonic Feb 13, 2026
b88f128
fix: address pre-existing code review issues
deemonic Feb 13, 2026
3d092a3
fix: address follow-up review comments
deemonic Feb 13, 2026
477f398
fix: use mb_strtolower for false positives and stabilize dedup sort i…
deemonic Feb 14, 2026
412806d
fix: replace str_word_count with multibyte-safe word counting
deemonic Feb 14, 2026
cc92dad
fix: add UTF-8 guard to PatternDriver and use original text in Phonet…
deemonic Feb 14, 2026
c31117c
fix: cap regex separator repetition to prevent PCRE JIT stack overflow
deemonic Feb 15, 2026
bab9047
fix: eliminate nested quantifiers in separator regex to prevent JIT s…
deemonic Feb 17, 2026
a67ccd8
docs: update README with --detail flag and separator limit note
deemonic Feb 18, 2026
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
703 changes: 436 additions & 267 deletions README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"extra": {
"laravel": {
"providers": [
"Blaspsoft\\Blasp\\ServiceProvider"
"Blaspsoft\\Blasp\\BlaspServiceProvider"
],
"aliases": {
"Blasp": "Blaspsoft\\Blasp\\Facades\\Blasp"
Expand Down
233 changes: 233 additions & 0 deletions config/blasp.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
<?php

return [

/*
|--------------------------------------------------------------------------
| Default Driver
|--------------------------------------------------------------------------
|
| The default detection driver. 'regex' provides full obfuscation
| detection. 'pattern' is faster but only matches exact words.
|
*/
'default' => env('BLASP_DRIVER', 'regex'),

/*
|--------------------------------------------------------------------------
| Default Language
|--------------------------------------------------------------------------
|
| The default language to use for profanity detection.
|
*/
'language' => env('BLASP_LANGUAGE', 'english'),

// Backward compat alias
'default_language' => env('BLASP_LANGUAGE', 'english'),

/*
|--------------------------------------------------------------------------
| Mask Character
|--------------------------------------------------------------------------
|
| The character used to mask detected profanities.
|
*/
'mask' => '*',

// Backward compat alias
'mask_character' => '*',

/*
|--------------------------------------------------------------------------
| Minimum Severity
|--------------------------------------------------------------------------
|
| The minimum severity level to detect. Words below this severity
| will be ignored. Options: mild, moderate, high, extreme
|
*/
'severity' => 'mild',

/*
|--------------------------------------------------------------------------
| Events
|--------------------------------------------------------------------------
|
| When enabled, ProfanityDetected events will be fired automatically
| when profanity is found during a check.
|
*/
'events' => false,

/*
|--------------------------------------------------------------------------
| Cache Configuration
|--------------------------------------------------------------------------
*/
'cache' => [
'enabled' => true,
'driver' => env('BLASP_CACHE_DRIVER'),
'ttl' => 86400,
'results' => true,
],

// Backward compat alias
'cache_driver' => env('BLASP_CACHE_DRIVER'),

/*
|--------------------------------------------------------------------------
| Middleware Configuration
|--------------------------------------------------------------------------
*/
'middleware' => [
'action' => 'reject',
'fields' => ['*'],
'except' => ['password', 'email', '_token'],
'severity' => 'mild',
],

/*
|--------------------------------------------------------------------------
| Model Configuration
|--------------------------------------------------------------------------
|
| Controls how the Blaspable trait behaves on Eloquent models.
| 'sanitize' replaces profanity with the mask character.
| 'reject' throws a ProfanityRejectedException instead of saving.
|
*/
'model' => [
'mode' => env('BLASP_MODEL_MODE', 'sanitize'),
],

/*
|--------------------------------------------------------------------------
| Driver-Specific Configuration
|--------------------------------------------------------------------------
*/
'drivers' => [
'pipeline' => [
'drivers' => ['regex', 'phonetic'],
],

'phonetic' => [
'phonemes' => 4, // metaphone code length (2-8, lower=more aggressive)
'min_word_length' => 3, // skip words shorter than this
'max_distance_ratio' => 0.6, // levenshtein threshold (0.3-0.8, lower=stricter)
'supported_languages' => ['english'],
'false_positives' => [
'fork', 'forked', 'forking',
'beach', 'beaches',
'witch', 'witches',
'sheet', 'sheets',
'deck', 'decks',
'count', 'counts', 'counter', 'county',
'ship', 'shipped', 'shipping',
'duck', 'ducked', 'ducking',
'fudge', 'fudging',
'buck', 'bucks',
'puck', 'pucks',
'bass',
'mass',
'pass', 'passed',
'heck',
'shoot', 'shot',
'what', 'white', 'while', 'whole',
],
],
],

/*
|--------------------------------------------------------------------------
| Character Separators
|--------------------------------------------------------------------------
*/
'separators' => [
'@', '#', '%', '&', '_', ';', "'", '"', ',', '~', '`', '|',
'!', '$', '^', '*', '(', ')', '-', '+', '=', '{', '}',
'[', ']', ':', '<', '>', '?', '.', '/',
],

/*
|--------------------------------------------------------------------------
| Character Substitutions
|--------------------------------------------------------------------------
*/
'substitutions' => [
'/a/' => ['a', '4', '@', 'Á', 'á', 'À', 'Â', 'à', 'Â', 'â', 'Ä', 'ä', 'Ã', 'ã', 'Å', 'å', 'æ', 'Æ', 'α', 'Δ', 'Λ', 'λ'],
'/b/' => ['b', '8', '\\', '3', 'ß', 'Β', 'β'],
'/c/' => ['c', 'Ç', 'ç', 'ć', 'Ć', 'č', 'Č', '¢', '€', '<', '(', '{', '©'],
'/d/' => ['d', '\\', ')', 'Þ', 'þ', 'Ð', 'ð'],
'/e/' => ['e', '3', '€', 'È', 'è', 'É', 'é', 'Ê', 'ê', 'ë', 'Ë', 'ē', 'Ē', 'ė', 'Ė', 'ę', 'Ę', '∑'],
'/f/' => ['f', 'ƒ'],
'/g/' => ['g', '6', '9'],
'/h/' => ['h', 'Η'],
'/i/' => ['i', '!', '|', ']', '[', '1', '∫', 'Ì', 'Í', 'Î', 'Ï', 'ì', 'í', 'î', 'ï', 'ī', 'Ī', 'į', 'Į'],
'/j/' => ['j'],
'/k/' => ['k', 'Κ', 'κ'],
'/l/' => ['l', '!', '|', ']', '[', '£', '∫', 'Ì', 'Í', 'Î', 'Ï', 'ł', 'Ł'],
'/m/' => ['m'],
'/n/' => ['n', 'η', 'Ν', 'Π', 'ñ', 'Ñ', 'ń', 'Ń'],
'/o/' => ['o', '0', 'Ο', 'ο', 'Φ', '¤', '°', 'ø', 'ô', 'Ô', 'ö', 'Ö', 'ò', 'Ò', 'ó', 'Ó', 'œ', 'Œ', 'ø', 'Ø', 'ō', 'Ō', 'õ', 'Õ'],
'/p/' => ['p', 'ρ', 'Ρ', '¶', 'þ'],
'/q/' => ['q'],
'/r/' => ['r', '®'],
'/s/' => ['s', '5', '\$', '§', 'ß', 'Ś', 'ś', 'Š', 'š'],
'/t/' => ['t', 'Τ', 'τ'],
'/u/' => ['u', 'υ', 'µ', 'û', 'ü', 'ù', 'ú', 'ū', 'Û', 'Ü', 'Ù', 'Ú', 'Ū', '@', '*'],
'/v/' => ['v', 'υ', 'ν'],
'/w/' => ['w', 'ω', 'ψ', 'Ψ'],
'/x/' => ['x', 'Χ', 'χ'],
'/y/' => ['y', '¥', 'γ', 'ÿ', 'ý', 'Ÿ', 'Ý'],
'/z/' => ['z', 'Ζ', 'ž', 'Ž', 'ź', 'Ź', 'ż', 'Ż'],
],

/*
|--------------------------------------------------------------------------
| False Positives
|--------------------------------------------------------------------------
*/
'false_positives' => [
'hello', 'scunthorpe', 'cockburn', 'penistone', 'lightwater',
'assume', 'bass', 'class', 'compass', 'pass',
'dickinson', 'middlesex', 'cockerel', 'butterscotch', 'blackcock',
'countryside', 'arsenal', 'flick', 'flicker', 'analyst',
'cocktail', 'musicals hit', 'is hit', 'blackcocktail', 'its not',
],

/*
|--------------------------------------------------------------------------
| Global Allow List
|--------------------------------------------------------------------------
|
| Words in this list will never be flagged as profanity.
|
*/
'allow' => [],

/*
|--------------------------------------------------------------------------
| Global Block List
|--------------------------------------------------------------------------
|
| Additional words to always flag as profanity.
|
*/
'block' => [],

/*
|--------------------------------------------------------------------------
| Backward Compatibility: Profanities
|--------------------------------------------------------------------------
|
| Basic profanity list for backward compatibility.
| Full lists are in config/languages/*.php
|
*/
'profanities' => [
'fuck', 'shit', 'damn', 'bitch', 'ass', 'hell',
],

];
Loading