Simple user management

This commit is contained in:
nsde 2023-08-01 02:39:20 +02:00
parent cce6cc5152
commit e8bc01fbf5
9 changed files with 252 additions and 102 deletions

2
.gitignore vendored
View file

@ -1,3 +1,5 @@
*.log
# Byte-compiled / optimized / DLL files # Byte-compiled / optimized / DLL files
__pycache__/ __pycache__/
*.py[cod] *.py[cod]

47
cord/accounts.py Normal file
View file

@ -0,0 +1,47 @@
"""Account system functionality."""
import os
import json
import requests
import embedder
from dotenv import load_dotenv
load_dotenv()
async def request_user_by_discord_id(discord_id):
return requests.get(
url=f'https://api.nova-oss.com/users?discord_id={discord_id}',
timeout=3,
headers={
'Content-Type': 'application/json',
'Authorization': os.getenv('CORE_API_KEY')
}
)
async def get_account(interaction):
try:
get_response = await request_user_by_discord_id(interaction.user.id)
except Exception as exc:
await embedder.error(interaction, """Sorry,
there was an error while checking if you have an account.
Please report this issue to the staff!""", ephemeral=True)
raise exc
if get_response.status_code == 404:
return await embedder.error(interaction, """You
don't have an account yet!""", ephemeral=True)
await embedder.info(interaction, f"""**Your account**
This is all we have stored about your API account in our database.
Feel free to request a removal of your account by contacting the staff.
||```json
{json.dumps(get_response.json(), indent=4)}
```||
(Click to reveal)
Learn more about how to use our API at **https://nova-oss.com**.
""", ephemeral=True)

View file

@ -1,18 +1,31 @@
import random
import embedder import embedder
from nextcord import DMChannel
async def process(message): async def process(message):
if message.content == '/key': text = message.content
responses = [
'https://media.tenor.com/t9f91LQWsM4AAAAS/breaking-bad-funny.gif',
'NPC detected, command rejected.',
'https://images-ext-1.discordapp.net/external/DXc3r4PyRR3m_4AzevpxWhfFtavdcMeDpZqFj3Ig4hc/https/media.tenor.com/b7swbvaVKhUAAAPo/seriously-laugh.mp4',
'there👏is👏no👏/key👏command👏',
'https://i.imgflip.com/7tuhc6.jpg'
]
await message.reply(random.choice(responses)) # IGNORE BOTS
await message.channel.send('Jokes aside - the project is still under development. There\'s no **`/key`** command.') if message.author.bot:
return
if message.content.startswith('/') and ('commands' not in message.channel.name) and (not message.author.guild_permissions.manage_messages): # IGNORE DM CHANNELS
await embedder.warn(message, 'Please only run commands in `/commands`.') if isinstance(message.channel, DMChannel):
return
if 'N0V4x0SS' in text or 'T3BlbkFJ' in text:
await embedder.warn(message, f'{message.author.mention}, I think you sent an *OpenAI* or *NovaAI* key in here, which could lead to other users accessing your API account without your knowledge. Be very careful with API credentials!', delete_after=15)
await message.delete()
# COMMANDS: WRONG CHANNEL
commands_allowed = ('commands' in message.channel.name) or (message.author.guild_permissions.manage_messages)
if text.startswith('/') and not commands_allowed:
await embedder.error(message, f'{message.author.mention}, plesae __only__ run commands in <#1133103276871667722>.', delete_after=10)
await message.delete()
return
# COMMANDS: NOT RAN CORRECTLY
if text.startswith('/') and len(text) > 2:
await embedder.warn(message, """Need help running commands? Check out
**https://nova-oss.com/novacord**!""", delete_after=10)
return

View file

@ -1,13 +1,14 @@
# This example requires the 'members' and 'message_content' privileged intents to function. """Bot base."""
import os import os
import nextcord import nextcord
import system
import chatbot import chatbot
import embedder import embedder
import autochat import autochat
import accounts
import community import community
import credential_manager
from dotenv import load_dotenv from dotenv import load_dotenv
from nextcord.ext import commands from nextcord.ext import commands
@ -15,9 +16,11 @@ from nextcord import SlashOption
load_dotenv() load_dotenv()
guild_ids = [int(guild_id) for guild_id in os.getenv('DISCORD_GUILD_IDS').split()]
bot = commands.Bot( bot = commands.Bot(
intents=nextcord.Intents.all(), intents=nextcord.Intents.all(),
default_guild_ids=[int(guild_id) for guild_id in os.getenv('DISCORD_GUILD_IDS').split()] # so slash commands work default_guild_ids=guild_ids # so slash commands work
) )
@bot.event @bot.event
@ -33,29 +36,34 @@ async def on_message(message):
await autochat.process(message) await autochat.process(message)
await bot.process_commands(message) await bot.process_commands(message)
@bot.slash_command(description='Chat with AI') # @bot.slash_command(description='Chat with AI')
async def chat(interaction: nextcord.Interaction, # async def chat(interaction: nextcord.Interaction,
prompt: str = SlashOption(description='AI Prompt', required=True) # prompt: str = SlashOption(description='AI Prompt', required=True)
): # ):
await chatbot.respond(interaction, prompt) # await chatbot.respond(interaction, prompt)
@bot.slash_command(description='Sets your DMs up, so you can write the bot.') @bot.slash_command(description='Sets your DMs up, so you can write the bot.')
async def dm(interaction: nextcord.Interaction): async def dm_setup(interaction: nextcord.Interaction):
try: try:
await interaction.user.create_dm() await interaction.user.create_dm()
await embedder.info(interaction.user.dm_channel, 'Hello!') await embedder.info(interaction.user.dm_channel, 'Hello!')
except nextcord.Forbidden: except nextcord.Forbidden:
await embedder.error(interaction, text="""Please open this server\'s options, await embedder.error(interaction, text="""Please open this server\'s options,
go to `Privacy Settings` and enable `Direct Messages` as well as `Message Requests`.""") go to `Privacy Settings` and enable `Direct Messages` as well as `Message Requests`.""")
else:
else:
await embedder.ok(interaction, 'Great, DMs are set up successfully!') await embedder.ok(interaction, 'Great, DMs are set up successfully!')
@bot.slash_command(description='Get your secret NovaAI API credentials.') @bot.slash_command(description='Create your account and get your API key.')
async def credentials(interaction: nextcord.Interaction): async def credentials(interaction: nextcord.Interaction):
return await system.get_credentials(interaction) return await credential_manager.get_credentials(interaction)
@bot.slash_command(description='Leaderboard.') @bot.slash_command(description='Leaderboard.')
async def leaderboard(interaction: nextcord.Interaction): async def leaderboard(interaction: nextcord.Interaction):
await community.leaderboard(interaction) return await community.leaderboard(interaction)
@bot.slash_command(description='Get info and stats about your NovaAI API account.')
async def account(interaction: nextcord.Interaction):
return await accounts.get_account(interaction)
bot.run(os.getenv('DISCORD_TOKEN')) bot.run(os.getenv('DISCORD_TOKEN'))

View file

@ -0,0 +1,73 @@
"""Account system functionality."""
import os
import requests
import embedder
import accounts
import tos_verification
from dotenv import load_dotenv
load_dotenv()
async def get_credentials(interaction):
for _ in range(2):
try:
get_response = await accounts.request_user_by_discord_id(interaction.user.id)
except Exception as exc:
await embedder.error(interaction, """Sorry,
there was an issue while checking if you already have an account.
Please report this issue to the staff!""", ephemeral=True)
raise exc
if get_response.status_code == 200: # user exists
break
# NEW USER
read_tos = await tos_verification.verify(interaction)
if not read_tos:
await interaction.delete_original_message()
return
# CREATE USER
get_response = requests.post(
url='https://api.nova-oss.com/users',
timeout=3,
headers={
'Content-Type': 'application/json',
'Authorization': os.getenv('CORE_API_KEY')
},
json={
'discord_id': interaction.user.id
}
)
try:
get_response.raise_for_status()
except Exception as exc:
await embedder.error(interaction, """Sorry,
your account could not be created. Please report this issue to the staff!""", ephemeral=True)
raise exc
else:
await embedder.ok(interaction, f"""Welcome to NovaAI, {interaction.user.mention}!
Your account was created successfully.""", ephemeral=True)
api_key = get_response.json()['api_key']
await embedder.info(interaction, f"""This is your **secret** API key.
Don't paste it on untrusted websites, apps or programs.
Store it securely using a `.env` file in the environment variables
or use a secure password manager like *KeePass*, *ProtonPass* or *Bitwarden*.
We reserve the right to __disable your API key at any time__ if you violate our terms of service.
If you accept the terms of service and privacy policy, feel free to use the following API key:
## ||`{api_key}`||
Learn more about how to use our API at **https://nova-oss.com**.
""", ephemeral=True)

View file

@ -9,7 +9,8 @@ async def send(
text: str, text: str,
content: str = '', content: str = '',
ephemeral: bool = False, ephemeral: bool = False,
color: nextcord.Color = nextcord.Color.blue() color: nextcord.Color = nextcord.Color.blue(),
**kwargs
): ):
edit = False edit = False
@ -28,7 +29,7 @@ async def send(
end = '' end = ''
if milliseconds > 10000: # https://youtu.be/-5wpm-gesOY if milliseconds > 5000: # https://youtu.be/-5wpm-gesOY
end = f' in {milliseconds}ms' end = f' in {milliseconds}ms'
embed.set_footer(text=f'Powered by NovaAI{end}', icon_url='https://i.ibb.co/LDyFcSh/fav-blurple.png') embed.set_footer(text=f'Powered by NovaAI{end}', icon_url='https://i.ibb.co/LDyFcSh/fav-blurple.png')
@ -36,19 +37,19 @@ async def send(
interaction_type = Union[nextcord.Interaction, nextcord.InteractionResponse] interaction_type = Union[nextcord.Interaction, nextcord.InteractionResponse]
# these checks are done so this function is easy as fuck to use # these checks are done so this function is easy to use
if edit: if edit:
return await ctx.edit(embed=embed, content=content) return await ctx.edit(embed=embed, content=content, **kwargs)
if isinstance(ctx, nextcord.Message): if isinstance(ctx, nextcord.Message):
response = await ctx.reply(embed=embed, content=content) response = await ctx.reply(embed=embed, content=content, **kwargs)
elif isinstance(ctx, interaction_type): elif isinstance(ctx, interaction_type):
response = await ctx.send(embed=embed, ephemeral=ephemeral, content=content) response = await ctx.send(embed=embed, ephemeral=ephemeral, content=content, **kwargs)
else: else:
response = await ctx.send(embed=embed, content=content) response = await ctx.send(embed=embed, content=content, **kwargs)
return response return response

View file

@ -1,4 +0,0 @@
import secrets
async def create(user):
return 'nv-' + secrets.token_urlsafe(32)

View file

@ -1,65 +0,0 @@
import os
import asyncio
import requests
import keys
import embedder
from dotenv import load_dotenv
load_dotenv()
async def get_credentials(interaction):
try:
resp = requests.post(
url='https://nova-oss.com/api/tos-verification',
timeout=5,
headers={'Content-Type': 'application/json', 'Authorization': os.getenv('TOS_VERIFICATION_KEY')}
).json()
except Exception as exc:
await embedder.error(interaction, """Sorry, the API server for the verification system is not functioning,
which means you can\'t create a new key right now. Please report this issue to the staff!""")
raise exc
tos_code = resp['code']
tos_emoji = resp['emoji']
tos_message = await embedder.warn(interaction, f"""# THIS IS JUST A DEMO/EXAMPLE!
# THE KEY WON'T WORK!
# THE SYSTEM ISN'T READY YET.
# DON'T SAVE THE KEY!!!
You have to read the privacy policy and terms of service first.
In the latter, there is a hidden emoji which you'll have to send (NOT react!) in here.
https://nova-oss.com/legal/privacy
https://nova-oss.com/legal/terms?verify={tos_code}
I know it's annoying, but it really helps combat spam bots and abuse.
This message will be deleted and your code will run out **after about 10 minutes**
if you don't pass the verification, but **feel free to run this command again** at any time.
""", ephemeral=True)
def check(message): return interaction.user.id == message.author.id and message.content == tos_emoji
try:
answer = await interaction.client.wait_for('message', timeout=666, check=check)
except asyncio.TimeoutError:
await tos_message.delete()
requests.delete(
url=f'https://nova-oss.com/api/tos-verification/{tos_code}',
timeout=5,
headers={'Content-Type': 'application/json', 'Authorization': os.getenv('TOS_VERIFICATION_KEY')}
)
else:
await answer.delete()
api_key = await keys.create(interaction.user)
await embedder.ok(interaction, f"""This is your **secret** API key. Don't paste it on untrusted websites, apps or programs.
Store it securely using a `.env` file in the environment variables or use a secure password manager like *KeePass*, *ProtonPass* or *Bitwarden*.
We reserve the right to __disable your API key at any time__ if you violate our terms of service.
If you accept the terms of service and privacy policy, feel free to use the following API key:
## ||`{api_key}`||
""", ephemeral=True)

75
cord/tos_verification.py Normal file
View file

@ -0,0 +1,75 @@
"""The module for the Terms of Service verification system."""
import os
import asyncio
import requests
import embedder
from dotenv import load_dotenv
load_dotenv()
async def verify(interaction) -> bool:
try:
resp = requests.post(
url='https://nova-oss.com/api/tos-verification',
timeout=5,
headers={
'Content-Type': 'application/json',
'Authorization': os.getenv('TOS_VERIFICATION_KEY')
}
).json()
except Exception as exc:
await embedder.error(interaction, """Sorry,
the API server for the verification system is not functioning,
which means you can\'t create a new key right now. Please report this issue to the staff!""")
raise exc
success = False
tos_code = resp['code']
tos_emoji = resp['emoji']
tos_message = await embedder.warn(interaction, f"""
You have to read the privacy policy and terms of service first.
In the latter, there is a hidden emoji which you'll have to __send__ (NOT react!) in here.
https://nova-oss.com/legal/privacy
https://nova-oss.com/legal/terms?verify={tos_code}
I know it's annoying, but it really helps combat spam bots and abuse.
This message will be deleted and your code will run out **after 10 minutes**
if you don't pass the verification, but **feel free to run this command again** at any time.
""", ephemeral=True)
def check(message):
correct_user = interaction.user.id == message.author.id
return correct_user and message.content == tos_emoji
try:
while True:
received_answer = await interaction.client.wait_for('message', timeout=600, check=check)
await received_answer.delete()
if received_answer.content == tos_emoji:
break
except asyncio.TimeoutError:
await tos_message.delete()
else:
success = True
finally:
await tos_message.delete()
requests.delete(
url=f'https://nova-oss.com/api/tos-verification/{tos_code}',
timeout=5,
headers={
'Content-Type': 'application/json',
'Authorization': os.getenv('TOS_VERIFICATION_KEY')
}
)
return success