or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application-commands.mdautomod.mdchannels-messaging.mdclient-bot.mdcommand-framework.mderror-handling.mdevents-gateway.mdguild-management.mdindex.mdinteractions-ui.mdlocalization-i18n.mdpermissions-security.mdpolls.mdusers-members.mdvoice-audio.md

permissions-security.mddocs/

0

# Permissions and Security

1

2

Discord permissions system, role management, and security features including comprehensive permission handling, role hierarchy, access control for commands and features, and security best practices for Discord bot development.

3

4

## Capabilities

5

6

### Permissions System

7

8

Discord's bitfield-based permission system for fine-grained access control.

9

10

```python { .api }

11

class Permissions:

12

def __init__(self, value: int = 0, **kwargs):

13

"""

14

Initialize permissions object.

15

16

Parameters:

17

- value: Raw permission integer value

18

- kwargs: Individual permission flags

19

"""

20

21

value: int

22

23

@classmethod

24

def none(cls) -> Permissions:

25

"""Create permissions with no flags set."""

26

27

@classmethod

28

def all(cls) -> Permissions:

29

"""Create permissions with all flags set."""

30

31

@classmethod

32

def all_channel(cls) -> Permissions:

33

"""Create permissions with all channel-applicable flags."""

34

35

@classmethod

36

def general(cls) -> Permissions:

37

"""Create permissions with general user flags."""

38

39

@classmethod

40

def text(cls) -> Permissions:

41

"""Create permissions for text channels."""

42

43

@classmethod

44

def voice(cls) -> Permissions:

45

"""Create permissions for voice channels."""

46

47

@classmethod

48

def stage(cls) -> Permissions:

49

"""Create permissions for stage channels."""

50

51

@classmethod

52

def stage_moderator(cls) -> Permissions:

53

"""Create stage moderator permissions."""

54

55

@classmethod

56

def advanced(cls) -> Permissions:

57

"""Create advanced user permissions."""

58

59

def update(self, **kwargs) -> Permissions:

60

"""

61

Update permissions with new values.

62

63

Parameters:

64

- kwargs: Permission flags to update

65

66

Returns:

67

New permissions object

68

"""

69

70

def handle_overwrite(self, allow: int, deny: int) -> None:

71

"""

72

Apply permission overwrite.

73

74

Parameters:

75

- allow: Allowed permission bits

76

- deny: Denied permission bits

77

"""

78

79

# General Permissions

80

@property

81

def create_instant_invite(self) -> bool:

82

"""Create instant invite."""

83

84

@property

85

def kick_members(self) -> bool:

86

"""Kick members."""

87

88

@property

89

def ban_members(self) -> bool:

90

"""Ban members."""

91

92

@property

93

def administrator(self) -> bool:

94

"""Administrator (bypasses all permission checks)."""

95

96

@property

97

def manage_channels(self) -> bool:

98

"""Manage channels (create, edit, delete)."""

99

100

@property

101

def manage_guild(self) -> bool:

102

"""Manage server settings."""

103

104

@property

105

def add_reactions(self) -> bool:

106

"""Add reactions to messages."""

107

108

@property

109

def view_audit_log(self) -> bool:

110

"""View audit log."""

111

112

@property

113

def priority_speaker(self) -> bool:

114

"""Priority speaker in voice channels."""

115

116

@property

117

def stream(self) -> bool:

118

"""Video stream in voice channels."""

119

120

@property

121

def view_channel(self) -> bool:

122

"""View channels."""

123

124

@property

125

def send_messages(self) -> bool:

126

"""Send messages in text channels."""

127

128

@property

129

def send_tts_messages(self) -> bool:

130

"""Send text-to-speech messages."""

131

132

@property

133

def manage_messages(self) -> bool:

134

"""Manage messages (delete, pin)."""

135

136

@property

137

def embed_links(self) -> bool:

138

"""Embed links in messages."""

139

140

@property

141

def attach_files(self) -> bool:

142

"""Attach files to messages."""

143

144

@property

145

def read_message_history(self) -> bool:

146

"""Read message history."""

147

148

@property

149

def mention_everyone(self) -> bool:

150

"""Mention @everyone, @here, and all roles."""

151

152

@property

153

def use_external_emojis(self) -> bool:

154

"""Use emojis from other servers."""

155

156

@property

157

def view_guild_insights(self) -> bool:

158

"""View server insights."""

159

160

@property

161

def connect(self) -> bool:

162

"""Connect to voice channels."""

163

164

@property

165

def speak(self) -> bool:

166

"""Speak in voice channels."""

167

168

@property

169

def mute_members(self) -> bool:

170

"""Mute members in voice channels."""

171

172

@property

173

def deafen_members(self) -> bool:

174

"""Deafen members in voice channels."""

175

176

@property

177

def move_members(self) -> bool:

178

"""Move members between voice channels."""

179

180

@property

181

def use_voice_activation(self) -> bool:

182

"""Use voice activation (push-to-talk not required)."""

183

184

@property

185

def change_nickname(self) -> bool:

186

"""Change own nickname."""

187

188

@property

189

def manage_nicknames(self) -> bool:

190

"""Manage other members' nicknames."""

191

192

@property

193

def manage_roles(self) -> bool:

194

"""Manage roles and permissions."""

195

196

@property

197

def manage_webhooks(self) -> bool:

198

"""Manage webhooks."""

199

200

@property

201

def manage_emojis_and_stickers(self) -> bool:

202

"""Manage emojis and stickers."""

203

204

@property

205

def manage_emojis(self) -> bool:

206

"""Manage emojis (legacy alias)."""

207

208

@property

209

def use_slash_commands(self) -> bool:

210

"""Use slash commands."""

211

212

@property

213

def use_application_commands(self) -> bool:

214

"""Use application commands."""

215

216

@property

217

def request_to_speak(self) -> bool:

218

"""Request to speak in stage channels."""

219

220

@property

221

def manage_events(self) -> bool:

222

"""Manage scheduled events."""

223

224

@property

225

def manage_threads(self) -> bool:

226

"""Manage threads."""

227

228

@property

229

def create_public_threads(self) -> bool:

230

"""Create public threads."""

231

232

@property

233

def create_private_threads(self) -> bool:

234

"""Create private threads."""

235

236

@property

237

def use_external_stickers(self) -> bool:

238

"""Use stickers from other servers."""

239

240

@property

241

def send_messages_in_threads(self) -> bool:

242

"""Send messages in threads."""

243

244

@property

245

def use_embedded_activities(self) -> bool:

246

"""Use activities in voice channels."""

247

248

@property

249

def moderate_members(self) -> bool:

250

"""Moderate members (timeout)."""

251

252

@property

253

def use_soundboard(self) -> bool:

254

"""Use soundboard."""

255

256

@property

257

def create_expressions(self) -> bool:

258

"""Create expressions."""

259

260

@property

261

def use_external_sounds(self) -> bool:

262

"""Use external sounds."""

263

264

@property

265

def send_voice_messages(self) -> bool:

266

"""Send voice messages."""

267

268

@property

269

def set_voice_channel_status(self) -> bool:

270

"""Set voice channel status."""

271

272

def is_subset(self, other: Permissions) -> bool:

273

"""

274

Check if permissions are subset of another.

275

276

Parameters:

277

- other: Permissions to compare with

278

279

Returns:

280

True if this is subset of other

281

"""

282

283

def is_superset(self, other: Permissions) -> bool:

284

"""

285

Check if permissions are superset of another.

286

287

Parameters:

288

- other: Permissions to compare with

289

290

Returns:

291

True if this is superset of other

292

"""

293

294

def is_strict_subset(self, other: Permissions) -> bool:

295

"""

296

Check if permissions are strict subset of another.

297

298

Parameters:

299

- other: Permissions to compare with

300

301

Returns:

302

True if this is strict subset of other

303

"""

304

305

def is_strict_superset(self, other: Permissions) -> bool:

306

"""

307

Check if permissions are strict superset of another.

308

309

Parameters:

310

- other: Permissions to compare with

311

312

Returns:

313

True if this is strict superset of other

314

"""

315

```

316

317

### Permission Overwrites

318

319

Channel-specific permission overrides for roles and members.

320

321

```python { .api }

322

class PermissionOverwrite:

323

def __init__(self, **kwargs):

324

"""

325

Initialize permission overwrite.

326

327

Parameters:

328

- kwargs: Permission flags (can be True, False, or None)

329

"""

330

331

@classmethod

332

def from_pair(cls, allow: Permissions, deny: Permissions) -> PermissionOverwrite:

333

"""

334

Create overwrite from allow/deny permission pairs.

335

336

Parameters:

337

- allow: Allowed permissions

338

- deny: Denied permissions

339

340

Returns:

341

Permission overwrite

342

"""

343

344

def pair(self) -> Tuple[Permissions, Permissions]:

345

"""

346

Get allow/deny permission pair.

347

348

Returns:

349

Tuple of (allow, deny) permissions

350

"""

351

352

def update(self, **kwargs) -> PermissionOverwrite:

353

"""

354

Update overwrite with new values.

355

356

Parameters:

357

- kwargs: Permission flags to update

358

359

Returns:

360

New overwrite object

361

"""

362

363

def is_empty(self) -> bool:

364

"""

365

Check if overwrite has any settings.

366

367

Returns:

368

True if no permissions are set

369

"""

370

371

# All permission properties available as Optional[bool]

372

create_instant_invite: Optional[bool]

373

kick_members: Optional[bool]

374

ban_members: Optional[bool]

375

administrator: Optional[bool]

376

manage_channels: Optional[bool]

377

manage_guild: Optional[bool]

378

add_reactions: Optional[bool]

379

view_audit_log: Optional[bool]

380

priority_speaker: Optional[bool]

381

stream: Optional[bool]

382

view_channel: Optional[bool]

383

send_messages: Optional[bool]

384

send_tts_messages: Optional[bool]

385

manage_messages: Optional[bool]

386

embed_links: Optional[bool]

387

attach_files: Optional[bool]

388

read_message_history: Optional[bool]

389

mention_everyone: Optional[bool]

390

use_external_emojis: Optional[bool]

391

view_guild_insights: Optional[bool]

392

connect: Optional[bool]

393

speak: Optional[bool]

394

mute_members: Optional[bool]

395

deafen_members: Optional[bool]

396

move_members: Optional[bool]

397

use_voice_activation: Optional[bool]

398

change_nickname: Optional[bool]

399

manage_nicknames: Optional[bool]

400

manage_roles: Optional[bool]

401

manage_webhooks: Optional[bool]

402

manage_emojis_and_stickers: Optional[bool]

403

use_application_commands: Optional[bool]

404

request_to_speak: Optional[bool]

405

manage_events: Optional[bool]

406

manage_threads: Optional[bool]

407

create_public_threads: Optional[bool]

408

create_private_threads: Optional[bool]

409

use_external_stickers: Optional[bool]

410

send_messages_in_threads: Optional[bool]

411

use_embedded_activities: Optional[bool]

412

moderate_members: Optional[bool]

413

use_soundboard: Optional[bool]

414

create_expressions: Optional[bool]

415

use_external_sounds: Optional[bool]

416

send_voice_messages: Optional[bool]

417

set_voice_channel_status: Optional[bool]

418

```

419

420

### Role System

421

422

Role-based permission management with hierarchy and role properties.

423

424

```python { .api }

425

class Role:

426

def __init__(self): ...

427

428

id: int

429

name: str

430

guild: Guild

431

color: Colour

432

colour: Colour

433

hoist: bool

434

position: int

435

managed: bool

436

mentionable: bool

437

permissions: Permissions

438

tags: Optional[RoleTags]

439

icon: Optional[Asset]

440

unicode_emoji: Optional[str]

441

flags: RoleFlags

442

443

@property

444

def display_icon(self) -> Optional[Asset]:

445

"""Role display icon."""

446

447

@property

448

def created_at(self) -> datetime:

449

"""When role was created."""

450

451

@property

452

def mention(self) -> str:

453

"""String to mention role."""

454

455

@property

456

def members(self) -> List[Member]:

457

"""Members with this role."""

458

459

def is_default(self) -> bool:

460

"""

461

Check if role is @everyone.

462

463

Returns:

464

True if default role

465

"""

466

467

def is_bot_managed(self) -> bool:

468

"""

469

Check if role is managed by a bot.

470

471

Returns:

472

True if bot managed

473

"""

474

475

def is_premium_subscriber(self) -> bool:

476

"""

477

Check if role is Nitro booster role.

478

479

Returns:

480

True if premium subscriber role

481

"""

482

483

def is_integration(self) -> bool:

484

"""

485

Check if role is integration role.

486

487

Returns:

488

True if integration role

489

"""

490

491

async def edit(

492

self,

493

*,

494

name: str = ...,

495

permissions: Permissions = ...,

496

colour: Union[Colour, int] = ...,

497

color: Union[Colour, int] = ...,

498

hoist: bool = ...,

499

display_icon: Optional[Union[bytes, str]] = ...,

500

unicode_emoji: Optional[str] = ...,

501

mentionable: bool = ...,

502

position: int = ...,

503

reason: Optional[str] = None

504

) -> Role:

505

"""

506

Edit role properties.

507

508

Parameters:

509

- name: Role name

510

- permissions: Role permissions

511

- colour/color: Role color

512

- hoist: Show separately in member list

513

- display_icon: Role icon bytes or unicode emoji

514

- unicode_emoji: Unicode emoji for role icon

515

- mentionable: Allow role mentions

516

- position: Role position in hierarchy

517

- reason: Audit log reason

518

519

Returns:

520

Updated role

521

"""

522

523

async def delete(self, *, reason: Optional[str] = None) -> None:

524

"""

525

Delete the role.

526

527

Parameters:

528

- reason: Audit log reason

529

"""

530

531

class RoleTags:

532

"""Role tag metadata."""

533

534

def __init__(self): ...

535

536

bot_id: Optional[int]

537

integration_id: Optional[int]

538

premium_subscriber: Optional[bool]

539

subscription_listing_id: Optional[int]

540

available_for_purchase: Optional[bool]

541

guild_connections: Optional[bool]

542

543

class RoleFlags:

544

"""Role flags bitfield."""

545

546

def __init__(self, value: int = 0): ...

547

548

@property

549

def in_prompt(self) -> bool:

550

"""Role can be selected in onboarding."""

551

```

552

553

### Security Checks

554

555

Command permission checking system for access control and security.

556

557

```python { .api }

558

def has_role(name: Union[str, int]):

559

"""

560

Check if user has specific role.

561

562

Parameters:

563

- name: Role name or ID

564

565

Returns:

566

Check decorator

567

"""

568

569

def has_any_role(*names: Union[str, int]):

570

"""

571

Check if user has any of the specified roles.

572

573

Parameters:

574

- names: Role names or IDs

575

576

Returns:

577

Check decorator

578

"""

579

580

def has_permissions(**perms: bool):

581

"""

582

Check if user has specific permissions in channel.

583

584

Parameters:

585

- perms: Permission flags that must be True

586

587

Returns:

588

Check decorator

589

"""

590

591

def has_guild_permissions(**perms: bool):

592

"""

593

Check if user has guild-wide permissions.

594

595

Parameters:

596

- perms: Permission flags that must be True

597

598

Returns:

599

Check decorator

600

"""

601

602

def bot_has_permissions(**perms: bool):

603

"""

604

Check if bot has specific permissions in channel.

605

606

Parameters:

607

- perms: Permission flags that must be True

608

609

Returns:

610

Check decorator

611

"""

612

613

def bot_has_guild_permissions(**perms: bool):

614

"""

615

Check if bot has guild-wide permissions.

616

617

Parameters:

618

- perms: Permission flags that must be True

619

620

Returns:

621

Check decorator

622

"""

623

624

def is_owner():

625

"""

626

Check if user is bot owner.

627

628

Returns:

629

Check decorator

630

"""

631

632

def guild_only():

633

"""

634

Check if command is used in a guild.

635

636

Returns:

637

Check decorator

638

"""

639

640

def dm_only():

641

"""

642

Check if command is used in DMs.

643

644

Returns:

645

Check decorator

646

"""

647

648

def is_nsfw():

649

"""

650

Check if channel is marked as NSFW.

651

652

Returns:

653

Check decorator

654

"""

655

656

def check(predicate: Callable[[Context], bool]):

657

"""

658

Create custom permission check.

659

660

Parameters:

661

- predicate: Function that takes context and returns bool

662

663

Returns:

664

Check decorator

665

"""

666

667

def check_any(*checks: Check):

668

"""

669

Check that passes if any of the provided checks pass.

670

671

Parameters:

672

- checks: Check decorators

673

674

Returns:

675

Check decorator

676

"""

677

678

async def has_role_check(ctx: Context, name: Union[str, int]) -> bool:

679

"""

680

Check if context author has role.

681

682

Parameters:

683

- ctx: Command context

684

- name: Role name or ID

685

686

Returns:

687

True if user has role

688

"""

689

690

async def has_any_role_check(ctx: Context, *names: Union[str, int]) -> bool:

691

"""

692

Check if context author has any of the specified roles.

693

694

Parameters:

695

- ctx: Command context

696

- names: Role names or IDs

697

698

Returns:

699

True if user has any role

700

"""

701

702

async def has_permissions_check(ctx: Context, **perms: bool) -> bool:

703

"""

704

Check if context author has permissions.

705

706

Parameters:

707

- ctx: Command context

708

- perms: Required permissions

709

710

Returns:

711

True if user has permissions

712

"""

713

714

async def bot_has_permissions_check(ctx: Context, **perms: bool) -> bool:

715

"""

716

Check if bot has permissions.

717

718

Parameters:

719

- ctx: Command context

720

- perms: Required permissions

721

722

Returns:

723

True if bot has permissions

724

"""

725

726

async def is_owner_check(ctx: Context) -> bool:

727

"""

728

Check if user is bot owner.

729

730

Parameters:

731

- ctx: Command context

732

733

Returns:

734

True if user is owner

735

"""

736

737

class MissingRole(CheckFailure):

738

"""Exception for missing role checks."""

739

740

def __init__(self, missing_role: Union[str, int]): ...

741

742

class MissingAnyRole(CheckFailure):

743

"""Exception for missing any role checks."""

744

745

def __init__(self, missing_roles: List[Union[str, int]]): ...

746

747

class MissingPermissions(CheckFailure):

748

"""Exception for missing permissions."""

749

750

def __init__(self, missing_permissions: List[str]): ...

751

752

class BotMissingPermissions(CheckFailure):

753

"""Exception for bot missing permissions."""

754

755

def __init__(self, missing_permissions: List[str]): ...

756

757

class NotOwner(CheckFailure):

758

"""Exception for non-owner access."""

759

760

class NoPrivateMessage(CheckFailure):

761

"""Exception for guild-only commands in DMs."""

762

763

class PrivateMessageOnly(CheckFailure):

764

"""Exception for DM-only commands in guilds."""

765

766

class NSFWChannelRequired(CheckFailure):

767

"""Exception for NSFW commands in non-NSFW channels."""

768

```

769

770

### Application Command Permissions

771

772

Permission system for slash commands and context menu commands.

773

774

```python { .api }

775

class ApplicationCommandPermissions:

776

"""Application command permissions for a target."""

777

778

def __init__(self): ...

779

780

id: int

781

type: ApplicationCommandPermissionType

782

permission: bool

783

784

@classmethod

785

def from_role(cls, role: Role, permission: bool = True) -> ApplicationCommandPermissions:

786

"""

787

Create permissions from role.

788

789

Parameters:

790

- role: Role target

791

- permission: Whether to allow or deny

792

793

Returns:

794

Application command permissions

795

"""

796

797

@classmethod

798

def from_user(cls, user: Union[User, Member], permission: bool = True) -> ApplicationCommandPermissions:

799

"""

800

Create permissions from user.

801

802

Parameters:

803

- user: User target

804

- permission: Whether to allow or deny

805

806

Returns:

807

Application command permissions

808

"""

809

810

@classmethod

811

def from_channel(cls, channel: GuildChannel, permission: bool = True) -> ApplicationCommandPermissions:

812

"""

813

Create permissions from channel.

814

815

Parameters:

816

- channel: Channel target

817

- permission: Whether to allow or deny

818

819

Returns:

820

Application command permissions

821

"""

822

823

class GuildApplicationCommandPermissions:

824

"""Guild-specific application command permissions."""

825

826

def __init__(self): ...

827

828

id: int

829

application_id: int

830

guild_id: int

831

permissions: List[ApplicationCommandPermissions]

832

833

@property

834

def guild(self) -> Optional[Guild]:

835

"""Guild these permissions apply to."""

836

837

@property

838

def command(self) -> Optional[APIApplicationCommand]:

839

"""Command these permissions apply to."""

840

841

# Permission decorators for application commands

842

def default_member_permissions(**perms: bool):

843

"""

844

Set default member permissions for application commands.

845

846

Parameters:

847

- perms: Required permissions

848

849

Returns:

850

Decorator for application commands

851

"""

852

853

def guild_only():

854

"""Mark application command as guild-only."""

855

856

def dm_permission(enabled: bool = True):

857

"""

858

Set DM permission for application commands.

859

860

Parameters:

861

- enabled: Whether command can be used in DMs

862

863

Returns:

864

Decorator for application commands

865

"""

866

```

867

868

### Security Features

869

870

Additional security features and utilities for bot protection.

871

872

```python { .api }

873

class SecurityManager:

874

"""Security management utilities."""

875

876

def __init__(self, bot: Bot):

877

self.bot = bot

878

self.rate_limits = {}

879

self.blacklisted_users = set()

880

self.trusted_users = set()

881

882

def is_blacklisted(self, user_id: int) -> bool:

883

"""

884

Check if user is blacklisted.

885

886

Parameters:

887

- user_id: User ID to check

888

889

Returns:

890

True if blacklisted

891

"""

892

893

def blacklist_user(self, user_id: int) -> None:

894

"""

895

Add user to blacklist.

896

897

Parameters:

898

- user_id: User ID to blacklist

899

"""

900

901

def whitelist_user(self, user_id: int) -> None:

902

"""

903

Remove user from blacklist.

904

905

Parameters:

906

- user_id: User ID to remove

907

"""

908

909

def is_trusted(self, user_id: int) -> bool:

910

"""

911

Check if user is trusted.

912

913

Parameters:

914

- user_id: User ID to check

915

916

Returns:

917

True if trusted

918

"""

919

920

def add_trusted_user(self, user_id: int) -> None:

921

"""

922

Add user to trusted list.

923

924

Parameters:

925

- user_id: User ID to trust

926

"""

927

928

def check_rate_limit(self, user_id: int, command: str, limit: int = 5, window: int = 60) -> bool:

929

"""

930

Check command rate limit for user.

931

932

Parameters:

933

- user_id: User ID

934

- command: Command name

935

- limit: Maximum uses per window

936

- window: Time window in seconds

937

938

Returns:

939

True if within rate limit

940

"""

941

942

def security_check():

943

"""Security check decorator for sensitive operations."""

944

945

async def predicate(ctx: Context) -> bool:

946

# Check if user is blacklisted

947

if hasattr(ctx.bot, 'security') and ctx.bot.security.is_blacklisted(ctx.author.id):

948

return False

949

950

# Additional security checks

951

return True

952

953

return check(predicate)

954

955

def owner_or_trusted():

956

"""Check for bot owner or trusted user."""

957

958

async def predicate(ctx: Context) -> bool:

959

if await ctx.bot.is_owner(ctx.author):

960

return True

961

962

if hasattr(ctx.bot, 'security') and ctx.bot.security.is_trusted(ctx.author.id):

963

return True

964

965

return False

966

967

return check(predicate)

968

969

def require_hierarchy(target_param: str = 'member'):

970

"""

971

Check role hierarchy for moderation commands.

972

973

Parameters:

974

- target_param: Parameter name for target member

975

976

Returns:

977

Check decorator

978

"""

979

980

def decorator(func):

981

async def wrapper(*args, **kwargs):

982

ctx = args[0] if args else None

983

984

if not isinstance(ctx, Context):

985

return await func(*args, **kwargs)

986

987

# Get target member from parameters

988

target = kwargs.get(target_param)

989

if not isinstance(target, Member):

990

return await func(*args, **kwargs)

991

992

# Check hierarchy

993

if target.top_role >= ctx.author.top_role and ctx.author != ctx.guild.owner:

994

raise CheckFailure("You cannot perform this action on this member due to role hierarchy.")

995

996

if target.top_role >= ctx.me.top_role:

997

raise CheckFailure("I cannot perform this action on this member due to role hierarchy.")

998

999

return await func(*args, **kwargs)

1000

1001

return wrapper

1002

1003

return decorator

1004

1005

def audit_log(action: str):

1006

"""

1007

Log command usage for auditing.

1008

1009

Parameters:

1010

- action: Action description

1011

1012

Returns:

1013

Command decorator

1014

"""

1015

1016

def decorator(func):

1017

async def wrapper(*args, **kwargs):

1018

ctx = args[0] if args else None

1019

1020

if isinstance(ctx, Context):

1021

print(f"AUDIT: {ctx.author} ({ctx.author.id}) used {func.__name__} in {ctx.guild.name if ctx.guild else 'DM'}: {action}")

1022

1023

return await func(*args, **kwargs)

1024

1025

return wrapper

1026

1027

return decorator

1028

```

1029

1030

### OAuth and App Permissions

1031

1032

OAuth URL generation and application permission management.

1033

1034

```python { .api }

1035

def oauth_url(

1036

client_id: int,

1037

*,

1038

permissions: Permissions = None,

1039

guild: Guild = None,

1040

redirect_uri: str = None,

1041

scopes: Iterable[str] = None,

1042

disable_guild_select: bool = False,

1043

state: str = None

1044

) -> str:

1045

"""

1046

Generate OAuth2 authorization URL.

1047

1048

Parameters:

1049

- client_id: Application client ID

1050

- permissions: Bot permissions to request

1051

- guild: Pre-select guild for bot invitation

1052

- redirect_uri: OAuth redirect URI

1053

- scopes: OAuth scopes to request

1054

- disable_guild_select: Disable guild selection

1055

- state: OAuth state parameter

1056

1057

Returns:

1058

OAuth2 URL

1059

"""

1060

1061

class ApplicationFlags:

1062

"""Application flags bitfield."""

1063

1064

def __init__(self, value: int = 0): ...

1065

1066

@property

1067

def application_auto_moderation_rule_create_badge(self) -> bool:

1068

"""Application has auto-moderation rule create badge."""

1069

1070

@property

1071

def gateway_presence(self) -> bool:

1072

"""Application can read presence data."""

1073

1074

@property

1075

def gateway_presence_limited(self) -> bool:

1076

"""Application has limited presence data access."""

1077

1078

@property

1079

def gateway_guild_members(self) -> bool:

1080

"""Application can read guild member data."""

1081

1082

@property

1083

def gateway_guild_members_limited(self) -> bool:

1084

"""Application has limited guild member data access."""

1085

1086

@property

1087

def verification_pending_guild_limit(self) -> bool:

1088

"""Application has unusual growth and pending verification."""

1089

1090

@property

1091

def embedded(self) -> bool:

1092

"""Application is embedded within Discord client."""

1093

1094

@property

1095

def gateway_message_content(self) -> bool:

1096

"""Application can read message content."""

1097

1098

@property

1099

def gateway_message_content_limited(self) -> bool:

1100

"""Application has limited message content access."""

1101

1102

@property

1103

def application_command_badge(self) -> bool:

1104

"""Application has application command badge."""

1105

1106

class AppInfo:

1107

"""Application information."""

1108

1109

def __init__(self): ...

1110

1111

id: int

1112

name: str

1113

icon: Optional[Asset]

1114

description: str

1115

rpc_origins: Optional[List[str]]

1116

bot_public: bool

1117

bot_require_code_grant: bool

1118

bot: Optional[User]

1119

owner: Optional[User]

1120

team: Optional[Team]

1121

summary: str

1122

verify_key: str

1123

guild_id: Optional[int]

1124

guild: Optional[Guild]

1125

primary_sku_id: Optional[int]

1126

slug: Optional[str]

1127

cover_image: Optional[Asset]

1128

flags: ApplicationFlags

1129

approximate_guild_count: Optional[int]

1130

redirect_uris: Optional[List[str]]

1131

interactions_endpoint_url: Optional[str]

1132

role_connections_verification_url: Optional[str]

1133

tags: Optional[List[str]]

1134

install_params: Optional[ApplicationInstallParams]

1135

custom_install_url: Optional[str]

1136

1137

@property

1138

def icon_url(self) -> Optional[str]:

1139

"""Application icon URL."""

1140

1141

@property

1142

def cover_image_url(self) -> Optional[str]:

1143

"""Application cover image URL."""

1144

1145

class ApplicationInstallParams:

1146

"""Application installation parameters."""

1147

1148

def __init__(self): ...

1149

1150

scopes: List[str]

1151

permissions: Permissions

1152

```

1153

1154

## Usage Examples

1155

1156

### Basic Permission Checking

1157

1158

```python

1159

import disnake

1160

from disnake.ext import commands

1161

1162

bot = commands.Bot(command_prefix='!', intents=disnake.Intents.all())

1163

1164

# Basic permission checks

1165

@bot.command()

1166

@commands.has_permissions(manage_messages=True)

1167

async def clear(ctx, amount: int = 5):

1168

"""Clear messages (requires Manage Messages)."""

1169

if amount > 100:

1170

return await ctx.send("Cannot clear more than 100 messages.")

1171

1172

deleted = await ctx.channel.purge(limit=amount)

1173

await ctx.send(f"Cleared {len(deleted)} messages.", delete_after=5)

1174

1175

@bot.command()

1176

@commands.has_guild_permissions(ban_members=True)

1177

@commands.bot_has_guild_permissions(ban_members=True)

1178

async def ban(ctx, member: disnake.Member, *, reason="No reason provided"):

1179

"""Ban a member (requires Ban Members for both user and bot)."""

1180

if member.top_role >= ctx.author.top_role and ctx.author != ctx.guild.owner:

1181

return await ctx.send("You cannot ban this member due to role hierarchy.")

1182

1183

await member.ban(reason=reason)

1184

await ctx.send(f"Banned {member} for: {reason}")

1185

1186

@bot.command()

1187

@commands.has_any_role('Admin', 'Moderator', 'Helper')

1188

async def warn(ctx, member: disnake.Member, *, reason):

1189

"""Warn a member (requires Admin, Moderator, or Helper role)."""

1190

# Implementation here

1191

await ctx.send(f"Warned {member} for: {reason}")

1192

1193

@bot.command()

1194

@commands.is_owner()

1195

async def shutdown(ctx):

1196

"""Shutdown bot (owner only)."""

1197

await ctx.send("Shutting down...")

1198

await bot.close()

1199

1200

@bot.command()

1201

@commands.guild_only()

1202

async def serverinfo(ctx):

1203

"""Server info (guild only)."""

1204

guild = ctx.guild

1205

embed = disnake.Embed(title=guild.name)

1206

embed.add_field(name="Members", value=guild.member_count)

1207

await ctx.send(embed=embed)

1208

1209

@bot.command()

1210

@commands.dm_only()

1211

async def profile(ctx):

1212

"""User profile (DM only for privacy)."""

1213

await ctx.send("Your private profile information...")

1214

1215

@bot.command()

1216

@commands.is_nsfw()

1217

async def nsfw_command(ctx):

1218

"""NSFW command (requires NSFW channel)."""

1219

await ctx.send("This is NSFW content.")

1220

1221

# Error handling for permission failures

1222

@bot.event

1223

async def on_command_error(ctx, error):

1224

if isinstance(error, commands.MissingPermissions):

1225

missing = ', '.join(error.missing_permissions)

1226

await ctx.send(f"You're missing permissions: {missing}")

1227

1228

elif isinstance(error, commands.BotMissingPermissions):

1229

missing = ', '.join(error.missing_permissions)

1230

await ctx.send(f"I'm missing permissions: {missing}")

1231

1232

elif isinstance(error, commands.MissingRole):

1233

await ctx.send(f"You need the {error.missing_role} role to use this command.")

1234

1235

elif isinstance(error, commands.MissingAnyRole):

1236

roles = ', '.join(str(role) for role in error.missing_roles)

1237

await ctx.send(f"You need one of these roles: {roles}")

1238

1239

elif isinstance(error, commands.NotOwner):

1240

await ctx.send("Only the bot owner can use this command.")

1241

1242

elif isinstance(error, commands.NoPrivateMessage):

1243

await ctx.send("This command cannot be used in private messages.")

1244

1245

elif isinstance(error, commands.PrivateMessageOnly):

1246

await ctx.send("This command can only be used in private messages.")

1247

1248

elif isinstance(error, commands.NSFWChannelRequired):

1249

await ctx.send("This command can only be used in NSFW channels.")

1250

```

1251

1252

### Custom Permission Checks

1253

1254

```python

1255

def is_staff():

1256

"""Custom check for staff members."""

1257

async def predicate(ctx):

1258

staff_roles = ['Owner', 'Admin', 'Moderator', 'Helper']

1259

user_roles = [role.name for role in ctx.author.roles]

1260

return any(role in staff_roles for role in user_roles)

1261

1262

return commands.check(predicate)

1263

1264

def has_higher_role_than(target_param='member'):

1265

"""Check if user has higher role than target."""

1266

def predicate(ctx):

1267

target = ctx.kwargs.get(target_param) if hasattr(ctx, 'kwargs') else None

1268

if not isinstance(target, disnake.Member):

1269

return True # Skip check if target not found

1270

1271

return ctx.author.top_role > target.top_role or ctx.author == ctx.guild.owner

1272

1273

return commands.check(predicate)

1274

1275

def channel_locked():

1276

"""Check if channel is in maintenance mode."""

1277

async def predicate(ctx):

1278

# Check if channel has "locked" in topic or name

1279

if hasattr(ctx.channel, 'topic') and ctx.channel.topic:

1280

if 'locked' in ctx.channel.topic.lower():

1281

return False

1282

1283

if 'locked' in ctx.channel.name.lower():

1284

return False

1285

1286

return True

1287

1288

return commands.check(predicate)

1289

1290

def cooldown_bypass():

1291

"""Bypass cooldowns for trusted users."""

1292

def predicate(ctx):

1293

# Check if user should bypass cooldowns

1294

bypass_roles = ['Owner', 'Admin']

1295

user_roles = [role.name for role in ctx.author.roles]

1296

return any(role in bypass_roles for role in user_roles)

1297

1298

return commands.check(predicate)

1299

1300

# Using custom checks

1301

@bot.command()

1302

@is_staff()

1303

@has_higher_role_than('target')

1304

async def timeout(ctx, target: disnake.Member, duration: str, *, reason="No reason"):

1305

"""Timeout a member (staff only, must have higher role)."""

1306

# Parse duration and apply timeout

1307

await ctx.send(f"Timed out {target} for {duration}")

1308

1309

@bot.command()

1310

@channel_locked()

1311

async def chat(ctx, *, message):

1312

"""Chat command (disabled in locked channels)."""

1313

await ctx.send(f"{ctx.author.mention}: {message}")

1314

1315

@bot.command()

1316

@commands.cooldown(1, 30, commands.BucketType.user)

1317

@cooldown_bypass()

1318

async def expensive_command(ctx):

1319

"""Expensive command with cooldown bypass for admins."""

1320

await ctx.send("This is an expensive operation...")

1321

```

1322

1323

### Role Management System

1324

1325

```python

1326

@bot.group()

1327

@commands.has_permissions(manage_roles=True)

1328

async def role(ctx):

1329

"""Role management commands."""

1330

if ctx.invoked_subcommand is None:

1331

await ctx.send_help(ctx.command)

1332

1333

@role.command()

1334

async def create(ctx, name: str, color: disnake.Color = None, hoist: bool = False, mentionable: bool = True):

1335

"""Create a new role with specified properties."""

1336

if color is None:

1337

color = disnake.Color.default()

1338

1339

try:

1340

role = await ctx.guild.create_role(

1341

name=name,

1342

color=color,

1343

hoist=hoist,

1344

mentionable=mentionable,

1345

reason=f"Role created by {ctx.author}"

1346

)

1347

1348

embed = disnake.Embed(

1349

title="Role Created",

1350

description=f"Successfully created {role.mention}",

1351

color=role.color

1352

)

1353

embed.add_field(name="Name", value=role.name)

1354

embed.add_field(name="Color", value=f"#{role.color.value:06x}")

1355

embed.add_field(name="Hoisted", value=hoist)

1356

embed.add_field(name="Mentionable", value=mentionable)

1357

1358

await ctx.send(embed=embed)

1359

1360

except disnake.Forbidden:

1361

await ctx.send("I don't have permission to create roles.")

1362

except disnake.HTTPException as e:

1363

await ctx.send(f"Failed to create role: {e}")

1364

1365

@role.command()

1366

async def delete(ctx, role: disnake.Role):

1367

"""Delete a role."""

1368

if role >= ctx.author.top_role and ctx.author != ctx.guild.owner:

1369

return await ctx.send("You cannot delete this role due to hierarchy.")

1370

1371

if role >= ctx.me.top_role:

1372

return await ctx.send("I cannot delete this role due to hierarchy.")

1373

1374

if role.is_default():

1375

return await ctx.send("Cannot delete the @everyone role.")

1376

1377

role_name = role.name

1378

await role.delete(reason=f"Role deleted by {ctx.author}")

1379

await ctx.send(f"Deleted role: {role_name}")

1380

1381

@role.command()

1382

async def edit(ctx, role: disnake.Role, *, properties):

1383

"""Edit role properties (format: name=NewName color=#ff0000 hoist=true)."""

1384

if role >= ctx.author.top_role and ctx.author != ctx.guild.owner:

1385

return await ctx.send("You cannot edit this role due to hierarchy.")

1386

1387

# Parse properties

1388

changes = {}

1389

for prop in properties.split():

1390

if '=' in prop:

1391

key, value = prop.split('=', 1)

1392

1393

if key == 'name':

1394

changes['name'] = value

1395

elif key == 'color':

1396

try:

1397

if value.startswith('#'):

1398

changes['color'] = disnake.Color(int(value[1:], 16))

1399

else:

1400

changes['color'] = getattr(disnake.Color, value.lower())()

1401

except (ValueError, AttributeError):

1402

return await ctx.send(f"Invalid color: {value}")

1403

elif key in ['hoist', 'mentionable']:

1404

changes[key] = value.lower() in ['true', '1', 'yes']

1405

1406

if not changes:

1407

return await ctx.send("No valid properties provided.")

1408

1409

try:

1410

await role.edit(reason=f"Role edited by {ctx.author}", **changes)

1411

await ctx.send(f"Successfully edited {role.mention}")

1412

except disnake.Forbidden:

1413

await ctx.send("I don't have permission to edit this role.")

1414

except disnake.HTTPException as e:

1415

await ctx.send(f"Failed to edit role: {e}")

1416

1417

@role.command()

1418

async def give(ctx, member: disnake.Member, role: disnake.Role):

1419

"""Give a role to a member."""

1420

if role >= ctx.author.top_role and ctx.author != ctx.guild.owner:

1421

return await ctx.send("You cannot assign this role due to hierarchy.")

1422

1423

if role >= ctx.me.top_role:

1424

return await ctx.send("I cannot assign this role due to hierarchy.")

1425

1426

if role in member.roles:

1427

return await ctx.send(f"{member} already has the {role.name} role.")

1428

1429

try:

1430

await member.add_roles(role, reason=f"Role assigned by {ctx.author}")

1431

await ctx.send(f"Gave {role.name} to {member.mention}")

1432

except disnake.Forbidden:

1433

await ctx.send("I don't have permission to assign roles.")

1434

1435

@role.command()

1436

async def remove(ctx, member: disnake.Member, role: disnake.Role):

1437

"""Remove a role from a member."""

1438

if role >= ctx.author.top_role and ctx.author != ctx.guild.owner:

1439

return await ctx.send("You cannot manage this role due to hierarchy.")

1440

1441

if role not in member.roles:

1442

return await ctx.send(f"{member} doesn't have the {role.name} role.")

1443

1444

try:

1445

await member.remove_roles(role, reason=f"Role removed by {ctx.author}")

1446

await ctx.send(f"Removed {role.name} from {member.mention}")

1447

except disnake.Forbidden:

1448

await ctx.send("I don't have permission to remove roles.")

1449

1450

@role.command()

1451

async def info(ctx, role: disnake.Role):

1452

"""Display detailed role information."""

1453

embed = disnake.Embed(title=f"Role: {role.name}", color=role.color)

1454

1455

embed.add_field(name="ID", value=role.id, inline=True)

1456

embed.add_field(name="Position", value=role.position, inline=True)

1457

embed.add_field(name="Color", value=f"#{role.color.value:06x}", inline=True)

1458

embed.add_field(name="Hoisted", value=role.hoist, inline=True)

1459

embed.add_field(name="Mentionable", value=role.mentionable, inline=True)

1460

embed.add_field(name="Managed", value=role.managed, inline=True)

1461

embed.add_field(name="Members", value=len(role.members), inline=True)

1462

embed.add_field(name="Created", value=f"<t:{int(role.created_at.timestamp())}:F>", inline=True)

1463

1464

if role.tags:

1465

tags = []

1466

if role.tags.bot_id:

1467

tags.append(f"Bot Role (ID: {role.tags.bot_id})")

1468

if role.tags.integration_id:

1469

tags.append(f"Integration Role (ID: {role.tags.integration_id})")

1470

if role.tags.premium_subscriber:

1471

tags.append("Nitro Booster Role")

1472

1473

if tags:

1474

embed.add_field(name="Tags", value="\n".join(tags), inline=False)

1475

1476

# Show permissions

1477

perms = []

1478

for perm, value in role.permissions:

1479

if value:

1480

perms.append(perm.replace('_', ' ').title())

1481

1482

if perms:

1483

embed.add_field(

1484

name=f"Permissions ({len(perms)})",

1485

value=", ".join(perms) if len(", ".join(perms)) < 1024 else f"{len(perms)} permissions",

1486

inline=False

1487

)

1488

1489

await ctx.send(embed=embed)

1490

1491

@role.command()

1492

async def members(ctx, role: disnake.Role):

1493

"""List all members with a specific role."""

1494

members = role.members

1495

1496

if not members:

1497

return await ctx.send(f"No members have the {role.name} role.")

1498

1499

embed = disnake.Embed(

1500

title=f"Members with {role.name} ({len(members)})",

1501

color=role.color

1502

)

1503

1504

# Split members into pages if too many

1505

member_list = [f"{member.mention} ({member})" for member in members]

1506

1507

if len(member_list) <= 20:

1508

embed.description = "\n".join(member_list)

1509

await ctx.send(embed=embed)

1510

else:

1511

# Paginate results

1512

for i in range(0, len(member_list), 20):

1513

page_members = member_list[i:i+20]

1514

embed.description = "\n".join(page_members)

1515

embed.set_footer(text=f"Page {i//20 + 1}/{(len(member_list)-1)//20 + 1}")

1516

await ctx.send(embed=embed)

1517

```

1518

1519

### Permission Overwrite Management

1520

1521

```python

1522

@bot.group()

1523

@commands.has_permissions(manage_channels=True)

1524

async def perms(ctx):

1525

"""Channel permission management."""

1526

if ctx.invoked_subcommand is None:

1527

await ctx.send_help(ctx.command)

1528

1529

@perms.command()

1530

async def allow(ctx, target: Union[disnake.Member, disnake.Role], channel: disnake.GuildChannel = None, *permissions):

1531

"""Allow permissions for a member or role in a channel."""

1532

if channel is None:

1533

channel = ctx.channel

1534

1535

if not permissions:

1536

return await ctx.send("Please specify permissions to allow.")

1537

1538

# Get current overwrites or create new

1539

overwrites = channel.overwrites_for(target)

1540

1541

# Set permissions to True

1542

changes = {}

1543

for perm in permissions:

1544

perm_name = perm.lower().replace('-', '_').replace(' ', '_')

1545

if hasattr(overwrites, perm_name):

1546

changes[perm_name] = True

1547

1548

if not changes:

1549

return await ctx.send("No valid permissions specified.")

1550

1551

# Update overwrites

1552

overwrites.update(**changes)

1553

1554

try:

1555

await channel.set_permissions(target, overwrite=overwrites, reason=f"Permissions allowed by {ctx.author}")

1556

1557

perms_str = ", ".join(changes.keys()).replace('_', ' ').title()

1558

await ctx.send(f"Allowed {perms_str} for {target.mention} in {channel.mention}")

1559

1560

except disnake.Forbidden:

1561

await ctx.send("I don't have permission to manage channel permissions.")

1562

except disnake.HTTPException as e:

1563

await ctx.send(f"Failed to update permissions: {e}")

1564

1565

@perms.command()

1566

async def deny(ctx, target: Union[disnake.Member, disnake.Role], channel: disnake.GuildChannel = None, *permissions):

1567

"""Deny permissions for a member or role in a channel."""

1568

if channel is None:

1569

channel = ctx.channel

1570

1571

if not permissions:

1572

return await ctx.send("Please specify permissions to deny.")

1573

1574

overwrites = channel.overwrites_for(target)

1575

1576

changes = {}

1577

for perm in permissions:

1578

perm_name = perm.lower().replace('-', '_').replace(' ', '_')

1579

if hasattr(overwrites, perm_name):

1580

changes[perm_name] = False

1581

1582

if not changes:

1583

return await ctx.send("No valid permissions specified.")

1584

1585

overwrites.update(**changes)

1586

1587

try:

1588

await channel.set_permissions(target, overwrite=overwrites, reason=f"Permissions denied by {ctx.author}")

1589

1590

perms_str = ", ".join(changes.keys()).replace('_', ' ').title()

1591

await ctx.send(f"Denied {perms_str} for {target.mention} in {channel.mention}")

1592

1593

except disnake.Forbidden:

1594

await ctx.send("I don't have permission to manage channel permissions.")

1595

1596

@perms.command()

1597

async def reset(ctx, target: Union[disnake.Member, disnake.Role], channel: disnake.GuildChannel = None, *permissions):

1598

"""Reset permissions to inherit from role/default for a member or role."""

1599

if channel is None:

1600

channel = ctx.channel

1601

1602

if not permissions:

1603

# Reset all overwrites

1604

try:

1605

await channel.set_permissions(target, overwrite=None, reason=f"All permissions reset by {ctx.author}")

1606

await ctx.send(f"Reset all permissions for {target.mention} in {channel.mention}")

1607

except disnake.Forbidden:

1608

await ctx.send("I don't have permission to manage channel permissions.")

1609

return

1610

1611

overwrites = channel.overwrites_for(target)

1612

1613

changes = {}

1614

for perm in permissions:

1615

perm_name = perm.lower().replace('-', '_').replace(' ', '_')

1616

if hasattr(overwrites, perm_name):

1617

changes[perm_name] = None

1618

1619

if not changes:

1620

return await ctx.send("No valid permissions specified.")

1621

1622

overwrites.update(**changes)

1623

1624

try:

1625

await channel.set_permissions(target, overwrite=overwrites, reason=f"Permissions reset by {ctx.author}")

1626

1627

perms_str = ", ".join(changes.keys()).replace('_', ' ').title()

1628

await ctx.send(f"Reset {perms_str} for {target.mention} in {channel.mention}")

1629

1630

except disnake.Forbidden:

1631

await ctx.send("I don't have permission to manage channel permissions.")

1632

1633

@perms.command()

1634

async def view(ctx, target: Union[disnake.Member, disnake.Role] = None, channel: disnake.GuildChannel = None):

1635

"""View permissions for a member or role in a channel."""

1636

if channel is None:

1637

channel = ctx.channel

1638

1639

if target is None:

1640

target = ctx.author

1641

1642

if isinstance(target, disnake.Member):

1643

permissions = channel.permissions_for(target)

1644

title = f"Permissions for {target} in #{channel.name}"

1645

else:

1646

# For roles, show overwrites

1647

overwrites = channel.overwrites_for(target)

1648

title = f"Permission overwrites for {target} in #{channel.name}"

1649

1650

embed = disnake.Embed(title=title, color=0x00ff00)

1651

1652

if isinstance(target, disnake.Member):

1653

# Show actual permissions

1654

allowed = []

1655

denied = []

1656

1657

for perm, value in permissions:

1658

perm_display = perm.replace('_', ' ').title()

1659

if value:

1660

allowed.append(perm_display)

1661

else:

1662

denied.append(perm_display)

1663

1664

if allowed:

1665

embed.add_field(

1666

name=f"✅ Allowed ({len(allowed)})",

1667

value=", ".join(allowed[:20]) + ("..." if len(allowed) > 20 else ""),

1668

inline=False

1669

)

1670

1671

if denied:

1672

embed.add_field(

1673

name=f"❌ Denied ({len(denied)})",

1674

value=", ".join(denied[:20]) + ("..." if len(denied) > 20 else ""),

1675

inline=False

1676

)

1677

1678

else:

1679

# Show overwrites

1680

allowed_overwrites = []

1681

denied_overwrites = []

1682

neutral_overwrites = []

1683

1684

for perm, value in overwrites:

1685

perm_display = perm.replace('_', ' ').title()

1686

if value is True:

1687

allowed_overwrites.append(perm_display)

1688

elif value is False:

1689

denied_overwrites.append(perm_display)

1690

else:

1691

neutral_overwrites.append(perm_display)

1692

1693

if allowed_overwrites:

1694

embed.add_field(

1695

name="✅ Explicitly Allowed",

1696

value=", ".join(allowed_overwrites),

1697

inline=False

1698

)

1699

1700

if denied_overwrites:

1701

embed.add_field(

1702

name="❌ Explicitly Denied",

1703

value=", ".join(denied_overwrites),

1704

inline=False

1705

)

1706

1707

if not allowed_overwrites and not denied_overwrites:

1708

embed.description = "No permission overwrites set."

1709

1710

await ctx.send(embed=embed)

1711

```

1712

1713

### Security System Implementation

1714

1715

```python

1716

import json

1717

import asyncio

1718

from collections import defaultdict, deque

1719

from datetime import datetime, timedelta

1720

1721

class SecuritySystem:

1722

"""Comprehensive security system for Discord bots."""

1723

1724

def __init__(self, bot):

1725

self.bot = bot

1726

self.blacklist = set()

1727

self.whitelist = set()

1728

self.trusted_guilds = set()

1729

self.rate_limits = defaultdict(lambda: defaultdict(deque))

1730

self.failed_attempts = defaultdict(int)

1731

self.load_security_data()

1732

1733

def load_security_data(self):

1734

"""Load security data from file."""

1735

try:

1736

with open('security.json', 'r') as f:

1737

data = json.load(f)

1738

self.blacklist = set(data.get('blacklist', []))

1739

self.whitelist = set(data.get('whitelist', []))

1740

self.trusted_guilds = set(data.get('trusted_guilds', []))

1741

except FileNotFoundError:

1742

pass

1743

1744

def save_security_data(self):

1745

"""Save security data to file."""

1746

data = {

1747

'blacklist': list(self.blacklist),

1748

'whitelist': list(self.whitelist),

1749

'trusted_guilds': list(self.trusted_guilds)

1750

}

1751

with open('security.json', 'w') as f:

1752

json.dump(data, f, indent=2)

1753

1754

def is_blacklisted(self, user_id: int) -> bool:

1755

"""Check if user is blacklisted."""

1756

return user_id in self.blacklist

1757

1758

def is_whitelisted(self, user_id: int) -> bool:

1759

"""Check if user is whitelisted."""

1760

return user_id in self.whitelist

1761

1762

def is_trusted_guild(self, guild_id: int) -> bool:

1763

"""Check if guild is trusted."""

1764

return guild_id in self.trusted_guilds

1765

1766

def blacklist_user(self, user_id: int, reason: str = None):

1767

"""Add user to blacklist."""

1768

self.blacklist.add(user_id)

1769

self.save_security_data()

1770

print(f"Blacklisted user {user_id}: {reason}")

1771

1772

def whitelist_user(self, user_id: int):

1773

"""Add user to whitelist."""

1774

self.whitelist.add(user_id)

1775

self.blacklist.discard(user_id)

1776

self.save_security_data()

1777

1778

def check_rate_limit(self, user_id: int, action: str, limit: int = 5, window: int = 60) -> bool:

1779

"""Check if user is within rate limit for action."""

1780

now = datetime.utcnow()

1781

user_actions = self.rate_limits[user_id][action]

1782

1783

# Remove old entries

1784

while user_actions and user_actions[0] < now - timedelta(seconds=window):

1785

user_actions.popleft()

1786

1787

# Check limit

1788

if len(user_actions) >= limit:

1789

self.failed_attempts[user_id] += 1

1790

1791

# Auto-blacklist after too many failures

1792

if self.failed_attempts[user_id] >= 10:

1793

self.blacklist_user(user_id, "Excessive rate limit violations")

1794

1795

return False

1796

1797

# Add current attempt

1798

user_actions.append(now)

1799

return True

1800

1801

def log_suspicious_activity(self, user_id: int, guild_id: int, activity: str):

1802

"""Log suspicious activity."""

1803

timestamp = datetime.utcnow().isoformat()

1804

print(f"SECURITY WARNING [{timestamp}]: User {user_id} in guild {guild_id}: {activity}")

1805

1806

# Could save to database or send to logging channel

1807

1808

def scan_message(self, message: disnake.Message) -> bool:

1809

"""Scan message for security threats."""

1810

content = message.content.lower()

1811

1812

# Check for common threats

1813

threats = [

1814

'discord.gg/', # Invite links

1815

'http://', # Potentially unsafe links

1816

'@everyone', # Mass mentions

1817

'nitro', # Scam keywords

1818

'free', # Scam keywords

1819

]

1820

1821

threat_count = sum(1 for threat in threats if threat in content)

1822

1823

if threat_count >= 2:

1824

self.log_suspicious_activity(

1825

message.author.id,

1826

message.guild.id if message.guild else 0,

1827

f"Suspicious message content (threats: {threat_count})"

1828

)

1829

return False

1830

1831

return True

1832

1833

# Initialize security system

1834

security = SecuritySystem(bot)

1835

1836

# Security middleware

1837

@bot.check

1838

async def security_check(ctx):

1839

"""Global security check for all commands."""

1840

# Skip checks for whitelisted users

1841

if security.is_whitelisted(ctx.author.id):

1842

return True

1843

1844

# Block blacklisted users

1845

if security.is_blacklisted(ctx.author.id):

1846

await ctx.send("You are not authorized to use this bot.", delete_after=5)

1847

return False

1848

1849

# Rate limit check

1850

if not security.check_rate_limit(ctx.author.id, 'command', limit=10, window=60):

1851

await ctx.send("You're being rate limited. Please slow down.", delete_after=5)

1852

return False

1853

1854

return True

1855

1856

@bot.event

1857

async def on_message(message):

1858

"""Security monitoring for messages."""

1859

if message.author.bot:

1860

return

1861

1862

# Security scan

1863

if not security.scan_message(message):

1864

try:

1865

await message.delete()

1866

await message.channel.send(

1867

f"{message.author.mention}, your message was flagged by security systems.",

1868

delete_after=10

1869

)

1870

except disnake.NotFound:

1871

pass

1872

1873

await bot.process_commands(message)

1874

1875

# Security management commands

1876

@bot.group()

1877

@commands.is_owner()

1878

async def security(ctx):

1879

"""Security management commands."""

1880

if ctx.invoked_subcommand is None:

1881

await ctx.send_help(ctx.command)

1882

1883

@security.command()

1884

async def blacklist(ctx, user: disnake.User, *, reason="No reason provided"):

1885

"""Blacklist a user."""

1886

security.blacklist_user(user.id, reason)

1887

await ctx.send(f"Blacklisted {user} ({user.id}): {reason}")

1888

1889

@security.command()

1890

async def whitelist(ctx, user: disnake.User):

1891

"""Whitelist a user."""

1892

security.whitelist_user(user.id)

1893

await ctx.send(f"Whitelisted {user} ({user.id})")

1894

1895

@security.command()

1896

async def status(ctx, user: disnake.User = None):

1897

"""Check security status of a user."""

1898

if user is None:

1899

user = ctx.author

1900

1901

embed = disnake.Embed(title=f"Security Status: {user}")

1902

1903

if security.is_blacklisted(user.id):

1904

embed.color = 0xff0000

1905

embed.add_field(name="Status", value="❌ BLACKLISTED", inline=False)

1906

elif security.is_whitelisted(user.id):

1907

embed.color = 0x00ff00

1908

embed.add_field(name="Status", value="✅ WHITELISTED", inline=False)

1909

else:

1910

embed.color = 0xffff00

1911

embed.add_field(name="Status", value="⚠️ NORMAL", inline=False)

1912

1913

# Rate limit info

1914

command_attempts = len(security.rate_limits[user.id]['command'])

1915

embed.add_field(name="Recent Commands", value=f"{command_attempts}/10 (last 60s)", inline=True)

1916

1917

failed_attempts = security.failed_attempts.get(user.id, 0)

1918

embed.add_field(name="Failed Attempts", value=failed_attempts, inline=True)

1919

1920

await ctx.send(embed=embed)

1921

1922

@security.command()

1923

async def trust_guild(ctx, guild_id: int = None):

1924

"""Mark a guild as trusted."""

1925

if guild_id is None:

1926

guild_id = ctx.guild.id

1927

1928

security.trusted_guilds.add(guild_id)

1929

security.save_security_data()

1930

1931

guild = bot.get_guild(guild_id)

1932

guild_name = guild.name if guild else f"Guild {guild_id}"

1933

await ctx.send(f"Marked {guild_name} as trusted.")

1934

1935

@security.command()

1936

async def stats(ctx):

1937

"""Show security statistics."""

1938

embed = disnake.Embed(title="Security Statistics", color=0x0099ff)

1939

1940

embed.add_field(name="Blacklisted Users", value=len(security.blacklist), inline=True)

1941

embed.add_field(name="Whitelisted Users", value=len(security.whitelist), inline=True)

1942

embed.add_field(name="Trusted Guilds", value=len(security.trusted_guilds), inline=True)

1943

1944

active_rate_limits = len([uid for uid, actions in security.rate_limits.items() if any(actions.values())])

1945

embed.add_field(name="Active Rate Limits", value=active_rate_limits, inline=True)

1946

1947

total_failures = sum(security.failed_attempts.values())

1948

embed.add_field(name="Total Failed Attempts", value=total_failures, inline=True)

1949

1950

await ctx.send(embed=embed)

1951

```