From e94cd4628d5393019ab8f6e55c30cb62ec7b4bf3 Mon Sep 17 00:00:00 2001 From: smallkirby Date: Sun, 29 Sep 2024 12:43:07 +0900 Subject: [PATCH] =?UTF-8?q?pwnyaa:=20AlpacaHack=20=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: smallkirby --- achievements/achievements.ts | 14 ++++++ pwnyaa/index.ts | 5 +++ pwnyaa/lib/AHManager.ts | 82 ++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 pwnyaa/lib/AHManager.ts diff --git a/achievements/achievements.ts b/achievements/achievements.ts index dd1863ae..20308235 100644 --- a/achievements/achievements.ts +++ b/achievements/achievements.ts @@ -2273,6 +2273,20 @@ const achievements: Achievement[] = [ condition: 'ksnctfを全完する', category: 'pwnyaa', }, + { + id: 'pwnyaa-ah-half', + difficulty: 'hard', + title: 'アルパカかわいい!', + condition: 'AlpacaHackで半分以上の問題を解く', + category: 'pwnyaa', + }, + { + id: 'pwnyaa-ah-complete', + difficulty: 'professional', + title: 'しば犬かわいい!', + condition: 'AlpacaHackを全完する', + category: 'pwnyaa', + }, // anime diff --git a/pwnyaa/index.ts b/pwnyaa/index.ts index f7eb1909..c1a7efa4 100644 --- a/pwnyaa/index.ts +++ b/pwnyaa/index.ts @@ -8,6 +8,7 @@ import {unlock} from '../achievements/index.js'; import logger from '../lib/logger'; import type {SlackInterface} from '../lib/slack'; import {getMemberIcon, getMemberName} from '../lib/slackUtils'; +import {fetchChallsAH, fetchUserProfileAH, findUserByNameAH} from './lib/AHManager'; import {Contest, User, SolvedInfo} from './lib/BasicTypes'; import {fetchChallsCH, fetchUserProfileCH, findUserByNameCH} from './lib/CHManager'; import {fetchChallsKSN, fetchUserProfileKSN, findUserByNameKSN} from './lib/KSNManager'; @@ -36,12 +37,14 @@ export const TW_ID = 0; export const XYZ_ID = 1; export const CH_ID = 2; export const KSN_ID = 3; +export const AH_ID = 4; const CONTESTS: Contest[] = [ {url: 'https://pwnable.xyz', id: XYZ_ID, title: 'pwnable.xyz', alias: ['xyz', 'pnwable.xyz'], achievementStr: 'xyz', fetchUserProfile: fetchUserProfileXYZ, findUserByName: findUserByNameXYZ, fetchChalls: fetchChallsXYZ, numChalls: 0, joiningUsers: []}, {url: 'https://pwnable.tw', id: TW_ID, title: 'pwnable.tw', alias: ['tw', 'pwnable.tw'], achievementStr: 'tw', fetchUserProfile: fetchUserProfileTW, findUserByName: findUserByNameTW, fetchChalls: fetchChallsTW, numChalls: 0, joiningUsers: []}, {url: 'https://cryptohack.org', id: CH_ID, title: 'cryptohack', alias: ['cryptohack', 'ch'], achievementStr: 'ch', fetchUserProfile: fetchUserProfileCH, findUserByName: findUserByNameCH, fetchChalls: fetchChallsCH, numChalls: 0, joiningUsers: []}, {url: 'https://ksnctf.sweetduet.info', id: KSN_ID, title: 'ksnctf', alias: ['ksn', 'ksnctf'], achievementStr: 'ksn', fetchUserProfile: fetchUserProfileKSN, findUserByName: findUserByNameKSN, fetchChalls: fetchChallsKSN, numChalls: 0, joiningUsers: []}, + {url: 'https://alpacahack.com', id: AH_ID, title: 'AlpacaHack', alias: ['ah', 'alpacahack', 'alpaca'], achievementStr: 'ah', fetchUserProfile: fetchUserProfileAH, findUserByName: findUserByNameAH, fetchChalls: fetchChallsAH, numChalls: 0, joiningUsers: []}, ]; const UPDATE_INTERVAL = 12; @@ -72,6 +75,8 @@ const getContestColor = (ctfId: number) => { return '#0099ff'; case KSN_ID: return '#99cc00'; + case AH_ID: + return '#873e23'; default: return '#000000'; } diff --git a/pwnyaa/lib/AHManager.ts b/pwnyaa/lib/AHManager.ts new file mode 100644 index 00000000..9a198196 --- /dev/null +++ b/pwnyaa/lib/AHManager.ts @@ -0,0 +1,82 @@ +// AlpacaHack + +import axios from "axios"; +import { Challenge, SolvedInfo, Profile } from "./BasicTypes"; + +const client = axios.create({ + withCredentials: false, +}); + +export const fetchChallsAH = async function (): Promise { + try { + const { data: json } = await client.get( + "https://alpacahack.com/challenges?_data=routes%2F_root.challenges", + { + headers: {}, + } + ); + return json.challenges.map( + (chall: any): Challenge => ({ + id: "?", // not available + name: chall.name, + score: 0, // not available + }) + ); + } catch { + return null; + } +}; + +export const fetchUserProfileAH = async function ( + userId: string +): Promise { + try { + const { data: json } = await client.get( + `https://alpacahack.com/users/${userId}?_data=routes%2F_root.users_.%24userName`, + { + headers: {}, + } + ); + return { + username: json.name, + country: json.country, + rank: "?", + score: json.submissions + .filter((sub: any) => sub.isCorrect) + .length.toString(), + comment: "", + registeredAt: "", // not available + solvedChalls: json.submissions + .filter((sub: any) => sub.isCorrect) + .map( + (sub: any): SolvedInfo => ({ + id: "", // not available + solvedAt: new Date(sub.createdAt.value), + name: sub.challenge.name, + score: 0, // not available + }) + ), + }; + } catch { + return null; + } +}; + +export const findUserByNameAH = async function ( + username: string +): Promise<{ userid: string; name: string }> { + try { + const { data: json } = await client.get( + `https://alpacahack.com/users/${username}?_data=routes%2F_root.users_.%24userName`, + { + headers: {}, + } + ); + return { + userid: json.name, + name: json.name, + }; + } catch { + return null; + } +};