1
0
This repository has been archived on 2024-10-06. You can view files and clone it, but cannot push or open issues or pull requests.
Achievement-Promotion/app.py

141 lines
5.2 KiB
Python
Raw Normal View History

2023-03-22 21:28:15 +09:00
import asyncio
import os
from urllib import parse
from typing import Any
import aiohttp
import uvicorn
2023-03-22 21:49:19 +09:00
from cryptography.fernet import Fernet
2023-03-22 21:28:15 +09:00
from dotenv import load_dotenv
from fastapi import Cookie, FastAPI, HTTPException, Request, Response
from fastapi.responses import RedirectResponse
from linked_roles import LinkedRolesOAuth2, RoleConnection
load_dotenv()
app = FastAPI(
title="Achievement Promotion with Steam - Discord",
description="This API is used to verify that you have achievement of the game and give you a role.",
version="1.0.0",
openapi_url=None
)
client = LinkedRolesOAuth2(
client_id=os.getenv("CLIENT_ID"),
client_secret=os.getenv("CLIENT_SECRET"),
redirect_uri=f"{os.getenv('REDIRECT_URI')}/discord",
token=os.getenv("BOT_TOKEN"),
2023-03-22 23:23:54 +09:00
scopes=("identify", "role_connections.write"),
2023-03-22 21:28:15 +09:00
state=os.getenv("COOKIE_SECRET")
)
2023-03-22 21:52:58 +09:00
fn = Fernet(os.getenv("ENCRYPT_KEY"))
2023-03-22 21:28:15 +09:00
def encrypt(text: str) -> str:
return fn.encrypt(text.encode())
def decrypt(text: str) -> str:
return fn.decrypt(text).decode()
async def async_list(values: list) -> Any:
for value in values:
yield value
await asyncio.sleep(0)
@app.on_event('startup')
async def startup():
await client.start()
@app.on_event('shutdown')
async def shutdown():
await client.close()
@app.get('/verify')
async def link():
steam_openid_url = "https://steamcommunity.com/openid/login"
u = {
'openid.ns': "http://specs.openid.net/auth/2.0",
'openid.identity': "http://specs.openid.net/auth/2.0/identifier_select",
'openid.claimed_id': "http://specs.openid.net/auth/2.0/identifier_select",
'openid.mode': "checkid_setup",
'openid.return_to': f"{os.getenv('REDIRECT_URI')}/steam",
2023-03-22 23:13:42 +09:00
'openid.realm': f"{os.getenv('REDIRECT_URI')}/steam"
2023-03-22 21:28:15 +09:00
}
query_string = parse.urlencode(u)
auth_url = steam_openid_url + "?" + query_string
return RedirectResponse(auth_url)
@app.get('/callback/steam')
async def setup(request: Request, response: Response):
2023-03-22 23:17:06 +09:00
valid = await validate(dict(request.query_params))
2023-03-22 21:28:15 +09:00
if not valid:
raise HTTPException(status_code=404, detail="We can't verify that you have Steam profile.")
url = client.get_oauth_url()
2023-03-22 23:30:08 +09:00
response.set_cookie(key="steam_id", value=encrypt(request.query_params.get("openid.claimed_id")), max_age=1800)
2023-03-22 21:28:15 +09:00
return RedirectResponse(url=url)
2023-03-22 23:17:06 +09:00
async def validate(data: dict) -> bool:
2023-03-22 21:28:15 +09:00
base = "https://steamcommunity.com/openid/login"
params = {
"openid.assoc_handle": data["openid.assoc_handle"],
"openid.sig": data["openid.sig"],
"openid.ns": data["openid.ns"],
"openid.mode": "check_authentication"
}
data.update(params)
data["openid.mode"] = "check_authentication"
data["openid.signed"] = data["openid.signed"]
session = aiohttp.ClientSession()
r = await session.post(base, data=data)
text = await r.text()
2023-03-22 21:28:15 +09:00
if "is_valid:true" in text:
2023-03-22 21:28:15 +09:00
return True
return False
@app.get('/callback/discord')
2023-03-22 23:30:08 +09:00
async def update_metadata(response: Response, code: str, steam_id: str = Cookie()):
2023-03-22 21:28:15 +09:00
token = await client.get_access_token(code)
user = await client.fetch_user(token)
if user is None:
raise HTTPException(status_code=404, detail="We can't verify that you have Discord profile.")
steam_id = decrypt(steam_id)
session = aiohttp.ClientSession()
r = await session.get(f"http://api.steampowered.com/ISteamUserStats/GetPlayerAchievements/v0001/?appid={os.getenv('STEAM_GAME_ID')}&key={os.getenv('STEAM_API_KEY')}&steamid={steam_id}&l=en")
res = await r.json()
data = res["playerstats"]
if data["success"] is False:
if data["error"] == "Profile is not public":
raise HTTPException(status_code=403, detail="We can't verify that you have achievement because your profile is private.")
else:
raise HTTPException(status_code=500, detail=data["error"])
2023-03-22 21:39:14 +09:00
abc = await session.get(f"http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key={os.getenv('STEAM_API_KEY')}&steamids={steam_id}")
abc = await abc.json()
2023-03-22 21:28:15 +09:00
role = await user.fetch_role_connection()
if role is None:
2023-03-22 21:39:14 +09:00
role = RoleConnection(platform_name=f"Steam - {data['gameName']}", platform_username=abc["response"]["players"][0]["personaname"])
2023-03-22 21:28:15 +09:00
success = 0
total = len(data["achievements"])
2023-03-22 23:06:29 +09:00
role.add_or_edit_metadata(key="tutorial", value=False)
role.add_or_edit_metadata(key="allperfetct", value=False)
2023-03-22 21:28:15 +09:00
async for achieve in async_list(data["achievements"]):
if achieve["achieved"] == 1:
2023-03-22 23:06:29 +09:00
if achieve["apiname"] == "honor_roll":
role.add_or_edit_metadata(key="tutorial", value=True)
if achieve["apiname"] == "go_to_bed":
role.add_or_edit_metadata(key="allperfetct", value=True)
2023-03-22 21:28:15 +09:00
success += 1
percentage = (success / total) * 100
role.add_or_edit_metadata(key="percentage", value=percentage)
2023-03-22 22:55:33 +09:00
role.add_or_edit_metadata(key="completed", value=False)
2023-03-22 21:28:15 +09:00
if percentage == 100:
role.add_or_edit_metadata(key="completed", value=True)
await user.edit_role_connection(role)
response.set_cookie(key="steam_id", value="", max_age=1)
2023-03-22 21:39:14 +09:00
return "연동이 완료되었습니다! Discord로 돌아가세요."
2023-03-22 21:28:15 +09:00
uvicorn.run(app, host="0.0.0.0", port=4278)