From 076da56b5a1aae3f5c786b67cb4733276209401c Mon Sep 17 00:00:00 2001 From: toaru05 Date: Fri, 20 Feb 2026 03:54:05 +0900 Subject: [PATCH] TmpCommit --- Backend/TestSpace/Register.test.js | 87 +-- Backend/Workspace/Routes/CreateRoom.js | 67 +- Backend/Workspace/Routes/Login.js | 20 +- Backend/Workspace/Routes/NFC.js | 13 +- Backend/Workspace/Routes/Register.js | 95 +++ Backend/Workspace/Routes/RoomList.js | 8 +- Backend/Workspace/Routes/SendToken.js | 18 +- Backend/Workspace/Routes/SendTokenByNFC.js | 16 +- Backend/Workspace/Server.js | 31 +- Backend/Workspace/Tools/AESControl.js | 8 +- Backend/Workspace/Tools/CreateCookie.js | 4 +- Backend/Workspace/Tools/CreateMosaicTx.js | 60 ++ Backend/Workspace/Tools/CreateTransferTx.js | 9 +- Backend/Workspace/Tools/DBPerf.js | 15 +- Backend/Workspace/Tools/InverseVCM.js | 4 +- Backend/Workspace/Tools/LeftToken.js | 4 +- Backend/Workspace/Tools/SignAndAnnounce.js | 2 +- Backend/Workspace/Tools/VCM.js | 4 +- .../Workspace/Tools/VerifyCookieMiddleware.js | 4 +- .../.bin/baseline-browser-mapping | 17 +- Backend/node_modules/.bin/browserslist | 17 +- Backend/node_modules/.bin/esparse | 17 +- Backend/node_modules/.bin/esvalidate | 17 +- Backend/node_modules/.bin/glob | 17 +- .../node_modules/.bin/import-local-fixture | 17 +- Backend/node_modules/.bin/jest | 17 +- Backend/node_modules/.bin/js-yaml | 17 +- Backend/node_modules/.bin/jsesc | 17 +- Backend/node_modules/.bin/json5 | 17 +- Backend/node_modules/.bin/mime | 17 +- Backend/node_modules/.bin/napi-postinstall | 17 +- Backend/node_modules/.bin/node-which | 17 +- Backend/node_modules/.bin/parser | 17 +- Backend/node_modules/.bin/semver | 17 +- .../node_modules/.bin/update-browserslist-db | 17 +- Backend/node_modules/.package-lock.json | 101 ++- .../resolver-binding-linux-x64-gnu/README.md | 3 - .../package.json | 26 - .../resolver.linux-x64-gnu.node | Bin 2272024 -> 0 bytes .../resolver-binding-linux-x64-musl/README.md | 3 - .../package.json | 26 - .../resolver.linux-x64-musl.node | Bin 2275480 -> 0 bytes .../node_modules/.bin/semver | 17 +- .../jest-snapshot/node_modules/.bin/semver | 17 +- .../make-dir/node_modules/.bin/semver | 17 +- Backend/package-lock.json | 64 +- Backend/package.json | 7 +- Frontend/package-lock.json | 16 +- node_modules/.package-lock.json | 694 +++++++++++++++++ package-lock.json | 697 +++++++++++++++++- package.json | 3 +- 51 files changed, 2140 insertions(+), 292 deletions(-) create mode 100644 Backend/Workspace/Routes/Register.js create mode 100644 Backend/Workspace/Tools/CreateMosaicTx.js delete mode 100644 Backend/node_modules/@unrs/resolver-binding-linux-x64-gnu/README.md delete mode 100644 Backend/node_modules/@unrs/resolver-binding-linux-x64-gnu/package.json delete mode 100644 Backend/node_modules/@unrs/resolver-binding-linux-x64-gnu/resolver.linux-x64-gnu.node delete mode 100644 Backend/node_modules/@unrs/resolver-binding-linux-x64-musl/README.md delete mode 100644 Backend/node_modules/@unrs/resolver-binding-linux-x64-musl/package.json delete mode 100644 Backend/node_modules/@unrs/resolver-binding-linux-x64-musl/resolver.linux-x64-musl.node diff --git a/Backend/TestSpace/Register.test.js b/Backend/TestSpace/Register.test.js index ff91aa65..b31e7abe 100644 --- a/Backend/TestSpace/Register.test.js +++ b/Backend/TestSpace/Register.test.js @@ -1,91 +1,74 @@ -const request = require('supertest'); -const express = require('express'); -const cookieParser = require('cookie-parser'); -const fs = require('fs'); -const path = require('path'); +import request from 'supertest'; +import express from 'express'; +import cookieParser from 'cookie-parser'; +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import { jest } from '@jest/globals'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); -// Register.js の存在確認 const registerPath = path.resolve(__dirname, '../Workspace/Routes/Register.js'); const registerExists = fs.existsSync(registerPath); - -// describe を動的切り替え const describeIf = registerExists ? describe : describe.skip; -// Router を条件付きで読み込み -let registerRouter; -if (registerExists) { - registerRouter = require('../Workspace/Routes/Register'); -} +jest.unstable_mockModule('../Workspace/Tools/DBPerf.js', () => ({ + default: jest.fn() +})); -// DBPerfモック化 -jest.mock('../Workspace/Tools/DBPerf', () => jest.fn()); -const DBPerf = require('../Workspace/Tools/DBPerf'); +jest.unstable_mockModule('../Workspace/Tools/AESControl.js', () => ({ + encrypt: jest.fn(() => 'encrypted-key'), + decrypt: jest.fn() +})); -// Symbol SDKをモック化 -jest.mock('symbol-sdk', () => { - const original = jest.requireActual('symbol-sdk'); +jest.unstable_mockModule('symbol-sdk', async () => { + const original = await jest.requireActual('symbol-sdk'); return { ...original, - PrivateKey: { random: () => 'dummy-private-key' }, - Account: { createFromPrivateKey: () => ({ address: { plain: () => 'dummy-address' } }) }, - NetworkType: { TEST_NET: 'TEST_NET' }, - facade: { SymbolFacade: jest.fn() }, + PrivateKey: { + random: () => ({ toString: () => 'dummy-private-key' }) + }, + facade: { + SymbolFacade: jest.fn(() => ({ + createAccount: () => ({ address: { toString: () => 'dummy-address' } }) + })) + } }; }); -// AESControlをモック化 -jest.mock('../Workspace/Tools/AESControl', () => ({ - encrypt: jest.fn(() => 'encrypted-key') -})); +const { default: DBPerf } = await import('../Workspace/Tools/DBPerf.js'); + +let registerRouter; +if (registerExists) { + const registerModule = await import('../Workspace/Routes/Register.js'); + registerRouter = registerModule.default; +} const app = express(); app.use(express.json()); app.use(cookieParser()); -if (registerExists) { +if (registerExists && registerRouter) { app.use('/Register', registerRouter); } -describeIf('/Register', () => { - // cookieがある場合 - it('should redirect to Home if cookie exists', async () => { - const res = await request(app) - .get('/Register') - .set('Cookie', ['LoginToken=dummy-jwt']); - - expect(res.status).toBe(302); // リダイレクト - expect(res.headers.location).toBe('/Home'); - }); - - // cookieがない場合 - it('should render register page if no cookie', async () => { - const res = await request(app) - .get('/Register'); - - expect(res.status).toBe(200); - expect(res.text).toContain('index.html'); // 登録画面が返る - }); -}); - describeIf('/Register/Submit', () => { beforeEach(() => { DBPerf.mockReset(); }); - // 空送信 it('should return 400 if userId or password missing', async () => { const res = await request(app).post('/Register/Submit').send({}); expect(res.status).toBe(400); }); - // 重複検知 it('should return 409 if userId exists', async () => { DBPerf.mockResolvedValue([{ UserID: 'test' }]); const res = await request(app).post('/Register/Submit').send({ userId: 'test', password: 'pass' }); expect(res.status).toBe(409); }); - // 登録成功処理 it('should succeed with new user', async () => { DBPerf.mockResolvedValue([]); const res = await request(app).post('/Register/Submit').send({ userId: 'newuser', password: 'pass' }); diff --git a/Backend/Workspace/Routes/CreateRoom.js b/Backend/Workspace/Routes/CreateRoom.js index f9542d24..4c118385 100644 --- a/Backend/Workspace/Routes/CreateRoom.js +++ b/Backend/Workspace/Routes/CreateRoom.js @@ -1,13 +1,29 @@ -const express = require('express'); +import express from 'express'; const router = express.Router(); -const jwt = require("jsonwebtoken"); -const cookieParser = require("cookie-parser"); -const dotenv = require("dotenv"); -const path = require("path"); -const multer = require("multer"); -const fs = require("fs"); -const VCM = require('../Tools/VerifyCookieMiddleware'); -const DBPerf = require('../Tools/DBPerf'); +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 VCM from '../Tools/VerifyCookieMiddleware.js'; +import DBPerf from '../Tools/DBPerf.js'; +import CreateMosaic from '../Tools/CreateMosaicTx.js'; +import { decrypt } from '../Tools/AESControl.js'; + +// DB から取得した encryptedPrivateKey を復号 +const decryptedPrivateKey = decrypt(passwordWithPepper, encryptedPrivateKey); + +// mosaic 作成時に渡す +const { mosaicId, mosaicDefinitionTx } = CreateMosaicTx({ + senderPrivateKey: decryptedPrivateKey, + networkType: 'testnet' +}); + + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); // cookieを使う router.use(cookieParser()); @@ -42,30 +58,49 @@ function createFileName(originalName) { // ===ルーム作成API=== -router.post("/", VCM('LoginToken', process.env.LOGIN_SECRET), upload.fields([{ name: "RoomIcon", maxCount: 1 },{ name: "TokenIcon", maxCount: 1 }]), async (req, res) => { +router.post("/", VCM('LOGIN_TOKEN', process.env.LOGIN_SECRET), upload.fields([{ name: "RoomIcon", maxCount: 1 },{ name: "MosaicIcon", maxCount: 1 }]), async (req, res) => { try { const userID = req.auth.userId; + if (!userID) { + return res.status(401).json({ message: "Unauthorized" }); + } + const { RoomName, MosaicName } = req.body; if (!RoomName ||!MosaicName||!req.files?.RoomIcon ||!req.files?.MosaicIcon) { return res.status(400).json({ message: "Bad Request" }); } - //受け取ったルームIDをMosaic名としてブロックチェーンに登録する処理をここに追加しても良い //受け取ったMosaic情報をブロックチェーンに登録(発行)する処理をここに追加しても良い + //秘密鍵 + const senderPrivateKey = await DBPerf("秘密鍵の抽出", "SELECT PrivateKey FROM Identify WHERE UserID = ?", [userID]); + const RoomIconPath = await saveIcon(req.files.RoomIcon[0], "rooms"); - const MosaicIconPath = await saveIcon(req.files.TokenIcon[0], "tokens"); + const MosaicIconPath = await saveIcon(req.files.MosaicIcon[0], "mosaics"); await DBPerf( "INSERT Rooms", - "INSERT INTO Rooms(UserID, RoomName, isAdmin) VALUES (?, ?, ?)",[userID, RoomName, 1] + "INSERT INTO Rooms(UserID, RoomName) VALUES (?, ?)",[userID, RoomName] ); await DBPerf( "INSERT RoomsDetail", - "INSERT INTO RoomsDetail (RoomName, RoomIconPath, MosaicName, MosaicIconPath) VALUES (?, ?, ?, ?)", - [RoomName, RoomIconPath, MosaicName, MosaicIconPath] + "INSERT INTO RoomsDetails (RoomName, RoomIconPath, MosaicName) VALUES (?, ?, ?)", + [RoomName, RoomIconPath, MosaicName] + ); + + const { mosaicId: MosaicID } = await CreateMosaic({ + networkType: 'testnet', + senderPrivateKey: senderPrivateKey[0].PrivateKey, + transferable: false, + deadlineHours: 2 + }); + + await DBPerf( + "INSERT Mosaics", + "INSERT INTO Mosaics (MosaicName, MosaicID, MosaicIconPath) VALUES (?, ?, ?)", + [MosaicName, MosaicID, MosaicIconPath] ); res.status(201).json({ message: "Room created successfully" }); @@ -76,4 +111,4 @@ router.post("/", VCM('LoginToken', process.env.LOGIN_SECRET), upload.fields([{ n } ); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/Backend/Workspace/Routes/Login.js b/Backend/Workspace/Routes/Login.js index d953a73d..6704b8a1 100644 --- a/Backend/Workspace/Routes/Login.js +++ b/Backend/Workspace/Routes/Login.js @@ -1,10 +1,14 @@ -const express = require('express'); -const path = require('path'); -const dotenv = require('dotenv'); +import express from 'express'; +import path from 'path'; +import dotenv from 'dotenv'; const router = express.Router(); -const argon2 = require('argon2'); -const DBPerf = require('../Tools/DBPerf'); -const CreateCookie = require('../Tools/CreateCookie'); +import argon2 from 'argon2'; +import { fileURLToPath } from 'url'; +import DBPerf from '../Tools/DBPerf.js'; +import CreateCookie from '../Tools/CreateCookie.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); // use系 dotenv.config({ path: path.join(__dirname, "..", ".env") }); @@ -12,7 +16,7 @@ router.use(express.json()); // ========== ブロックチェーンの準備 ========== //const symbolSdk = require('symbol-sdk'); -const InverseVCM = require('../Tools/InverseVCM'); +import InverseVCM from '../Tools/InverseVCM.js'; //const facade = new symbolSdk.facade.SymbolFacade('testnet'); // ========== 画面表示 ========== @@ -64,4 +68,4 @@ router.post("/Submit", async (req, res) => { } }) -module.exports = router; +export default router; diff --git a/Backend/Workspace/Routes/NFC.js b/Backend/Workspace/Routes/NFC.js index 7e0dfa9e..8ee941db 100644 --- a/Backend/Workspace/Routes/NFC.js +++ b/Backend/Workspace/Routes/NFC.js @@ -1,11 +1,12 @@ -const express = require('express'); -const path = require('path'); -const dotenv = require('dotenv').config(); -const DBPref = require('../Tools/DBPerf'); -const argon2 = require('argon2'); +import express from 'express'; +import dotenv from 'dotenv'; +import DBPref from '../Tools/DBPerf.js'; +import argon2 from 'argon2'; const router = express.Router(); +dotenv.config(); + let latestcardUid = null; // 最新のカードUIDを保存する変数 let latestcardTime = null; // 最新のカード検知時間を保存する変数 @@ -71,5 +72,5 @@ router.post('/NFC', (req, res) => { res.status(200).send({ message: 'Success' }); }); -module.exports = router; +export default router; diff --git a/Backend/Workspace/Routes/Register.js b/Backend/Workspace/Routes/Register.js new file mode 100644 index 00000000..814379e0 --- /dev/null +++ b/Backend/Workspace/Routes/Register.js @@ -0,0 +1,95 @@ +// Register.js +import express from 'express'; +import dotenv from 'dotenv'; +import cookieParser from 'cookie-parser'; +import argon2 from 'argon2'; +import DBPerf from '../Tools/DBPerf.js'; +import { encrypt } from '../Tools/AESControl.js'; +import { PrivateKey } from 'symbol-sdk'; +import { SymbolFacade } from 'symbol-sdk/symbol'; +import { fileURLToPath } from 'url'; +import { dirname, join } from 'path'; + +const router = express.Router(); + +// ES Module で __dirname を使えるようにする +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +// 環境変数読み込み +dotenv.config({ path: join(__dirname, '..', '.env') }); + +// use系 +router.use(cookieParser()); +router.use(express.json()); + +// ========== 画面表示 ========== +// /Register/へのアクセスでRegister画面表示 +router.get('/', (req, res) => { + console.log("/Register-API is running"); + res.sendFile(join(__dirname, "..", "..", "..", "Frontend", "dist", "index.html")); +}); + +// ========== 情報送信 ========== +// /Register/SubmitへのアクセスでRegister情報を登録 +router.post('/Submit', async (req, res) => { + console.log("Submit-API is running"); + try { + // 情報の取得 + const { userId, password } = req.body; + + if (!userId || !password) { + return res.status(400).json({ message: "Bad Request: UserIDかPasswordが不足しています。" }); + } + + // ユーザーIDが被っていないか確認 + const exist = await DBPerf( + "Duplicate Check For UserID", + "SELECT * FROM Identify WHERE UserID = ?", + [userId] + ); + if (exist.length > 0) { + return res.status(409).json({ message: "Conflict: このユーザーIDはすでに使われています" }); + } + + // ========== 秘密鍵保存 ========== + const privateKeyObject = PrivateKey.random(); + const privateKey = privateKeyObject.toString(); + const facade = new SymbolFacade('testnet'); + const account = facade.createAccount(privateKeyObject); + const address = account.address.toString(); + + // Pepper を .env から取得 + const pepper = process.env.PEPPER; + if (!pepper) { + return res.status(500).json({ message: "Internal Server Error: サーバー設定エラー" }); + } + + const passwordWithPepper = password + pepper; + + // 秘密鍵の暗号化 + const encryptedPrivateKey = encrypt(passwordWithPepper, privateKey); + + // パスワード + Pepper を Hash 化 + const hashedPassword = await argon2.hash(passwordWithPepper, { + type: argon2.argon2id, + memoryCost: 2 ** 16, // 推奨: 64MB + timeCost: 5, // 計算回数 + parallelism: 1 // 並列数 + }); + + // DB に登録 + await DBPerf( + "Insert Into Identify", + "INSERT INTO Identify (UserID, Password, PrivateKey, Address) VALUES (?, ?, ?, ?)", + [userId, hashedPassword, encryptedPrivateKey, address] + ); + + res.status(200).json({ redirect: "/Home" }); + } catch (err) { + console.error("Register Error:", err); + res.status(500).json({ message: "Internal Server Error: サーバーエラーが発生しました。" }); + } +}); + +export default router; diff --git a/Backend/Workspace/Routes/RoomList.js b/Backend/Workspace/Routes/RoomList.js index cb8c4c80..59f1e70b 100644 --- a/Backend/Workspace/Routes/RoomList.js +++ b/Backend/Workspace/Routes/RoomList.js @@ -1,6 +1,6 @@ -const express = require('express'); -const DBPerf = require('../Tools/DBPerf'); -const VCM = require('../Tools/VerifyCookieMiddleware'); +import express from 'express'; +import DBPerf from '../Tools/DBPerf.js'; +import VCM from '../Tools/VerifyCookieMiddleware.js'; const router = express.Router(); @@ -16,4 +16,4 @@ router.get('/RoomList', VCM('LoginToken', process.env.LOGIN_SECRET), async (req, res.json({ RoomList }); }); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/Backend/Workspace/Routes/SendToken.js b/Backend/Workspace/Routes/SendToken.js index 6654c182..dbba3007 100644 --- a/Backend/Workspace/Routes/SendToken.js +++ b/Backend/Workspace/Routes/SendToken.js @@ -1,12 +1,12 @@ -const express = require('express'); +import express from 'express'; const router = express.Router(); -const jwt = require('jsonwebtoken'); -const DBPerf = require('../Tools/DBPerf'); -const VCM = require('../Tools/VerifyCookieMiddleware'); -const LeftToken = require('../Tools/LeftToken'); -const decrypt = require('../Tools/AESControl'); -const CreateTransferTx = require('../Tools/CreateTransferTx'); -const SignAndAnnounce = require('../Tools/SignAndAnnounce'); +import jwt from 'jsonwebtoken'; +import DBPerf from '../Tools/DBPerf.js'; +import VCM from '../Tools/VerifyCookieMiddleware.js'; +import LeftToken from '../Tools/LeftToken.js'; +import { decrypt } from '../Tools/AESControl.js'; +import CreateTransferTx from '../Tools/CreateTransferTx.js'; +import SignAndAnnounce from '../Tools/SignAndAnnounce.js'; // 送金処理 router.post('/SendToken', VCM('LoginToken', process.env.LOGIN_SECRET), async(req, res) => { @@ -93,7 +93,7 @@ router.get('/LeftToken', VCM('LoginToken', process.env.LOGIN_SECRET), async(req, // res.status(200).send(roomDetail); // }); -module.exports = router; +export default router; diff --git a/Backend/Workspace/Routes/SendTokenByNFC.js b/Backend/Workspace/Routes/SendTokenByNFC.js index 25bda3b5..95c01391 100644 --- a/Backend/Workspace/Routes/SendTokenByNFC.js +++ b/Backend/Workspace/Routes/SendTokenByNFC.js @@ -1,13 +1,13 @@ -const express = require('express'); +import express from 'express'; const router = express.Router(); -const crypto = require('crypto'); +import crypto from 'crypto'; // ツール類の読み込み -const DBPerf = require('../Tools/DBPerf'); -const VCM = require('../Tools/VerifyCookieMiddleware'); -const decrypt = require('../Tools/AESControl'); -const CreateTransferTx = require('../Tools/CreateTransferTx'); -const SignAndAnnounce = require('../Tools/SignAndAnnounce'); +import DBPerf from '../Tools/DBPerf.js'; +import VCM from '../Tools/VerifyCookieMiddleware.js'; +import { decrypt } from '../Tools/AESControl.js'; +import CreateTransferTx from '../Tools/CreateTransferTx.js'; +import SignAndAnnounce from '../Tools/SignAndAnnounce.js'; // ============================== // 予約管理 (オンメモリ) @@ -193,4 +193,4 @@ router.post('/NFC', async (req, res) => { } }); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/Backend/Workspace/Server.js b/Backend/Workspace/Server.js index 0a53740b..6cb08a05 100644 --- a/Backend/Workspace/Server.js +++ b/Backend/Workspace/Server.js @@ -1,16 +1,20 @@ -const express = require('express'); -const path = require('path'); -// 絶対パス指定 -const dotenv = require('dotenv').config({ path: path.resolve(__dirname, '.env') }); -const cookieParser = require('cookie-parser'); -// Routing自動化 -const fs = require('fs'); +import express from 'express'; +import path from 'path'; +import dotenv from 'dotenv'; +import cookieParser from 'cookie-parser'; +import cors from 'cors'; +import fs from 'fs'; +import { fileURLToPath, pathToFileURL } from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +dotenv.config({ path: path.resolve(__dirname, '.env') }); const routesDir = path.join(__dirname, 'Routes'); const app = express(); // ========== 初期設定 ========== -PORT = process.env.PORT || 5000; +const PORT = process.env.PORT || 5000; // ========== use系 ========== app.use(express.json()); @@ -21,21 +25,22 @@ app.use(express.static(path.join(__dirname, '..', 'Frontend', 'dist'))); // ========== Routes ========== // fs.readdirSync(ディレクトリパス)でそのディレクトリ内のファイル名を配列で取得 -fs.readdirSync(routesDir).forEach((file) => { +for (const file of fs.readdirSync(routesDir)) { // js ファイルだけ対象 - if (!file.endsWith('.js')) return; + if (!file.endsWith('.js')) continue; // APIのエンドポイントをファイル名から作成 const routeName = path.basename(file, '.js'); const routePath = `/${routeName}`; // Routing処理 - const route = require(path.join(routesDir, file)); - app.use(routePath, route); + const routeFileUrl = pathToFileURL(path.join(routesDir, file)).href; + const routeModule = await import(routeFileUrl); + app.use(routePath, routeModule.default); // コンソール表示 console.log(`Route mounted: ${routePath}`); -}); +} // ========== listen ========== // SPA fallback: 未処理の GET リクエストは index.html を返す diff --git a/Backend/Workspace/Tools/AESControl.js b/Backend/Workspace/Tools/AESControl.js index aab86947..d57255ff 100644 --- a/Backend/Workspace/Tools/AESControl.js +++ b/Backend/Workspace/Tools/AESControl.js @@ -1,7 +1,7 @@ -const crypto = require('crypto'); +import crypto from 'crypto'; // ========== 暗号化 ========== -function encrypt(plainKey, plainText) { +export function encrypt(plainKey, plainText) { // ① 平文1から32byteの鍵を作る const key = crypto .createHash('sha256') @@ -29,7 +29,7 @@ function encrypt(plainKey, plainText) { } // ========== 復号化 ========== -function decrypt(plainKey, encryptedObj) { +export function decrypt(plainKey, encryptedObj) { const key = crypto .createHash('sha256') .update(plainKey) @@ -50,7 +50,7 @@ function decrypt(plainKey, encryptedObj) { return decrypted.toString('utf8'); } -module.exports = { +export default { encrypt, decrypt }; \ No newline at end of file diff --git a/Backend/Workspace/Tools/CreateCookie.js b/Backend/Workspace/Tools/CreateCookie.js index efa95cc4..7788ac1b 100644 --- a/Backend/Workspace/Tools/CreateCookie.js +++ b/Backend/Workspace/Tools/CreateCookie.js @@ -16,7 +16,7 @@ Server.jsにおいて.envを絶対パス指定にしておきましょう。 例: const dotenv = require('dotenv').config({ path: path.resolve(__dirname, '.env') }); ========== Manual ==========*/ -const jwt = require('jsonwebtoken'); +import jwt from 'jsonwebtoken'; // CreateCookie.js function CreateCookie({res, cookieName, payload, secretKey, deadlineHours, httpOnly = true, sameSite = 'strict'}) { @@ -35,4 +35,4 @@ function CreateCookie({res, cookieName, payload, secretKey, deadlineHours, httpO console.log(`[${logOwner}] Shutdown!`); } -module.exports = CreateCookie; \ No newline at end of file +export default CreateCookie; \ No newline at end of file diff --git a/Backend/Workspace/Tools/CreateMosaicTx.js b/Backend/Workspace/Tools/CreateMosaicTx.js new file mode 100644 index 00000000..1db01b7d --- /dev/null +++ b/Backend/Workspace/Tools/CreateMosaicTx.js @@ -0,0 +1,60 @@ +// CreateMosaicTx.js +import { PrivateKey } from 'symbol-sdk'; +import { SymbolFacade, KeyPair } from 'symbol-sdk/symbol'; + +export default function CreateMosaicTx({ + networkType = 'testnet', + senderPrivateKey, + transferable = true, + deadlineHours = 2 +}) { + const logOwner = "CreateMosaicTx"; + console.log(`\n${logOwner}-Function is running!\n`); + console.log(`[${logOwner}] Input => networkType: ${networkType}, transferable: ${transferable}, deadlineHours: ${deadlineHours}`); + + // Facade 初期化 + const facade = new SymbolFacade(networkType); + + // 秘密鍵 → KeyPair + const keyPair = new KeyPair(new PrivateKey(senderPrivateKey)); + + // Deadline 作成 + const deadline = facade.network.fromDatetime(Date.now()).addHours(deadlineHours).timestamp; + + // 0〜2^32-1のランダム数からMosaicIDを生成するためのnonceを生成 + const nonce = Math.floor(Math.random() * 0xffffffff); + + // モザイクを定義するトランザクション作成 + const mosaicDefinitionTx = facade.transactionFactory.create({ + type: 'mosaic_definition_transaction_v1', + signerPublicKey: keyPair.publicKey, + duration: 0, + nonce: nonce, + mosaicId: undefined, + flags: { + supplyMutable: true, + transferable: transferable, + restrictable: false, + revocable: false, + }, + divisibility: 0, + deadline: deadline + }); + + // MosaicIDの計算 + const mosaicId = facade.mosaic.createMosaicId(nonce, keyPair.publicKey).toHex(); + + console.log(`[${logOwner}] Output => mosaicDefinitionTx: \n${{ + type: mosaicDefinitionTx.type, + supplyMutable: mosaicDefinitionTx.flags.supplyMutable, + transferable: mosaicDefinitionTx.flags.transferable, + }}\nMosaicID: ${mosaicId}`); + console.log(`[${logOwner}] Shutdown!`); + + return { + mosaicId, + mosaicDefinitionTx, + keyPair, + facade + }; +} diff --git a/Backend/Workspace/Tools/CreateTransferTx.js b/Backend/Workspace/Tools/CreateTransferTx.js index bb9f8308..58179e90 100644 --- a/Backend/Workspace/Tools/CreateTransferTx.js +++ b/Backend/Workspace/Tools/CreateTransferTx.js @@ -23,7 +23,8 @@ mosaicはBigint型(数字末尾にnがつく)で指定する必要がある。 ========== Manual ==========*/ // CreateTransferTx.js -const symbolSdk = require('symbol-sdk'); +import { PrivateKey } from 'symbol-sdk'; +import { SymbolFacade, KeyPair } from 'symbol-sdk/symbol'; function CreateTransferTx({ networkType = 'testnet', @@ -40,9 +41,9 @@ function CreateTransferTx({ console.log(`[${logOwner}] Input => networkType: ${networkType}, recipientRawAddress: ${recipientRawAddress}, messageText: ${messageText}, mosaics: ${mosaics}, deadlineHours: ${deadlineHours}`); // Facade 初期化 - const facade = new symbolSdk.facade.SymbolFacade(networkType); + const facade = new SymbolFacade(networkType); // 秘密鍵 → KeyPair - const keyPair = new symbolSdk.symbol.KeyPair( new symbolSdk.PrivateKey(senderPrivateKey) ); + const keyPair = new KeyPair(new PrivateKey(senderPrivateKey)); // 宛先アドレス解析(Base32 → 生データ + ネットワーク検証) const recipient = facade.network.parseAddress(recipientRawAddress); // Deadline 作成 @@ -78,4 +79,4 @@ function CreateTransferTx({ }; } -module.exports = CreateTransferTx; +export default CreateTransferTx; diff --git a/Backend/Workspace/Tools/DBPerf.js b/Backend/Workspace/Tools/DBPerf.js index 2d1a9b49..0d645578 100644 --- a/Backend/Workspace/Tools/DBPerf.js +++ b/Backend/Workspace/Tools/DBPerf.js @@ -19,6 +19,19 @@ JSON ========== Manual ==========*/ // DBPerf.js +import mysql from 'mysql2/promise'; + +// DB接続設定 + +// DB接続プールを作成 +const db = mysql.createPool({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.DB_NAME, +}); + +// DB接続プールの作成 async function DBPerf(label, query, elements) { // Startup Log const logOwner = "DBPerf"; @@ -46,4 +59,4 @@ async function DBPerf(label, query, elements) { } } -module.exports = DBPerf; \ No newline at end of file +export default DBPerf; \ No newline at end of file diff --git a/Backend/Workspace/Tools/InverseVCM.js b/Backend/Workspace/Tools/InverseVCM.js index 217075fb..24606094 100644 --- a/Backend/Workspace/Tools/InverseVCM.js +++ b/Backend/Workspace/Tools/InverseVCM.js @@ -15,7 +15,7 @@ app.get("/", InverseVCM('LoginToken', LOGIN_SECRET), (req, res) => {...]}); のようにしてミドルウェアとして使う ========== Manual ==========*/ -const jwt = require('jsonwebtoken'); +import jwt from 'jsonwebtoken'; // InverseVCM.js function InverseVCM(cookieName, secretKey) { @@ -49,4 +49,4 @@ function InverseVCM(cookieName, secretKey) { }; } -module.exports = InverseVCM; \ No newline at end of file +export default InverseVCM; \ No newline at end of file diff --git a/Backend/Workspace/Tools/LeftToken.js b/Backend/Workspace/Tools/LeftToken.js index e6321ba4..46232a88 100644 --- a/Backend/Workspace/Tools/LeftToken.js +++ b/Backend/Workspace/Tools/LeftToken.js @@ -1,4 +1,4 @@ -const axios = require('axios'); +import axios from 'axios'; async function LeftToken(address, NODE_URL) { try{ @@ -10,4 +10,4 @@ async function LeftToken(address, NODE_URL) { } } -module.exports = LeftToken; \ No newline at end of file +export default LeftToken; \ No newline at end of file diff --git a/Backend/Workspace/Tools/SignAndAnnounce.js b/Backend/Workspace/Tools/SignAndAnnounce.js index f2138918..cab3840c 100644 --- a/Backend/Workspace/Tools/SignAndAnnounce.js +++ b/Backend/Workspace/Tools/SignAndAnnounce.js @@ -45,4 +45,4 @@ async function SignAndAnnounce(tx, keyPair, facade, nodeUrl) { return; } -module.exports = SignAndAnnounce; +export default SignAndAnnounce; diff --git a/Backend/Workspace/Tools/VCM.js b/Backend/Workspace/Tools/VCM.js index a0a1b996..1610e669 100644 --- a/Backend/Workspace/Tools/VCM.js +++ b/Backend/Workspace/Tools/VCM.js @@ -16,7 +16,7 @@ app.get("/", VCM('LoginToken', LOGIN_SECRET), (req, res) => {...]}); のようにしてミドルウェアとして使う ========== Manual ==========*/ -const jwt = require('jsonwebtoken'); +import jwt from 'jsonwebtoken'; // VerifyCookieMiddleware.js function VCM(cookieName, secretKey) { @@ -49,4 +49,4 @@ function VCM(cookieName, secretKey) { }; } -module.exports = VCM; \ No newline at end of file +export default VCM; \ No newline at end of file diff --git a/Backend/Workspace/Tools/VerifyCookieMiddleware.js b/Backend/Workspace/Tools/VerifyCookieMiddleware.js index 8adfd7fd..1de96241 100644 --- a/Backend/Workspace/Tools/VerifyCookieMiddleware.js +++ b/Backend/Workspace/Tools/VerifyCookieMiddleware.js @@ -16,7 +16,7 @@ app.get("/", Auth(LOGIN_SECRET, 'LoginToken'), (req, res) => {...]}); のようにしてミドルウェアとして使う ========== Manual ==========*/ -const jwt = require('jsonwebtoken'); +import jwt from 'jsonwebtoken'; // VerifyCookieMiddleware.js function VCM(cookieName, secretKey) { @@ -47,4 +47,4 @@ function VCM(cookieName, secretKey) { }; } -module.exports = VCM; +export default VCM; diff --git a/Backend/node_modules/.bin/baseline-browser-mapping b/Backend/node_modules/.bin/baseline-browser-mapping index d2961883..1977474b 120000 --- a/Backend/node_modules/.bin/baseline-browser-mapping +++ b/Backend/node_modules/.bin/baseline-browser-mapping @@ -1 +1,16 @@ -../baseline-browser-mapping/dist/cli.js \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../baseline-browser-mapping/dist/cli.js" "$@" +else + exec node "$basedir/../baseline-browser-mapping/dist/cli.js" "$@" +fi diff --git a/Backend/node_modules/.bin/browserslist b/Backend/node_modules/.bin/browserslist index 3cd991b2..60e71ad8 120000 --- a/Backend/node_modules/.bin/browserslist +++ b/Backend/node_modules/.bin/browserslist @@ -1 +1,16 @@ -../browserslist/cli.js \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../browserslist/cli.js" "$@" +else + exec node "$basedir/../browserslist/cli.js" "$@" +fi diff --git a/Backend/node_modules/.bin/esparse b/Backend/node_modules/.bin/esparse index 7423b18b..601762ce 120000 --- a/Backend/node_modules/.bin/esparse +++ b/Backend/node_modules/.bin/esparse @@ -1 +1,16 @@ -../esprima/bin/esparse.js \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../esprima/bin/esparse.js" "$@" +else + exec node "$basedir/../esprima/bin/esparse.js" "$@" +fi diff --git a/Backend/node_modules/.bin/esvalidate b/Backend/node_modules/.bin/esvalidate index 16069eff..e2fee1f1 120000 --- a/Backend/node_modules/.bin/esvalidate +++ b/Backend/node_modules/.bin/esvalidate @@ -1 +1,16 @@ -../esprima/bin/esvalidate.js \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../esprima/bin/esvalidate.js" "$@" +else + exec node "$basedir/../esprima/bin/esvalidate.js" "$@" +fi diff --git a/Backend/node_modules/.bin/glob b/Backend/node_modules/.bin/glob index 85c9c1db..6fbc4bb8 120000 --- a/Backend/node_modules/.bin/glob +++ b/Backend/node_modules/.bin/glob @@ -1 +1,16 @@ -../glob/dist/esm/bin.mjs \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../glob/dist/esm/bin.mjs" "$@" +else + exec node "$basedir/../glob/dist/esm/bin.mjs" "$@" +fi diff --git a/Backend/node_modules/.bin/import-local-fixture b/Backend/node_modules/.bin/import-local-fixture index ff4b1048..3a654413 120000 --- a/Backend/node_modules/.bin/import-local-fixture +++ b/Backend/node_modules/.bin/import-local-fixture @@ -1 +1,16 @@ -../import-local/fixtures/cli.js \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../import-local/fixtures/cli.js" "$@" +else + exec node "$basedir/../import-local/fixtures/cli.js" "$@" +fi diff --git a/Backend/node_modules/.bin/jest b/Backend/node_modules/.bin/jest index 61c18615..61b6f565 120000 --- a/Backend/node_modules/.bin/jest +++ b/Backend/node_modules/.bin/jest @@ -1 +1,16 @@ -../jest/bin/jest.js \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../jest/bin/jest.js" "$@" +else + exec node "$basedir/../jest/bin/jest.js" "$@" +fi diff --git a/Backend/node_modules/.bin/js-yaml b/Backend/node_modules/.bin/js-yaml index 9dbd010d..82416ef1 120000 --- a/Backend/node_modules/.bin/js-yaml +++ b/Backend/node_modules/.bin/js-yaml @@ -1 +1,16 @@ -../js-yaml/bin/js-yaml.js \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../js-yaml/bin/js-yaml.js" "$@" +else + exec node "$basedir/../js-yaml/bin/js-yaml.js" "$@" +fi diff --git a/Backend/node_modules/.bin/jsesc b/Backend/node_modules/.bin/jsesc index 7237604c..879c4133 120000 --- a/Backend/node_modules/.bin/jsesc +++ b/Backend/node_modules/.bin/jsesc @@ -1 +1,16 @@ -../jsesc/bin/jsesc \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../jsesc/bin/jsesc" "$@" +else + exec node "$basedir/../jsesc/bin/jsesc" "$@" +fi diff --git a/Backend/node_modules/.bin/json5 b/Backend/node_modules/.bin/json5 index 217f3798..abf72a4e 120000 --- a/Backend/node_modules/.bin/json5 +++ b/Backend/node_modules/.bin/json5 @@ -1 +1,16 @@ -../json5/lib/cli.js \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../json5/lib/cli.js" "$@" +else + exec node "$basedir/../json5/lib/cli.js" "$@" +fi diff --git a/Backend/node_modules/.bin/mime b/Backend/node_modules/.bin/mime index fbb7ee0e..7751de3c 120000 --- a/Backend/node_modules/.bin/mime +++ b/Backend/node_modules/.bin/mime @@ -1 +1,16 @@ -../mime/cli.js \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../mime/cli.js" "$@" +else + exec node "$basedir/../mime/cli.js" "$@" +fi diff --git a/Backend/node_modules/.bin/napi-postinstall b/Backend/node_modules/.bin/napi-postinstall index 8407c964..985cc4c7 120000 --- a/Backend/node_modules/.bin/napi-postinstall +++ b/Backend/node_modules/.bin/napi-postinstall @@ -1 +1,16 @@ -../napi-postinstall/lib/cli.js \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../napi-postinstall/lib/cli.js" "$@" +else + exec node "$basedir/../napi-postinstall/lib/cli.js" "$@" +fi diff --git a/Backend/node_modules/.bin/node-which b/Backend/node_modules/.bin/node-which index 6f8415ec..b49b03f7 120000 --- a/Backend/node_modules/.bin/node-which +++ b/Backend/node_modules/.bin/node-which @@ -1 +1,16 @@ -../which/bin/node-which \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../which/bin/node-which" "$@" +else + exec node "$basedir/../which/bin/node-which" "$@" +fi diff --git a/Backend/node_modules/.bin/parser b/Backend/node_modules/.bin/parser index ce7bf97e..7696ad41 120000 --- a/Backend/node_modules/.bin/parser +++ b/Backend/node_modules/.bin/parser @@ -1 +1,16 @@ -../@babel/parser/bin/babel-parser.js \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../@babel/parser/bin/babel-parser.js" "$@" +else + exec node "$basedir/../@babel/parser/bin/babel-parser.js" "$@" +fi diff --git a/Backend/node_modules/.bin/semver b/Backend/node_modules/.bin/semver index 5aaadf42..97c53279 120000 --- a/Backend/node_modules/.bin/semver +++ b/Backend/node_modules/.bin/semver @@ -1 +1,16 @@ -../semver/bin/semver.js \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../semver/bin/semver.js" "$@" +else + exec node "$basedir/../semver/bin/semver.js" "$@" +fi diff --git a/Backend/node_modules/.bin/update-browserslist-db b/Backend/node_modules/.bin/update-browserslist-db index b11e16f3..cced63c4 120000 --- a/Backend/node_modules/.bin/update-browserslist-db +++ b/Backend/node_modules/.bin/update-browserslist-db @@ -1 +1,16 @@ -../update-browserslist-db/cli.js \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../update-browserslist-db/cli.js" "$@" +else + exec node "$basedir/../update-browserslist-db/cli.js" "$@" +fi diff --git a/Backend/node_modules/.package-lock.json b/Backend/node_modules/.package-lock.json index fd111c8b..43f55e0c 100644 --- a/Backend/node_modules/.package-lock.json +++ b/Backend/node_modules/.package-lock.json @@ -1026,6 +1026,12 @@ "@sinonjs/commons": "^3.0.1" } }, + "node_modules/@symbol-blockchain-community/symbol-rest-client": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@symbol-blockchain-community/symbol-rest-client/-/symbol-rest-client-1.0.2.tgz", + "integrity": "sha512-RaSmjsQ+BKXNtnzSPa+y+O6wQaAfjawZ1uiRHmPZs3g7xB4ATwWRAD/IZCRjAzoQdh/xFakO05q0vnpqL6KrGQ==", + "license": "MIT" + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -1139,38 +1145,10 @@ "dev": true, "license": "ISC" }, - "node_modules/@unrs/resolver-binding-darwin-arm64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", - "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@unrs/resolver-binding-linux-x64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", - "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", - "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", "cpu": [ "x64" ], @@ -1178,7 +1156,7 @@ "license": "MIT", "optional": true, "os": [ - "linux" + "win32" ] }, "node_modules/accepts": { @@ -1296,7 +1274,6 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true, "license": "MIT" }, "node_modules/available-typed-arrays": { @@ -1323,6 +1300,17 @@ "node": ">= 6.0.0" } }, + "node_modules/axios": { + "version": "1.13.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", + "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/babel-jest": { "version": "30.2.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.2.0.tgz", @@ -1910,7 +1898,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" @@ -2155,7 +2142,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.4.0" @@ -2349,7 +2335,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -2584,6 +2569,26 @@ "node": ">=8" } }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", @@ -2620,7 +2625,6 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", - "dev": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -2637,7 +2641,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -2647,7 +2650,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -2699,21 +2701,6 @@ "dev": true, "license": "ISC" }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -4790,6 +4777,12 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/pure-rand": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", diff --git a/Backend/node_modules/@unrs/resolver-binding-linux-x64-gnu/README.md b/Backend/node_modules/@unrs/resolver-binding-linux-x64-gnu/README.md deleted file mode 100644 index 4051db30..00000000 --- a/Backend/node_modules/@unrs/resolver-binding-linux-x64-gnu/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# `@unrs/resolver-binding-linux-x64-gnu` - -This is the **x86_64-unknown-linux-gnu** binary for `@unrs/resolver-binding` diff --git a/Backend/node_modules/@unrs/resolver-binding-linux-x64-gnu/package.json b/Backend/node_modules/@unrs/resolver-binding-linux-x64-gnu/package.json deleted file mode 100644 index 61b8720d..00000000 --- a/Backend/node_modules/@unrs/resolver-binding-linux-x64-gnu/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "@unrs/resolver-binding-linux-x64-gnu", - "version": "1.11.1", - "cpu": [ - "x64" - ], - "main": "resolver.linux-x64-gnu.node", - "files": [ - "resolver.linux-x64-gnu.node" - ], - "description": "UnRS Resolver Node API with PNP support", - "author": "JounQin (https://www.1stG.me)", - "homepage": "https://github.com/unrs/unrs-resolver#readme", - "license": "MIT", - "publishConfig": { - "registry": "https://registry.npmjs.org", - "access": "public" - }, - "repository": "git+https://github.com/unrs/unrs-resolver.git", - "os": [ - "linux" - ], - "libc": [ - "glibc" - ] -} \ No newline at end of file diff --git a/Backend/node_modules/@unrs/resolver-binding-linux-x64-gnu/resolver.linux-x64-gnu.node b/Backend/node_modules/@unrs/resolver-binding-linux-x64-gnu/resolver.linux-x64-gnu.node deleted file mode 100644 index 0fff14d98fdf9223dd690a9c6454b190a4bc2922..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2272024 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