nodebb-plugin-restrict-usernames
Advanced tools
Comparing version 0.6.0 to 0.7.0
'use strict'; | ||
const { metaphone3 } = require('metaphone3'); | ||
const meta = require.main.require('./src/meta'); | ||
const batch = require.main.require('./src/batch'); | ||
const groups = require.main.require('./src/groups'); | ||
const user = require.main.require('./src/user'); | ||
@@ -26,9 +29,11 @@ const routeHelpers = require.main.require('./src/routes/helpers'); | ||
plugin.settings['similarity-value'] = 85; | ||
plugin.settingsgroupsChecked = '[""]'; | ||
await meta.settings.set(plugin.id, plugin.settings, true); | ||
} | ||
routeHelpers.setupAdminPageRoute(router, '/admin/plugins/restrict-usernames', [], (req, res) => { | ||
res.render('admin/plugins/restrict-usernames', { rules: plugin.userFilters }); | ||
routeHelpers.setupAdminPageRoute(router, '/admin/plugins/restrict-usernames', [], async (req, res) => { | ||
res.render('admin/plugins/restrict-usernames', { rules: plugin.userFilters, groupsChecked: [{ name: '' }, ...(await groups.getGroupsBySort('count', 0, -1)).filter(group => group?.name)] }); | ||
}); | ||
}; | ||
plugin.userFilters = { | ||
@@ -75,16 +80,60 @@ duplicate: { | ||
// just precompute the bigrams for the current username to avoid redoing the work | ||
const usernameBigrams = bigram(username); | ||
await batch.processSortedSet('username:uid', (checkedUsernames) => { | ||
if (!checkedUsernames.length) { | ||
checkedUsernames = [checkedUsernames]; | ||
} | ||
for (const checkedUsername of checkedUsernames) { | ||
const similarity = diceCoefficient(usernameBigrams, checkedUsername); | ||
if (similarity >= parseInt(plugin.settings['similarity-value'] ?? plugin.userFilters.similarity.placeholder, 10) / 100) { | ||
throw new Error(`[[restrict-usernames:error.username-too-similar, ${checkedUsername}]]`); | ||
const usernameBigrams = bigram(username.normalize('NFD')); | ||
const checkedGroups = JSON.parse(plugin.settings.groupsChecked); | ||
const checkedSets = checkedGroups.filter(group => group.length).map(group => `group:${group}:members`); | ||
if (checkedSets.length === 0) { | ||
checkedSets.push('username:uid'); | ||
} | ||
const batchPromises = checkedSets.map(checkedSet => batch.processSortedSet( | ||
checkedSet, | ||
async (checkedUsernames) => { | ||
if (checkedSet !== 'username:uid') { | ||
checkedUsernames = await user.getUsernamesByUids(checkedUsernames); | ||
} | ||
} | ||
}, {}); | ||
if (!checkedUsernames.length) { | ||
checkedUsernames = [checkedUsernames]; | ||
} | ||
for (const checkedUsername of checkedUsernames) { | ||
const similarity = diceCoefficient(usernameBigrams, checkedUsername.normalize('NFD')); | ||
if (similarity >= parseInt(plugin.settings['similarity-value'] ?? plugin.userFilters.similarity.placeholder, 10) / 100) { | ||
throw new Error(`[[restrict-usernames:error.username-too-similar, ${checkedUsername}]]`); | ||
} | ||
} | ||
}, | ||
{} | ||
)); | ||
await Promise.all(batchPromises); | ||
}, | ||
}, | ||
phonetic: { | ||
type: 'boolean', | ||
name: '[[restrict-usernames:filter.phonetic.name]]', | ||
description: '[[restrict-usernames:filter.phonetic.description]]', | ||
function: async (username) => { | ||
const phonetic = new Set(metaphone3(username)); | ||
const checkedGroups = JSON.parse(plugin.settings.groupsChecked); | ||
const checkedSets = checkedGroups.filter(group => group.length).map(group => `group:${group}:members`); | ||
if (checkedSets.length === 0) { | ||
checkedSets.push('username:uid'); | ||
} | ||
const batchPromises = checkedSets.map(checkedSet => batch.processSortedSet( | ||
checkedSet, | ||
async (checkedUsernames) => { | ||
if (checkedSet !== 'username:uid') { | ||
checkedUsernames = await user.getUsernamesByUids(checkedUsernames); | ||
} | ||
if (!checkedUsernames.length) { | ||
checkedUsernames = [checkedUsernames]; | ||
} | ||
for (const checkedUsername of checkedUsernames) { | ||
if (metaphone3(checkedUsername).filter(p => p && phonetic.has(p)).length) { | ||
throw new Error(`[[restrict-usernames:error.username-too-similar-phonetic, ${checkedUsername}]]`); | ||
} | ||
} | ||
}, | ||
{} | ||
)); | ||
await Promise.all(batchPromises); | ||
}, | ||
}, | ||
regex: { | ||
@@ -111,3 +160,2 @@ type: 'rules', | ||
plugin.settings = await meta.settings.get(plugin.id); | ||
console.log(plugin.settings); | ||
} | ||
@@ -130,4 +178,4 @@ return data; | ||
route: '/plugins/restrict-usernames', | ||
icon: 'fa-tint', | ||
name: 'restrict-usernames', | ||
icon: 'fa-user-lock', | ||
name: 'Restrict Usernames', | ||
}); | ||
@@ -134,0 +182,0 @@ |
{ | ||
"name": "nodebb-plugin-restrict-usernames", | ||
"version": "0.6.0", | ||
"version": "0.7.0", | ||
"description": "Set rules for what usernames are allowed on your forum", | ||
@@ -37,14 +37,15 @@ "main": "library.js", | ||
"devDependencies": { | ||
"@commitlint/cli": "17.2.0", | ||
"@commitlint/config-angular": "17.2.0", | ||
"eslint": "8.27.0", | ||
"eslint-config-nodebb": "0.1.1", | ||
"eslint-plugin-import": "2.26.0", | ||
"husky": "8.0.2", | ||
"lint-staged": "13.0.3" | ||
"@commitlint/cli": "19.2.1", | ||
"@commitlint/config-angular": "19.1.0", | ||
"eslint": "8.57.0", | ||
"eslint-config-nodebb": "0.2.1", | ||
"eslint-plugin-import": "2.29.1", | ||
"husky": "9.0.11", | ||
"lint-staged": "15.2.2" | ||
}, | ||
"dependencies": { | ||
"dice-coefficient": "^2.1.1", | ||
"metaphone3": "^1.0.1", | ||
"n-gram": "^2.0.2" | ||
} | ||
} | ||
} |
{ | ||
"add-item": "Add Item", | ||
"rules": "Rules", | ||
"enabled": "Enabled", | ||
"error.username-too-similar": "The username is too similar to existing user %1", | ||
"error.username-too-similar-phonetic": "The username sounds too similar to existing user %1", | ||
"error.invalid-username": "The username is invalid", | ||
@@ -19,5 +19,10 @@ "error.username-taken": "The username is already taken", | ||
"filter.similarity.description": "If enabled, registering with a username that is too similar to an existing username will be rejected. This is calculated using Sørensen-Dice coefficient of these two usernames. The value is the maximum similarity allowed, so 85 means that usernames with coeffient of 0.85 or more will be rejected. Warning: setting this too low will cause a lot of false positives.", | ||
"filter.phonetic.name": "Phonetic similarity to existing usernames", | ||
"filter.phonetic.description": "If enabled, registering with a username that sounds very similar to an existing username will be rejected. This is calculated using Metaphone algorithm.", | ||
"filter.regex.name": "Custom blacklist (words or regex)", | ||
"filter.regex.description": "If enabled, registering with a username that matches any of the rules will be rejected. Rules are matched using JavaScript regex, but for basic usage just inputting the word will match it as is. Just be weary of special characters like parentheses or periods, which need to be escaped by prepending them with \\", | ||
"insensitive": "(case insensitive)" | ||
"groups-checked": "Checked Groups", | ||
"groups-checked-description": "If any groups is selected here, similarity checks will only compare new usernames to their members", | ||
"insensitive": "(case insensitive)", | ||
"rules": "Rules" | ||
} |
@@ -10,3 +10,5 @@ { | ||
"error.no-letters": "Nazwa użytkownika musi zawierać przy najmniej jedną literę", | ||
"insensitive": "(ignoruje wielkość liter)" | ||
"insensitive": "(ignoruje wielkość liter)", | ||
"groups-checked": "Sprawdzane grupy", | ||
"groups-checked-description": "Jeśli przynajmniej jedna z tych grup jest zaznaczona, zasady podobności będą stosowane tylko do nich" | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
64530
27
397
3
+ Addedmetaphone3@^1.0.1
+ Addedmetaphone3@1.0.1(transitive)
+ Addedtypescript@5.7.2(transitive)