增加学号属性
数据库配置
在 sqlite
数据库,也就是 ctf.db
的文件里,添加一个列名为 sid
的字段:
我是用图形管理工具添加的,命令的话参考:
1
| alter table users add column sid varchar(20) default 0;
|
- 字段需要设置默认值,不然 flask 会报错
- 字段位置不能在中间的某个位置,只能放置在最后面(默认是最后)
html 文件配置
在 /CTFd/CTFd/themes/core/templates/register.html
中添加 html 表单数据,这里主要是注意 name 的值,因为是 html 的 form 表单使用这个字段名来取值
auth.py 文件配置
在 /CTFd/CTFd/auth.py
中的 register 函数中添加
1
| sid = Users.query.add_columns('sid','id').filter_by(sid=request.form['sid']).first()
|
用 sid = request.form.get("sid", "").strip()
取学号,然后在 validators
里写一个验证学号格式的函数:
1 2 3 4 5 6 7
| def validate_sid(sid): if sid == "wctf2020": return True elif len(sid) == 12 and sid.isdigit() and sid.startswith("201"): return True else: return False
|
函数位置:/CTFd/CTFd/utils/validators/__init__.py
接着还是在 auth.py
,创建用户的时候写上 sid
models 类中的配置
在 /CTFd/CTFd/models/__init__.py
中的 Users 类中添加一个表单名:
1
| sid = db.Column(db.String(20))
|
admin面板中users的学号显示
文件地址 /CTFd/CTFd/themes/admin/templates/users/users.html
这里把国家的一列用来显示学号
在过滤的下拉框增加学号的搜索选项:
然后在表中输出学号:
效果
Scoreboard
校内外分类
基于学号来进行分类,首先在 /CTFd/CTFd/themes/core/templates/scoreboard.html
增加下拉框:
1 2 3 4 5 6
| <select class="form-control custom-select w-10" onchange="top.location.href=this.value"> <option value="/">排名方式</option> <option value="/scoreboard">总排名</option> <option value="/scoreboard/1">校内排名</option> <option value="/scoreboard/2">校外排名</option> </select>
|
更改 /CTFd/utils/scores/__init__.py
里的 get_standings
查询方式:
增加参数
分情况查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| else: if request == "total": standings_query = ( db.session.query( Model.id.label("account_id"), Model.oauth_id.label("oauth_id"), Model.name.label("name"), sumscores.columns.score, ) .join(sumscores, Model.id == sumscores.columns.account_id) .filter(Model.banned == False, Model.hidden == False) .order_by(sumscores.columns.score.desc(), sumscores.columns.id) ) elif request == "wust": standings_query = ( db.session.query( Model.id.label("account_id"), Model.oauth_id.label("oauth_id"), Model.name.label("name"), sumscores.columns.score, ) .join(sumscores, Model.id == sumscores.columns.account_id) .filter(Model.banned == False, Model.hidden == False, Model.sid != "wctf2020") .order_by(sumscores.columns.score.desc(), sumscores.columns.id) ) elif request == "others": standings_query = ( db.session.query( Model.id.label("account_id"), Model.oauth_id.label("oauth_id"), Model.name.label("name"), sumscores.columns.score, ) .join(sumscores, Model.id == sumscores.columns.account_id) .filter(Model.banned == False, Model.hidden == False, Model.sid == "wctf2020") .order_by(sumscores.columns.score.desc(), sumscores.columns.id) )
|
默认是总榜(0),1为校内,2为校外。
然后在 /CTFd/scoreboard.py
添加路由:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| @scoreboard.route("/scoreboard") @check_score_visibility @cache.cached(timeout=60, key_prefix=make_cache_key) def listing(): standings = get_standings(None, False, request=0) return render_template( "scoreboard.html", standings=standings, score_frozen=config.is_scoreboard_frozen(), )
@scoreboard.route("/scoreboard/1") @check_score_visibility @cache.cached(timeout=60, key_prefix=make_cache_key) def listing1(): standings = get_standings(None, False, request=1) return render_template( "scoreboard.html", standings=standings, score_frozen=config.is_scoreboard_frozen(), )
@scoreboard.route("/scoreboard/2") @check_score_visibility @cache.cached(timeout=60, key_prefix=make_cache_key) def listing2(): standings = get_standings(None, False, request=2) return render_template( "scoreboard.html", standings=standings, score_frozen=config.is_scoreboard_frozen(), )
|
计分板图表
/CTFd/CTFd/api/v1/scoreboard.py
,对接口请求时的 url 进行分类,先添加 request
1
| from flask import request
|
然后对接口 @scoreboard_namespace.route("/top/<count>")
里进行修改,添加
1 2 3 4 5 6
| if "/scoreboard/1" in request.headers['Referer']: board_type = 1 elif "/scoreboard/2" in request.headers['Referer']: board_type = 2 else: board_type = 0
|
然后将 get_standings
的参数改成 standings = get_standings(count=count, request=board_type)
前三血自动播报
/CTFd/CTFd/api/v1/challenges.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| if app.config['AUTO_BROADCAST']: solve_count = Solves.query.filter_by(challenge_id=challenge_id).count() blood_number = "" if solve_count == 1: blood_number = "first" elif solve_count == 2: blood_number = "second" elif solve_count == 3: blood_number = "third" else: pass if blood_number: broad = { 'title':"Congratulations!", 'content':"User [{0}] got the {1} blood of [{2}]".format(user_name, blood_number, challenge_name) } schema = NotificationSchema() broad_result = schema.load(broad)
db.session.add(broad_result.data) db.session.commit()
broad["type"] = "toast" broad["sound"] = False broad["blood"] = blood_number
app.events_manager.publish(data=broad, type="notification") return { "success": True, "data": {"status": "correct", "message": message}, }
|
然后在 /CTFd/config.py
里增加 AUTO_BROADCAST = True
提示音修改
将准备的三杀的音效放进 /CTFd/CTFd/themes/core/static/sounds
,然后在 /CTFd/CTFd/themes/core/static/js/events.js
修改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| const howl = new Howl({ src: [ root + "/themes/core/static/sounds/notification.webm", root + "/themes/core/static/sounds/notification.mp3" ] }); const howl_f = new Howl({ src: [ root + "/themes/core/static/sounds/first.webm", root + "/themes/core/static/sounds/first.mp3" ] }); const howl_s = new Howl({ src: [ root + "/themes/core/static/sounds/second.webm", root + "/themes/core/static/sounds/second.mp3" ] }); const howl_t = new Howl({ src: [ root + "/themes/core/static/sounds/third.webm", root + "/themes/core/static/sounds/third.mp3" ] });
|
然后添加:
1 2 3 4 5 6 7 8 9
| switch (data.blood) { case "first": howl_f.play(); break; case "second": howl_s.play(); break; case "third": howl_t.play(); break; default: break; }
|
然后全局搜索,将带有 notification.webm
的所有 min.js
全部按照这个格式修改(大概20+个文件),还要注意混淆:root -> e
,data.blood -> e.blood
。
题目solves显示
将solves的用户筛选只显示前三,并且增加小图标:
增加一个列,在 /themes/core/static/js/pages/challenges.min.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| for (var n = 0; n < 3; n++) { var s = t[n].account_id, a = t[n].name, i = (0, d.default)(t[n].date).local().fromNow(), l = t[n].account_url; if(n == 0){ rk = '<img src="themes/core/static/img/1.png" width="33" height="33">'; }else if(n == 1){ rk = '<img src="themes/core/static/img/2.png" width="27" height="27">'; }else{ rk = '<img src="themes/core/static/img/3.png" width="15" height="15">'; } o.append('<tr><td>{4}</td><td><a href="{0}">{2}</td><td>{3}</td></tr>'.format(l, s, (0, r.htmlEntities)(a), i, rk)) }
|