-
Notifications
You must be signed in to change notification settings - Fork 0
Done #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Done #32
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,116 @@ | ||||||||||||||||||||||||||||||||||||||||||||
| import express from 'express'; | ||||||||||||||||||||||||||||||||||||||||||||
| import jwt from 'jsonwebtoken'; | ||||||||||||||||||||||||||||||||||||||||||||
| import cookieParser from 'cookie-parser'; | ||||||||||||||||||||||||||||||||||||||||||||
| import dotenv from 'dotenv'; | ||||||||||||||||||||||||||||||||||||||||||||
| import path from 'path'; | ||||||||||||||||||||||||||||||||||||||||||||
| import multer from 'multer'; | ||||||||||||||||||||||||||||||||||||||||||||
| import fs from 'fs'; | ||||||||||||||||||||||||||||||||||||||||||||
| import { fileURLToPath } from 'url'; | ||||||||||||||||||||||||||||||||||||||||||||
| import { randomUUID } from "crypto"; | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| // 注意1: Node.jsのESMでは、独自ファイルのimportに拡張子(.js)が必須です | ||||||||||||||||||||||||||||||||||||||||||||
| import VCM from '../Tools/VCM.js'; | ||||||||||||||||||||||||||||||||||||||||||||
| import DBPerf from '../Tools/DBPerf.js'; | ||||||||||||||||||||||||||||||||||||||||||||
| import { decrypt } from '../Tools/AESControl.js'; | ||||||||||||||||||||||||||||||||||||||||||||
| import { CreateMosaicTx } from '../Tools/CreateMosaicTx.js'; | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| // 注意2: ESMでは __dirname がデフォルトで存在しないため、自作する必要があります | ||||||||||||||||||||||||||||||||||||||||||||
| const __filename = fileURLToPath(import.meta.url); | ||||||||||||||||||||||||||||||||||||||||||||
| const __dirname = path.dirname(__filename); | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| const router = express.Router(); | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| // cookieを使う | ||||||||||||||||||||||||||||||||||||||||||||
| router.use(cookieParser()); | ||||||||||||||||||||||||||||||||||||||||||||
| dotenv.config({ path: path.join(__dirname, "..", ".env")}); | ||||||||||||||||||||||||||||||||||||||||||||
| const upload = multer({ storage: multer.memoryStorage() }); | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
| const upload = multer({ storage: multer.memoryStorage() }); | |
| const upload = multer({ | |
| storage: multer.memoryStorage(), | |
| limits: { | |
| fileSize: 1 * 1024 * 1024, // 最大1MB | |
| files: 1 // 1リクエストあたり1ファイル | |
| } | |
| }); |
Copilot
AI
Feb 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mkdirSync/writeFileSync blocks the Node.js event loop inside a request handler, which can reduce throughput under load. Prefer async fs.promises.mkdir/fs.promises.writeFile (or streaming) and await them in the route.
Copilot
AI
Feb 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mkdirSync/writeFileSync blocks the Node.js event loop inside a request handler, which can reduce throughput under load. Prefer async fs.promises.mkdir/fs.promises.writeFile (or streaming) and await them in the route.
Copilot
AI
Feb 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mkdirSync/writeFileSync blocks the Node.js event loop inside a request handler, which can reduce throughput under load. Prefer async fs.promises.mkdir/fs.promises.writeFile (or streaming) and await them in the route.
| function saveIcon(file, folder) { | |
| const fileName = createFileName(file.originalname); | |
| const dir = path.join(__dirname, "..", "icons", folder); | |
| // フォルダが存在しない場合は作成 | |
| fs.mkdirSync(dir, { recursive: true }); | |
| // ファイルを保存 | |
| const fullPath = path.join(dir, fileName); | |
| fs.writeFileSync(fullPath, file.buffer); | |
| async function saveIcon(file, folder) { | |
| const fileName = createFileName(file.originalname); | |
| const dir = path.join(__dirname, "..", "icons", folder); | |
| // フォルダが存在しない場合は作成 | |
| await fs.promises.mkdir(dir, { recursive: true }); | |
| // ファイルを保存 | |
| const fullPath = path.join(dir, fileName); | |
| await fs.promises.writeFile(fullPath, file.buffer); |
Copilot
AI
Feb 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deriving the stored extension directly from user-supplied filenames can allow uploading and later serving potentially dangerous file types (e.g., .html, .svg) if /icons is publicly served. Enforce an allowlist based on MIME type and/or content sniffing (e.g., only png/jpg/webp), and normalize extension accordingly.
Copilot
AI
Feb 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refilename uses PascalCase in the middle of a function where other locals are camelCase (fileName, originalName, ext). Rename to refilename/fileName/uniqueFileName to match common JS conventions and improve readability.
| const Refilename = `${randomUUID()}${ext}`; | |
| console.log(`Generated unique filename: ${Refilename}`); | |
| //タイムスタンプを付与して被らないようにする | |
| return Refilename; | |
| const uniqueFileName = `${randomUUID()}${ext}`; | |
| console.log(`Generated unique filename: ${uniqueFileName}`); | |
| //タイムスタンプを付与して被らないようにする | |
| return uniqueFileName; |
Copilot
AI
Feb 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logs Password from the request body, which is highly sensitive. Avoid logging credentials; log only non-sensitive request metadata (e.g., userID and presence/validation results).
| console.log("Received CreateRoom request:", { userID, RoomName, MosaicName, Password }); | |
| console.log("Received CreateRoom request:", { userID, RoomName, MosaicName, PasswordProvided: Boolean(Password) }); |
Copilot
AI
Feb 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Request validation is duplicated and partially overlapping (RoomName/MosaicName checked twice; icons validated separately). Consolidate into a single validation block that checks all required fields/files once so future edits don’t diverge.
Copilot
AI
Feb 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Request validation is duplicated and partially overlapping (RoomName/MosaicName checked twice; icons validated separately). Consolidate into a single validation block that checks all required fields/files once so future edits don’t diverge.
| if (!userID || !RoomName || !MosaicName || !Password) { | |
| console.log("Missing required fields in CreateRoom request"); | |
| return res.status(400).json({ message: "UserID, RoomName, MosaicName, and Password are required" }); | |
| } | |
| if (!RoomName || !MosaicName || !req.files?.RoomIcon || !req.files?.MosaicIcon) { | |
| return res.status(400).json({ message: "Bad Request" }); | |
| const hasRequiredBody = !!(userID && RoomName && MosaicName && Password); | |
| const hasRequiredFiles = | |
| !!(req.files && | |
| req.files.RoomIcon && req.files.RoomIcon[0] && | |
| req.files.MosaicIcon && req.files.MosaicIcon[0]); | |
| if (!hasRequiredBody || !hasRequiredFiles) { | |
| console.log("Missing required fields or files in CreateRoom request"); | |
| const message = !hasRequiredBody | |
| ? "UserID, RoomName, MosaicName, and Password are required" | |
| : "Bad Request"; | |
| return res.status(400).json({ message }); |
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -157,8 +157,11 @@ router.post( | |||||||||||||||
|
|
||||||||||||||||
| // ユーザーのパスワードから復号可能にする設計 | ||||||||||||||||
| const encryptedPrivateKey = | ||||||||||||||||
| encrypt(passwordWithPepper, privateKeyString); | ||||||||||||||||
|
|
||||||||||||||||
| JSON.stringify( | ||||||||||||||||
| encrypt(passwordWithPepper, privateKeyString) | ||||||||||||||||
| ); | ||||||||||||||||
| console.log("暗号化された秘密鍵オブジェクト:", privateKeyString); | ||||||||||||||||
| console.log("暗号化された秘密鍵:", encryptedPrivateKey); | ||||||||||||||||
|
|
||||||||||||||||
|
Comment on lines
+163
to
165
|
||||||||||||||||
| console.log("暗号化された秘密鍵オブジェクト:", privateKeyString); | |
| console.log("暗号化された秘密鍵:", encryptedPrivateKey); | |
| // 本番環境では秘密鍵の内容をログ出力しない | |
| if (process.env.NODE_ENV !== 'production') { | |
| console.log("暗号化された秘密鍵が生成されました。長さ:", encryptedPrivateKey.length); | |
| } |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,100 @@ | ||||||||||
| /*========== Manual ========== | ||||||||||
| # Input(obj) | ||||||||||
| networkType: mainnet or testnet | ||||||||||
| senderPrivateKey: 送り元の秘密鍵 | ||||||||||
| transferable: 発行者以外が送信できるかどうか(true or false) | ||||||||||
| deadlineHours: 有効期限[h] | ||||||||||
|
|
||||||||||
| # Output | ||||||||||
| mosaicId: 発行したMosaicIDの16進数表現 | ||||||||||
| mosaicDefinitionTx: 実際のトランザクション | ||||||||||
| keyPair: 署名時に必要な秘密鍵/公開鍵 | ||||||||||
| facade: mainnet or testnetの指定をしているがそれが一貫性を保てるように引き継ぐ | ||||||||||
| ========== Manual ==========*/ | ||||||||||
|
|
||||||||||
| // CreateMosaicTx.js | ||||||||||
| import { PrivateKey } from 'symbol-sdk'; | ||||||||||
| import { SymbolFacade } from 'symbol-sdk/symbol'; | ||||||||||
| import { generateMosaicId } from 'symbol-sdk/symbol'; | ||||||||||
|
|
||||||||||
| export function CreateMosaicTx({ | ||||||||||
| networkType = 'testnet', | ||||||||||
| senderPrivateKey, | ||||||||||
| transferable = true, | ||||||||||
| deadlineHours = 2 | ||||||||||
| }) { | ||||||||||
| // Startup Log | ||||||||||
| const logOwner = "CreateMosaicTx"; | ||||||||||
| console.log(`\n${logOwner}-Function is running!\n`); | ||||||||||
| console.log(`[${logOwner}] Input => networkType: ${networkType}, transferable: ${transferable}, deadlineHours: ${deadlineHours}`); | ||||||||||
|
|
||||||||||
| if (!senderPrivateKey) { | ||||||||||
| throw new Error("senderPrivateKey is undefined"); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| console.log("senderPrivateKey:", senderPrivateKey); | ||||||||||
| console.log("type:", typeof senderPrivateKey); | ||||||||||
| console.log("length:", senderPrivateKey?.length); | ||||||||||
|
Comment on lines
+35
to
+37
|
||||||||||
| console.log("senderPrivateKey:", senderPrivateKey); | |
| console.log("type:", typeof senderPrivateKey); | |
| console.log("length:", senderPrivateKey?.length); | |
| console.log(`[${logOwner}] senderPrivateKey provided: ${senderPrivateKey ? 'yes' : 'no'}`); |
Copilot
AI
Feb 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Math.random() isn’t ideal for values that contribute to identifiers and should be unpredictable. Prefer a cryptographically strong source (e.g., crypto.randomBytes(4) / crypto.getRandomValues) and convert to an unsigned 32-bit integer.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
jwtis imported but not used in this new file, which adds noise and can confuse readers. Remove the unused import.