Skip to content

Commit 43bb662

Browse files
Merge pull request #75 from adithyasunil04/api_docs
docs: added documentation to all API endpoint routes so far
2 parents d78be6b + 2a7076e commit 43bb662

17 files changed

+514
-90
lines changed

src/pwncore/models/ctf.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from tortoise.models import Model
66
from tortoise import fields
77
from tortoise.contrib.pydantic import pydantic_model_creator
8-
8+
from pydantic import BaseModel
99
from pwncore.models.user import Team
1010

1111
__all__ = (
@@ -19,6 +19,8 @@
1919
"BaseProblem",
2020
)
2121

22+
class Flag(BaseModel):
23+
flag: str
2224

2325
class BaseProblem(Model):
2426
name = fields.TextField()
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from pydantic import BaseModel
2+
from typing import List, Optional
3+
4+
class CTF_ErrorResponse(BaseModel):
5+
"""
6+
Error response for CTF operations
7+
- 404: ctf_not_found : 2
8+
- 403: hint_limit_reached : 9
9+
- 412: Insufficient coins : 22
10+
- 406: container_already_running : 7
11+
- 429: container_limit_reached : 8
12+
- 500: db_error : 0
13+
"""
14+
msg_code: int
15+
16+
class ContainerStartResponse(BaseModel):
17+
"""
18+
Response for container start operation
19+
msg_codes:
20+
- (success) container_start : 3
21+
"""
22+
msg_code: int
23+
ports: Optional[List[int]] = None
24+
ctf_id: Optional[int] = None
25+
26+
class ContainerStopResponse(BaseModel):
27+
"""
28+
Response for container stop operations
29+
- (success) container_stop : 4
30+
- (fail)
31+
- 404: ctf_not_found : 2
32+
- 400: container_not_found : 6
33+
- 500: db_error : 0
34+
"""
35+
msg_code: int
36+
37+
class ContainerPortsResponse(BaseModel):
38+
"""
39+
Response for all open ports of containers
40+
"""
41+
ports: dict[int, list[int]]
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from pydantic import BaseModel
2+
from typing import Optional
3+
4+
class AdminBaseResponse(BaseModel):
5+
"""
6+
Generic response for admin operations
7+
"""
8+
success: bool
9+
message: Optional[str] = None
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from pydantic import BaseModel
2+
from typing import List, Optional
3+
4+
class CTF_ErrorResponse(BaseModel):
5+
"""
6+
Generic error response
7+
msg_code: 0 (db_error), 2 (ctf_not_found)
8+
"""
9+
msg_code: int
10+
11+
class ContainerStartResponse(BaseModel):
12+
"""
13+
Response for container start operation
14+
msg_code: 3 (success), 7 (already running), 8 (limit reached), 0 (db_error)
15+
"""
16+
msg_code: int
17+
ports: Optional[List[int]] = None
18+
ctf_id: Optional[int] = None
19+
20+
class ContainerStopResponse(BaseModel):
21+
"""
22+
Response for container stop operations
23+
msg_code: 4 (stop success), 5 (stopall success), 6 (not found), 0 (db_error)
24+
"""
25+
msg_code: int
26+
27+
class ContainerPortsResponse(BaseModel):
28+
"""
29+
Response for all open ports of containers
30+
ports: array of port numbers
31+
"""
32+
ports: dict[int, list[int]]
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from pydantic import BaseModel
2+
3+
# defining Pydantic response model
4+
class LeaderboardEntry(BaseModel):
5+
"""
6+
Returns the leaderboard entry for a team.
7+
name: team name
8+
tpoints: total points
9+
"""
10+
name: str
11+
tpoints: int
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from pydantic import BaseModel
2+
3+
# pydantic response models
4+
class PreEventFlag(BaseModel):
5+
"""
6+
Response for pre-event flag submission
7+
"""
8+
tag: str
9+
flag: str
10+
email: str
11+
12+
13+
class CoinsQuery(BaseModel):
14+
"""
15+
Response for pre-event coins query
16+
"""
17+
tag: str
18+
19+
class CoinsResponse(BaseModel):
20+
"""
21+
Response for pre-event coins query
22+
"""
23+
coins: int
24+
25+
class FlagSubmissionResponse(BaseModel):
26+
"""
27+
Response for pre-event flag submission
28+
"""
29+
status: bool
30+
coins: int
31+
32+
class preEventCTF_ErrorResponse(BaseModel):
33+
msg_code: int
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
from pydantic import BaseModel
2+
import typing as t
3+
4+
# defining Pydantic response models
5+
class AuthBody(BaseModel):
6+
"""
7+
Request body for login
8+
name: name of the user
9+
password: password of the user
10+
"""
11+
name: str
12+
password: str
13+
14+
15+
class SignupBody(BaseModel):
16+
name: str
17+
password: str
18+
tags: set[str]
19+
20+
21+
# Response Models
22+
class SignupResponse(BaseModel):
23+
"""
24+
msg_code: 13 (signup_success)
25+
"""
26+
msg_code: t.Literal[13]
27+
28+
class SignupErrorUsersNotFound(BaseModel):
29+
"""
30+
msg_code: 24 (users_not_found)
31+
tags: list[str]
32+
"""
33+
msg_code: t.Literal[24]
34+
tags: list[str]
35+
36+
class SignupErrorUsersInTeam(BaseModel):
37+
"""
38+
msg_code: 20 (user_already_in_team)
39+
tags: list[str]
40+
"""
41+
msg_code: t.Literal[20]
42+
tags: list[str]
43+
44+
class LoginResponse(BaseModel):
45+
"""
46+
msg_code: 15 (login_success)
47+
access_token: JWT access token
48+
token_type: "bearer"
49+
"""
50+
msg_code: t.Literal[15]
51+
access_token: str
52+
token_type: str
53+
54+
class Auth_ErrorResponse(BaseModel):
55+
"""
56+
msg_code can be:
57+
0 (db_error)
58+
17 (team_exists)
59+
10 (team_not_found)
60+
14 (wrong_password)
61+
"""
62+
msg_code: t.Literal[0, 17, 10, 14]
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from pydantic import BaseModel
2+
import typing as t
3+
4+
5+
class UserAddBody(BaseModel):
6+
"""
7+
Request body for adding a user
8+
"""
9+
tag: str
10+
name: str
11+
email: str
12+
phone_num: str
13+
14+
15+
class UserRemoveBody(BaseModel):
16+
"""
17+
Request body for removing a user
18+
"""
19+
tag: str
20+
21+
class MemberStatusResponse(BaseModel):
22+
"""
23+
Response for user management operations in teams
24+
msg_code for response:
25+
- (success)
26+
- user_added: 18
27+
- user_removed: 19
28+
29+
- (fail)
30+
- user_already_in_team: 20
31+
- user_not_in_team : 21
32+
- db_error: 0
33+
"""
34+
msg_code: int
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from pydantic import BaseModel
2+
import typing as t
3+
4+
class UserAddBody(BaseModel):
5+
"""
6+
Request body for adding a user
7+
tag: team tag
8+
name: name of the user
9+
email: email of the user
10+
phone_num: phone number of the user
11+
"""
12+
tag: str
13+
name: str
14+
email: str
15+
phone_num: str
16+
17+
18+
class UserRemoveBody(BaseModel):
19+
"""
20+
Request body for removing a user
21+
tag: team tag
22+
"""
23+
tag: str
24+
25+
26+
class MessageResponse(BaseModel):
27+
"""
28+
Response for user management operations
29+
msg_code: message code
30+
"""
31+
msg_code: int

src/pwncore/routes/admin.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
from fastapi import APIRouter, Request, Response
55
from passlib.hash import bcrypt, bcrypt_sha256
66
from tortoise.transactions import atomic, in_transaction
7+
from pydantic import BaseModel
8+
from typing import Optional
79

810
import pwncore.containerASD as containerASD
911
from pwncore.config import config
@@ -51,14 +53,21 @@ async def _del_cont(id: str):
5153
await container.delete()
5254

5355

56+
class AdminResponse(BaseModel):
57+
success: bool
58+
message: Optional[str] = None
59+
60+
5461
@atomic()
55-
@router.get("/union")
62+
@router.get("/union",
63+
response_model=AdminResponse,
64+
)
5665
async def calculate_team_coins(
5766
response: Response, req: Request
5867
): # Inefficient, anyways will be used only once
5968
if not bcrypt_sha256.verify((await req.body()).strip(), config.admin_hash): # Use config.admin_hash
6069
response.status_code = 401
61-
return
70+
return AdminResponse(success=False, message="Authentication failed")
6271
async with in_transaction():
6372
logging.info("Calculating team points form pre-event CTFs:")
6473
team_ids = await Team.filter().values_list("id", flat=True)
@@ -82,14 +91,18 @@ async def calculate_team_coins(
8291
logging.info(f"{team.id}) {team.name}: {team.coins}")
8392
await team.save()
8493

94+
return AdminResponse(success=True, message="Team coins updated successfully")
8595

86-
@router.get("/create")
96+
97+
@router.get("/create",
98+
response_model=AdminResponse
99+
)
87100
async def init_db(
88101
response: Response, req: Request
89102
): # Inefficient, anyways will be used only once
90103
if not bcrypt_sha256.verify((await req.body()).strip(), config.admin_hash):
91104
response.status_code = 401
92-
return
105+
return AdminResponse(success=False, message="Authentication failed")
93106
await Problem.create(
94107
name="Invisible-Incursion",
95108
description="Chod de tujhe se na ho paye",
@@ -207,3 +220,5 @@ async def init_db(
207220
await SolvedProblem.create(team_id=2, problem_id=1)
208221
await SolvedProblem.create(team_id=2, problem_id=2)
209222
await SolvedProblem.create(team_id=1, problem_id=2)
223+
224+
return AdminResponse(success=True, message="Database initialized with sample data")

0 commit comments

Comments
 (0)