@amatiscorp/disguard 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1028 -0
- package/dist/AntiSpam.d.ts +36 -0
- package/dist/AntiSpam.d.ts.map +1 -0
- package/dist/AntiSpam.js +196 -0
- package/dist/AntiSpam.js.map +1 -0
- package/dist/defaults.d.ts +5 -0
- package/dist/defaults.d.ts.map +1 -0
- package/dist/defaults.js +184 -0
- package/dist/defaults.js.map +1 -0
- package/dist/detectors/caps.d.ts +3 -0
- package/dist/detectors/caps.d.ts.map +1 -0
- package/dist/detectors/caps.js +29 -0
- package/dist/detectors/caps.js.map +1 -0
- package/dist/detectors/duplicates.d.ts +3 -0
- package/dist/detectors/duplicates.d.ts.map +1 -0
- package/dist/detectors/duplicates.js +40 -0
- package/dist/detectors/duplicates.js.map +1 -0
- package/dist/detectors/emojis.d.ts +3 -0
- package/dist/detectors/emojis.d.ts.map +1 -0
- package/dist/detectors/emojis.js +35 -0
- package/dist/detectors/emojis.js.map +1 -0
- package/dist/detectors/flood.d.ts +3 -0
- package/dist/detectors/flood.d.ts.map +1 -0
- package/dist/detectors/flood.js +24 -0
- package/dist/detectors/flood.js.map +1 -0
- package/dist/detectors/images.d.ts +9 -0
- package/dist/detectors/images.d.ts.map +1 -0
- package/dist/detectors/images.js +105 -0
- package/dist/detectors/images.js.map +1 -0
- package/dist/detectors/incident.d.ts +10 -0
- package/dist/detectors/incident.d.ts.map +1 -0
- package/dist/detectors/incident.js +18 -0
- package/dist/detectors/incident.js.map +1 -0
- package/dist/detectors/links.d.ts +3 -0
- package/dist/detectors/links.d.ts.map +1 -0
- package/dist/detectors/links.js +85 -0
- package/dist/detectors/links.js.map +1 -0
- package/dist/detectors/mentions.d.ts +3 -0
- package/dist/detectors/mentions.d.ts.map +1 -0
- package/dist/detectors/mentions.js +47 -0
- package/dist/detectors/mentions.js.map +1 -0
- package/dist/enforcement.d.ts +4 -0
- package/dist/enforcement.d.ts.map +1 -0
- package/dist/enforcement.js +153 -0
- package/dist/enforcement.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/store/MemoryStore.d.ts +18 -0
- package/dist/store/MemoryStore.d.ts.map +1 -0
- package/dist/store/MemoryStore.js +96 -0
- package/dist/store/MemoryStore.js.map +1 -0
- package/dist/types.d.ts +208 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/hash.d.ts +9 -0
- package/dist/utils/hash.d.ts.map +1 -0
- package/dist/utils/hash.js +42 -0
- package/dist/utils/hash.js.map +1 -0
- package/dist/utils/normalize.d.ts +5 -0
- package/dist/utils/normalize.d.ts.map +1 -0
- package/dist/utils/normalize.js +35 -0
- package/dist/utils/normalize.js.map +1 -0
- package/dist/utils/similarity.d.ts +5 -0
- package/dist/utils/similarity.d.ts.map +1 -0
- package/dist/utils/similarity.js +45 -0
- package/dist/utils/similarity.js.map +1 -0
- package/dist/utils/urls.d.ts +18 -0
- package/dist/utils/urls.d.ts.map +1 -0
- package/dist/utils/urls.js +148 -0
- package/dist/utils/urls.js.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MemoryStore = void 0;
|
|
4
|
+
class MemoryStore {
|
|
5
|
+
users = new Map();
|
|
6
|
+
images = [];
|
|
7
|
+
userKey(guildId, userId) {
|
|
8
|
+
return `${guildId}:${userId}`;
|
|
9
|
+
}
|
|
10
|
+
bucket(guildId, userId) {
|
|
11
|
+
const key = this.userKey(guildId, userId);
|
|
12
|
+
let bucket = this.users.get(key);
|
|
13
|
+
if (!bucket) {
|
|
14
|
+
bucket = { messages: [], strikes: 0, lastStrikeAt: 0 };
|
|
15
|
+
this.users.set(key, bucket);
|
|
16
|
+
}
|
|
17
|
+
return bucket;
|
|
18
|
+
}
|
|
19
|
+
pushMessage(guildId, userId, snapshot, maxAgeMs) {
|
|
20
|
+
const bucket = this.bucket(guildId, userId);
|
|
21
|
+
bucket.messages.push(snapshot);
|
|
22
|
+
this.pruneUser(bucket, snapshot.timestamp, maxAgeMs);
|
|
23
|
+
return bucket.messages;
|
|
24
|
+
}
|
|
25
|
+
getHistory(guildId, userId, now, windowMs) {
|
|
26
|
+
const bucket = this.users.get(this.userKey(guildId, userId));
|
|
27
|
+
if (!bucket)
|
|
28
|
+
return [];
|
|
29
|
+
return bucket.messages.filter((item) => now - item.timestamp <= windowMs);
|
|
30
|
+
}
|
|
31
|
+
addImageHit(hash, userId, timestamp) {
|
|
32
|
+
this.images.push({ hash, userId, timestamp });
|
|
33
|
+
}
|
|
34
|
+
countImageHits(hash, now, windowMs, userId) {
|
|
35
|
+
return this.images.filter((hit) => {
|
|
36
|
+
if (now - hit.timestamp > windowMs)
|
|
37
|
+
return false;
|
|
38
|
+
if (hit.hash !== hash)
|
|
39
|
+
return false;
|
|
40
|
+
if (userId && hit.userId !== userId)
|
|
41
|
+
return false;
|
|
42
|
+
return true;
|
|
43
|
+
}).length;
|
|
44
|
+
}
|
|
45
|
+
countDistinctUsersForImage(hash, now, windowMs) {
|
|
46
|
+
const users = new Set();
|
|
47
|
+
for (const hit of this.images) {
|
|
48
|
+
if (now - hit.timestamp > windowMs)
|
|
49
|
+
continue;
|
|
50
|
+
if (hit.hash !== hash)
|
|
51
|
+
continue;
|
|
52
|
+
users.add(hit.userId);
|
|
53
|
+
}
|
|
54
|
+
return users.size;
|
|
55
|
+
}
|
|
56
|
+
addStrike(guildId, userId, now, decayMs) {
|
|
57
|
+
const bucket = this.bucket(guildId, userId);
|
|
58
|
+
if (decayMs > 0 && bucket.lastStrikeAt > 0 && now - bucket.lastStrikeAt > decayMs) {
|
|
59
|
+
bucket.strikes = 0;
|
|
60
|
+
}
|
|
61
|
+
bucket.strikes += 1;
|
|
62
|
+
bucket.lastStrikeAt = now;
|
|
63
|
+
return bucket.strikes;
|
|
64
|
+
}
|
|
65
|
+
getStrikes(guildId, userId, now, decayMs) {
|
|
66
|
+
const bucket = this.users.get(this.userKey(guildId, userId));
|
|
67
|
+
if (!bucket)
|
|
68
|
+
return 0;
|
|
69
|
+
if (decayMs > 0 && bucket.lastStrikeAt > 0 && now - bucket.lastStrikeAt > decayMs) {
|
|
70
|
+
return 0;
|
|
71
|
+
}
|
|
72
|
+
return bucket.strikes;
|
|
73
|
+
}
|
|
74
|
+
resetUser(guildId, userId) {
|
|
75
|
+
this.users.delete(this.userKey(guildId, userId));
|
|
76
|
+
}
|
|
77
|
+
cleanup(now, maxAgeMs) {
|
|
78
|
+
for (const [key, bucket] of this.users) {
|
|
79
|
+
this.pruneUser(bucket, now, maxAgeMs);
|
|
80
|
+
const staleStrikes = bucket.lastStrikeAt > 0 && now - bucket.lastStrikeAt > maxAgeMs;
|
|
81
|
+
if (bucket.messages.length === 0 && (bucket.strikes === 0 || staleStrikes)) {
|
|
82
|
+
this.users.delete(key);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
for (let i = this.images.length - 1; i >= 0; i -= 1) {
|
|
86
|
+
if (now - this.images[i].timestamp > maxAgeMs) {
|
|
87
|
+
this.images.splice(i, 1);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
pruneUser(bucket, now, maxAgeMs) {
|
|
92
|
+
bucket.messages = bucket.messages.filter((item) => now - item.timestamp <= maxAgeMs);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
exports.MemoryStore = MemoryStore;
|
|
96
|
+
//# sourceMappingURL=MemoryStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MemoryStore.js","sourceRoot":"","sources":["../../src/store/MemoryStore.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import type { Client, Message } from "discord.js";
|
|
2
|
+
export type DetectorType = "flood" | "duplicate" | "link" | "image" | "mention" | "caps" | "emoji";
|
|
3
|
+
export type Severity = "low" | "medium" | "high" | "critical";
|
|
4
|
+
export type ActionType = "delete" | "warn" | "timeout" | "kick" | "ban";
|
|
5
|
+
export type ImageHashMode = "meta" | "content";
|
|
6
|
+
export type PresetName = "lenient" | "balanced" | "strict";
|
|
7
|
+
export type DeepPartial<T> = {
|
|
8
|
+
[K in keyof T]?: T[K] extends Array<infer U> ? Array<DeepPartial<U>> : T[K] extends object ? DeepPartial<T[K]> : T[K];
|
|
9
|
+
};
|
|
10
|
+
export interface Incident {
|
|
11
|
+
type: DetectorType;
|
|
12
|
+
severity: Severity;
|
|
13
|
+
userId: string;
|
|
14
|
+
guildId: string;
|
|
15
|
+
channelId: string;
|
|
16
|
+
messageId: string;
|
|
17
|
+
reason: string;
|
|
18
|
+
details: Record<string, unknown>;
|
|
19
|
+
recommendedActions: ActionType[];
|
|
20
|
+
timestamp: number;
|
|
21
|
+
}
|
|
22
|
+
export interface ActionResult {
|
|
23
|
+
incident: Incident;
|
|
24
|
+
dryRun: boolean;
|
|
25
|
+
applied: ActionType[];
|
|
26
|
+
skipped: Array<{
|
|
27
|
+
action: ActionType;
|
|
28
|
+
reason: string;
|
|
29
|
+
}>;
|
|
30
|
+
error?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface MessageSnapshot {
|
|
33
|
+
id: string;
|
|
34
|
+
channelId: string;
|
|
35
|
+
content: string;
|
|
36
|
+
normalized: string;
|
|
37
|
+
timestamp: number;
|
|
38
|
+
attachmentHashes: string[];
|
|
39
|
+
}
|
|
40
|
+
export interface IgnoreLists {
|
|
41
|
+
users: string[];
|
|
42
|
+
roles: string[];
|
|
43
|
+
channels: string[];
|
|
44
|
+
categories: string[];
|
|
45
|
+
guilds: string[];
|
|
46
|
+
}
|
|
47
|
+
export interface FloodConfig {
|
|
48
|
+
/** Activa el detector de flood (muchos mensajes en poco tiempo). */
|
|
49
|
+
enabled: boolean;
|
|
50
|
+
/** Máximo de mensajes permitidos dentro de la ventana. */
|
|
51
|
+
maxMessages: number;
|
|
52
|
+
/** Ventana deslizante en milisegundos. */
|
|
53
|
+
windowMs: number;
|
|
54
|
+
severity: Severity;
|
|
55
|
+
}
|
|
56
|
+
export interface DuplicateConfig {
|
|
57
|
+
/** Activa el detector de texto repetido. */
|
|
58
|
+
enabled: boolean;
|
|
59
|
+
/** Veces que se puede repetir el mismo (o muy similar) mensaje. */
|
|
60
|
+
maxRepeats: number;
|
|
61
|
+
windowMs: number;
|
|
62
|
+
/**
|
|
63
|
+
* Umbral 0-1. 1 = solo coincidencia exacta.
|
|
64
|
+
* 0.85 detecta variaciones leves ("hola!!" vs "hola!").
|
|
65
|
+
*/
|
|
66
|
+
similarity: number;
|
|
67
|
+
severity: Severity;
|
|
68
|
+
}
|
|
69
|
+
export interface LinkConfig {
|
|
70
|
+
enabled: boolean;
|
|
71
|
+
/** Bloquea invitaciones de Discord (discord.gg / discord.com/invite). */
|
|
72
|
+
blockInvites: boolean;
|
|
73
|
+
/** Bloquea acortadores (bit.ly, t.co, tinyurl, etc.). */
|
|
74
|
+
blockShorteners: boolean;
|
|
75
|
+
/** Bloquea enlaces a IPs literales (http://1.2.3.4). */
|
|
76
|
+
blockIpLinks: boolean;
|
|
77
|
+
/** Bloquea dominios punycode / homógrafos (xn--). */
|
|
78
|
+
blockPunycode: boolean;
|
|
79
|
+
/** Detecta clones de marcas (dlscord, steamcommunnity, ...). */
|
|
80
|
+
blockBrandLookalikes: boolean;
|
|
81
|
+
/** Combina palabras de estafa + enlace (nitro gratis, steam gift...). */
|
|
82
|
+
detectPhishingKeywords: boolean;
|
|
83
|
+
/** Dominios o hosts siempre permitidos. */
|
|
84
|
+
allowList: string[];
|
|
85
|
+
/** Dominios o hosts siempre bloqueados. */
|
|
86
|
+
blockList: string[];
|
|
87
|
+
/** TLDs sospechosos extra. Vacío = no se usa. */
|
|
88
|
+
suspiciousTlds: string[];
|
|
89
|
+
/** Expresiones regulares extra sobre la URL o el mensaje. */
|
|
90
|
+
customPatterns: string[];
|
|
91
|
+
/** Palabras extra que, junto a un enlace, se consideran phishing. */
|
|
92
|
+
extraPhishingKeywords: string[];
|
|
93
|
+
severity: Severity;
|
|
94
|
+
}
|
|
95
|
+
export interface ImageConfig {
|
|
96
|
+
enabled: boolean;
|
|
97
|
+
/** Veces que se puede reenviar la misma imagen. */
|
|
98
|
+
maxRepeats: number;
|
|
99
|
+
windowMs: number;
|
|
100
|
+
/**
|
|
101
|
+
* `meta` usa tamaño + tipo + nombre (rápido, sin descargar).
|
|
102
|
+
* `content` descarga el archivo y hace SHA-256 (más preciso).
|
|
103
|
+
*/
|
|
104
|
+
hashMode: ImageHashMode;
|
|
105
|
+
/** Tamaño máximo a descargar en modo `content` (bytes). */
|
|
106
|
+
maxDownloadBytes: number;
|
|
107
|
+
/** Incluye stickers en la detección. */
|
|
108
|
+
includeStickers: boolean;
|
|
109
|
+
/** Incluye imágenes de embeds. */
|
|
110
|
+
includeEmbeds: boolean;
|
|
111
|
+
/**
|
|
112
|
+
* Si varios usuarios distintos pegan la misma imagen en poco tiempo
|
|
113
|
+
* (raid / copypasta visual). 0 = desactivado.
|
|
114
|
+
*/
|
|
115
|
+
crossUserThreshold: number;
|
|
116
|
+
severity: Severity;
|
|
117
|
+
}
|
|
118
|
+
export interface MentionConfig {
|
|
119
|
+
enabled: boolean;
|
|
120
|
+
maxMentions: number;
|
|
121
|
+
blockEveryone: boolean;
|
|
122
|
+
blockHere: boolean;
|
|
123
|
+
severity: Severity;
|
|
124
|
+
}
|
|
125
|
+
export interface CapsConfig {
|
|
126
|
+
enabled: boolean;
|
|
127
|
+
minLength: number;
|
|
128
|
+
/** Porcentaje 0-100 de mayúsculas para considerarlo spam. */
|
|
129
|
+
maxPercent: number;
|
|
130
|
+
severity: Severity;
|
|
131
|
+
}
|
|
132
|
+
export interface EmojiConfig {
|
|
133
|
+
enabled: boolean;
|
|
134
|
+
maxEmojis: number;
|
|
135
|
+
maxStickers: number;
|
|
136
|
+
severity: Severity;
|
|
137
|
+
}
|
|
138
|
+
export interface TimeoutPunishment {
|
|
139
|
+
enabled: boolean;
|
|
140
|
+
durationMs: number;
|
|
141
|
+
minStrikes: number;
|
|
142
|
+
}
|
|
143
|
+
export interface BooleanPunishment {
|
|
144
|
+
enabled: boolean;
|
|
145
|
+
minStrikes: number;
|
|
146
|
+
}
|
|
147
|
+
export interface PunishmentConfig {
|
|
148
|
+
deleteMessage: boolean;
|
|
149
|
+
warnUser: boolean;
|
|
150
|
+
/** Si es true, avisa por DM. Si no, responde en el canal. */
|
|
151
|
+
dmUser: boolean;
|
|
152
|
+
/** Plantilla. Placeholders: {user}, {reason}, {type}, {strikes}. */
|
|
153
|
+
warnMessage: string;
|
|
154
|
+
timeout: TimeoutPunishment;
|
|
155
|
+
kick: BooleanPunishment;
|
|
156
|
+
ban: BooleanPunishment;
|
|
157
|
+
/** Acumula strikes y aplica el castigo más alto alcanzado. */
|
|
158
|
+
escalate: boolean;
|
|
159
|
+
/** Canal donde se envía un embed de log. */
|
|
160
|
+
logChannelId: string | null;
|
|
161
|
+
/** Los strikes caducan tras este tiempo. 0 = nunca. */
|
|
162
|
+
strikeDecayMs: number;
|
|
163
|
+
}
|
|
164
|
+
export interface ResolvedConfig {
|
|
165
|
+
enabled: boolean;
|
|
166
|
+
dryRun: boolean;
|
|
167
|
+
ignoreBots: boolean;
|
|
168
|
+
ignoreWebhooks: boolean;
|
|
169
|
+
ignoreOwner: boolean;
|
|
170
|
+
/** Ignora miembros con permiso Administrator. */
|
|
171
|
+
ignoreAdministrators: boolean;
|
|
172
|
+
ignored: IgnoreLists;
|
|
173
|
+
flood: FloodConfig;
|
|
174
|
+
duplicates: DuplicateConfig;
|
|
175
|
+
links: LinkConfig;
|
|
176
|
+
images: ImageConfig;
|
|
177
|
+
mentions: MentionConfig;
|
|
178
|
+
caps: CapsConfig;
|
|
179
|
+
emojis: EmojiConfig;
|
|
180
|
+
punishment: PunishmentConfig;
|
|
181
|
+
/** Revisa también ediciones de mensajes. */
|
|
182
|
+
checkEdits: boolean;
|
|
183
|
+
/** Intervalo de limpieza de memoria. */
|
|
184
|
+
cleanupIntervalMs: number;
|
|
185
|
+
}
|
|
186
|
+
export interface AntiSpamOptions extends DeepPartial<ResolvedConfig> {
|
|
187
|
+
preset?: PresetName;
|
|
188
|
+
onDetect?: (incident: Incident, message: Message) => void | Promise<void>;
|
|
189
|
+
onAction?: (result: ActionResult) => void | Promise<void>;
|
|
190
|
+
onError?: (error: unknown, context: string) => void;
|
|
191
|
+
}
|
|
192
|
+
export interface AnalyzeContext {
|
|
193
|
+
client: Client;
|
|
194
|
+
config: ResolvedConfig;
|
|
195
|
+
now: number;
|
|
196
|
+
}
|
|
197
|
+
export interface DetectorInput {
|
|
198
|
+
message: Message;
|
|
199
|
+
snapshot: MessageSnapshot;
|
|
200
|
+
history: MessageSnapshot[];
|
|
201
|
+
config: ResolvedConfig;
|
|
202
|
+
now: number;
|
|
203
|
+
}
|
|
204
|
+
export interface Detector {
|
|
205
|
+
type: DetectorType;
|
|
206
|
+
inspect(input: DetectorInput): Promise<Incident | null> | Incident | null;
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,MAAM,YAAY,GACpB,OAAO,GACP,WAAW,GACX,MAAM,GACN,OAAO,GACP,SAAS,GACT,MAAM,GACN,OAAO,CAAC;AAEZ,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;AAE9D,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,KAAK,CAAC;AAExE,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,CAAC;AAE/C,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAC;AAE3D,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;KAC1B,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,MAAM,CAAC,CAAC,GACxC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GACrB,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GACjB,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GACjB,CAAC,CAAC,CAAC,CAAC;CACX,CAAC;AAEF,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,kBAAkB,EAAE,UAAU,EAAE,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,OAAO,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,UAAU,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,oEAAoE;IACpE,OAAO,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,4CAA4C;IAC5C,OAAO,EAAE,OAAO,CAAC;IACjB,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,yEAAyE;IACzE,YAAY,EAAE,OAAO,CAAC;IACtB,yDAAyD;IACzD,eAAe,EAAE,OAAO,CAAC;IACzB,wDAAwD;IACxD,YAAY,EAAE,OAAO,CAAC;IACtB,qDAAqD;IACrD,aAAa,EAAE,OAAO,CAAC;IACvB,gEAAgE;IAChE,oBAAoB,EAAE,OAAO,CAAC;IAC9B,yEAAyE;IACzE,sBAAsB,EAAE,OAAO,CAAC;IAChC,2CAA2C;IAC3C,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,2CAA2C;IAC3C,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,iDAAiD;IACjD,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,6DAA6D;IAC7D,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,qEAAqE;IACrE,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,QAAQ,EAAE,aAAa,CAAC;IACxB,2DAA2D;IAC3D,gBAAgB,EAAE,MAAM,CAAC;IACzB,wCAAwC;IACxC,eAAe,EAAE,OAAO,CAAC;IACzB,kCAAkC;IAClC,aAAa,EAAE,OAAO,CAAC;IACvB;;;OAGG;IACH,kBAAkB,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,OAAO,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,6DAA6D;IAC7D,MAAM,EAAE,OAAO,CAAC;IAChB,oEAAoE;IACpE,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,IAAI,EAAE,iBAAiB,CAAC;IACxB,GAAG,EAAE,iBAAiB,CAAC;IACvB,8DAA8D;IAC9D,QAAQ,EAAE,OAAO,CAAC;IAClB,4CAA4C;IAC5C,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,uDAAuD;IACvD,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,EAAE,OAAO,CAAC;IACrB,iDAAiD;IACjD,oBAAoB,EAAE,OAAO,CAAC;IAC9B,OAAO,EAAE,WAAW,CAAC;IACrB,KAAK,EAAE,WAAW,CAAC;IACnB,UAAU,EAAE,eAAe,CAAC;IAC5B,KAAK,EAAE,UAAU,CAAC;IAClB,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,aAAa,CAAC;IACxB,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,4CAA4C;IAC5C,UAAU,EAAE,OAAO,CAAC;IACpB,wCAAwC;IACxC,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,eAAgB,SAAQ,WAAW,CAAC,cAAc,CAAC;IAClE,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1E,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACrD;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,cAAc,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,eAAe,CAAC;IAC1B,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,MAAM,EAAE,cAAc,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,QAAQ,GAAG,IAAI,CAAC;CAC3E"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function sha256(value: string | Buffer): string;
|
|
2
|
+
export declare function metaAttachmentHash(input: {
|
|
3
|
+
name?: string | null;
|
|
4
|
+
size?: number | null;
|
|
5
|
+
contentType?: string | null;
|
|
6
|
+
url?: string | null;
|
|
7
|
+
}): string;
|
|
8
|
+
export declare function contentHashFromUrl(url: string, maxBytes: number): Promise<string | null>;
|
|
9
|
+
//# sourceMappingURL=hash.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/utils/hash.ts"],"names":[],"mappings":"AAEA,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,GAAG,MAAM,CAKT;AAED,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA0BxB"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sha256 = sha256;
|
|
4
|
+
exports.metaAttachmentHash = metaAttachmentHash;
|
|
5
|
+
exports.contentHashFromUrl = contentHashFromUrl;
|
|
6
|
+
const node_crypto_1 = require("node:crypto");
|
|
7
|
+
function sha256(value) {
|
|
8
|
+
return (0, node_crypto_1.createHash)("sha256").update(value).digest("hex");
|
|
9
|
+
}
|
|
10
|
+
function metaAttachmentHash(input) {
|
|
11
|
+
const name = (input.name ?? "unknown").toLowerCase().trim();
|
|
12
|
+
const size = input.size ?? 0;
|
|
13
|
+
const type = (input.contentType ?? "application/octet-stream").toLowerCase();
|
|
14
|
+
return sha256(`meta:${size}:${type}:${name}`);
|
|
15
|
+
}
|
|
16
|
+
async function contentHashFromUrl(url, maxBytes) {
|
|
17
|
+
const response = await fetch(url, {
|
|
18
|
+
redirect: "follow",
|
|
19
|
+
headers: { "User-Agent": "@amatiscorp/disguard/1.0" },
|
|
20
|
+
});
|
|
21
|
+
if (!response.ok || !response.body)
|
|
22
|
+
return null;
|
|
23
|
+
const length = Number(response.headers.get("content-length") ?? 0);
|
|
24
|
+
if (length > maxBytes)
|
|
25
|
+
return null;
|
|
26
|
+
const reader = response.body.getReader();
|
|
27
|
+
const chunks = [];
|
|
28
|
+
let total = 0;
|
|
29
|
+
while (true) {
|
|
30
|
+
const { done, value } = await reader.read();
|
|
31
|
+
if (done)
|
|
32
|
+
break;
|
|
33
|
+
total += value.byteLength;
|
|
34
|
+
if (total > maxBytes) {
|
|
35
|
+
await reader.cancel();
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
chunks.push(value);
|
|
39
|
+
}
|
|
40
|
+
return sha256(Buffer.concat(chunks));
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=hash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/utils/hash.ts"],"names":[],"mappings":";;AAEA,wBAEC;AAED,gDAUC;AAED,gDA6BC;AA/CD,6CAAyC;AAEzC,SAAgB,MAAM,CAAC,KAAsB;IAC3C,OAAO,IAAA,wBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC1D,CAAC;AAED,SAAgB,kBAAkB,CAAC,KAKlC;IACC,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IAC5D,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,WAAW,IAAI,0BAA0B,CAAC,CAAC,WAAW,EAAE,CAAC;IAC7E,OAAO,MAAM,CAAC,QAAQ,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC;AAChD,CAAC;AAEM,KAAK,UAAU,kBAAkB,CACtC,GAAW,EACX,QAAgB;IAEhB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,QAAQ,EAAE,QAAQ;QAClB,OAAO,EAAE,EAAE,YAAY,EAAE,0BAA0B,EAAE;KACtD,CAAC,CAAC;IACH,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEhD,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;IACnE,IAAI,MAAM,GAAG,QAAQ;QAAE,OAAO,IAAI,CAAC;IAEnC,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;IACzC,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QAC5C,IAAI,IAAI;YAAE,MAAM;QAChB,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC;QAC1B,IAAI,KAAK,GAAG,QAAQ,EAAE,CAAC;YACrB,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IAED,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function stripZalgo(text: string): string;
|
|
2
|
+
export declare function normalizeText(text: string): string;
|
|
3
|
+
export declare function lettersOnly(text: string): string;
|
|
4
|
+
export declare function countEmojis(text: string): number;
|
|
5
|
+
//# sourceMappingURL=normalize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../src/utils/normalize.ts"],"names":[],"mappings":"AAKA,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAYlD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIhD"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stripZalgo = stripZalgo;
|
|
4
|
+
exports.normalizeText = normalizeText;
|
|
5
|
+
exports.lettersOnly = lettersOnly;
|
|
6
|
+
exports.countEmojis = countEmojis;
|
|
7
|
+
const ZALGO = /[\u0300-\u036f\u0489\u1ab0-\u1aff\u1dc0-\u1dff\u20d0-\u20ff\ufe20-\ufe2f]/g;
|
|
8
|
+
const INVISIBLE = /[\u200b-\u200f\u202a-\u202e\u2060-\u206f\ufeff]/g;
|
|
9
|
+
const MARKDOWN = /[`*_~|]+/g;
|
|
10
|
+
const SPOILER = /\|\|/g;
|
|
11
|
+
function stripZalgo(text) {
|
|
12
|
+
return text.normalize("NFKD").replace(ZALGO, "");
|
|
13
|
+
}
|
|
14
|
+
function normalizeText(text) {
|
|
15
|
+
return stripZalgo(text)
|
|
16
|
+
.replace(INVISIBLE, "")
|
|
17
|
+
.replace(SPOILER, "")
|
|
18
|
+
.replace(MARKDOWN, "")
|
|
19
|
+
.replace(/https?:\/\/\S+/gi, "")
|
|
20
|
+
.replace(/<a?:[\w~]+:\d+>/g, "")
|
|
21
|
+
.replace(/<[@#&!]\d+>/g, "")
|
|
22
|
+
.toLowerCase()
|
|
23
|
+
.replace(/[^\p{L}\p{N}\s]/gu, " ")
|
|
24
|
+
.replace(/\s+/g, " ")
|
|
25
|
+
.trim();
|
|
26
|
+
}
|
|
27
|
+
function lettersOnly(text) {
|
|
28
|
+
return stripZalgo(text).replace(/[^\p{L}]/gu, "");
|
|
29
|
+
}
|
|
30
|
+
function countEmojis(text) {
|
|
31
|
+
const custom = text.match(/<a?:[\w~]+:\d+>/g)?.length ?? 0;
|
|
32
|
+
const unicode = text.match(/\p{Extended_Pictographic}/gu)?.length ?? 0;
|
|
33
|
+
return custom + unicode;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=normalize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../src/utils/normalize.ts"],"names":[],"mappings":";;AAKA,gCAEC;AAED,sCAYC;AAED,kCAEC;AAED,kCAIC;AA/BD,MAAM,KAAK,GAAG,4EAA4E,CAAC;AAC3F,MAAM,SAAS,GAAG,kDAAkD,CAAC;AACrE,MAAM,QAAQ,GAAG,WAAW,CAAC;AAC7B,MAAM,OAAO,GAAG,OAAO,CAAC;AAExB,SAAgB,UAAU,CAAC,IAAY;IACrC,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACnD,CAAC;AAED,SAAgB,aAAa,CAAC,IAAY;IACxC,OAAO,UAAU,CAAC,IAAI,CAAC;SACpB,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;SACtB,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;SACpB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;SACrB,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;SAC/B,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;SAC/B,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC;SAC3B,WAAW,EAAE;SACb,OAAO,CAAC,mBAAmB,EAAE,GAAG,CAAC;SACjC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,SAAgB,WAAW,CAAC,IAAY;IACtC,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;AACpD,CAAC;AAED,SAAgB,WAAW,CAAC,IAAY;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC,CAAC;IAC3D,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,6BAA6B,CAAC,EAAE,MAAM,IAAI,CAAC,CAAC;IACvE,OAAO,MAAM,GAAG,OAAO,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function levenshtein(a: string, b: string): number;
|
|
2
|
+
/** Similitud 0-1 (1 = idéntico). */
|
|
3
|
+
export declare function similarity(a: string, b: string): number;
|
|
4
|
+
export declare function looksLike(value: string, target: string, maxDistance?: number): boolean;
|
|
5
|
+
//# sourceMappingURL=similarity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"similarity.d.ts","sourceRoot":"","sources":["../../src/utils/similarity.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAwBxD;AAED,oCAAoC;AACpC,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAMvD;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,SAAI,GAAG,OAAO,CAIjF"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.levenshtein = levenshtein;
|
|
4
|
+
exports.similarity = similarity;
|
|
5
|
+
exports.looksLike = looksLike;
|
|
6
|
+
function levenshtein(a, b) {
|
|
7
|
+
if (a === b)
|
|
8
|
+
return 0;
|
|
9
|
+
if (!a.length)
|
|
10
|
+
return b.length;
|
|
11
|
+
if (!b.length)
|
|
12
|
+
return a.length;
|
|
13
|
+
const rows = a.length + 1;
|
|
14
|
+
const cols = b.length + 1;
|
|
15
|
+
const matrix = Array.from({ length: rows }, () => new Array(cols).fill(0));
|
|
16
|
+
for (let i = 0; i < rows; i += 1)
|
|
17
|
+
matrix[i][0] = i;
|
|
18
|
+
for (let j = 0; j < cols; j += 1)
|
|
19
|
+
matrix[0][j] = j;
|
|
20
|
+
for (let i = 1; i < rows; i += 1) {
|
|
21
|
+
for (let j = 1; j < cols; j += 1) {
|
|
22
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
23
|
+
matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j - 1] + cost);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return matrix[a.length][b.length];
|
|
27
|
+
}
|
|
28
|
+
/** Similitud 0-1 (1 = idéntico). */
|
|
29
|
+
function similarity(a, b) {
|
|
30
|
+
if (!a && !b)
|
|
31
|
+
return 1;
|
|
32
|
+
if (!a || !b)
|
|
33
|
+
return 0;
|
|
34
|
+
const max = Math.max(a.length, b.length);
|
|
35
|
+
if (max === 0)
|
|
36
|
+
return 1;
|
|
37
|
+
return 1 - levenshtein(a, b) / max;
|
|
38
|
+
}
|
|
39
|
+
function looksLike(value, target, maxDistance = 2) {
|
|
40
|
+
if (value === target)
|
|
41
|
+
return false;
|
|
42
|
+
const distance = levenshtein(value, target);
|
|
43
|
+
return distance > 0 && distance <= maxDistance;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=similarity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"similarity.js","sourceRoot":"","sources":["../../src/utils/similarity.ts"],"names":[],"mappings":";;AAAA,kCAwBC;AAGD,gCAMC;AAED,8BAIC;AAvCD,SAAgB,WAAW,CAAC,CAAS,EAAE,CAAS;IAC9C,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IACtB,IAAI,CAAC,CAAC,CAAC,MAAM;QAAE,OAAO,CAAC,CAAC,MAAM,CAAC;IAC/B,IAAI,CAAC,CAAC,CAAC,MAAM;QAAE,OAAO,CAAC,CAAC,MAAM,CAAC;IAE/B,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IAC1B,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IAC1B,MAAM,MAAM,GAAe,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,KAAK,CAAS,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAE/F,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC;QAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACnD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC;QAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAEnD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YACjC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3C,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CACrB,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EACpB,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EACpB,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAC5B,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AACpC,CAAC;AAED,oCAAoC;AACpC,SAAgB,UAAU,CAAC,CAAS,EAAE,CAAS;IAC7C,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC;IACvB,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC;IACvB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;IACzC,IAAI,GAAG,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IACxB,OAAO,CAAC,GAAG,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC;AACrC,CAAC;AAED,SAAgB,SAAS,CAAC,KAAa,EAAE,MAAc,EAAE,WAAW,GAAG,CAAC;IACtE,IAAI,KAAK,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC;IACnC,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC5C,OAAO,QAAQ,GAAG,CAAC,IAAI,QAAQ,IAAI,WAAW,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const DEFAULT_SHORTENERS: string[];
|
|
2
|
+
export declare const OFFICIAL_BRANDS: Record<string, string[]>;
|
|
3
|
+
export declare const DEFAULT_PHISHING_KEYWORDS: string[];
|
|
4
|
+
export interface ExtractedUrl {
|
|
5
|
+
raw: string;
|
|
6
|
+
href: string;
|
|
7
|
+
hostname: string;
|
|
8
|
+
isInvite: boolean;
|
|
9
|
+
isIp: boolean;
|
|
10
|
+
isPunycode: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function extractUrls(text: string): ExtractedUrl[];
|
|
13
|
+
export declare function isDiscordInvite(hostname: string, pathname: string): boolean;
|
|
14
|
+
export declare function hostMatchesList(hostname: string, list: string[]): boolean;
|
|
15
|
+
export declare function isShortener(hostname: string, extra?: string[]): boolean;
|
|
16
|
+
export declare function brandLookalike(hostname: string): string | null;
|
|
17
|
+
export declare function messageHasPhishingKeywords(text: string, extra?: string[]): string | null;
|
|
18
|
+
//# sourceMappingURL=urls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"urls.d.ts","sourceRoot":"","sources":["../../src/utils/urls.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,kBAAkB,UAgB9B,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAUpD,CAAC;AAEF,eAAO,MAAM,yBAAyB,UAkBrC,CAAC;AAEF,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;CACrB;AAaD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,EAAE,CA+BxD;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAM3E;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAMzE;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,GAAE,MAAM,EAAO,GAAG,OAAO,CAE3E;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAsB9D;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,GAAE,MAAM,EAAO,GAAG,MAAM,GAAG,IAAI,CAM5F"}
|