Spaces:
Build error
Build error
| /** | |
| npm install hono jsonwebtoken bcrypt | |
| npm install -D typescript ts-node @types/node @types/jsonwebtoken @types/bcrypt | |
| */ | |
| //@ts-ignore | |
| import bcrypt from "bcrypt"; | |
| //@ts-ignore | |
| import jwt from "jsonwebtoken"; | |
| //@ts-ignore | |
| import crypto from "crypto"; | |
| import { v4 as uuidv4 } from "uuid"; | |
| // π ν€ κΈΈμ΄λ₯Ό AES-256-CBC μꡬμ¬νμΈ 32λ°μ΄νΈλ‘ λ§μΆλ μ νΈλ¦¬ν° ν¨μ | |
| // κΈΈμ΄κ° λΆμ‘±νλ©΄ 0x00μΌλ‘ ν¨λ©νκ³ , μ΄κ³Όνλ©΄ μλΌλ λλ€. (보μ κ²½κ³ ) | |
| const getEncryptionKeyBuffer = (): Buffer => { | |
| const KEY_BYTE_LENGTH = 32; | |
| let keyBuffer = Buffer.from(ENCRYPTION_KEY, "utf8"); | |
| if (keyBuffer.length === KEY_BYTE_LENGTH) { | |
| return keyBuffer; | |
| } | |
| if (keyBuffer.length > KEY_BYTE_LENGTH) { | |
| // 32λ°μ΄νΈ μ΄κ³Ό μ, μ λΆλΆλ§ μ¬μ© (μλΌλ) | |
| return keyBuffer.subarray(0, KEY_BYTE_LENGTH); | |
| } else { | |
| // 32λ°μ΄νΈ λ―Έλ¬ μ, 0μΌλ‘ μ±μμ (ν¨λ©) 32λ°μ΄νΈλ₯Ό λ§λλλ€. | |
| const padding = Buffer.alloc(KEY_BYTE_LENGTH - keyBuffer.length, 0); | |
| return Buffer.concat([keyBuffer, padding]); | |
| } | |
| }; | |
| const JWT_SECRET = String(process.env.JWT_SECRET); | |
| const ENCRYPTION_KEY = | |
| process.env.ENCRYPTION_KEY || "your_32_byte_encryption_key_123456"; // 32 bytes | |
| const ENCRYPTION_KEY_BUFFER = getEncryptionKeyBuffer(); | |
| const IV_LENGTH = 16; // AES block size | |
| // λ¨λ°©ν₯ μνΈν: λΉλ°λ²νΈ ν΄μ μμ± | |
| export const hashPassword = async (password: string): Promise<string> => { | |
| const saltRounds = 10; | |
| return await bcrypt.hash(password, saltRounds); | |
| }; | |
| // λ¨λ°©ν₯ μνΈν: λΉλ°λ²νΈ κ²μ¦ | |
| export const comparePassword = async ( | |
| password: string, | |
| hash: string | |
| ): Promise<boolean> => { | |
| return await bcrypt.compare(password, hash); | |
| }; | |
| // μλ°©ν₯ μνΈν: λ°μ΄ν° μνΈν | |
| export const encryptData = (data: string): string => { | |
| const iv = crypto.randomBytes(IV_LENGTH); | |
| const cipher = crypto.createCipheriv( | |
| "aes-256-cbc", | |
| ENCRYPTION_KEY_BUFFER, | |
| iv | |
| ); | |
| let encrypted = cipher.update(data); | |
| encrypted = Buffer.concat([encrypted, cipher.final()]); | |
| return iv.toString("hex") + ":" + encrypted.toString("hex"); | |
| }; | |
| // μλ°©ν₯ μνΈν: λ°μ΄ν° 볡νΈν | |
| export const decryptData = (encryptedData: string): string => { | |
| const parts = encryptedData.split(":"); | |
| const iv = Buffer.from(parts[0], "hex"); | |
| const encryptedText = Buffer.from(parts[1], "hex"); | |
| const decipher = crypto.createDecipheriv( | |
| "aes-256-cbc", | |
| ENCRYPTION_KEY_BUFFER, | |
| iv | |
| ); | |
| let decrypted = decipher.update(encryptedText); | |
| decrypted = Buffer.concat([decrypted, decipher.final()]); | |
| return decrypted.toString(); | |
| }; | |
| // JWT μμ± | |
| export const generateToken = ( | |
| payload: any, | |
| expiresIn: string = "1h" | |
| ): string => { | |
| //@ts-ignore | |
| return jwt.sign(payload, JWT_SECRET, { expiresIn }); | |
| }; | |
| /** JWT κ²μ¦. return := payload */ | |
| export const verifyToken = (token: string): any => { | |
| try { | |
| return jwt.verify(token, JWT_SECRET); | |
| } catch (error) { | |
| return null; | |
| } | |
| }; | |
| // JWT ν΄λ (κ²μ¦ μμ΄ νμ΄λ‘λλ§ μΆμΆ) | |
| export const decodeToken = (token: string): object | null => { | |
| try { | |
| const payload = token.split(".")[1]; | |
| const decoded = Buffer.from(payload, "base64").toString("utf-8"); | |
| return JSON.parse(decoded); | |
| } catch (error) { | |
| return null; | |
| } | |
| }; | |
| /** | |
| * νμ¬ μκ°(λ°λ¦¬μ΄)κ³Ό UUIDλ₯Ό μ‘°ν©νμ¬ νμΌ μ΄λ¦μΌλ‘ μμ νκ² μ¬μ©ν μ μλ λ¬Έμμ΄μ μμ±ν©λλ€. | |
| * μμ±λ λ¬Έμμ΄μ κΈΈμ΄λ 255μ λ―Έλ§μ λλ€. | |
| * (UUID: 36μ, λ°λ¦¬μ΄: μ½ 13μ, ꡬλΆμ: 1μ = μ΅λ μ½ 50μ) | |
| * * @returns {string} μ‘°ν©λ νμΌ μ΄λ¦ λ¬Έμμ΄ (μ: "1730635200000-a1b2c3d4-e5f6-4000-8000-000000000000") | |
| */ | |
| export function createUniqueFileName(): string { | |
| // 1. νμ¬ μκ°μ λ°λ¦¬μ΄ λ¨μλ‘ κ°μ Έμ΅λλ€. | |
| const timestamp = Date.now().toString(); | |
| // 2. UUID v4λ₯Ό μμ±ν©λλ€. (μ: "a1b2c3d4-e5f6-4000-8000-000000000000") | |
| // μ΄ λ¬Έμμ΄μ νμΌ μ΄λ¦μΌλ‘ μμ νκ² μ¬μ©λ μ μλ νμ΄νμ ν¬ν¨ν©λλ€. | |
| const uniqueId = uuidv4(); | |
| // 3. λ κ°μ νμ΄ν(-)μΌλ‘ μ°κ²°ν©λλ€. | |
| const uniqueFileName = `${timestamp}-${uniqueId}`; | |
| // λ¬Έμμ΄ κΈΈμ΄ νμΈ (255μ λ―Έλ§μ νμ€ν λ§μ‘±ν©λλ€) | |
| // console.log(`μμ±λ νμΌ μ΄λ¦: ${uniqueFileName}, κΈΈμ΄: ${uniqueFileName.length}`); | |
| return uniqueFileName; | |
| } | |
| /** | |
| * μ΄λ―Έμ§ κ²½λ‘κ° ν΄λλ‘ λμμΌλ©΄, μ΄κ±Έ μλ²μμ μ§μ μ€νΈλ¦¬λ° νλ μ£Όμλ‘ λ°κΏλλ€. | |
| * ν΄λΉ νλ‘μ νΈ κ²μν μ μ©μΌλ‘ λ§λ€μ΄μ‘μ΅λλ€. λ²μ© μ»΄ν¬λνΈ μλλλ€. | |
| * localhost:3000 λΆλΆμ μμμ μμ νμΈμ. | |
| */ | |
| export function makeBoardImgURL(data: any): string { | |
| try { | |
| console.log(`# mkburl data: `, data); | |
| let metaData: any = {}; | |
| metaData.dir = data?.imgurl ?? ""; | |
| metaData.mimetype = data?.minetype ?? ""; | |
| metaData = JSON.stringify(metaData); | |
| metaData = Buffer.from(metaData).toString("base64url"); | |
| let imgurl = `http://localhost:3000/api/stream/img?data=${metaData}`; | |
| return imgurl; | |
| } catch (error: any) { | |
| console.log(`# mkburl data err: `, data); | |
| return "/no_img.jpg"; | |
| } | |
| } | |
| /** | |
| * λ¬Έμμ΄μ΄ μΌλ°μ μΈ ν΄λ/νμΌ κ²½λ‘ νμμΈμ§ κ²μ¬ν©λλ€. | |
| * μ΄ μ κ·ννμμ μλ²½ν μ ν¨μ± κ²μ¬(μ€μ νμΌ μμ€ν κ·μΉ)κ° μλ, | |
| * κ²½λ‘ κ΅¬μ‘°(μ¬λμ, μ , νμΌλͺ λ±)λ₯Ό ν¬ν¨νλμ§ νμΈνλ λ° μ€μ μ λ‘λλ€. | |
| * @param pathString κ²μ¬ν λ¬Έμμ΄ | |
| * @returns κ²½λ‘ νμμΈ κ²½μ° true, μλλ©΄ false | |
| */ | |
| export function isPathFormat(pathString: string): boolean { | |
| if (typeof pathString !== "string" || pathString.trim() === "") { | |
| return false; | |
| } | |
| // ν¬κ΄μ μΈ κ²½λ‘ νμ μ κ·ννμ | |
| // 1. λλΌμ΄λΈ λ¬Έμ (C:\) λλ μ λμ€ λ£¨νΈ (/)λ‘ μμ | |
| // 2. κ²½λ‘ κ΅¬λΆμ (/, \)μ μΌλ°μ μΈ λ¬Έμ(λ¬Έμ, μ«μ, νμ΄ν, μΈλλ°, λ§μΉ¨ν) ν¬ν¨ | |
| // 3. UNC κ²½λ‘ (\\server\share)λ νμ© | |
| const pathRegex = new RegExp( | |
| /^((?:[a-zA-Z]:)?[\\\/]|\.{1,2}[\\\/]?|(?:[a-zA-Z0-9_-]+\/|\\)+|(?:[a-zA-Z]:))?(?:[a-zA-Z0-9_\-.\s]+[\\\/]?)*[a-zA-Z0-9_\-.\s]+$/, | |
| "i" // λμλ¬Έμ κ΅¬λΆ μμ | |
| ); | |
| // κ²½λ‘μ '?'λ '*' κ°μ glob λ¬Έμκ° ν¬ν¨λ κ²½μ°λ₯Ό λ¨μ κ²½λ‘λ‘ κ°μ£Όνμ§ μμ μ μμ΅λλ€. | |
| // μ¬κΈ°μλ μΌλ°μ μΈ κ²½λ‘ νμλ§ νμΈν©λλ€. | |
| return pathRegex.test(pathString); | |
| } | |