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+ // ==========================
425const 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リクエストボディをパースできるようにする
1128router . 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 ;
0 commit comments