Skip to content

Commit b71aa55

Browse files
authored
Merge pull request #13 from ut-code/lv2make
Lv2完成
2 parents 3e1ebc1 + 4a34946 commit b71aa55

File tree

9 files changed

+128
-52
lines changed

9 files changed

+128
-52
lines changed

src/content.ts

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
1+
// content.tsx
12
export {}
23

4+
// 複数の問題の「現在の値」をまとめて取得する
5+
function getCurrentValues() {
6+
// 問題1: テキストのチェック
7+
const el1 = document.querySelector<HTMLElement>('[data-check]')
8+
const val1 = el1 ? (el1.textContent ?? '').trim() : ''
39

4-
// -> 要素の「現在の値」を取得するだけの関数に変更
5-
function getActualValue(): string {
6-
const el = document.querySelector<HTMLElement>('[data-check]')
7-
if (!el) return '' // 見つからなければ空文字を返す
8-
return (el.textContent ?? '').trim()
10+
// 問題2: 画像のsrcチェック
11+
// data-check2属性を持つ画像のsrcを取得する
12+
const el2 = document.querySelector('[data-check2]') as HTMLImageElement
13+
// src属性そのもの(例: "img/star5.png")を取得。絶対パス化されるのを防ぐため getAttribute を推奨
14+
const val2 = el2 ? (el2.getAttribute('src') ?? '') : ''
15+
16+
return {
17+
p1: val1,
18+
p2: val2,
19+
}
920
}
1021

1122
// デバウンス
@@ -23,24 +34,22 @@ const ports = new Set<chrome.runtime.Port>()
2334
chrome.runtime.onConnect.addListener((port) => {
2435
if (port.name !== 'sidepanel') return
2536
ports.add(port)
26-
27-
// 接続直後に「現在の値」を送る (判定結果ではない)
28-
port.postMessage({ type: 'DOM_VALUE_UPDATE', actual: getActualValue() })
29-
37+
38+
// 接続直後に現在の状態を送る
39+
port.postMessage({ type: 'DOM_VALUE_UPDATE', values: getCurrentValues() })
40+
3041
port.onDisconnect.addListener(() => ports.delete(port))
3142
})
3243

33-
// DevTools等でのDOM変更を監視し、「現在の値」をサイドパネルへ通知
44+
// DOM変更を監視し、まとめて通知
3445
const notify = debounce(() => {
35-
// 判定(checkAnswer)はしない
36-
const actual = getActualValue()
46+
const values = getCurrentValues()
3747
for (const p of ports) {
38-
try {
39-
// 判定結果ではなく、「現在の値」をそのまま送る
40-
p.postMessage({ type: 'DOM_VALUE_UPDATE', actual })
48+
try {
49+
p.postMessage({ type: 'DOM_VALUE_UPDATE', values })
4150
} catch {}
4251
}
43-
}, 200) // 200ms ディレイ
52+
}, 200)
4453

4554
const mo = new MutationObserver(() => notify())
4655
mo.observe(document.documentElement, {

src/sidepanel/App.tsx

Lines changed: 96 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,34 @@
1+
// App.tsx
12
import { useEffect, useRef, useState } from 'react'
23
import './App.css'
34

45
type CheckResult = { ok: boolean; details: string }
56

6-
const CORRECT_ANSWER = "すばらしい。"
7-
8-
function checkAnswer(actual: string): CheckResult {
9-
if (actual === CORRECT_ANSWER) {
10-
return { ok: true, details: `一致: "${actual}"` }
11-
} else {
12-
return { ok: false, details: `不一致: あなたの入力="${actual}"` }
13-
}
7+
// 答えの定義
8+
const ANSWERS = {
9+
p1: "すばらしい。",
10+
p2: "./images/star5.png"
1411
}
1512

1613
function App() {
14+
// 現在の問題番号
15+
const [step, setStep] = useState(1)
16+
// 判定結果
1717
const [result, setResult] = useState<CheckResult | null>(null)
1818
const [error, setError] = useState<string | null>(null)
19-
const baselineRef = useRef<string | null>(null)
19+
20+
// イベントリスナー内で最新の step を参照するための Ref
21+
const stepRef = useRef(step)
22+
// 各ステップの初期値を保持するベースライン
23+
const baselineRef = useRef<{ p1: string | null; p2: string | null }>({
24+
p1: null,
25+
p2: null,
26+
})
27+
28+
// state が変わったら ref も更新しておく
29+
useEffect(() => {
30+
stepRef.current = step
31+
}, [step])
2032

2133
useEffect(() => {
2234
let port: chrome.runtime.Port | null = null
@@ -30,27 +42,61 @@ function App() {
3042

3143
port.onMessage.addListener((msg) => {
3244
if (msg?.type === 'DOM_VALUE_UPDATE') {
33-
const actual = String(msg.actual ?? '')
45+
const { p1, p2 } = msg.values
46+
const currentStep = stepRef.current
3447

35-
// 初回はベースラインの設定のみ行う
36-
if (baselineRef.current === null) {
37-
baselineRef.current = actual
38-
setResult(null) // 待機画面を維持
39-
return
48+
49+
if (currentStep === 1) {
50+
// 初回ロード時の値をベースラインとして記憶
51+
if (baselineRef.current.p1 === null) {
52+
baselineRef.current.p1 = p1
53+
return
54+
}
55+
56+
// ベースラインから変化があった場合のみ判定
57+
if (p1 !== baselineRef.current.p1) {
58+
const isCorrect = p1 === ANSWERS.p1
59+
setResult({
60+
ok: isCorrect,
61+
details: isCorrect ? `一致: "${p1}"` : `不一致: "${p1}"`
62+
})
63+
64+
// 正解なら2秒後に次の問題へ
65+
if (isCorrect) {
66+
setTimeout(() => {
67+
setStep(2)
68+
setResult(null)
69+
baselineRef.current.p2 = p2
70+
}, 2000)
71+
}
72+
}
4073
}
4174

42-
// 2回目以降で、かつ値がベースラインから変更された場合のみ判定する
43-
if (actual !== baselineRef.current) {
44-
setResult(checkAnswer(actual))
75+
76+
if (currentStep === 2) {
77+
if (baselineRef.current.p2 === null) {
78+
baselineRef.current.p2 = p2
79+
return
80+
}
81+
82+
if (p2 !== baselineRef.current.p2) {
83+
84+
const isCorrect = p2.includes(ANSWERS.p2)
85+
setResult({
86+
ok: isCorrect,
87+
details: isCorrect ? `一致: (${p2})` : `不一致: (${p2})`
88+
})
89+
// ※ここでさらに step3 へ遷移させることも可能
90+
}
4591
}
4692
}
4793
})
4894

4995
port.onDisconnect.addListener(() => {
50-
// ページ更新・遷移でリセット
51-
baselineRef.current = null
96+
baselineRef.current = { p1: null, p2: null }
5297
port = null
53-
setResult(null) // 待機画面に戻す
98+
setResult(null)
99+
setStep(1) // 接続が切れたら最初に戻す
54100
})
55101
} catch (e: any) {
56102
setError(e?.message ?? String(e))
@@ -61,29 +107,45 @@ function App() {
61107

62108
return () => {
63109
if (port) {
64-
try {
65-
port.disconnect()
66-
} catch {}
110+
try { port.disconnect() } catch {}
67111
}
68-
baselineRef.current = null
112+
baselineRef.current = { p1: null, p2: null }
69113
}
70114
}, [])
71115

116+
// UI描画
72117
return (
73118
<div className="container">
74119
{error && <p style={{ color: 'red' }}>Error: {error}</p>}
75-
{result ? (
76-
<>
77-
<h2>問題1</h2>
78-
<p>レビューの「とにかくひどい。」を「すばらしい。」に書き換えてみよう!</p>
79-
<h2>判定: {result.ok ? '正解' : '不正解'}</h2>
80-
<div>詳細: {result.details}</div>
81-
</>
82-
) : (
120+
121+
{/* ステップ1の表示 */}
122+
{step === 1 && (
83123
<div>
84124
<h2>問題1</h2>
85125
<p>レビューの「とにかくひどい。」を「すばらしい。」に書き換えてみよう!</p>
86-
<p>ヒント:開発者ツールを使って、レビューに当たる要素を探してみよう。</p>
126+
{result && (
127+
<div className={result.ok ? "result-ok" : "result-ng"}>
128+
<h3>判定: {result.ok ? '正解!' : '不正解'}</h3>
129+
<p>{result.details}</p>
130+
{result.ok && <p>次の問題へ進みます...</p>}
131+
</div>
132+
)}
133+
{!result && <p className="hint">ヒント:開発者ツールを使って、レビューに当たる要素を探してみよう。</p>}
134+
</div>
135+
)}
136+
137+
{/* ステップ2の表示 */}
138+
{step === 2 && (
139+
<div>
140+
<h2>問題2</h2>
141+
<p>星1の画像(star1.png)の <code>src</code> を書き換えて、星5 (star5.png) にしてみよう!</p>
142+
{result && (
143+
<div className={result.ok ? "result-ok" : "result-ng"}>
144+
<h3>判定: {result.ok ? '正解!' : '不正解'}</h3>
145+
<p>{result.details}</p>
146+
</div>
147+
)}
148+
{!result && <p className="hint">ヒント:imgタグの src 属性を探そう。</p>}
87149
</div>
88150
)}
89151
</div>

vulnerable-web/images/star1.png

8.27 KB
Loading

vulnerable-web/images/star2.png

8.77 KB
Loading

vulnerable-web/images/star3.png

8.54 KB
Loading

vulnerable-web/images/star4.png

8.45 KB
Loading

vulnerable-web/images/star5.png

7.49 KB
Loading

vulnerable-web/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ <h2>レビュー</h2>
5050
<img src="./images/reviewIcon.png" class="reviewIcon" />
5151
<div class="reviewContent">
5252
<p class="username">Username</p>
53-
<div id="starIcon1">⭐⭐</div>
53+
<div id="starIcon1"><img src="./images/star2.png"></div>
5454
<p class="reviewText">
5555
ワイヤレスには対応しているものの、有線接続用のケーブルを取り外すことができず、非常に邪魔くさい。
5656
音質も値段の割には悪い。ノイキャンは効いているかどうかわからないレベルであり、
@@ -62,7 +62,7 @@ <h2>レビュー</h2>
6262
<img src="./images/reviewIcon.png" class="reviewIcon" />
6363
<div class="reviewContent">
6464
<p class="username">Username</p>
65-
<div id="starIcon1"></div>
65+
<div id="starIcon2"><img src="./images/star1.png" data-check2></div>
6666
<p class="reviewText" data-check>
6767
とにかくひどい。
6868
</p>

vulnerable-web/style.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,3 +234,8 @@ footer {
234234
.closeBtn {
235235
background-color: gray;
236236
}
237+
238+
#starIcon1 img, #starIcon2 img {
239+
width: 100px; /* お好みのサイズに調整してください */
240+
height: auto;
241+
}

0 commit comments

Comments
 (0)