diff --git a/achievements/achievements.ts b/achievements/achievements.ts index b21afa90..0b6d28b1 100644 --- a/achievements/achievements.ts +++ b/achievements/achievements.ts @@ -2276,17 +2276,45 @@ const achievements: Achievement[] = [ { id: 'pwnyaa-ah-half', difficulty: 'hard', - title: 'アルパカかわいい!', + title: '_アルパカかわいい!', condition: 'AlpacaHackで半分以上の問題を解く', category: 'pwnyaa', }, { id: 'pwnyaa-ah-complete', difficulty: 'professional', - title: 'しば犬かわいい!', + title: '_しば犬かわいい!', condition: 'AlpacaHackを全完する', category: 'pwnyaa', }, + { + id: 'pwnyaa-ah-5', + difficulty: 'easy', + title: 'アルパカかわいい!', + condition: 'AlpacaHackで5問以上の問題を解く', + category: 'pwnyaa', + }, + { + id: 'pwnyaa-ah-10', + difficulty: 'medium', + title: 'しば犬かわいい!', + condition: 'AlpacaHackで10問以上の問題を解く', + category: 'pwnyaa', + }, + { + id: 'pwnyaa-ah-20', + difficulty: 'hard', + title: '猫かわいい!', + condition: 'AlpacaHackで20問以上の問題を解く', + category: 'pwnyaa', + }, + { + id: 'pwnyaa-ah-50', + difficulty: 'professional', + title: '狼かわいい!', + condition: 'AlpacaHackを50問以上の問題を解く', + category: 'pwnyaa', + }, // anime diff --git a/pwnyaa/index.test.ts b/pwnyaa/index.test.ts index 46ee9d9b..b274c9bd 100644 --- a/pwnyaa/index.test.ts +++ b/pwnyaa/index.test.ts @@ -3,7 +3,7 @@ import {constants, promises as fs} from 'fs'; import path from 'path'; import Slack from '../lib/slackMock'; import {getMemberName} from '../lib/slackUtils'; -import {Challenge, SolvedInfo, Profile} from './lib/BasicTypes'; +import {AchievementType, Challenge, SolvedInfo, Profile} from './lib/BasicTypes'; import {fetchChallsCH, fetchUserProfileCH} from './lib/CHManager'; import {fetchChallsKSN, fetchUserProfileKSN} from './lib/KSNManager'; import {fetchChallsTW, fetchUserProfileTW} from './lib/TWManager'; @@ -171,6 +171,7 @@ beforeEach(async () => { alias: ['tw'], joiningUsers: [{slackId: slack.fakeUser, idCtf: '23718'}], numChalls: 46, + achievementType: AchievementType.RATIO, achievementStr: 'tw', fetchUserProfile: (_username: string) => getProfile(sampleProfileTW), fetchChalls: () => getChalls(sampleChallsTW), @@ -183,6 +184,7 @@ beforeEach(async () => { alias: ['xyz'], joiningUsers: [], numChalls: 51, + achievementType: AchievementType.RATIO, achievementStr: 'xyz', fetchUserProfile: (_username: string) => getProfile(sampleProfileXYZ), fetchChalls: () => getChalls(sampleChallsXYZ), @@ -195,6 +197,7 @@ beforeEach(async () => { alias: ['cryptohack', 'ch'], joiningUsers: [], numChalls: 51, + achievementType: AchievementType.RATIO, achievementStr: 'ch', fetchUserProfile: (_username: string) => getProfile(sampleProfileCH), fetchChalls: () => getChalls(sampleChallsCH), @@ -207,6 +210,7 @@ beforeEach(async () => { alias: ['ksn', 'ksnctf'], joiningUsers: [], numChalls: 31, + achievementType: AchievementType.RATIO, achievementStr: 'ksn', fetchUserProfile: (_username: string) => getProfile(sampleProfileKSN), fetchChalls: () => getChalls(sampleChallsKSN), diff --git a/pwnyaa/index.ts b/pwnyaa/index.ts index c1a7efa4..aaa98261 100644 --- a/pwnyaa/index.ts +++ b/pwnyaa/index.ts @@ -9,7 +9,7 @@ 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 {AchievementType, Contest, User, SolvedInfo} from './lib/BasicTypes'; import {fetchChallsCH, fetchUserProfileCH, findUserByNameCH} from './lib/CHManager'; import {fetchChallsKSN, fetchUserProfileKSN, findUserByNameKSN} from './lib/KSNManager'; import {fetchUserProfileTW, fetchChallsTW, findUserByNameTW} from './lib/TWManager'; @@ -40,11 +40,11 @@ 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: []}, + {url: 'https://pwnable.xyz', id: XYZ_ID, title: 'pwnable.xyz', alias: ['xyz', 'pnwable.xyz'], achievementType: AchievementType.RATIO,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'], achievementType: AchievementType.RATIO, achievementStr: 'tw', fetchUserProfile: fetchUserProfileTW, findUserByName: findUserByNameTW, fetchChalls: fetchChallsTW, numChalls: 0, joiningUsers: []}, + {url: 'https://cryptohack.org', id: CH_ID, title: 'cryptohack', alias: ['cryptohack', 'ch'], achievementType: AchievementType.RATIO, achievementStr: 'ch', fetchUserProfile: fetchUserProfileCH, findUserByName: findUserByNameCH, fetchChalls: fetchChallsCH, numChalls: 0, joiningUsers: []}, + {url: 'https://ksnctf.sweetduet.info', id: KSN_ID, title: 'ksnctf', alias: ['ksn', 'ksnctf'], achievementType: AchievementType.RATIO, achievementStr: 'ksn', fetchUserProfile: fetchUserProfileKSN, findUserByName: findUserByNameKSN, fetchChalls: fetchChallsKSN, numChalls: 0, joiningUsers: []}, + {url: 'https://alpacahack.com', id: AH_ID, title: 'AlpacaHack', alias: ['ah', 'alpacahack', 'alpaca'], achievementType: AchievementType.COUNT, achievementStr: 'ah', fetchUserProfile: fetchUserProfileAH, findUserByName: findUserByNameAH, fetchChalls: fetchChallsAH, numChalls: 0, joiningUsers: []}, ]; const UPDATE_INTERVAL = 12; @@ -828,13 +828,26 @@ export default async ({eventClient, webClient: slack}: SlackInterface) => { if (!profile) { return; } - if (profile.solvedChalls.length >= contest.numChalls) { - log.info(`[+] pwnyaa: unlocking: pwnyaa-${contest.achievementStr}-complete`); - await unlock(user.slackId, `pwnyaa-${contest.achievementStr}-complete`); - } - if (profile.solvedChalls.length >= contest.numChalls / 2) { - log.info(`[+] pwnyaa: unlocking: pwnyaa-${contest.achievementStr}-half`); - await unlock(user.slackId, `pwnyaa-${contest.achievementStr}-half`); + switch(contest.achievementType){ + case AchievementType.RATIO: + if (profile.solvedChalls.length >= contest.numChalls) { + log.info(`[+] pwnyaa: unlocking: pwnyaa-${contest.achievementStr}-complete`); + await unlock(user.slackId, `pwnyaa-${contest.achievementStr}-complete`); + } + if (profile.solvedChalls.length >= contest.numChalls / 2) { + log.info(`[+] pwnyaa: unlocking: pwnyaa-${contest.achievementStr}-half`); + await unlock(user.slackId, `pwnyaa-${contest.achievementStr}-half`); + } + break; + case AchievementType.COUNT: + const achievements_count: number[] = [50,20,10,5]; + for (const num of achievements_count){ + if (profile.solvedChalls.length >= num) { + log.info(`[+] pwnyaa: unlocking: pwnyaa-${contest.achievementStr}-${num}`); + await unlock(user.slackId, `pwnyaa-${contest.achievementStr}-${num}`); + } + } + break; } } } diff --git a/pwnyaa/lib/BasicTypes.ts b/pwnyaa/lib/BasicTypes.ts index 6fd30742..d3b3fb40 100644 --- a/pwnyaa/lib/BasicTypes.ts +++ b/pwnyaa/lib/BasicTypes.ts @@ -7,12 +7,19 @@ export interface User { currentStreak?: number, } +// Achievement Type +export enum AchievementType { + RATIO = 0, // half and all + COUNT = 1, // 5, 10, 20, 50 problems +} + // Site Information export interface Contest{ id: number, url: string, title: string, alias: string[], + achievementType: AchievementType, numChalls: number, joiningUsers: User[], achievementStr?: string,