mirror of
https://github.com/fromchat-messenger/web.git
synced 2026-09-22 19:15:08 +03:00
Implement verification checkmark
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
"""
|
||||
Similarity detection utilities for username and display name comparison.
|
||||
Implements both edit distance and visual similarity detection.
|
||||
"""
|
||||
|
||||
def levenshtein_distance(s1: str, s2: str) -> int:
|
||||
"""Calculate Levenshtein distance between two strings."""
|
||||
if len(s1) < len(s2):
|
||||
return levenshtein_distance(s2, s1)
|
||||
|
||||
if len(s2) == 0:
|
||||
return len(s1)
|
||||
|
||||
previous_row = list(range(len(s2) + 1))
|
||||
for i, c1 in enumerate(s1):
|
||||
current_row = [i + 1]
|
||||
for j, c2 in enumerate(s2):
|
||||
insertions = previous_row[j + 1] + 1
|
||||
deletions = current_row[j] + 1
|
||||
substitutions = previous_row[j] + (c1 != c2)
|
||||
current_row.append(min(insertions, deletions, substitutions))
|
||||
previous_row = current_row
|
||||
|
||||
return previous_row[-1]
|
||||
|
||||
|
||||
def check_visual_similarity(s1: str, s2: str) -> bool:
|
||||
"""
|
||||
Check if two strings are visually similar using common homoglyphs.
|
||||
Returns True if strings are visually similar.
|
||||
"""
|
||||
if len(s1) != len(s2):
|
||||
return False
|
||||
|
||||
# Common homoglyph mappings
|
||||
homoglyphs = {
|
||||
'0': ['O', 'o', 'Q'],
|
||||
'O': ['0', 'o', 'Q'],
|
||||
'o': ['0', 'O', 'Q'],
|
||||
'1': ['l', 'I', '|'],
|
||||
'l': ['1', 'I', '|'],
|
||||
'I': ['1', 'l', '|'],
|
||||
'5': ['S', 's'],
|
||||
'S': ['5', 's'],
|
||||
's': ['5', 'S'],
|
||||
'6': ['G', 'g'],
|
||||
'G': ['6', 'g'],
|
||||
'g': ['6', 'G'],
|
||||
'8': ['B', 'b'],
|
||||
'B': ['8', 'b'],
|
||||
'b': ['8', 'B'],
|
||||
'9': ['g', 'q'],
|
||||
'g': ['9', 'q'],
|
||||
'q': ['9', 'g'],
|
||||
'2': ['Z', 'z'],
|
||||
'Z': ['2', 'z'],
|
||||
'z': ['2', 'Z'],
|
||||
'3': ['E'],
|
||||
'E': ['3'],
|
||||
'4': ['A'],
|
||||
'A': ['4'],
|
||||
'7': ['T', 't'],
|
||||
'T': ['7', 't'],
|
||||
't': ['7', 'T'],
|
||||
}
|
||||
|
||||
for i in range(len(s1)):
|
||||
c1, c2 = s1[i], s2[i]
|
||||
if c1 == c2:
|
||||
continue
|
||||
|
||||
# Check if characters are homoglyphs
|
||||
if (c1 in homoglyphs and c2 in homoglyphs[c1]) or \
|
||||
(c2 in homoglyphs and c1 in homoglyphs[c2]):
|
||||
continue
|
||||
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def check_username_similarity(username1: str, username2: str) -> bool:
|
||||
"""
|
||||
Check if two usernames are similar using both edit distance and visual similarity.
|
||||
Returns True if usernames are considered similar.
|
||||
"""
|
||||
if username1 == username2:
|
||||
return False
|
||||
|
||||
# Check edit distance (Levenshtein distance <= 2)
|
||||
edit_distance = levenshtein_distance(username1.lower(), username2.lower())
|
||||
if edit_distance <= 2:
|
||||
return True
|
||||
|
||||
# Check visual similarity
|
||||
if check_visual_similarity(username1, username2):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def check_display_name_similarity(display_name1: str, display_name2: str) -> bool:
|
||||
"""
|
||||
Check if two display names are similar using both edit distance and visual similarity.
|
||||
Returns True if display names are considered similar.
|
||||
"""
|
||||
if display_name1 == display_name2:
|
||||
return False
|
||||
|
||||
# Check edit distance (Levenshtein distance <= 2)
|
||||
edit_distance = levenshtein_distance(display_name1.lower(), display_name2.lower())
|
||||
if edit_distance <= 2:
|
||||
return True
|
||||
|
||||
# Check visual similarity
|
||||
if check_visual_similarity(display_name1, display_name2):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def is_user_similar_to_verified(user_username: str, user_display_name: str,
|
||||
verified_users: list[dict]) -> tuple[bool, str]:
|
||||
"""
|
||||
Check if a user is similar to any verified user.
|
||||
|
||||
Args:
|
||||
user_username: Username to check
|
||||
user_display_name: Display name to check
|
||||
verified_users: List of verified user dictionaries with 'username' and 'display_name' keys
|
||||
|
||||
Returns:
|
||||
Tuple of (is_similar, similar_to_username)
|
||||
"""
|
||||
for verified_user in verified_users:
|
||||
verified_username = verified_user.get('username', '')
|
||||
verified_display_name = verified_user.get('display_name', '')
|
||||
|
||||
# Check username similarity
|
||||
if check_username_similarity(user_username, verified_username):
|
||||
return True, verified_username
|
||||
|
||||
# Check display name similarity
|
||||
if check_display_name_similarity(user_display_name, verified_display_name):
|
||||
return True, verified_username
|
||||
|
||||
return False, ""
|
||||
Reference in New Issue
Block a user