|
36 | 36 | # How long an OAuth "state" nonce (see /login and /callback) stays valid. |
37 | 37 | OAUTH_STATE_MAX_AGE_SECONDS = 300 |
38 | 38 |
|
| 39 | +# Upper bound for a single /api/send gift, mirroring the Discord slash-command |
| 40 | +# gift path (cog/admin_gift.py) rejecting non-positive counts. |
| 41 | +GIFT_AMOUNT_MAX = 100000 |
| 42 | + |
39 | 43 | discord_client_id = os.getenv("DISCORD_CLIENT_ID") |
40 | 44 | discord_client_secret = os.getenv("DISCORD_CLIENT_SECRET") |
41 | 45 | discord_redirect_uri = os.getenv("DISCORD_REDIRECT_URI") |
@@ -151,8 +155,11 @@ def listt(): |
151 | 155 | return response.json() |
152 | 156 |
|
153 | 157 |
|
154 | | -@app.route("/api/send/<int:target_user_id>") |
155 | | -# api/send/{recipient}?gift_type={電電點|抽獎券}count={count} |
| 158 | +@app.route("/api/send/<int:target_user_id>", methods=["POST"]) |
| 159 | +# POST api/send/{recipient}?gift_type={電電點|抽獎券}count={count} |
| 160 | +# POST-only so a cross-site top-level navigation (link/img/redirect) can't |
| 161 | +# trigger this as a simple GET request; SameSite=Lax still blocks the cookie |
| 162 | +# on cross-site POSTs. |
156 | 163 | def send(target_user_id): |
157 | 164 | if not flask.session: |
158 | 165 | return flask.jsonify({"result": "you must login", "status": 403}) |
@@ -187,6 +194,14 @@ def send(target_user_id): |
187 | 194 | gift_amount = int(gift_amount) # 確保 count 是整數 |
188 | 195 | except ValueError: |
189 | 196 | return flask.jsonify({"result": "Invalid count value", "status": 400}) |
| 197 | + # 不能發送 0 以下或超過上限的數量,跟 Discord 斜線指令的驗證保持一致 |
| 198 | + if not 0 < gift_amount <= GIFT_AMOUNT_MAX: |
| 199 | + return flask.jsonify( |
| 200 | + { |
| 201 | + "result": f"count must be between 1 and {GIFT_AMOUNT_MAX}", |
| 202 | + "status": 400, |
| 203 | + } |
| 204 | + ) |
190 | 205 | # 確保目標用戶存在 |
191 | 206 | user_data = discord_api.get_user(target_user_id) |
192 | 207 | if "error" in user_data: |
|
0 commit comments