Kembali ke katalog plugin
group
guard
Lihat status proteksi grup
Show group protection status
plugins/group/guard.js
Lokasi file di repo kana-md
2
Perintah termasuk alias
6.4 KB
Ukuran file sumber
4/11/2026
Update terakhir, commit ab47575
Daftar perintah
Ketuk tombol salin untuk menyalin perintah, lalu tempel di chat WhatsApp bot KANA.
.guard.proteksiCara pakai
.guard
Contoh
.guard
Kode sumber plugin
Cara pasang: simpan file ini ke folder plugins/group/ di bot KANA kamu, lalu restart bot. Pemilik source code lain bisa mengambil update plugin terbaru dari halaman ini kapan saja.
import { getGroupSettings, updateGroupSettings } from '../../src/services/group-service.js'
import { applyWarnToSettings, detectGambling, detectLinks, detectPhishing, detectToxic, digitsOf, floodCheck } from '../../src/services/guard-rules.js'
import { sendButtons } from '../../src/ui/buttons.js'
export const config = {
name: 'guard',
alias: ['proteksi'],
category: 'group',
description: { id: 'Lihat status proteksi grup', en: 'Show group protection status' },
usage: '.guard',
example: '.guard',
cooldown: 5,
isGroup: true,
priority: 20,
}
export const i18n = {
id: {
guard: {
status: 'Status proteksi grup ini:\nWelcome: {welcome}\nGoodbye: {goodbye}\nAntilink: {antilink}\nAntispam: {antispam}\nAntitoxic: {antitoxic}\nAntijudol: {antijudol}\nAntiphising: {antiphising}\nBatas warn: {warnLimit}\n{mood}',
on: 'AKTIF', off: 'mati', footer: 'Proteksi grup KANA',
deletedLink: 'Ehh, linknya KANA hapus yaa. @{digits} dapat warn {count}/{limit}. Jangan kirim link di sini~',
deletedGambling: 'Itu promosi judi, KANA hapus yaa. @{digits} dapat warn {count}/{limit}.',
deletedPhishing: 'Pesan itu terindikasi phishing, KANA hapus demi keamanan grup. @{digits} dapat warn {count}/{limit}.',
deletedToxic: 'Mouu, kata katanya kurang sopan, KANA hapus yaa @{digits}. Jaga kata kata yuk~',
spamWarn: 'Pelan pelan yaa @{digits}, jangan spam. Pesan terakhir KANA hapus~',
kicked: '@{digits} mencapai batas warn ({limit}) jadi KANA keluarkan dari grup. Maaf ya, demi ketertiban grup~',
kickFailed: '@{digits} mencapai batas warn ({limit}), tapi KANA belum bisa mengeluarkannya. Bot perlu jadi admin dulu yaa.',
},
},
en: {
guard: {
status: 'Protection status for this group:\nWelcome: {welcome}\nGoodbye: {goodbye}\nAntilink: {antilink}\nAntispam: {antispam}\nAntitoxic: {antitoxic}\nAntijudol: {antijudol}\nAntiphising: {antiphising}\nWarn limit: {warnLimit}\n{mood}',
on: 'ON', off: 'off', footer: 'KANA group protection',
deletedLink: 'Eh, I removed that link. @{digits} gets warn {count}/{limit}. Please do not send links here~',
deletedGambling: 'That is gambling promotion, I removed it. @{digits} gets warn {count}/{limit}.',
deletedPhishing: 'That message looks like phishing, I removed it to keep the group safe. @{digits} gets warn {count}/{limit}.',
deletedToxic: 'Mouu, those words are not polite, I removed it @{digits}. Let us keep it kind~',
spamWarn: 'Slow down @{digits}, please do not spam. I removed the last message~',
kicked: '@{digits} reached the warn limit ({limit}) so I removed them from the group. Sorry, for the group order~',
kickFailed: '@{digits} reached the warn limit ({limit}), but I cannot remove them yet. The bot needs to be admin first.',
},
},
}
const FEATURES = ['welcome', 'goodbye', 'antilink', 'antispam', 'antitoxic', 'antijudol', 'antiphising']
const spamState = new Map()
async function senderIsAdminOrOwner(ctx) {
if (ctx.isOwner) return true
try {
const meta = await ctx.getGroupMetadata()
if (!meta?.participants) return false
const myDigits = digitsOf(ctx.sender)
return meta.participants.some((p) => {
if (!p.admin) return false
return [p.id, p.phoneNumber, p.lid, p.jid].some((c) => c && digitsOf(c) === myDigits)
})
} catch {
return false
}
}
async function deleteMessage(ctx) {
try { await ctx.sock.sendMessage(ctx.chat, { delete: ctx.raw.key }) } catch {}
}
export async function applyWarn(ctx, settings, reasonKey) {
const digits = digitsOf(ctx.sender)
const result = applyWarnToSettings(settings, digits, settings.warnLimit)
await updateGroupSettings(ctx.storage, ctx.chat, { warns: result.warns })
if (result.shouldKick) {
let kicked = false
try {
await ctx.sock.groupParticipantsUpdate(ctx.chat, [ctx.sender], 'remove')
kicked = true
} catch { kicked = false }
await ctx.sock.sendMessage(ctx.chat, {
text: ctx.t(kicked ? 'guard.kicked' : 'guard.kickFailed', { digits, limit: result.limit }),
mentions: [ctx.sender],
})
return result
}
await ctx.sock.sendMessage(ctx.chat, {
text: ctx.t(reasonKey, { digits, count: result.count, limit: result.limit }),
mentions: [ctx.sender],
})
return result
}
export async function before(ctx) {
if (!ctx.isGroup || !ctx.text) return
if (await senderIsAdminOrOwner(ctx)) return
const settings = await getGroupSettings(ctx.storage, ctx.chat)
const text = ctx.text
if (settings.antispam) {
const key = `${ctx.chat}:${digitsOf(ctx.sender)}`
const now = Date.now()
const arr = [...(spamState.get(key) ?? []), now].filter((ts) => now - ts < 10000)
spamState.set(key, arr)
if (floodCheck(arr, now)) {
spamState.set(key, [])
await deleteMessage(ctx)
await ctx.sock.sendMessage(ctx.chat, { text: ctx.t('guard.spamWarn', { digits: digitsOf(ctx.sender) }), mentions: [ctx.sender] })
return false
}
}
let violated = null
if (settings.antilink && detectLinks(text).length) violated = 'guard.deletedLink'
else if (settings.antijudol && detectGambling(text).length) violated = 'guard.deletedGambling'
else if (settings.antiphising && detectPhishing(text).length) violated = 'guard.deletedPhishing'
if (violated) {
await deleteMessage(ctx)
await applyWarn(ctx, settings, violated)
return false
}
if (settings.antitoxic && detectToxic(text, settings.toxicWords).length) {
await deleteMessage(ctx)
await ctx.sock.sendMessage(ctx.chat, { text: ctx.t('guard.deletedToxic', { digits: digitsOf(ctx.sender) }), mentions: [ctx.sender] })
return false
}
}
export const test = { input: '.guard', expect: /grup|group/i }
export async function handler(ctx) {
const s = await getGroupSettings(ctx.storage, ctx.chat)
const onOff = (v) => ctx.t(v ? 'guard.on' : 'guard.off')
const body = ctx.t('guard.status', {
welcome: onOff(s.welcome), goodbye: onOff(s.goodbye), antilink: onOff(s.antilink),
antispam: onOff(s.antispam), antitoxic: onOff(s.antitoxic), antijudol: onOff(s.antijudol),
antiphising: onOff(s.antiphising), warnLimit: s.warnLimit, mood: ctx.say('senang'),
})
const offFeatures = FEATURES.filter((f) => !s[f]).slice(0, 4)
await sendButtons(ctx.sock, ctx.chat, {
title: 'KANA',
body,
footer: ctx.t('guard.footer'),
replies: [
...offFeatures.map((f) => ({ text: `Aktifkan ${f}`, id: `.protect ${f} on` })),
{ text: 'Menu grup', id: '.menu group' },
],
textFallback: body,
})
}
