|
from flask import Flask, request, jsonify, make_response, render_template_string, send_from_directory |
|
import random |
|
import string |
|
import json |
|
|
|
app = Flask(__name__, static_folder='dist') |
|
|
|
def generate_random_id(): |
|
chars = string.ascii_lowercase + string.digits |
|
return ''.join(random.choices(chars, k=5)) |
|
|
|
|
|
@app.after_request |
|
def add_cors_headers(response): |
|
origin = request.headers.get('Origin') |
|
if origin: |
|
response.headers['Access-Control-Allow-Origin'] = origin |
|
response.headers['Access-Control-Allow-Credentials'] = 'true' |
|
response.headers['Access-Control-Allow-Headers'] = 'Content-Type' |
|
return response |
|
|
|
|
|
@app.route('/') |
|
def index(): |
|
id_list = request.cookies.get('ids') |
|
ids = json.loads(id_list) if id_list else [] |
|
|
|
html = ''' |
|
<!DOCTYPE html> |
|
<html lang="ja"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<title>IDリスト</title> |
|
</head> |
|
<body> |
|
<h1>IDリスト</h1> |
|
<ul> |
|
{% for id in ids %} |
|
<li> |
|
{{ id }} |
|
<button onclick="copyToClipboard('{{ id }}')">コピー</button> |
|
<form method="post" action="/delete" style="display:inline;"> |
|
<input type="hidden" name="id" value="{{ id }}"> |
|
<button type="submit">削除</button> |
|
</form> |
|
</li> |
|
{% endfor %} |
|
</ul> |
|
|
|
<form method="post" action="/add"> |
|
<button type="submit">IDを追加</button> |
|
</form> |
|
|
|
<a href="/eruda.js">/eruda.js</a> |
|
<script src="/eruda.js"></script> |
|
<script>eruda.init();</script> |
|
|
|
<hr> |
|
<h2>getid のデータ</h2> |
|
<pre id="id-data">ここにデータが表示されます</pre> |
|
|
|
<button onclick="updateServiceWorker()">getid のサービスワーカーを設定・更新</button> |
|
<button onclick="loadGetID()">getid を取得</button> |
|
|
|
<script> |
|
function copyToClipboard(text) { |
|
navigator.clipboard.writeText(text).then(() => { |
|
alert('コピーしました: ' + text); |
|
}).catch(() => { |
|
alert('コピーに失敗しました'); |
|
}); |
|
} |
|
|
|
async function updateServiceWorker() { |
|
if ('serviceWorker' in navigator) { |
|
try { |
|
await navigator.serviceWorker.register('/service-worker.js'); |
|
alert("サービスワーカーを登録しました。"); |
|
} catch (e) { |
|
console.error("サービスワーカーの登録に失敗しました:", e); |
|
} |
|
} else { |
|
alert("このブラウザはサービスワーカーに対応していません。"); |
|
} |
|
} |
|
|
|
async function loadGetID() { |
|
try { |
|
const res = await fetch('/getid'); |
|
const data = await res.json(); |
|
document.getElementById('id-data').textContent = JSON.stringify(data, null, 2); |
|
} catch (e) { |
|
console.error("データの取得に失敗しました:", e); |
|
document.getElementById('id-data').textContent = "取得に失敗しました"; |
|
} |
|
} |
|
</script> |
|
</body> |
|
</html> |
|
''' |
|
return render_template_string(html, ids=ids) |
|
|
|
@app.route("/load.js") |
|
def load_js(): |
|
js_code = """ |
|
(async () => { |
|
const script = document.currentScript; |
|
if (!script) { |
|
console.error('currentScriptが取得できませんでした。'); |
|
return; |
|
} |
|
|
|
const debugMode = script.getAttribute('debug') === 'alert'; |
|
const activeValue = script.getAttribute('active'); |
|
if (!activeValue) { |
|
console.log('active属性が見つかりません。処理を終了します。'); |
|
return; |
|
} |
|
|
|
const ids = activeValue.trim().split(/\\s+/).filter(id => /^[a-zA-Z0-9]{5}$/.test(id)); |
|
if (ids.length === 0) { |
|
console.warn('active属性に5桁の番号または文字列が見つかりません。処理を終了します。'); |
|
return; |
|
} |
|
|
|
try { |
|
const url = 'https://soiz1-eruda3.hf.space/getid'; |
|
const res = await fetch(url, { method: 'GET', credentials: 'include' }); |
|
|
|
if (!res.ok) { |
|
const msg = `Fetchエラー: ステータス ${res.status} ${res.statusText}`; |
|
console.error(msg); |
|
if (debugMode) alert(msg); |
|
return; |
|
} |
|
|
|
const data = await res.json(); |
|
|
|
console.log('fetchレスポンス:', data); |
|
if (debugMode) alert(`fetchレスポンス:\\n${JSON.stringify(data)}`); |
|
|
|
if (!Array.isArray(data)) { |
|
const msg = 'fetchレスポンスが配列ではありません。認証失敗とみなします。'; |
|
console.error(msg); |
|
if (debugMode) alert(msg); |
|
return; |
|
} |
|
|
|
const hasAuthorized = ids.some(id => data.includes(id)); |
|
|
|
if (hasAuthorized) { |
|
const msg = '認証成功: 対象IDがfetchレスポンスに含まれています。runeruda()を実行します。'; |
|
console.log(msg); |
|
if (debugMode) alert(msg); |
|
runeruda(); |
|
} else { |
|
const msg = '認証失敗: 対象IDがfetchレスポンスに含まれていません。'; |
|
console.warn(msg); |
|
if (debugMode) alert(msg); |
|
} |
|
|
|
} catch (err) { |
|
const msg = `例外発生: ${err.message}`; |
|
console.error(msg, err); |
|
if (debugMode) alert(msg); |
|
} |
|
})(); |
|
""" |
|
return Response(js_code, mimetype='application/javascript') |
|
|
|
@app.route('/add', methods=['POST']) |
|
def add_id(): |
|
id_list = request.cookies.get('ids') |
|
ids = json.loads(id_list) if id_list else [] |
|
new_id = generate_random_id() |
|
ids.append(new_id) |
|
resp = make_response('', 303) |
|
resp.headers['Location'] = '/' |
|
resp.set_cookie( |
|
'ids', |
|
json.dumps(ids), |
|
samesite='None', |
|
secure=True |
|
) |
|
return resp |
|
|
|
@app.route('/delete', methods=['POST']) |
|
def delete_id(): |
|
id_to_delete = request.form.get('id') |
|
id_list = request.cookies.get('ids') |
|
ids = json.loads(id_list) if id_list else [] |
|
if id_to_delete in ids: |
|
ids.remove(id_to_delete) |
|
resp = make_response('', 303) |
|
resp.headers['Location'] = '/' |
|
resp.set_cookie( |
|
'ids', |
|
json.dumps(ids), |
|
samesite='None', |
|
secure=True |
|
) |
|
return resp |
|
|
|
@app.route('/getid') |
|
def get_ids(): |
|
id_list = request.cookies.get('ids') |
|
ids = json.loads(id_list) if id_list else [] |
|
return jsonify(ids) |
|
|
|
@app.route('/service-worker.js') |
|
def service_worker(): |
|
response = make_response(send_from_directory('.', 'service-worker.js')) |
|
response.headers['Content-Type'] = 'application/javascript' |
|
return response |
|
|
|
@app.route('/<path:filename>') |
|
def serve_static(filename): |
|
return send_from_directory(app.static_folder, filename) |
|
|
|
if __name__ == '__main__': |
|
app.run(host='0.0.0.0', port=7860, debug=True) |
|
|