def challenges(self) -> Generator[Challenge, None, None]: # Request the list of challenges r = self.session.get(f"{self.url}/api/v1/challenges") if r.status_code != 200: raise RuntimeError(f"failed to retrieve challenges") # Extract json data data = r.json()["data"] # Grab self me = self.me # Grab solves solves = self._get_solves() # Iterate over challenges for c in data: challenge = Challenge( title=c["name"], value=c["value"], ident=str(c["id"]), provider=self, tags=[c["category"]] + c["tags"], ) if challenge.ident in [solve.ident for solve in solves]: challenge.solved = True yield challenge return
def get_challenge(self, ident: int) -> Challenge: # Request challenge details r = self.session.get(f"{self.url}/api/v1/challenges/{ident}") if r.status_code != 200: raise RuntimeError("failed to get challenge details") # Extract data data = r.json()["data"] # Build challenge structure challenge = Challenge( title=data["name"], value=data["value"], ident=str(data["id"]), provider=self, description=data["description"], files={ f.split("?")[0].split("/")[-1]: f"{self.url}{f}" for f in data["files"] }, tags=[data["category"]] + data["tags"], ) # Set solved flag if challenge.ident in [c.ident for c in self.me.solves]: challenge.solved = True # Return challenge structure return challenge
def _parse_challenge(self, result) -> Challenge: """ Parse the result of a challenge/problem request (either from /problem or from a specific problem) :param result: The result dictionary from the API call :return: A new challenge instance """ file_pattern = re.compile(r"href='(//[^/]+/static/[^']+)'>") matches: List[Tuple[str, str]] = file_pattern.findall(result["description"]) method = "http" if "://" in self.url: method = self.url.split(":")[0] files = {} if matches is not None: files = { match.split("/")[-1]: f"{method}:{match}" for match in matches } return Challenge( result["name"], result["score"], result["pid"], self, result["description"], files, [result["category"]], result["solved"], )
def _get_solves(self) -> List[Challenge]: """ Get the list of solves for this user :return: List of challenges we have solved """ # Get user solves r = self.session.get(f"{self.url}/api/v1/users/me/solves") if r.status_code != 200: raise RuntimeError("failed to retrieve solves") # Extract solve data data = r.json()["data"] solves = [] for solve in data: solves.append( Challenge( title=solve["challenge"]["name"], value=solve["challenge"]["value"], ident=str(solve["challenge_id"]), provider=self, tags=[solve["challenge"]["category"]], solved=True, )) return solves
def submit(self, challenge: Challenge, flag: str) -> Tuple[bool, int]: # Attempt to submit flag r = self.session.post( f"{self.url}/api/v1/challenges/attempt", json={ "challenge_id": challenge.ident, "submission": flag }, headers={"CSRF-Token": self.csrf_token}, ) if r.status_code != 200: raise RuntimeError("failed to submit flag") # Check if it was right data = r.json()["data"] if data["status"] != "incorrect": challenge.solved = True return True, 1 else: return False, 1