Skip to content

Commit c1a14c1

Browse files
authored
Add the ignore flag to disable setting of certain challenge properties (#60)
* Add the ignore flag to disable setting of certain challenge properties * Usage: `ctf challenge install challenge.yml --ignore=flags,tags` * Usage: `ctf challenge install --ignore=flags,tags` * Usage: `ctf challenge sync challenge.yml --ignore=flags,tags` * Usage: `ctf challenge sync --ignore=flags,tags` * Closes #25
1 parent a8ff2ba commit c1a14c1

File tree

2 files changed

+64
-58
lines changed

2 files changed

+64
-58
lines changed

ctfcli/cli/challenges.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,17 @@ def restore(self, challenge=None):
9595
else:
9696
click.echo(f"Skipping {url} - {folder}")
9797

98-
def install(self, challenge=None, force=False):
98+
def install(self, challenge=None, force=False, ignore=()):
9999
if challenge is None:
100100
# Get all challenges if not specifying a challenge
101101
config = load_config()
102102
challenges = dict(config["challenges"]).keys()
103103
else:
104104
challenges = [challenge]
105105

106+
if isinstance(ignore, str):
107+
ignore = (ignore,)
108+
106109
for challenge in challenges:
107110
path = Path(challenge)
108111

@@ -129,17 +132,20 @@ def install(self, challenge=None, force=False):
129132
break
130133
else: # If we don't break because of duplicated challenge names
131134
click.secho(f'Installing {challenge["name"]}', fg="yellow")
132-
create_challenge(challenge=challenge)
135+
create_challenge(challenge=challenge, ignore=ignore)
133136
click.secho(f"Success!", fg="green")
134137

135-
def sync(self, challenge=None):
138+
def sync(self, challenge=None, ignore=()):
136139
if challenge is None:
137140
# Get all challenges if not specifying a challenge
138141
config = load_config()
139142
challenges = dict(config["challenges"]).keys()
140143
else:
141144
challenges = [challenge]
142145

146+
if isinstance(ignore, str):
147+
ignore = (ignore,)
148+
143149
for challenge in challenges:
144150
path = Path(challenge)
145151

@@ -162,7 +168,7 @@ def sync(self, challenge=None):
162168
continue # Go to the next challenge in the overall list
163169

164170
click.secho(f'Syncing {challenge["name"]}', fg="yellow")
165-
sync_challenge(challenge=challenge)
171+
sync_challenge(challenge=challenge, ignore=ignore)
166172
click.secho(f"Success!", fg="green")
167173

168174
def update(self, challenge=None):

ctfcli/utils/challenge.py

Lines changed: 54 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def load_installed_challenges():
2828
return s.get("/api/v1/challenges?view=admin", json=True).json()["data"]
2929

3030

31-
def sync_challenge(challenge):
31+
def sync_challenge(challenge, ignore=[]):
3232
data = {
3333
"name": challenge["name"],
3434
"category": challenge["category"],
@@ -43,7 +43,7 @@ def sync_challenge(challenge):
4343
if challenge["value"] is None:
4444
del challenge["value"]
4545

46-
if challenge.get("attempts"):
46+
if challenge.get("attempts") and "attempts" not in ignore:
4747
data["max_attempts"] = challenge.get("attempts")
4848

4949
data["state"] = "hidden"
@@ -65,16 +65,15 @@ def sync_challenge(challenge):
6565
r = s.patch(f"/api/v1/challenges/{challenge_id}", json=data)
6666
r.raise_for_status()
6767

68-
# Delete existing flags
69-
current_flags = s.get(f"/api/v1/flags", json=data).json()["data"]
70-
for flag in current_flags:
71-
if flag["challenge_id"] == challenge_id:
72-
flag_id = flag["id"]
73-
r = s.delete(f"/api/v1/flags/{flag_id}", json=True)
74-
r.raise_for_status()
75-
7668
# Create new flags
77-
if challenge.get("flags"):
69+
if challenge.get("flags") and "flags" not in ignore:
70+
# Delete existing flags
71+
current_flags = s.get(f"/api/v1/flags", json=data).json()["data"]
72+
for flag in current_flags:
73+
if flag["challenge_id"] == challenge_id:
74+
flag_id = flag["id"]
75+
r = s.delete(f"/api/v1/flags/{flag_id}", json=True)
76+
r.raise_for_status()
7877
for flag in challenge["flags"]:
7978
if type(flag) == str:
8079
data = {"content": flag, "type": "static", "challenge": challenge_id}
@@ -85,31 +84,31 @@ def sync_challenge(challenge):
8584
r = s.post(f"/api/v1/flags", json=flag)
8685
r.raise_for_status()
8786

88-
# Delete existing tags
89-
current_tags = s.get(f"/api/v1/tags", json=data).json()["data"]
90-
for tag in current_tags:
91-
if tag["challenge_id"] == challenge_id:
92-
tag_id = tag["id"]
93-
r = s.delete(f"/api/v1/tags/{tag_id}", json=True)
94-
r.raise_for_status()
95-
9687
# Update tags
97-
if challenge.get("tags"):
88+
if challenge.get("tags") and "tags" not in ignore:
89+
# Delete existing tags
90+
current_tags = s.get(f"/api/v1/tags", json=data).json()["data"]
91+
for tag in current_tags:
92+
if tag["challenge_id"] == challenge_id:
93+
tag_id = tag["id"]
94+
r = s.delete(f"/api/v1/tags/{tag_id}", json=True)
95+
r.raise_for_status()
9896
for tag in challenge["tags"]:
9997
r = s.post(f"/api/v1/tags", json={"challenge": challenge_id, "value": tag})
10098
r.raise_for_status()
10199

102-
# Delete existing files
103-
all_current_files = s.get(f"/api/v1/files?type=challenge", json=data).json()["data"]
104-
for f in all_current_files:
105-
for used_file in original_challenge["files"]:
106-
if f["location"] in used_file:
107-
file_id = f["id"]
108-
r = s.delete(f"/api/v1/files/{file_id}", json=True)
109-
r.raise_for_status()
110-
111100
# Upload files
112-
if challenge.get("files"):
101+
if challenge.get("files") and "files" not in ignore:
102+
# Delete existing files
103+
all_current_files = s.get(f"/api/v1/files?type=challenge", json=data).json()[
104+
"data"
105+
]
106+
for f in all_current_files:
107+
for used_file in original_challenge["files"]:
108+
if f["location"] in used_file:
109+
file_id = f["id"]
110+
r = s.delete(f"/api/v1/files/{file_id}", json=True)
111+
r.raise_for_status()
113112
files = []
114113
for f in challenge["files"]:
115114
file_path = Path(challenge.directory, f)
@@ -125,16 +124,16 @@ def sync_challenge(challenge):
125124
r = s.post(f"/api/v1/files", files=files, data=data)
126125
r.raise_for_status()
127126

128-
# Delete existing hints
129-
current_hints = s.get(f"/api/v1/hints", json=data).json()["data"]
130-
for hint in current_hints:
131-
if hint["challenge_id"] == challenge_id:
132-
hint_id = hint["id"]
133-
r = s.delete(f"/api/v1/hints/{hint_id}", json=True)
134-
r.raise_for_status()
135-
136127
# Create hints
137-
if challenge.get("hints"):
128+
if challenge.get("hints") and "hints" not in ignore:
129+
# Delete existing hints
130+
current_hints = s.get(f"/api/v1/hints", json=data).json()["data"]
131+
for hint in current_hints:
132+
if hint["challenge_id"] == challenge_id:
133+
hint_id = hint["id"]
134+
r = s.delete(f"/api/v1/hints/{hint_id}", json=True)
135+
r.raise_for_status()
136+
138137
for hint in challenge["hints"]:
139138
if type(hint) == str:
140139
data = {"content": hint, "cost": 0, "challenge": challenge_id}
@@ -149,7 +148,7 @@ def sync_challenge(challenge):
149148
r.raise_for_status()
150149

151150
# Update requirements
152-
if challenge.get("requirements"):
151+
if challenge.get("requirements") and "requirements" not in ignore:
153152
installed_challenges = load_installed_challenges()
154153
required_challenges = []
155154
for r in challenge["requirements"]:
@@ -166,16 +165,17 @@ def sync_challenge(challenge):
166165
r.raise_for_status()
167166

168167
# Unhide challenge depending upon the value of "state" in spec
169-
data = {"state": "visible"}
170-
if challenge.get("state"):
171-
if challenge["state"] in ["hidden", "visible"]:
172-
data["state"] = challenge["state"]
168+
if "state" not in ignore:
169+
data = {"state": "visible"}
170+
if challenge.get("state"):
171+
if challenge["state"] in ["hidden", "visible"]:
172+
data["state"] = challenge["state"]
173173

174-
r = s.patch(f"/api/v1/challenges/{challenge_id}", json=data)
175-
r.raise_for_status()
174+
r = s.patch(f"/api/v1/challenges/{challenge_id}", json=data)
175+
r.raise_for_status()
176176

177177

178-
def create_challenge(challenge):
178+
def create_challenge(challenge, ignore=[]):
179179
data = {
180180
"name": challenge["name"],
181181
"category": challenge["category"],
@@ -190,7 +190,7 @@ def create_challenge(challenge):
190190
if challenge["value"] is None:
191191
del challenge["value"]
192192

193-
if challenge.get("attempts"):
193+
if challenge.get("attempts") and "attempts" not in ignore:
194194
data["max_attempts"] = challenge.get("attempts")
195195

196196
s = generate_session()
@@ -202,7 +202,7 @@ def create_challenge(challenge):
202202
challenge_id = challenge_data["data"]["id"]
203203

204204
# Create flags
205-
if challenge.get("flags"):
205+
if challenge.get("flags") and "flags" not in ignore:
206206
for flag in challenge["flags"]:
207207
if type(flag) == str:
208208
data = {"content": flag, "type": "static", "challenge": challenge_id}
@@ -214,13 +214,13 @@ def create_challenge(challenge):
214214
r.raise_for_status()
215215

216216
# Create tags
217-
if challenge.get("tags"):
217+
if challenge.get("tags") and "tags" not in ignore:
218218
for tag in challenge["tags"]:
219219
r = s.post(f"/api/v1/tags", json={"challenge": challenge_id, "value": tag})
220220
r.raise_for_status()
221221

222222
# Upload files
223-
if challenge.get("files"):
223+
if challenge.get("files") and "files" not in ignore:
224224
files = []
225225
for f in challenge["files"]:
226226
file_path = Path(challenge.directory, f)
@@ -237,7 +237,7 @@ def create_challenge(challenge):
237237
r.raise_for_status()
238238

239239
# Add hints
240-
if challenge.get("hints"):
240+
if challenge.get("hints") and "hints" not in ignore:
241241
for hint in challenge["hints"]:
242242
if type(hint) == str:
243243
data = {"content": hint, "cost": 0, "challenge": challenge_id}
@@ -252,7 +252,7 @@ def create_challenge(challenge):
252252
r.raise_for_status()
253253

254254
# Add requirements
255-
if challenge.get("requirements"):
255+
if challenge.get("requirements") and "requirements" not in ignore:
256256
installed_challenges = load_installed_challenges()
257257
required_challenges = []
258258
for r in challenge["requirements"]:
@@ -269,7 +269,7 @@ def create_challenge(challenge):
269269
r.raise_for_status()
270270

271271
# Set challenge state
272-
if challenge.get("state"):
272+
if challenge.get("state") and "state" not in ignore:
273273
data = {"state": "hidden"}
274274
if challenge["state"] in ["hidden", "visible"]:
275275
data["state"] = challenge["state"]

0 commit comments

Comments
 (0)