diff --git a/@sammo/crypto/src/LiteHashDRBG.ts b/@sammo/crypto/src/LiteHashDRBG.ts index c2540f8..1b7341c 100644 --- a/@sammo/crypto/src/LiteHashDRBG.ts +++ b/@sammo/crypto/src/LiteHashDRBG.ts @@ -1,10 +1,8 @@ -import type { RNG } from "../../../server/util/RNG.js"; - -import { sha512 } from '../../../server/util/sha2.js'; - -import { convertBytesLikeToUint8Array } from "@sammo/util/convertBytesLikeToUint8Array.js"; -import type { BytesLike } from "../../../server/util/BytesLike.js"; -import { delay } from "./delay.js"; +import type { RNG } from "./RNG.js"; +import { sha512 } from './SHA2.js'; +import { convertBytesLikeToUint8Array } from "@sammo/util/converter"; +import type { BytesLike } from "@sammo/util"; +import { delay } from "@sammo/util"; const maxRngSupportBit = 53; const maxInt = 0x1f_ffff_ffff_ffff; // NOTE: b 0, 10000110011, 11...11 diff --git a/server/util/RNG.ts b/@sammo/crypto/src/RNG.ts similarity index 100% rename from server/util/RNG.ts rename to @sammo/crypto/src/RNG.ts diff --git a/server/util/RandUtil.ts b/@sammo/crypto/src/RandUtil.ts similarity index 100% rename from server/util/RandUtil.ts rename to @sammo/crypto/src/RandUtil.ts diff --git a/@sammo/gateway/package.json b/@sammo/gateway/package.json index 94b6e16..4aa0662 100644 --- a/@sammo/gateway/package.json +++ b/@sammo/gateway/package.json @@ -6,6 +6,10 @@ "scripts": { "build": "tsc --build" }, + "exports": { + ".": "./dist/index.js", + "./exports": "./dist/exports.js" + }, "author": "", "type": "module", "license": "MIT", diff --git a/@sammo/gateway/src/api/gatewayAPI.ts b/@sammo/gateway/src/api/gatewayAPI.ts deleted file mode 100644 index e75767a..0000000 --- a/@sammo/gateway/src/api/gatewayAPI.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { structure } from "../apiStructure/sammoGatewayAPI.js"; -import type { APINamespaceType } from "./defs.js"; -import { GetGameLoginToken } from "./GatewayAPI/GetGameLoginToken.js"; -import { Login } from "./GatewayAPI/Login/index.js"; - -export const sammoGatewayAPI = { - Login, - GetGameLoginToken -} satisfies APINamespaceType; \ No newline at end of file diff --git a/@sammo/gateway/src/exports.ts b/@sammo/gateway/src/exports.ts new file mode 100644 index 0000000..8013193 --- /dev/null +++ b/@sammo/gateway/src/exports.ts @@ -0,0 +1,9 @@ +export type { + ServerActionType, + UserIDType, + IUser, +} from "./schema/User.ts"; + +export type { + ILoginToken +} from "./schema/LoginToken.ts"; \ No newline at end of file diff --git a/server/schema/gateway/LoginToken.ts b/@sammo/gateway/src/schema/LoginToken.ts similarity index 100% rename from server/schema/gateway/LoginToken.ts rename to @sammo/gateway/src/schema/LoginToken.ts diff --git a/server/schema/gateway/ServerVersion.ts b/@sammo/gateway/src/schema/ServerVersion.ts similarity index 100% rename from server/schema/gateway/ServerVersion.ts rename to @sammo/gateway/src/schema/ServerVersion.ts diff --git a/@sammo/gateway/src/schema/User.ts b/@sammo/gateway/src/schema/User.ts index 3a3aed1..8b06972 100644 --- a/@sammo/gateway/src/schema/User.ts +++ b/@sammo/gateway/src/schema/User.ts @@ -17,7 +17,7 @@ const validGatewayActionTypeList = [ export type GatewayActionType = typeof validGatewayActionTypeList[number]; -interface IUser { +export interface IUser { _id: UserIDType; oauthID?: bigint; diff --git a/@sammo/server/package.json b/@sammo/server/package.json new file mode 100644 index 0000000..974ede2 --- /dev/null +++ b/@sammo/server/package.json @@ -0,0 +1,23 @@ +{ + "name": "@sammo/server", + "version": "1.0.0", + "description": "", + "main": "dist/index.js", + "scripts": { + "build": "tsc --build" + }, + "author": "", + "type": "module", + "license": "MIT", + "dependencies": { + "@sammo/api_def": "workspace:^", + "@sammo/server_util": "workspace:^", + "@sammo/util": "workspace:^", + "@strpc/express": "workspace:^", + "dotenv": "^16.3.1", + "mongoose": "^7.4.3" + }, + "devDependencies": { + "@types/node": "^20.6.3" + } +} diff --git a/server/connectDB.ts b/@sammo/server/src/connectDB.ts similarity index 100% rename from server/connectDB.ts rename to @sammo/server/src/connectDB.ts diff --git a/server/dotenv.d.ts b/@sammo/server/src/dotenv.d.ts similarity index 100% rename from server/dotenv.d.ts rename to @sammo/server/src/dotenv.d.ts diff --git a/server/index.ts b/@sammo/server/src/index.ts similarity index 100% rename from server/index.ts rename to @sammo/server/src/index.ts diff --git a/server/ProcDecorator/ReqGameLogin.ts b/@sammo/server/src/procDecorator/ReqGameLogin.ts similarity index 100% rename from server/ProcDecorator/ReqGameLogin.ts rename to @sammo/server/src/procDecorator/ReqGameLogin.ts diff --git a/server/ProcDecorator/ReqLogin.ts b/@sammo/server/src/procDecorator/ReqLogin.ts similarity index 100% rename from server/ProcDecorator/ReqLogin.ts rename to @sammo/server/src/procDecorator/ReqLogin.ts diff --git a/server/serverConfig.ts b/@sammo/server/src/serverConfig.ts similarity index 100% rename from server/serverConfig.ts rename to @sammo/server/src/serverConfig.ts diff --git a/@sammo/server/tsconfig.json b/@sammo/server/tsconfig.json new file mode 100644 index 0000000..ebff90d --- /dev/null +++ b/@sammo/server/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + }, + "references": [ + { + "path": "../../@strpc/express" + }, + { + "path": "../util" + }, + { + "path": "../crypto" + }, + { + "path": "../server_util" + }, + ] +} diff --git a/@sammo/util/package.json b/@sammo/util/package.json index afbfbcc..59ee5b9 100644 --- a/@sammo/util/package.json +++ b/@sammo/util/package.json @@ -8,9 +8,11 @@ }, "exports": { ".": "./dist/index.js", - "./converter": "./dist/converter.js", - "./datetime": "./dist/datetime.js", - "./korean": "./dist/korean.js" + "./converter": "./dist/converter/index.js", + "./datetime": "./dist/datetime/index.js", + "./korean": "./dist/korean/index.js", + "./josa_util": "./dist/korean/josa_util.js", + "./string": "./dist/string/index.js" }, "type": "module", "keywords": [], diff --git a/@sammo/util/src/converter/convertBytesLikeToArrayBuffer.ts b/@sammo/util/src/converter/convertBytesLikeToArrayBuffer.ts deleted file mode 100644 index edf76a3..0000000 --- a/@sammo/util/src/converter/convertBytesLikeToArrayBuffer.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { BytesLike } from "./BytesLike.js"; - -export function convertBytesLikeToArrayBuffer(data: BytesLike, encodeUTF8 = true): ArrayBuffer{ - if (data instanceof ArrayBuffer) { - return data; - } - if (data instanceof Uint8Array) { - return data.buffer; - } - if (typeof(data) === 'string'){ - if(encodeUTF8){ - return (new TextEncoder()).encode(data); - } - return new Uint8Array(data.split('').map(s=>s.codePointAt(0) as number)); - } - return data.buffer; -} \ No newline at end of file diff --git a/@sammo/util/src/converter/convertBytesLikeToUint8Array.ts b/@sammo/util/src/converter/convertBytesLikeToUint8Array.ts index 45769f8..9e3ae06 100644 --- a/@sammo/util/src/converter/convertBytesLikeToUint8Array.ts +++ b/@sammo/util/src/converter/convertBytesLikeToUint8Array.ts @@ -1,5 +1,7 @@ -import type { BytesLike } from "./BytesLike.js"; +import type { BytesLike, BufferSource } from "../types.js"; +export function convertBytesLikeToUint8Array(data: string, encodeUTF8: boolean): Uint8Array; +export function convertBytesLikeToUint8Array(data: BufferSource | string): Uint8Array; export function convertBytesLikeToUint8Array(data: BytesLike, encodeUTF8 = true): Uint8Array { if (data instanceof Uint8Array) { return data; @@ -7,11 +9,20 @@ export function convertBytesLikeToUint8Array(data: BytesLike, encodeUTF8 = true) if (data instanceof ArrayBuffer) { return new Uint8Array(data); } + if (data instanceof SharedArrayBuffer) { + return new Uint8Array(data); + } + if (data instanceof Uint8Array) { + return data; + } + if (ArrayBuffer.isView(data)) { + return new Uint8Array(data.buffer, data.byteOffset, data.byteLength); + } if (typeof (data) === 'string') { if(encodeUTF8){ return (new TextEncoder()).encode(data); } return new Uint8Array(data.split('').map(s=>s.codePointAt(0) as number)); } - return new Uint8Array(data.buffer); + throw new Error(`Unknown data type ${typeof (data)}`); } \ No newline at end of file diff --git a/server/util/entriesWithType.ts b/@sammo/util/src/converter/entriesWithType.ts similarity index 100% rename from server/util/entriesWithType.ts rename to @sammo/util/src/converter/entriesWithType.ts diff --git a/@sammo/util/src/converter/index.ts b/@sammo/util/src/converter/index.ts index cc667df..d826ee1 100644 --- a/@sammo/util/src/converter/index.ts +++ b/@sammo/util/src/converter/index.ts @@ -1,6 +1,5 @@ export * from "./combineObject.js"; export * from "./combineArray.js"; -export * from "./convertBytesLikeToArrayBuffer.js"; export * from "./convertBytesLikeToUint8Array.js"; export * from "./convertIDArray.js"; export * from "./convertIterableToMap.js" \ No newline at end of file diff --git a/server/util/merge2DArrToObjectArr.ts b/@sammo/util/src/converter/merge2DArrToObjectArr.ts similarity index 93% rename from server/util/merge2DArrToObjectArr.ts rename to @sammo/util/src/converter/merge2DArrToObjectArr.ts index eb77aea..c9f276d 100644 --- a/server/util/merge2DArrToObjectArr.ts +++ b/@sammo/util/src/converter/merge2DArrToObjectArr.ts @@ -1,5 +1,5 @@ -import type { ValuesOf } from "./defs.js"; +import type { ValuesOf } from "../types.js"; import { zip } from "lodash-es"; export function merge2DArrToObjectArr>(column: (keyof T)[], list: ValuesOf[][]): T[]{ diff --git a/server/util/mergeKVArray.ts b/@sammo/util/src/converter/mergeKVArray.ts similarity index 100% rename from server/util/mergeKVArray.ts rename to @sammo/util/src/converter/mergeKVArray.ts diff --git a/server/util/getDateTimeNow.ts b/@sammo/util/src/datetime/getDateTimeNow.ts similarity index 100% rename from server/util/getDateTimeNow.ts rename to @sammo/util/src/datetime/getDateTimeNow.ts diff --git a/server/util/joinYearMonth.ts b/@sammo/util/src/datetime/joinYearMonth.ts similarity index 100% rename from server/util/joinYearMonth.ts rename to @sammo/util/src/datetime/joinYearMonth.ts diff --git a/@sammo/util/src/index.ts b/@sammo/util/src/index.ts index 2e62dc1..207a2e4 100644 --- a/@sammo/util/src/index.ts +++ b/@sammo/util/src/index.ts @@ -3,58 +3,19 @@ export * from "./jsonify.js" export * from "./error.js" export * from "./unwrap.js" export * from "./types.js" +export * from "./web.js" + +export * from "./strongType.js" export * as converter from "./converter/index.js" -export * as datetime from "./datetime/index.js" -export * as korean from "./korean/index.js" - -import type { WrappedBuffer } from "./types.js" - -export function isEmail(addr: string): boolean { - return String(addr) - .toLowerCase() - .match( - /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|.(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ - ) !== null; -} - -export function isIPAddr4(addr: string): boolean { - if (/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(addr)) { - return (true) - } - return false; -} +export * as datetime from "./datetime/index.js"; +export * as korean from "./korean/index.js"; +export * as string from "./string/index.js"; export function calcBase64Len(length: number) { return ((4 * length / 3) + 3) & ~3; } -/** ArrayBuffer,Uint8Array,Buffer를 WrappedBuffer로 변환 - */ -export function wrapBuffer(buffer: BufferSource): T { - /** - * Buffer라면 wrapBuffer없이 그대로 대입 가능 - * ArrayBuffer, Uint8Array 등이라면 Buffer.from을 사용 가능 - * DataView 등인 경우는 ArrayBufferView 활용 - * 그냥 써도 되지만, 위 방법보다 아무렇게나 쓰기 좋다는 장점은 있음 - */ - if (buffer instanceof Buffer) { - return buffer as T; - } - if (buffer instanceof ArrayBuffer) { - return Buffer.from(buffer) as T; - } - if (buffer instanceof SharedArrayBuffer) { - return Buffer.from(buffer) as T; - } - return Buffer.from(buffer.buffer, buffer.byteOffset, buffer.byteLength) as T; -} - -/** 호출할 필요 없이 바로 Buffer에 대입해도 되지만, 누군가 찾을 수 있어서. */ -export function unwrapBuffer(buffer: T): Buffer { - return buffer; -} - export function delay(time: number): Promise; export function delay(time: number, result: T): Promise; export function delay(time: number, result?: T): Promise { @@ -65,15 +26,6 @@ export function delay(time: number, result?: T): Promise(buffer: T | ArrayBuffer | Uint8Array): Base64String { - return Buffer.from(buffer).toString('base64'); -} - -export function wrappedBufferFromBase64(base64: Base64String): T { - return Buffer.from(base64, 'base64') as T; -} - - export function isBufferSource(obj: unknown): obj is BufferSource { if (obj instanceof ArrayBuffer){ return true; @@ -85,4 +37,8 @@ export function isBufferSource(obj: unknown): obj is BufferSource { return true; } return false; +} + +export function isNotNull(value: T|null|undefined):value is T{ + return value !== null && value !== undefined; } \ No newline at end of file diff --git a/server/util/JosaUtil.ts b/@sammo/util/src/korean/JosaUtil.ts similarity index 99% rename from server/util/JosaUtil.ts rename to @sammo/util/src/korean/JosaUtil.ts index 2f61674..70b3db6 100644 --- a/server/util/JosaUtil.ts +++ b/@sammo/util/src/korean/JosaUtil.ts @@ -1,4 +1,4 @@ -import { unwrap_err } from "./unwrap_err.js"; +import { unwrap_err } from "../unwrap.js"; // https://github.com/coxcore/postposition 의 php 버전을 다시 typescript로 재 작성 const KO_START_CODE = 44032; diff --git a/@sammo/util/src/korean/index.ts b/@sammo/util/src/korean/index.ts index 43526e8..2b78bcd 100644 --- a/@sammo/util/src/korean/index.ts +++ b/@sammo/util/src/korean/index.ts @@ -1,4 +1,5 @@ export * from "./automata초성.js"; export * from "./convertSearch초성.js" export * from "./filter초성.js"; -export * from "./filter초성withAlphabet.js"; \ No newline at end of file +export * from "./filter초성withAlphabet.js"; +export * as JosaUtil from "./JosaUtil.js"; \ No newline at end of file diff --git a/server/util/simpleSerialize.ts b/@sammo/util/src/simpleSerialize.ts similarity index 100% rename from server/util/simpleSerialize.ts rename to @sammo/util/src/simpleSerialize.ts diff --git a/@sammo/util/src/string/index.ts b/@sammo/util/src/string/index.ts new file mode 100644 index 0000000..761e58b --- /dev/null +++ b/@sammo/util/src/string/index.ts @@ -0,0 +1,5 @@ +export * from "./mb_strimwidth.js" +export * from "./mb_strwidth.js" +export * from "./nl2br.js" +export * from "./numberWithCommas.js" +export * from "./randStr.js"; \ No newline at end of file diff --git a/server/util/mb_strimwidth.ts b/@sammo/util/src/string/mb_strimwidth.ts similarity index 100% rename from server/util/mb_strimwidth.ts rename to @sammo/util/src/string/mb_strimwidth.ts diff --git a/server/util/mb_strwidth.ts b/@sammo/util/src/string/mb_strwidth.ts similarity index 100% rename from server/util/mb_strwidth.ts rename to @sammo/util/src/string/mb_strwidth.ts diff --git a/server/util/nl2br.ts b/@sammo/util/src/string/nl2br.ts similarity index 100% rename from server/util/nl2br.ts rename to @sammo/util/src/string/nl2br.ts diff --git a/server/util/numberWithCommas.ts b/@sammo/util/src/string/numberWithCommas.ts similarity index 100% rename from server/util/numberWithCommas.ts rename to @sammo/util/src/string/numberWithCommas.ts diff --git a/server/util/randStr.ts b/@sammo/util/src/string/randStr.ts similarity index 93% rename from server/util/randStr.ts rename to @sammo/util/src/string/randStr.ts index 25bf16f..d462532 100644 --- a/server/util/randStr.ts +++ b/@sammo/util/src/string/randStr.ts @@ -3,10 +3,10 @@ const charList = [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', -]; +] as const; export function randStr(len: number): string { - const result = []; + const result: string[] = []; const charListLen = charList.length; let isStart = true; diff --git a/@sammo/util/src/strongType.ts b/@sammo/util/src/strongType.ts new file mode 100644 index 0000000..6d513a2 --- /dev/null +++ b/@sammo/util/src/strongType.ts @@ -0,0 +1,51 @@ + + +/** Buffer이지만 ts에서 타입 구분 편의를 제공 */ +export interface WrappedBuffer extends Buffer { + /** 타입구분자. 항상 undefined일 것이다 */ + _w_type?: string; +} + + +/** ArrayBuffer,Uint8Array,Buffer를 WrappedBuffer로 변환 + */ +export function wrapBuffer(buffer: BufferSource): T { + /** + * Buffer라면 wrapBuffer없이 그대로 대입 가능 + * ArrayBuffer, Uint8Array 등이라면 Buffer.from을 사용 가능 + * DataView 등인 경우는 ArrayBufferView 활용 + * 그냥 써도 되지만, 위 방법보다 아무렇게나 쓰기 좋다는 장점은 있음 + */ + if (buffer instanceof Buffer) { + return buffer as T; + } + if (buffer instanceof ArrayBuffer) { + return Buffer.from(buffer) as T; + } + if (buffer instanceof SharedArrayBuffer) { + return Buffer.from(buffer) as T; + } + return Buffer.from(buffer.buffer, buffer.byteOffset, buffer.byteLength) as T; +} + +/** 호출할 필요 없이 바로 Buffer에 대입해도 되지만, 누군가 찾을 수 있어서. */ +export function unwrapBuffer(buffer: T): Buffer { + return buffer; +} + +/** + * base64 string에 내부 타입으로 WrappedBuffer를 보관한 형태 + */ +// eslint-disable-next-line @typescript-eslint/ban-types +export type Base64String = string & { + /** 타입구분자. 항상 undefined일 것이다 */ + _b_type?: T; +} + +export function base64FromWrappedBuffer(buffer: T | ArrayBuffer | Uint8Array): Base64String { + return Buffer.from(buffer).toString('base64'); +} + +export function wrappedBufferFromBase64(base64: Base64String): T { + return Buffer.from(base64, 'base64') as T; +} diff --git a/@sammo/util/src/types.ts b/@sammo/util/src/types.ts index 997f463..4d46c37 100644 --- a/@sammo/util/src/types.ts +++ b/@sammo/util/src/types.ts @@ -6,23 +6,10 @@ export type IDItem = { id: T; }; +export type Entries = { + [K in keyof T]: [K, T[K]]; + }[keyof T][]; -/** Buffer이지만 ts에서 타입 구분 편의를 제공 */ -export interface WrappedBuffer extends Buffer { - /** 타입구분자. 항상 undefined일 것이다 */ - _w_type?: string; -} - export type BufferSource = ArrayBufferView | ArrayBuffer | SharedArrayBuffer; export type BytesLike = BufferSource | string; - - -/** - * base64 string에 내부 타입으로 WrappedBuffer를 보관한 형태 - */ -// eslint-disable-next-line @typescript-eslint/ban-types -export type Base64String = string & { - /** 타입구분자. 항상 undefined일 것이다 */ - _b_type?: T; -} diff --git a/@sammo/util/src/web.ts b/@sammo/util/src/web.ts new file mode 100644 index 0000000..4835494 --- /dev/null +++ b/@sammo/util/src/web.ts @@ -0,0 +1,34 @@ +import { unwrap } from "./unwrap.js"; + +export function isEmail(addr: string): boolean { + return String(addr) + .toLowerCase() + .match( + /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|.(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ + ) !== null; +} + +export function isIPAddr4(addr: string): boolean { + if (/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(addr)) { + return (true) + } + return false; +} + +export function hexToRgb(hex: string): { r: number; g: number; b: number; } | null { + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16) + } : null; +} + +export function isBrightColor(color: string): boolean { + const cv = unwrap(hexToRgb(color)); + if ((cv.r * 0.299 + cv.g * 0.587 + cv.b * 0.114) > 140) { + return true; + } else { + return false; + } +} diff --git a/server/entity/schemats.ts b/schemats.d.ts similarity index 100% rename from server/entity/schemats.ts rename to schemats.d.ts diff --git a/server/ProcDecorator/ReqGatewayLogin.ts b/server/ProcDecorator/ReqGatewayLogin.ts deleted file mode 100644 index a270d93..0000000 --- a/server/ProcDecorator/ReqGatewayLogin.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { GatewayActionType, ServerActionType } from "../schema/gateway/User.js"; -import type { SessionCtx } from "./StartSession.js"; -import type { ProcDecorator } from "./base.js"; - -export type GatewayLoginCtx = { - userID: number; - userName: string; - userLevel: number; - allowServerAction: Map>; - allowGatewayAction: Set; - loginDate: Date; -} -export const loginCtxSessionKey = 'loginCtx'; - -export function ReqGatewayLogin(): ProcDecorator { - return (ctx) => { - const loginCtx = ctx.session.getItem(loginCtxSessionKey); - if(!loginCtx){ - return [{ - result: false, - type: 'Required Login', - info: 'ReqLogin' - }, ctx]; - } - - return [{ - result: true, - },{ - ...loginCtx, - ...ctx, - }]; - } -} \ No newline at end of file diff --git a/server/ProcDecorator/StartSession.ts b/server/ProcDecorator/StartSession.ts deleted file mode 100644 index 486fa13..0000000 --- a/server/ProcDecorator/StartSession.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { type Session, type SessionData } from "express-session"; -import type { Empty, ProcDecoratorGenerator } from "./base.js"; - -export type SessionCtx = { - session: { - clear: () => Promise; - removeItem: (key: string) => boolean; - getItem: (key: string) => T | undefined; - setItem: (key: string, value: unknown) => void; - raw: Session & Partial & Record; - } -} - -export function StartSession(): ProcDecoratorGenerator { - return (inCtx, req) => { - if (!req.session) { - throw 'Express-session required'; - } - const sessionObj = { - raw: req.session - } as SessionCtx['session']; - sessionObj.clear = () => { - return new Promise((resolve) => { - sessionObj.raw = req.session.regenerate(resolve) as SessionCtx['session']['raw']; - }) - } - sessionObj.removeItem = (key: string): boolean => { - if (key in sessionObj.raw) { - delete sessionObj.raw[key]; - return true; - } - return false; - } - sessionObj.getItem = (key: string): T | undefined => { - if (!(key in sessionObj.raw)) { - return undefined; - } - return sessionObj.raw[key] as T; - } - sessionObj.setItem = (key: string, value: T | undefined): void => { - if (value === undefined) { - sessionObj.removeItem(key); - return; - } - sessionObj.raw[key] = value; - } - - return [ - { - result: true, - }, - { - session: sessionObj, - ...inCtx, - } - ] - } -} \ No newline at end of file diff --git a/server/ProcDecorator/base.ts b/server/ProcDecorator/base.ts deleted file mode 100644 index 3b0ab6f..0000000 --- a/server/ProcDecorator/base.ts +++ /dev/null @@ -1,183 +0,0 @@ -import type { Request, Response } from "express"; - -type MayBePromise = T | Promise; - -export type Empty = Record; -export type DecoratorResultTrue = { - result: true; - type?: string; - info?: string; -}; -export type DecoratorResultFalse = { - result: false; - type: string; - info: string; -} -export type DecoratorResult = DecoratorResultTrue | DecoratorResultFalse; -export type DecoratorStack = DecoratorResult[]; - -export interface ProcDecorator { - (inCtx: In & Partial, req: Request, res: Response) - : MayBePromise<[DecoratorResultTrue, Out] | [DecoratorResultFalse, In & Partial]>; -} - -export interface PostProcDecorator { - (ctx: T, preResult: DecoratorResult, req: Request, res: Response, isValidRoute: boolean): MayBePromise<[DecoratorResult, T]>; -} - -export interface ProcDecoratorRunner { - (inCtx: In, req: Request, res: Response): MayBePromise<[DecoratorStack, Out]>; -} - -export interface PostProcDecoratorRunner { - (ctx: T, preResult: DecoratorStack, req: Request, res: Response, isValidRoute: boolean): MayBePromise<[DecoratorStack, T]>; -} - - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -type PlainDecorator = ProcDecorator; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -type PlainPostDecorator = PostProcDecorator; - - -export type ProcDecoratorGenerator = ProcDecorator; -export type ProcDecoratorPrePostGenerator = [ProcDecorator, PostProcDecorator]; - -export type ProcDecoratorChain = readonly ((() => PlainDecorator) | (() => [PlainDecorator, PlainPostDecorator]))[]; - -export type ResolveChain = T extends undefined ? Empty : T extends ProcDecoratorChain ? Resolve> : never; - - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export type ParseInType = T extends ProcDecorator ? object extends A ? A : never : never; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export type ParseOutType = T extends ProcDecorator ? B : never; - -export const EmptyProcDecorator: readonly [ProcDecoratorRunner, PostProcDecoratorRunner] = [ - async (ctx) => [[], ctx], async (ctx, stack) => [stack, ctx] -]; - -export function declProcDecorators(...decorators: T) { - type OutType = Resolve>; - - const preDecorator: PlainDecorator[] = []; - const postDecorator: (PlainPostDecorator | undefined)[] = []; - if (decorators) { - for (const procGen of decorators) { - const proc = procGen(); - if (Array.isArray(proc)) { - preDecorator.push(proc[0]); - postDecorator.push(proc[1]); - } - else { - preDecorator.push(proc); - postDecorator.push(undefined); - } - } - } - - const packedDecorators: readonly [ProcDecoratorRunner, PostProcDecoratorRunner] = [ - async (ctx, req, res) => { - let rctx = ctx as unknown as OutType; - const decoratorStack: DecoratorStack = []; - if (!preDecorator.length) { - return [decoratorStack, rctx]; - } - - for (const [idx, proc] of preDecorator.entries()) { - try { - const [stackResult, newCtx] = await proc(rctx, req, res); - decoratorStack.push(stackResult); - - if (stackResult.result) { - rctx = newCtx; - continue; - } - - return [decoratorStack, newCtx]; - } - catch (e) { - while (decoratorStack.length > idx) { - decoratorStack.pop(); - } - decoratorStack.push({ - result: false, - type: 'PreThrow', - info: `internal error: ${e}`, - }); - - return [decoratorStack, rctx]; - } - } - - return [decoratorStack, rctx]; - }, - async (ctx, stack, req, res) => { - if (!postDecorator.length) { - return [stack, ctx]; - } - let isValidRoute = stack.length === postDecorator.length && stack.every(v => v.result); - for (let idx = stack.length - 1; idx >= 0; idx--) { - const preStackResult = stack[idx] as DecoratorResult; - if (!preStackResult.result) { - continue; - } - - const proc = postDecorator[idx]; - - if (!proc) { - if (isValidRoute) { - stack.pop(); - } - continue; - } - - try { - const [postStackResult, nextCtx] = await proc(ctx, preStackResult, req, res, isValidRoute); - if (postStackResult.result) { - if (isValidRoute) { - stack.pop(); - } - ctx = nextCtx; - continue; - } - - isValidRoute = false; - stack[idx] = postStackResult; - - ctx = nextCtx; - } - catch (e) { - isValidRoute = false; - stack[idx] = { - result: false, - type: 'PostThrow', - info: `internal error: ${e}`, - }; - } - - } - return [stack, ctx]; - }, - ] as const; - - return packedDecorators; -} - -type Compose2 = B extends C ? ProcDecorator : never; - -type PD1 = () => ProcDecorator; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -type PD2 = () => [ProcDecorator, PostProcDecorator]; - -export type PackChain = - T extends readonly [] ? ProcDecorator : - T extends readonly [PD1] ? ProcDecorator : - T extends readonly [PD2] ? ProcDecorator : - T extends readonly [PD1, PD1, ... infer R] ? PackChain<[() => Compose2, ...R]> : - T extends readonly [PD2, PD1, ... infer R] ? PackChain<[() => Compose2, ...R]> : - T extends readonly [PD1, PD2, ... infer R] ? PackChain<[() => Compose2, ...R]> : - T extends readonly [PD2, PD2, ... infer R] ? PackChain<[() => Compose2, ...R]> : - never; - -type Resolve = T extends ProcDecorator ? Empty extends A ? B : never : never; \ No newline at end of file diff --git a/server/clientAPI/APIPathGen.ts b/server/clientAPI/APIPathGen.ts deleted file mode 100644 index 660d343..0000000 --- a/server/clientAPI/APIPathGen.ts +++ /dev/null @@ -1,38 +0,0 @@ -export function APIPathGen( - obj: T, - callback: (path: string[], tail: V, pathParam?: Record) => unknown, - path: string[] = [], -): T { - const map = new Map(); - return new Proxy(obj, { - get(target, key) { - if(typeof key === 'symbol'){ - throw new Error('Symbol is not supported'); - } - - const cachedResult = map.get(key); - if(cachedResult !== undefined){ - return cachedResult; - } - - const nextPath = [...path, key]; - - let next: T[keyof T]; - if (key in target) { - next = target[key as keyof typeof target]; - } - else { - throw `${nextPath} is not exists`; - } - - if (typeof (next) === 'function') { - const result = callback(nextPath, next); - map.set(key, result); - return result; - } - const result = APIPathGen(next, callback, nextPath); - map.set(key, result); - return result; - } - }) as T; -}; \ No newline at end of file diff --git a/server/clientAPI/generator.ts b/server/clientAPI/generator.ts deleted file mode 100644 index d802bf4..0000000 --- a/server/clientAPI/generator.ts +++ /dev/null @@ -1,95 +0,0 @@ -import isArray from "lodash-es/isArray"; -import isEmpty from "lodash-es/isEmpty"; -import ky from "ky"; -import type { HttpMethod, InvalidResponse, RawArgType, ValidResponse } from "../apiStructure/defs.js"; - -export async function callClientAPI( - method: HttpMethod, - apiRoot: string, - path: string | string[], - args: RawArgType, - paramArgs: Record | undefined -): Promise; -export async function callClientAPI( - method: HttpMethod, - apiRoot: string, - path: string | string[], - args: RawArgType, - paramArgs: Record | undefined, - returnError: undefined -): Promise; -export async function callClientAPI( - method: HttpMethod, - apiRoot: string, - path: string | string[], - args: RawArgType, - paramArgs: Record | undefined, - returnError: false -): Promise; -export async function callClientAPI( - method: HttpMethod, - apiRoot: string, - path: string | string[], - args: RawArgType, - paramArgs: Record | undefined, - returnError: true -): Promise; -export async function callClientAPI( - method: HttpMethod, - apiRoot: string, - path: string | string[], - args: RawArgType, - paramArgs: Record | undefined, - returnError?: boolean -): Promise { - if (isArray(path)) { - path = [apiRoot, ...path].join("/"); - } - else if (path.startsWith("/")) { - path = `${apiRoot}${path}`; - } - else { - path = `${apiRoot}/${path}`; - } - - if (args && isEmpty(args)) { - args = undefined; - } - - const result = (await (() => { - if (method == "get") { - return ky(path, { - searchParams: { - ...paramArgs, - ...(args as typeof paramArgs), - }, - method, - headers: { - "content-type": "application/json", - }, - timeout: 30000, - retry: 0, - }); - } - return ky(path, { - searchParams: { - ...paramArgs, - }, - method, - json: args, - headers: { - "content-type": "application/json", - }, - timeout: 30000, - retry: 0, - }); - })().json()) as ErrorType | ResultType; - - if (!result.result) { - if (returnError) { - return result; - } - throw result.reason; - } - return result; -} \ No newline at end of file diff --git a/server/clientAPI/sammoGatewayAPI.ts b/server/clientAPI/sammoGatewayAPI.ts deleted file mode 100644 index f95c400..0000000 --- a/server/clientAPI/sammoGatewayAPI.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { APIPathGen } from "./APIPathGen.js"; -import type { APITail, RawArgType } from "../apiStructure/defs.js"; -import { structure } from "../apiStructure/sammoGatewayAPI.js"; -import { callClientAPI } from "./generator.js"; - -const apiRoot = process.env.API_ROOT_PATH ?? process.env.VITE_API_ROOT_PATH ?? '/rootAPI'; - -export const SammoGatewayAPI = APIPathGen(structure, (path: string[], tail: APITail, pathParam) => { - const method = tail.reqType; - return (args?: RawArgType, returnError?: boolean) => { - if (returnError) { - return callClientAPI(method, apiRoot, path.join('/'), args, pathParam, returnError); - } - return callClientAPI(method, apiRoot, path.join('/'), args, pathParam); - }; -}); \ No newline at end of file diff --git a/server/schema/gateway/ServerConfig.ts b/server/schema/gateway/ServerConfig.ts deleted file mode 100644 index 7519d06..0000000 --- a/server/schema/gateway/ServerConfig.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Mongoose, Schema, model } from "mongoose"; - -export interface IServerConfig { - allowLogin: boolean; - allowOAuthLogin: boolean; - allowRegister: boolean; -}; - -export const ServerConfig = new Schema({ - allowLogin: { type: Boolean, required: true }, - allowOAuthLogin: { type: Boolean, required: true }, - allowRegister: { type: Boolean, required: true }, -}, { - autoIndex: false, - autoCreate: false, - capped: { - max: 1, - } -}) -; - -//단일 document로 관리 -export default (conn:Mongoose)=>conn.model('ServerConfig', ServerConfig); \ No newline at end of file diff --git a/server/schema/gateway/User.ts b/server/schema/gateway/User.ts deleted file mode 100644 index 3a3aed1..0000000 --- a/server/schema/gateway/User.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { Schema, model } from 'mongoose'; - -export type UserIDType = number; - -const validOAuthTypeList = ['KAKAO', 'NONE'] as const; -export type validOAuthType = typeof validOAuthTypeList[number]; - -const validServerActionTypeList = [ - 'Update', 'UpdateByGitPath', 'ShowErrorLog', - 'CloseServer', 'OpenServer', 'StopAndResumeServer', 'OpenVote', -] as const; -export type ServerActionType = typeof validServerActionTypeList[number]; - -const validGatewayActionTypeList = [ - 'Update', 'UpdateByGitPath', 'ShowErrorLog', 'ResetUserPassword', 'ChangeGatewayState', 'DeleteUser', -] as const; - -export type GatewayActionType = typeof validGatewayActionTypeList[number]; - -interface IUser { - _id: UserIDType; - - oauthID?: bigint; - id: string; - email: string; - - oauthType: validOAuthType; - oauthInfo?: object; - tokenValidUntil?: Date; - - userSalt: string; - hashedPassword: string; - - allowThirdPartyUse: boolean; - - userName: string; - allowServerAction?: Map; - allowGatewayAction?: ServerActionType[]; - penalty?: Map; - - picture?: string; - useImgSvr?: boolean; - - regDate: Date; - deleteAfter?: Date; -} - -export const User = new Schema({ - _id: { type: Number, required: true }, - - oauthID: { type: BigInt, required: false }, - id: { type: String, required: true }, - email: { type: String, required: true }, - - oauthType: { type: String, required: true, enum: validOAuthTypeList }, - oauthInfo: { type: Object, required: false }, - tokenValidUntil: { type: Date, required: false }, - - userSalt: { type: String, required: true }, - hashedPassword: { type: String, required: true }, - - allowThirdPartyUse: { type: Boolean, required: true }, - - userName: { type: String, required: true }, - allowServerAction: { - type: Map, required: false, of: { - type: Array, - of: { type: String, enum: validServerActionTypeList } - } - }, - allowGatewayAction: { - type: Array, required: false, of: { - type: String, enum: validGatewayActionTypeList - } - }, - penalty: { type: Map, required: false, of: Date }, - - picture: { type: String, required: false }, - useImgSvr: { type: Boolean, required: false }, - - regDate: { type: Date, required: true }, - deleteAfter: { type: Date, required: false }, -}, { autoIndex: false, autoCreate: false }) - .index({ id: 1 }, { unique: true }) - .index({ email: 1 }, { unique: true }) - .index({ oauthID: 1 }, { unique: true, sparse: true }) - .index({ deleteAfter: 1 }) // 자동 삭제 아님! - ; - -export default model('User', User); \ No newline at end of file diff --git a/server/schema/gateway/UserLog.ts b/server/schema/gateway/UserLog.ts deleted file mode 100644 index 2742802..0000000 --- a/server/schema/gateway/UserLog.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Schema, model, } from 'mongoose'; -import { type UserIDType } from './User.js'; - -export type LogType = 'register' - | 'login_pw' | 'login_token' | 'login_oauth' | 'logout' - | 'change_pw' | 'reset_pw'; -const LogTypeList: LogType[] = [ - 'register', - 'login_pw', 'login_token', 'login_oauth', 'logout', - 'change_pw', 'reset_pw', -]; - -interface IUserLog { - userID: UserIDType; - logDate: Date; - logType: LogType; - action: object; -} - -export const UserLog = new Schema({ - userID: { type: Number, required: true }, - logDate: { type: Date, required: true }, - logType: { type: String, required: true, enum: LogTypeList }, - action: { type: Object, required: true }, -}, { autoIndex: false, autoCreate: false, }) - .index({ userID: 1, logDate: 1 }) - .index({ logDate: 1 }, { expireAfterSeconds: 60 * 60 * 24 * 365 * 3 }) - ; - -export default model('UserLog', UserLog); \ No newline at end of file diff --git a/server/util/Entries.ts b/server/util/Entries.ts deleted file mode 100644 index 9ff7a02..0000000 --- a/server/util/Entries.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type Entries = { - [K in keyof T]: [K, T[K]]; -}[keyof T][]; \ No newline at end of file diff --git a/server/util/NotNullExpected.ts b/server/util/NotNullExpected.ts deleted file mode 100644 index 7f6d941..0000000 --- a/server/util/NotNullExpected.ts +++ /dev/null @@ -1,4 +0,0 @@ - -export class NotNullExpected extends TypeError { - public override name = 'NotNullExpected'; -} diff --git a/server/util/RuntimeError.ts b/server/util/RuntimeError.ts deleted file mode 100644 index 9ca39c4..0000000 --- a/server/util/RuntimeError.ts +++ /dev/null @@ -1,14 +0,0 @@ -export class RuntimeError extends Error { - public override name = 'RuntimeError'; - constructor(public override message: string = '') { - super(message); - } - override toString(): string { - if (this.message) { - return this.name + ': ' + this.message; - } - else { - return this.name; - } - } -} diff --git a/server/util/UniqueNumberAllocator.ts b/server/util/UniqueNumberAllocator.ts deleted file mode 100644 index 5ce298f..0000000 --- a/server/util/UniqueNumberAllocator.ts +++ /dev/null @@ -1,198 +0,0 @@ -export interface StateIncrementer { - (state: number): Promise; -} - -export type NumberGroup = { - start: number; - remain: number; -} - -const AllocatorGroupBucketSize = 100; -const AllocatorPreserveThreshold = 50; - -export function* numberGenerator(numberGroups: NumberGroup[]): Generator { - for (const numberGroup of numberGroups) { - for (let i = 0; i < numberGroup.remain; i++) { - yield numberGroup.start + i; - } - } - return null; -} - -export class UniqueNumberAllocator { - private preservedNumbers: NumberGroup[]; - private incrementer: StateIncrementer; - private totalRemain: number; - private promisedCnt: number; - private promise: Promise; - - public constructor(incrementer: StateIncrementer, initialState?: NumberGroup) { - this.incrementer = incrementer; - if (!initialState) { - this.preservedNumbers = []; - this.totalRemain = 0; - } - else { - if (initialState.remain < 1) { - throw new Error('initialState.remain must be greater than 0'); - } - this.preservedNumbers = [initialState]; - this.totalRemain = initialState.remain; - } - this.promisedCnt = 0; - this.promise = Promise.resolve(); - this.preserveNext(); - } - - public static async generate(incrementer: StateIncrementer): Promise { - const initialStateEnd = await incrementer(AllocatorGroupBucketSize); - const initialState: NumberGroup = { - start: initialStateEnd - AllocatorGroupBucketSize + 1, - remain: AllocatorGroupBucketSize, - } - return new UniqueNumberAllocator(incrementer, initialState); - } - - private preserveNext(): void { - if (this.promisedCnt + this.totalRemain >= AllocatorGroupBucketSize) { - return; - } - - if (this.totalRemain >= AllocatorPreserveThreshold) { - return; - } - - const waiter = this.promise; - - this.promise = (async () => { - this.promisedCnt += AllocatorGroupBucketSize; - const nextP = this.incrementer(AllocatorGroupBucketSize); - await waiter; - const next = await nextP; - if (this.preservedNumbers.length > 0) { - const last = this.preservedNumbers[this.preservedNumbers.length - 1]; - if (last.start + last.remain === next - AllocatorGroupBucketSize + 1) { - // 마지막 그룹과 연속됨 - last.remain += AllocatorGroupBucketSize; - this.totalRemain += AllocatorGroupBucketSize; - this.promisedCnt -= AllocatorGroupBucketSize; - return; - } - } - const nextGroup: NumberGroup = { - start: next - AllocatorGroupBucketSize + 1, - remain: AllocatorGroupBucketSize, - } - this.preservedNumbers.push(nextGroup); - this.totalRemain += AllocatorGroupBucketSize; - this.promisedCnt -= AllocatorGroupBucketSize; - })(); - } - - public async allocateOne(): Promise { - if (this.totalRemain > 0) { - const head = this.preservedNumbers[0]; - if (head.remain > 1) { - const next = head.start; - head.start++; - head.remain--; - this.totalRemain--; - this.preserveNext(); - return next; - } - else { - this.preservedNumbers.shift(); - this.totalRemain--; - this.preserveNext(); - return head.start; - } - } - - const next = (await this.allocate(1)).next().value; - if (next === null) { - throw new Error('incrementer failed to allocate enough numbers'); - } - return next; - } - - public async allocate(n: number): Promise> { - n = Math.ceil(n); - if (n < 1) { - throw new Error('n must be greater than 0'); - } - - if (n > this.totalRemain + this.promisedCnt) { - const endP = this.incrementer(n); - this.preserveNext(); - const end = await endP; - - return numberGenerator([{ - start: end - n + 1, - remain: n, - }]); - } - - const result: NumberGroup[] = []; - - if (this.totalRemain > 0) { - const head = this.preservedNumbers[0]; - const headRemain = head.remain; - - if (n < headRemain) { - result.push({ - start: head.start, - remain: n, - }); - head.start += n; - head.remain -= n; - this.totalRemain -= n; - this.preserveNext(); - return numberGenerator(result); - } - if (n === headRemain) { - this.preservedNumbers.shift(); - result.push(head); - this.totalRemain -= n; - this.preserveNext(); - return numberGenerator(result); - } - - } - - //assert n <= this.totalRemain + this.promisedRemain - - if (n > this.totalRemain) { - await this.promise; - if (n > this.totalRemain) { - throw new Error('incrementer failed to allocate enough numbers'); - } - } - - this.totalRemain -= n; - this.preserveNext(); - - let remain = n; - let idx = 0; - while (remain > 0) { - const head = this.preservedNumbers[idx]; - if (head.remain <= remain) { - remain -= head.remain; - result.push(head); - idx++; - continue; - } - - result.push({ - start: head.start, - remain: remain, - }); - head.start += remain; - head.remain -= remain; - remain = 0; - break; - } - this.preservedNumbers = this.preservedNumbers.slice(idx); - - return numberGenerator(result); - } -} \ No newline at end of file diff --git a/server/util/aes.ts b/server/util/aes.ts deleted file mode 100644 index b0fc740..0000000 --- a/server/util/aes.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { webcrypto } from "crypto"; - -const subtle = webcrypto.subtle; -type BufferSource = ArrayBufferView | ArrayBuffer; - -export async function AES_GCM_Encrypt(key: BufferSource, iv: BufferSource, msg: BufferSource, aad?: BufferSource): Promise { - const keyObj = await subtle.importKey("raw", key, { - name: "AES-GCM", - }, false, ["encrypt"]); - - const ciphertext = await subtle.encrypt({ - name: "AES-GCM", - iv, - additionalData: aad - }, keyObj, msg); - - return ciphertext; -} - - -export async function AES_GCM_Decrypt(key: BufferSource, iv: BufferSource, ciphertext: BufferSource, aad?: BufferSource): Promise { - const keyObj = await subtle.importKey("raw", key, { - name: "AES-GCM", - }, false, ["decrypt"]); - - const plaintext = await subtle.decrypt({ - name: "AES-GCM", - iv: iv, - additionalData: aad - }, keyObj, ciphertext); - //아마도 tag 검증 실패시 예외가 발생할 것으로 예상 - - return plaintext; -} \ No newline at end of file diff --git a/server/util/defs.ts b/server/util/defs.ts deleted file mode 100644 index e69de29..0000000 diff --git a/server/util/hexToRgb.ts b/server/util/hexToRgb.ts deleted file mode 100644 index 8c396f0..0000000 --- a/server/util/hexToRgb.ts +++ /dev/null @@ -1,8 +0,0 @@ -export function hexToRgb(hex: string): { r: number; g: number; b: number; } | null { - const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); - return result ? { - r: parseInt(result[1], 16), - g: parseInt(result[2], 16), - b: parseInt(result[3], 16) - } : null; -} diff --git a/server/util/isBrightColor.ts b/server/util/isBrightColor.ts deleted file mode 100644 index acfbbea..0000000 --- a/server/util/isBrightColor.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { unwrap } from ".//unwrap.js"; -import { hexToRgb } from "./hexToRgb.js"; - -export function isBrightColor(color: string): boolean { - const cv = unwrap(hexToRgb(color)); - if ((cv.r * 0.299 + cv.g * 0.587 + cv.b * 0.114) > 140) { - return true; - } else { - return false; - } -} diff --git a/server/util/isNotNull.ts b/server/util/isNotNull.ts deleted file mode 100644 index 2e9cc2a..0000000 --- a/server/util/isNotNull.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function isNotNull(value: T|null|undefined):value is T{ - return value !== null && value !== undefined; -} \ No newline at end of file diff --git a/server/util/jsonify.ts b/server/util/jsonify.ts deleted file mode 100644 index 3ec8b4c..0000000 --- a/server/util/jsonify.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { every, isString } from "lodash-es"; - -type JsonifiableLite = - string | number | boolean | bigint | null | undefined | - Date | ArrayBuffer | SharedArrayBuffer | ArrayBufferView | - JsonifiableLite[] | { [key: string]: JsonifiableLite }; - -export type Jsonifiable = - JsonifiableLite | - Jsonifiable[] | - Map | - Set | - { jsonify(): Jsonifiable } | - { [key: string]: Jsonifiable }; - -export type Jsonified = - T extends string ? string : - T extends number ? number : - T extends boolean ? boolean : - T extends bigint ? string : - T extends null ? null : - T extends undefined ? undefined : - T extends Date ? string : - T extends ArrayBuffer ? string : - T extends SharedArrayBuffer ? string : - T extends ArrayBufferView ? string : - T extends (infer K extends Jsonifiable)[] ? Jsonified[] : - T extends Map ? ( - K extends string ? { [key in string]: Jsonified } : [Jsonified, Jsonified][]) : - T extends Set ? Jsonified[] : - T extends object ? ( - T extends { jsonify(): infer V extends Jsonifiable } ? Jsonified : //HACK: jsonify()는 Jsonified여야 함 - {[key in keyof T]: Jsonified}): - T extends unknown ? unknown : - never; - - -/** - * Convert any object to JSON-safe object - */ -export function jsonify(item: T): Jsonified { - if (typeof item === 'string' || typeof item === 'number' || typeof item === 'boolean') { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return item as any; - } - - if (typeof item === 'bigint') { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return item.toString() as any; - } - - if (item === undefined || item === null) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return item as any; - } - - if (item instanceof Date) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return item.toISOString() as any; - } - - if (item instanceof ArrayBuffer || item instanceof SharedArrayBuffer) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return Buffer.from(item).toString('base64') as any; - } - - if (ArrayBuffer.isView(item)) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return Buffer.from(item.buffer, item.byteOffset, item.byteLength).toString('base64') as any; - } - - if (Array.isArray(item)) { - //HACK: depth hack - const result: Jsonified[] = []; - for (const v of item) { - result.push(jsonify(v as string) as Jsonified); - } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return result as any; - } - - if (item instanceof Map) { - //HACK: depth hack - - const onlyStringKey = every(item.keys, isString); - if (onlyStringKey) { - const result: { [key: string]: Jsonified } = {}; - for (const [k, v] of item.entries()) { - result[k as string] = jsonify(v as string) as Jsonified; - } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return result as any; - } - - const result: [Jsonified, Jsonified][] = []; - for (const [k, v] of item.entries()) { - result.push([jsonify(k as string), jsonify(v as string)] as [Jsonified, Jsonified]); - } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return result as any; - } - - if (item instanceof Set) { - const result: Jsonified[] = []; - for (const v of item.values()) { - result.push(jsonify(v as string) as Jsonified); - } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return result as any; - } - - if (typeof item === 'object') { - if (typeof (item as { jsonify(): unknown }).jsonify === 'function') { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return (item as { jsonify(): unknown }).jsonify() as any; - } - - const result: { [key: string]: Jsonified } = {}; - for (const [k, v] of Object.entries(item)) { - if (typeof k !== 'string') { - continue; - } - if (typeof v === 'function') { - continue; - } - result[k] = jsonify(v as string) as Jsonified; - } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return result as any; - } - - throw new Error(`jsonify: invalid type ${typeof item}`); -} \ No newline at end of file diff --git a/server/util/sha2.ts b/server/util/sha2.ts deleted file mode 100644 index 4c9a198..0000000 --- a/server/util/sha2.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { webcrypto } from "node:crypto"; - -const subtle = webcrypto.subtle; - -export async function sha256(msg: ArrayBuffer): Promise{ - return await subtle.digest('SHA-256', msg); -} - -export async function sha512(msg: ArrayBuffer): Promise{ - return await subtle.digest('SHA-512', msg); -} \ No newline at end of file