Skip to content

Commit b1dea76

Browse files
xusheng6claude
andauthored
Fix search multi-select and x86/x86-64 matching issues (#144)
Problems: 1. Multiple selection in search (lang, arch, platform) never worked because the controller used form.get() instead of form.getlist() 2. Searching for "x86" also matched "x86-64" due to regex matching Fixes: - Controller: Use request.form.getlist() for multi-select fields - Model: Use exact matching with $in operator instead of regex for lang, arch, and platform fields - Template: Update selected state checks to work with lists, and generate multiple hidden inputs for pagination forms Closes #138, closes #141 Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent cf937de commit b1dea76

3 files changed

Lines changed: 62 additions & 50 deletions

File tree

app/controllers/search.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@ def search_post():
2020
"""Handle search form submission."""
2121
name = request.form.get('name', '')
2222
author = request.form.get('author', '')
23-
lang = request.form.get('lang', '')
24-
arch = request.form.get('arch', '')
25-
platform = request.form.get('platform', '')
23+
# Use getlist() for multi-select fields
24+
lang = request.form.getlist('lang')
25+
arch = request.form.getlist('arch')
26+
platform = request.form.getlist('platform')
2627

2728
# Get difficulty range
2829
try:
@@ -153,12 +154,13 @@ def parse_size_with_unit(value_str, unit_str):
153154
sort_order = 'desc'
154155

155156
# Store search params for pagination
157+
# lang, arch, platform are lists for multi-select support
156158
search_params = {
157159
'name': name,
158160
'author': author,
159-
'lang': lang,
160-
'arch': arch,
161-
'platform': platform,
161+
'lang': lang, # list
162+
'arch': arch, # list
163+
'platform': platform, # list
162164
'difficulty-min': difficulty_min,
163165
'difficulty-max': difficulty_max,
164166
'quality-min': quality_min,

app/models/crackme.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,22 @@ def search_crackme(name='', author='', lang='', arch='', platform='',
174174
query['name'] = {'$regex': name, '$options': 'i'}
175175
if author:
176176
query['author'] = {'$regex': author, '$options': 'i'}
177+
# lang, arch, platform support multiple values (lists) with exact matching
177178
if lang:
178-
query['lang'] = {'$regex': lang, '$options': 'i'}
179+
if isinstance(lang, list):
180+
query['lang'] = {'$in': lang}
181+
else:
182+
query['lang'] = lang
179183
if arch:
180-
query['arch'] = {'$regex': arch, '$options': 'i'}
184+
if isinstance(arch, list):
185+
query['arch'] = {'$in': arch}
186+
else:
187+
query['arch'] = arch
181188
if platform:
182-
query['platform'] = {'$regex': platform, '$options': 'i'}
189+
if isinstance(platform, list):
190+
query['platform'] = {'$in': platform}
191+
else:
192+
query['platform'] = platform
183193

184194
skip = (page - 1) * per_page
185195
# Determine sort field and direction

templates/search/search.html

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -116,17 +116,17 @@ <h2>Crackme search</h2>
116116
</div>
117117
<div class="col-9 col-sm-12">
118118
<select class="form-select" id="lang" name="lang" multiple="">
119-
<option value="C/C++" {{ 'selected' if search_params.lang == 'C/C++' else '' }}>C/C++</option>
120-
<option value="Assembler" {{ 'selected' if search_params.lang == 'Assembler' else '' }}>Assembler</option>
121-
<option value="Java" {{ 'selected' if search_params.lang == 'Java' else '' }}>Java</option>
122-
<option value="Go" {{ 'selected' if search_params.lang == 'Go' else '' }}>Go</option>
123-
<option value="Rust" {{ 'selected' if search_params.lang == 'Rust' else '' }}>Rust</option>
124-
<option value="WebAssembly" {{ 'selected' if search_params.lang == 'WebAssembly' else '' }}>WebAssembly</option>
125-
<option value="(Visual) Basic" {{ 'selected' if search_params.lang == '(Visual) Basic' else '' }}>(Visual) Basic</option>
126-
<option value="Borland Delphi" {{ 'selected' if search_params.lang == 'Borland Delphi' else '' }}>Borland Delphi</option>
127-
<option value="Turbo Pascal" {{ 'selected' if search_params.lang == 'Turbo Pascal' else '' }}>Turbo Pascal</option>
128-
<option value=".NET" {{ 'selected' if search_params.lang == '.NET' else '' }}>.NET</option>
129-
<option value="Unspecified/other" {{ 'selected' if search_params.lang == 'Unspecified/other' else '' }}>Unspecified/other</option>
119+
<option value="C/C++" {{ 'selected' if 'C/C++' in search_params.get('lang', []) else '' }}>C/C++</option>
120+
<option value="Assembler" {{ 'selected' if 'Assembler' in search_params.get('lang', []) else '' }}>Assembler</option>
121+
<option value="Java" {{ 'selected' if 'Java' in search_params.get('lang', []) else '' }}>Java</option>
122+
<option value="Go" {{ 'selected' if 'Go' in search_params.get('lang', []) else '' }}>Go</option>
123+
<option value="Rust" {{ 'selected' if 'Rust' in search_params.get('lang', []) else '' }}>Rust</option>
124+
<option value="WebAssembly" {{ 'selected' if 'WebAssembly' in search_params.get('lang', []) else '' }}>WebAssembly</option>
125+
<option value="(Visual) Basic" {{ 'selected' if '(Visual) Basic' in search_params.get('lang', []) else '' }}>(Visual) Basic</option>
126+
<option value="Borland Delphi" {{ 'selected' if 'Borland Delphi' in search_params.get('lang', []) else '' }}>Borland Delphi</option>
127+
<option value="Turbo Pascal" {{ 'selected' if 'Turbo Pascal' in search_params.get('lang', []) else '' }}>Turbo Pascal</option>
128+
<option value=".NET" {{ 'selected' if '.NET' in search_params.get('lang', []) else '' }}>.NET</option>
129+
<option value="Unspecified/other" {{ 'selected' if 'Unspecified/other' in search_params.get('lang', []) else '' }}>Unspecified/other</option>
130130
</select>
131131
</div>
132132
</div>
@@ -136,13 +136,13 @@ <h2>Crackme search</h2>
136136
</div>
137137
<div class="col-9 col-sm-12">
138138
<select class="form-select" id="arch" name="arch" multiple="">
139-
<option value="x86" {{ 'selected' if search_params.arch == 'x86' else '' }}>x86</option>
140-
<option value="x86-64" {{ 'selected' if search_params.arch == 'x86-64' else '' }}>x86-64</option>
141-
<option value="java" {{ 'selected' if search_params.arch == 'java' else '' }}>java</option>
142-
<option value="ARM" {{ 'selected' if search_params.arch == 'ARM' else '' }}>ARM</option>
143-
<option value="MIPS" {{ 'selected' if search_params.arch == 'MIPS' else '' }}>MIPS</option>
144-
<option value="RISC-V" {{ 'selected' if search_params.arch == 'RISC-V' else '' }}>RISC-V</option>
145-
<option value="other" {{ 'selected' if search_params.arch == 'other' else '' }}>other</option>
139+
<option value="x86" {{ 'selected' if 'x86' in search_params.get('arch', []) else '' }}>x86</option>
140+
<option value="x86-64" {{ 'selected' if 'x86-64' in search_params.get('arch', []) else '' }}>x86-64</option>
141+
<option value="java" {{ 'selected' if 'java' in search_params.get('arch', []) else '' }}>java</option>
142+
<option value="ARM" {{ 'selected' if 'ARM' in search_params.get('arch', []) else '' }}>ARM</option>
143+
<option value="MIPS" {{ 'selected' if 'MIPS' in search_params.get('arch', []) else '' }}>MIPS</option>
144+
<option value="RISC-V" {{ 'selected' if 'RISC-V' in search_params.get('arch', []) else '' }}>RISC-V</option>
145+
<option value="other" {{ 'selected' if 'other' in search_params.get('arch', []) else '' }}>other</option>
146146
</select>
147147
</div>
148148
</div>
@@ -152,17 +152,17 @@ <h2>Crackme search</h2>
152152
</div>
153153
<div class="col-9 col-sm-12">
154154
<select class="form-select" id="platform" name="platform" multiple="">
155-
<option value="DOS" {{ 'selected' if search_params.platform == 'DOS' else '' }}>DOS</option>
156-
<option value="Mac OS X" {{ 'selected' if search_params.platform == 'Mac OS X' else '' }}>Mac OS X</option>
157-
<option value="Multiplatform" {{ 'selected' if search_params.platform == 'Multiplatform' else '' }}>Multiplatform</option>
158-
<option value="Unix/linux etc." {{ 'selected' if search_params.platform == 'Unix/linux etc.' else '' }}>Unix/linux etc.</option>
159-
<option value="Windows" {{ 'selected' if search_params.platform == 'Windows' else '' }}>Windows</option>
160-
<option value="Windows 2000/XP only" {{ 'selected' if search_params.platform == 'Windows 2000/XP only' else '' }}>Windows 2000/XP only</option>
161-
<option value="Windows 7 Only" {{ 'selected' if search_params.platform == 'Windows 7 Only' else '' }}>Windows 7 Only</option>
162-
<option value="Windows Vista Only" {{ 'selected' if search_params.platform == 'Windows Vista Only' else '' }}>Windows Vista Only</option>
163-
<option value="Android" {{ 'selected' if search_params.platform == 'Android' else '' }}>Android</option>
164-
<option value="iOS" {{ 'selected' if search_params.platform == 'iOS' else '' }}>iOS</option>
165-
<option value="Unspecified/other" {{ 'selected' if search_params.platform == 'Unspecified/other' else '' }}>Unspecified/other</option>
155+
<option value="DOS" {{ 'selected' if 'DOS' in search_params.get('platform', []) else '' }}>DOS</option>
156+
<option value="Mac OS X" {{ 'selected' if 'Mac OS X' in search_params.get('platform', []) else '' }}>Mac OS X</option>
157+
<option value="Multiplatform" {{ 'selected' if 'Multiplatform' in search_params.get('platform', []) else '' }}>Multiplatform</option>
158+
<option value="Unix/linux etc." {{ 'selected' if 'Unix/linux etc.' in search_params.get('platform', []) else '' }}>Unix/linux etc.</option>
159+
<option value="Windows" {{ 'selected' if 'Windows' in search_params.get('platform', []) else '' }}>Windows</option>
160+
<option value="Windows 2000/XP only" {{ 'selected' if 'Windows 2000/XP only' in search_params.get('platform', []) else '' }}>Windows 2000/XP only</option>
161+
<option value="Windows 7 Only" {{ 'selected' if 'Windows 7 Only' in search_params.get('platform', []) else '' }}>Windows 7 Only</option>
162+
<option value="Windows Vista Only" {{ 'selected' if 'Windows Vista Only' in search_params.get('platform', []) else '' }}>Windows Vista Only</option>
163+
<option value="Android" {{ 'selected' if 'Android' in search_params.get('platform', []) else '' }}>Android</option>
164+
<option value="iOS" {{ 'selected' if 'iOS' in search_params.get('platform', []) else '' }}>iOS</option>
165+
<option value="Unspecified/other" {{ 'selected' if 'Unspecified/other' in search_params.get('platform', []) else '' }}>Unspecified/other</option>
166166
</select>
167167
</div>
168168
</div>
@@ -236,9 +236,9 @@ <h2>Crackme search</h2>
236236
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
237237
<input type="hidden" name="name" value="{{ search_params.name }}">
238238
<input type="hidden" name="author" value="{{ search_params.author }}">
239-
<input type="hidden" name="lang" value="{{ search_params.lang }}">
240-
<input type="hidden" name="arch" value="{{ search_params.arch }}">
241-
<input type="hidden" name="platform" value="{{ search_params.platform }}">
239+
{% for v in search_params.get('lang', []) %}<input type="hidden" name="lang" value="{{ v }}">{% endfor %}
240+
{% for v in search_params.get('arch', []) %}<input type="hidden" name="arch" value="{{ v }}">{% endfor %}
241+
{% for v in search_params.get('platform', []) %}<input type="hidden" name="platform" value="{{ v }}">{% endfor %}
242242
<input type="hidden" name="difficulty-min" value="{{ search_params['difficulty-min'] }}">
243243
<input type="hidden" name="difficulty-max" value="{{ search_params['difficulty-max'] }}">
244244
<input type="hidden" name="quality-min" value="{{ search_params['quality-min'] }}">
@@ -266,9 +266,9 @@ <h2>Crackme search</h2>
266266
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
267267
<input type="hidden" name="name" value="{{ search_params.name }}">
268268
<input type="hidden" name="author" value="{{ search_params.author }}">
269-
<input type="hidden" name="lang" value="{{ search_params.lang }}">
270-
<input type="hidden" name="arch" value="{{ search_params.arch }}">
271-
<input type="hidden" name="platform" value="{{ search_params.platform }}">
269+
{% for v in search_params.get('lang', []) %}<input type="hidden" name="lang" value="{{ v }}">{% endfor %}
270+
{% for v in search_params.get('arch', []) %}<input type="hidden" name="arch" value="{{ v }}">{% endfor %}
271+
{% for v in search_params.get('platform', []) %}<input type="hidden" name="platform" value="{{ v }}">{% endfor %}
272272
<input type="hidden" name="difficulty-min" value="{{ search_params['difficulty-min'] }}">
273273
<input type="hidden" name="difficulty-max" value="{{ search_params['difficulty-max'] }}">
274274
<input type="hidden" name="quality-min" value="{{ search_params['quality-min'] }}">
@@ -293,9 +293,9 @@ <h2>Crackme search</h2>
293293
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
294294
<input type="hidden" name="name" value="{{ search_params.name }}">
295295
<input type="hidden" name="author" value="{{ search_params.author }}">
296-
<input type="hidden" name="lang" value="{{ search_params.lang }}">
297-
<input type="hidden" name="arch" value="{{ search_params.arch }}">
298-
<input type="hidden" name="platform" value="{{ search_params.platform }}">
296+
{% for v in search_params.get('lang', []) %}<input type="hidden" name="lang" value="{{ v }}">{% endfor %}
297+
{% for v in search_params.get('arch', []) %}<input type="hidden" name="arch" value="{{ v }}">{% endfor %}
298+
{% for v in search_params.get('platform', []) %}<input type="hidden" name="platform" value="{{ v }}">{% endfor %}
299299
<input type="hidden" name="difficulty-min" value="{{ search_params['difficulty-min'] }}">
300300
<input type="hidden" name="difficulty-max" value="{{ search_params['difficulty-max'] }}">
301301
<input type="hidden" name="quality-min" value="{{ search_params['quality-min'] }}">
@@ -324,9 +324,9 @@ <h2>Crackme search</h2>
324324
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
325325
<input type="hidden" name="name" value="{{ search_params.name }}">
326326
<input type="hidden" name="author" value="{{ search_params.author }}">
327-
<input type="hidden" name="lang" value="{{ search_params.lang }}">
328-
<input type="hidden" name="arch" value="{{ search_params.arch }}">
329-
<input type="hidden" name="platform" value="{{ search_params.platform }}">
327+
{% for v in search_params.get('lang', []) %}<input type="hidden" name="lang" value="{{ v }}">{% endfor %}
328+
{% for v in search_params.get('arch', []) %}<input type="hidden" name="arch" value="{{ v }}">{% endfor %}
329+
{% for v in search_params.get('platform', []) %}<input type="hidden" name="platform" value="{{ v }}">{% endfor %}
330330
<input type="hidden" name="difficulty-min" value="{{ search_params['difficulty-min'] }}">
331331
<input type="hidden" name="difficulty-max" value="{{ search_params['difficulty-max'] }}">
332332
<input type="hidden" name="quality-min" value="{{ search_params['quality-min'] }}">

0 commit comments

Comments
 (0)