Skip to content

Commit e805c19

Browse files
authored
Merge pull request #33 from kc3hack/Add-toaru/RoomList
Done
2 parents ea5af12 + 1153d3c commit e805c19

7 files changed

Lines changed: 151 additions & 64 deletions

File tree

Backend/Workspace/Routes/CreateRoom.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,10 @@ function createFileName(originalName) {
5757
router.post("/", VCM('LOGIN_TOKEN', process.env.LOGIN_SECRET), upload.fields([{ name: "RoomIcon", maxCount: 1 },{ name: "MosaicIcon", maxCount: 1 }]), async (req, res) => {
5858
try {
5959
const userID = req.auth.userId;
60-
const { RoomName, MosaicName, Password } = req.body;
60+
const { RoomName, MosaicName, Password, password } = req.body;
61+
const inputPassword = Password ?? password;
6162
console.log("Received CreateRoom request:", { userID, RoomName, MosaicName, Password });
62-
if (!userID || !RoomName || !MosaicName || !Password) {
63+
if (!userID || !RoomName || !MosaicName || !inputPassword) {
6364
console.log("Missing required fields in CreateRoom request");
6465
return res.status(400).json({ message: "UserID, RoomName, MosaicName, and Password are required" });
6566
}
@@ -73,7 +74,7 @@ router.post("/", VCM('LOGIN_TOKEN', process.env.LOGIN_SECRET), upload.fields([{
7374
"Get Encrypted Private Key","SELECT PrivateKey FROM Identify WHERE userID = ?",[userID]
7475
);
7576
const encryptedPrivateKeyObj = JSON.parse(OwnerInfor[0].PrivateKey);
76-
const privateKey = decrypt(Password + process.env.PEPPER, encryptedPrivateKeyObj);
77+
const privateKey = decrypt(inputPassword + process.env.PEPPER, encryptedPrivateKeyObj);
7778

7879
const { mosaicId, mosaicDefinitionTx, keyPair, facade } = CreateMosaicTx({
7980
networkType: 'testnet',

Backend/Workspace/Routes/Login.js

Lines changed: 113 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,127 @@
1-
const express = require('express');
2-
const path = require('path');
3-
const dotenv = require('dotenv');
1+
// ==========================
2+
// 標準モジュール読み込み
3+
// ==========================
4+
import express from 'express'; // Webサーバーフレームワーク
5+
import path from 'path'; // パス操作用
6+
import { fileURLToPath } from 'url'; // ESMで __dirname を作るために必要
7+
8+
// ==========================
9+
// 自作モジュール読み込み
10+
// ==========================
11+
import argon2 from 'argon2'; // パスワードハッシュ検証用
12+
import DBPerf from '../Tools/DBPerf.js'; // DBラッパー
13+
import CreateCookie from '../Tools/CreateCookie.js'; // Cookie作成
14+
import InverseVCM from '../Tools/InverseVCM.js'; // ログイン状態チェックミドルウェア
15+
16+
// ==========================
17+
// __dirname 再生成 (ESM対応)
18+
// ==========================
19+
const __filename = fileURLToPath(import.meta.url);
20+
const __dirname = path.dirname(__filename);
21+
22+
// ==========================
23+
// Express Router 初期化
24+
// ==========================
425
const router = express.Router();
5-
const argon2 = require('argon2');
6-
const DBPerf = require('../Tools/DBPerf');
7-
const CreateCookie = require('../Tools/CreateCookie');
826

9-
// use系
10-
dotenv.config({ path: path.join(__dirname, "..", ".env") });
27+
// JSONリクエストボディをパースできるようにする
1128
router.use(express.json());
1229

13-
// ========== ブロックチェーンの準備 ==========
14-
//const symbolSdk = require('symbol-sdk');
15-
const InverseVCM = require('../Tools/InverseVCM');
16-
//const facade = new symbolSdk.facade.SymbolFacade('testnet');
30+
// ==========================
31+
// 画面表示ルート
32+
// ==========================
1733

18-
// ========== 画面表示 ==========
19-
// /Login/へのアクセスでLogin画面表示
20-
router.get('/', InverseVCM('LOGIN_TOKEN', process.env.LOGIN_SECRET) ,(req, res) => {
34+
/**
35+
* GET /Login/
36+
* - ログイン済みの場合はアクセス拒否(InverseVCM)
37+
* - ログイン画面を返却
38+
*/
39+
router.get(
40+
'/',
41+
InverseVCM('LOGIN_TOKEN', process.env.LOGIN_SECRET),
42+
(req, res) => {
2143
console.log("/Login-API is running");
22-
res.sendFile(path.join(__dirname, "..", "..", "..", "Frontend", "src", "index.html"));
23-
});
44+
res.sendFile(
45+
path.join(__dirname, "..", "..", "..", "Frontend", "dist", "index.html")
46+
);
47+
}
48+
);
2449

50+
// ==========================
51+
// ログイン処理ルート
52+
// ==========================
2553

26-
router.post("/Submit", async (req, res) => {
27-
// 0. Startup Log
28-
console.log("/Login/Submit-API is running!");
54+
/**
55+
* POST /Login/Submit
56+
* - フロントエンドから送信された UserID と Password を受け取る
57+
* - DBからユーザー情報を取得
58+
* - ハッシュ検証後にクッキーを発行
59+
*/
60+
router.post("/Submit", InverseVCM('LOGIN_TOKEN', process.env.LOGIN_SECRET), async (req, res) => {
2961

30-
// 1. Login情報を取得する
62+
// 0. 処理開始ログ
63+
console.log("/Login/Submit-API is running!");
64+
65+
try {
66+
// 1. フロントエンド送信情報取得
3167
const { userId, password } = req.body;
32-
//必要な情報が揃っているか確認
33-
if( !userId || !password ){
34-
return res.status(400).json({message: "Bad Request: UserIDかPasswordが不足しています。"});
68+
69+
// 1a. 必須情報のチェック
70+
if (!userId || !password) {
71+
return res.status(400).json({
72+
message: "Bad Request: UserIDかPasswordが不足しています。"
73+
});
3574
}
3675

37-
// 2. DB検索とサイドチャネル攻撃の対策
38-
const userInfo = await DBPerf("Select From Identify To Login", "SELECT Address, Password FROM Identify WHERE UserID = ?;", [userId]);
39-
const comparePassword = userInfo.length == 0 ? process.env.DUMMY_PASSWORD : userInfo[0].Password;
40-
41-
// 3. Hashの検証
42-
if (await argon2.verify(comparePassword, password + process.env.PEPPER)) {
43-
// Verify Success Log
44-
console.log("LoginToken is verified!");
45-
46-
CreateCookie({
47-
res,
48-
cookieName: 'LOGIN_TOKEN',
49-
payload: { userId: userId, address: userInfo[0].Address },
50-
secretKey: process.env.LOGIN_SECRET,
51-
deadlineHours: 24, // 1日
52-
httpOnly: true,
53-
sameSite: 'strict'
54-
});
55-
56-
// リダイレクト
57-
res.redirect("/Home");
58-
59-
}else{
60-
// Verify Error Log
61-
console.error("LoginToken is not verified!");
62-
return res.status(400).json({ error: 'Bad Request: ID or Password is failed.' });
76+
// 2. DB検索とサイドチャネル攻撃対策
77+
// ユーザーが存在しない場合でも固定ダミーパスワードを使用
78+
const userInfo = await DBPerf(
79+
"Select From Identify To Login",
80+
"SELECT Address, Password FROM Identify WHERE UserID = ?;",
81+
[userId]
82+
);
83+
const hashToVerify = userInfo.length === 0 ? process.env.DUMMY_PASSWORD : userInfo[0].Password;
84+
85+
// 3. パスワードハッシュ検証
86+
// PEPPER を付加してセキュリティ強化
87+
const isVerified = await argon2.verify(hashToVerify, password + process.env.PEPPER);
88+
89+
if (isVerified) {
90+
// 3a. 認証成功ログ
91+
console.log("LoginToken is verified!");
92+
93+
// 4. Cookie発行
94+
CreateCookie({
95+
res,
96+
cookieName: 'LOGIN_TOKEN',
97+
payload: { userId, address: userInfo[0].Address },
98+
secretKey: process.env.LOGIN_SECRET,
99+
deadlineHours: 24, // 1日有効
100+
httpOnly: true,
101+
sameSite: 'strict'
102+
});
103+
104+
// 5. リダイレクト
105+
res.redirect("/Home");
106+
107+
} else {
108+
// 3b. 認証失敗ログ
109+
console.error("LoginToken is not verified!");
110+
return res.status(400).json({
111+
error: 'Bad Request: IDまたはPasswordが正しくありません。'
112+
});
63113
}
64-
})
65114

66-
module.exports = router;
115+
} catch (err) {
116+
// 例外処理
117+
console.error("Login/Submit Error:", err);
118+
res.status(500).json({
119+
message: "Internal Server Error: サーバーエラーが発生しました。"
120+
});
121+
}
122+
});
123+
124+
// ==========================
125+
// Routerエクスポート
126+
// ==========================
127+
export default router;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import express from 'express';
2+
import DBPerf from '../Tools/DBPerf.js'; // ESMでは拡張子(.js)が必要です
3+
import VCM from '../Tools/VCM.js'; // ESMでは拡張子(.js)が必要です
4+
5+
const router = express.Router();
6+
7+
8+
// ========== 画面表示 ==========
9+
router.get('/', VCM('LOGIN_TOKEN', process.env.LOGIN_SECRET), async (req, res) => {
10+
console.log("/RoomList-API is running");
11+
12+
const userId = req.auth.userId;
13+
const RoomList = await DBPerf(
14+
"",
15+
"SELECT RoomName, RoomIconPath FROM RoomDetails WHERE RoomName IN (SELECT RoomName FROM Rooms WHERE UserID = ?)", [userId]
16+
);
17+
res.json({ RoomList });
18+
});
19+
20+
export default router;

Backend/Workspace/Server.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ app.use(express.urlencoded({ extended: true }));
7373
// publicフォルダを静的公開
7474
app.use(express.static(path.join(__dirname, 'public')));
7575

76+
// 保存されたアイコンフォルダを静的配信
77+
app.use('/icons', express.static(path.join(__dirname, 'icons')));
78+
79+
7680

7781
// ==========================
7882
// Routes自動マウント処理

Frontend/src/Workspace/Pages/Create/Create.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ function Create() {
2323
const formData = new FormData();
2424
formData.append("RoomName", RoomName);
2525
formData.append("MosaicName", TokenName);
26+
formData.append("password", password);
2627
if (RoomIcon) formData.append("RoomIcon", RoomIcon);
2728
if (TokenIcon) formData.append("MosaicIcon", TokenIcon);
2829

Frontend/src/Workspace/Pages/Home/Home.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,11 @@ function Home() {
106106
<div className="HomeRoom">
107107
{rooms.map((room) => (
108108
<RoomButton
109-
key={room.id}
110-
icon={room.RoomIcon || icon}
109+
key={room.RoomName}
110+
icon={`http://localhost:5000${room.RoomIconPath}` || icon}
111111
label={room.RoomName}
112112
onClick={() => {
113-
navigate(`/room/${room.id}`);
113+
navigate(`/room/${room.RoomName}`);
114114
}
115115
}
116116
type="button"

Frontend/src/Workspace/Pages/Register/Register.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ function Register() {
1414

1515
async function HandleLogin() {
1616
try {
17-
const res = await fetch('Login/Submit', {
17+
const res = await fetch('/Register/Submit', {
1818
method: 'POST',
1919
headers: { "Content-Type": "application/json" },
2020
credentials: "include",
@@ -23,17 +23,17 @@ function Register() {
2323

2424
if (!res.ok) {
2525
const data = await res.json();
26-
toast.error("ログインに失敗しました");
27-
console.log("Faild: Login", data);
26+
toast.error("登録に失敗しました");
27+
console.log("Failed: Register", data);
2828
return;
2929
} else {
30-
toast.success("ログインしました");
31-
console.log("Success: Login");
30+
toast.success("登録しました");
31+
console.log("Success: Register");
3232
navigate("/Home");
3333
}
3434
} catch (err) {
3535
toast.error('通信エラーが発生しました');
36-
console.log("Faild: Communication");
36+
console.log("Failed: Communication");
3737
}
3838
}
3939

0 commit comments

Comments
 (0)