Skip to content

Commit ea5af12

Browse files
authored
Merge pull request #32 from kc3hack/Add-toaru/CreateRoom
Done
2 parents 00d99c9 + b42bc04 commit ea5af12

31 files changed

Lines changed: 855 additions & 99 deletions

File tree

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import express from 'express';
2+
import jwt from 'jsonwebtoken';
3+
import cookieParser from 'cookie-parser';
4+
import dotenv from 'dotenv';
5+
import path from 'path';
6+
import multer from 'multer';
7+
import fs from 'fs';
8+
import { fileURLToPath } from 'url';
9+
import { randomUUID } from "crypto";
10+
11+
// 注意1: Node.jsのESMでは、独自ファイルのimportに拡張子(.js)が必須です
12+
import VCM from '../Tools/VCM.js';
13+
import DBPerf from '../Tools/DBPerf.js';
14+
import { decrypt } from '../Tools/AESControl.js';
15+
import { CreateMosaicTx } from '../Tools/CreateMosaicTx.js';
16+
17+
// 注意2: ESMでは __dirname がデフォルトで存在しないため、自作する必要があります
18+
const __filename = fileURLToPath(import.meta.url);
19+
const __dirname = path.dirname(__filename);
20+
21+
const router = express.Router();
22+
23+
// cookieを使う
24+
router.use(cookieParser());
25+
dotenv.config({ path: path.join(__dirname, "..", ".env")});
26+
const upload = multer({ storage: multer.memoryStorage() });
27+
28+
// ===アイコン保存処理===
29+
function saveIcon(file, folder) {
30+
const fileName = createFileName(file.originalname);
31+
const dir = path.join(__dirname, "..", "icons", folder);
32+
33+
// フォルダが存在しない場合は作成
34+
fs.mkdirSync(dir, { recursive: true });
35+
36+
// ファイルを保存
37+
const fullPath = path.join(dir, fileName);
38+
fs.writeFileSync(fullPath, file.buffer);
39+
40+
console.log(`Icon saved to ${fullPath}`);
41+
42+
// DBに入れる用の「相対パス」
43+
return `/icons/${folder}/${fileName}`;
44+
}
45+
46+
// ===被らないファイル名を作成===
47+
function createFileName(originalName) {
48+
//拡張子取り出し(extname: .pngなど)
49+
const ext = path.extname(originalName);
50+
const Refilename = `${randomUUID()}${ext}`;
51+
console.log(`Generated unique filename: ${Refilename}`);
52+
//タイムスタンプを付与して被らないようにする
53+
return Refilename;
54+
}
55+
56+
// ===ルーム作成API===
57+
router.post("/", VCM('LOGIN_TOKEN', process.env.LOGIN_SECRET), upload.fields([{ name: "RoomIcon", maxCount: 1 },{ name: "MosaicIcon", maxCount: 1 }]), async (req, res) => {
58+
try {
59+
const userID = req.auth.userId;
60+
const { RoomName, MosaicName, Password } = req.body;
61+
console.log("Received CreateRoom request:", { userID, RoomName, MosaicName, Password });
62+
if (!userID || !RoomName || !MosaicName || !Password) {
63+
console.log("Missing required fields in CreateRoom request");
64+
return res.status(400).json({ message: "UserID, RoomName, MosaicName, and Password are required" });
65+
}
66+
67+
68+
if (!RoomName || !MosaicName || !req.files?.RoomIcon || !req.files?.MosaicIcon) {
69+
return res.status(400).json({ message: "Bad Request" });
70+
}
71+
72+
const OwnerInfor = await DBPerf(
73+
"Get Encrypted Private Key","SELECT PrivateKey FROM Identify WHERE userID = ?",[userID]
74+
);
75+
const encryptedPrivateKeyObj = JSON.parse(OwnerInfor[0].PrivateKey);
76+
const privateKey = decrypt(Password + process.env.PEPPER, encryptedPrivateKeyObj);
77+
78+
const { mosaicId, mosaicDefinitionTx, keyPair, facade } = CreateMosaicTx({
79+
networkType: 'testnet',
80+
senderPrivateKey: privateKey,
81+
transferable: false,
82+
deadlineHours: 24
83+
});
84+
85+
const RoomIconPath = await saveIcon(req.files.RoomIcon[0], "rooms");
86+
console.log("RoomIcon saved at:", RoomIconPath);
87+
const MosaicIconPath = await saveIcon(req.files.MosaicIcon[0], "tokens");
88+
console.log("MosaicIcon saved at:", MosaicIconPath);
89+
90+
await DBPerf(
91+
"INSERT Mosaic",
92+
"INSERT INTO Mosaic (MosaicID, MosaicName) VALUES (?, ?)",
93+
[mosaicId, MosaicName ]
94+
);
95+
96+
await DBPerf(
97+
"INSERT RoomDetails",
98+
"INSERT INTO RoomDetails(RoomName, RoomIconPath, MosaicName) VALUES (?, ?, ?)",
99+
[RoomName, RoomIconPath, MosaicName]
100+
);
101+
102+
await DBPerf(
103+
"INSERT Rooms",
104+
"INSERT INTO Rooms(UserID, RoomName) VALUES (?, ?)",[userID, RoomName]
105+
);
106+
107+
res.status(201).json({ message: "Room created successfully" });
108+
} catch (err) {
109+
console.error("CreateRoom-API Error:", err);
110+
res.status(500).json({ message: "Internal Server Error" });
111+
}
112+
}
113+
);
114+
115+
// モジュールのエクスポート
116+
export default router;

Backend/Workspace/Routes/Register.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,11 @@ router.post(
157157

158158
// ユーザーのパスワードから復号可能にする設計
159159
const encryptedPrivateKey =
160-
encrypt(passwordWithPepper, privateKeyString);
161-
160+
JSON.stringify(
161+
encrypt(passwordWithPepper, privateKeyString)
162+
);
163+
console.log("暗号化された秘密鍵オブジェクト:", privateKeyString);
164+
console.log("暗号化された秘密鍵:", encryptedPrivateKey);
162165

163166
// =====================================================
164167
// 4. パスワードをArgon2でハッシュ化
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*========== Manual ==========
2+
# Input(obj)
3+
networkType: mainnet or testnet
4+
senderPrivateKey: 送り元の秘密鍵
5+
transferable: 発行者以外が送信できるかどうか(true or false)
6+
deadlineHours: 有効期限[h]
7+
8+
# Output
9+
mosaicId: 発行したMosaicIDの16進数表現
10+
mosaicDefinitionTx: 実際のトランザクション
11+
keyPair: 署名時に必要な秘密鍵/公開鍵
12+
facade: mainnet or testnetの指定をしているがそれが一貫性を保てるように引き継ぐ
13+
========== Manual ==========*/
14+
15+
// CreateMosaicTx.js
16+
import { PrivateKey } from 'symbol-sdk';
17+
import { SymbolFacade } from 'symbol-sdk/symbol';
18+
import { generateMosaicId } from 'symbol-sdk/symbol';
19+
20+
export function CreateMosaicTx({
21+
networkType = 'testnet',
22+
senderPrivateKey,
23+
transferable = true,
24+
deadlineHours = 2
25+
}) {
26+
// Startup Log
27+
const logOwner = "CreateMosaicTx";
28+
console.log(`\n${logOwner}-Function is running!\n`);
29+
console.log(`[${logOwner}] Input => networkType: ${networkType}, transferable: ${transferable}, deadlineHours: ${deadlineHours}`);
30+
31+
if (!senderPrivateKey) {
32+
throw new Error("senderPrivateKey is undefined");
33+
}
34+
35+
console.log("senderPrivateKey:", senderPrivateKey);
36+
console.log("type:", typeof senderPrivateKey);
37+
console.log("length:", senderPrivateKey?.length);
38+
39+
// Facade 初期化
40+
const facade = new SymbolFacade(networkType);
41+
42+
// 秘密鍵 → KeyPair
43+
const normalizedPrivateKey = senderPrivateKey.trim();
44+
const privateKeyObject = new PrivateKey(normalizedPrivateKey);
45+
const keyPair = facade.createAccount(privateKeyObject);
46+
47+
// Deadline 作成
48+
const deadline = facade.network
49+
.fromDatetime(new Date())
50+
.addHours(Number(deadlineHours))
51+
.timestamp;
52+
53+
console.log(`[${logOwner}] Intermediate => KeyPair created, Deadline calculated`);
54+
55+
// 0〜2^32-1 のランダムnonce生成
56+
const nonce = Math.floor(Math.random() * 0xffffffff);
57+
58+
console.log(`[${logOwner}] Intermediate => Nonce generated: ${nonce}`);
59+
60+
// Mosaic定義トランザクション作成
61+
const mosaicDefinitionTx = facade.transactionFactory.create({
62+
type: 'mosaic_definition_transaction_v1',
63+
signerPublicKey: keyPair.publicKey,
64+
duration: 0,
65+
nonce: nonce,
66+
flags: {
67+
supplyMutable: true,
68+
transferable: transferable,
69+
restrictable: false,
70+
revocable: false,
71+
},
72+
divisibility: 0,
73+
deadline: deadline
74+
});
75+
76+
console.log(`[${logOwner}] Intermediate => MosaicDefinitionTx created with type: ${mosaicDefinitionTx.type}`);
77+
78+
79+
const ownerAddress = facade.network.publicKeyToAddress(keyPair.publicKey);
80+
// MosaicID計算
81+
const mosaicIdBigInt = generateMosaicId(ownerAddress, nonce);
82+
const mosaicIdHex = mosaicIdBigInt.toString(16).toUpperCase().padStart(16, '0');
83+
84+
console.log(`[${logOwner}] Output =>
85+
Type: ${mosaicDefinitionTx.type}
86+
SupplyMutable: ${mosaicDefinitionTx.flags.supplyMutable}
87+
Transferable: ${mosaicDefinitionTx.flags.transferable}
88+
MosaicID: ${mosaicIdHex}
89+
`);
90+
91+
console.log(`[${logOwner}] Shutdown!`);
92+
93+
return {
94+
mosaicId: mosaicIdHex,
95+
mosaicDefinitionTx,
96+
keyPair,
97+
facade
98+
};
99+
}
100+

Backend/node_modules/.bin/baseline-browser-mapping

Lines changed: 16 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Backend/node_modules/.bin/browserslist

Lines changed: 16 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Backend/node_modules/.bin/esparse

Lines changed: 16 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Backend/node_modules/.bin/esvalidate

Lines changed: 16 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Backend/node_modules/.bin/glob

Lines changed: 16 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Backend/node_modules/.bin/import-local-fixture

Lines changed: 16 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Backend/node_modules/.bin/jest

Lines changed: 16 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)