From 959740af19c566f44008fd7e786d31c37bb24e75 Mon Sep 17 00:00:00 2001 From: CounterFire2023 <136581895+CounterFire2023@users.noreply.github.com> Date: Wed, 17 Jan 2024 18:54:50 +0800 Subject: [PATCH] move utils to zutils --- src/controllers/alchemyout.controller.ts | 2 +- src/modules/Account.ts | 2 +- src/modules/Base.ts | 2 +- src/plugins/zReqParser.ts | 45 ++--- src/plugins/zTokenParser.ts | 85 ++++----- src/providers/facebook.provider.ts | 22 +-- src/service/alchemy.svr.ts | 10 +- src/service/bridge.svr.ts | 2 +- src/service/game.svr.ts | 8 +- src/service/okxmarket.svr.ts | 2 +- src/test.ts | 2 +- src/utils/net.util.ts | 182 ------------------- src/utils/number.util.ts | 218 ----------------------- src/utils/promise.util.ts | 47 ----- src/utils/security.util.ts | 74 -------- src/utils/string.util.ts | 137 -------------- 16 files changed, 80 insertions(+), 760 deletions(-) delete mode 100644 src/utils/net.util.ts delete mode 100644 src/utils/number.util.ts delete mode 100644 src/utils/promise.util.ts delete mode 100644 src/utils/security.util.ts delete mode 100644 src/utils/string.util.ts diff --git a/src/controllers/alchemyout.controller.ts b/src/controllers/alchemyout.controller.ts index ce7ae86..675fc5a 100644 --- a/src/controllers/alchemyout.controller.ts +++ b/src/controllers/alchemyout.controller.ts @@ -7,7 +7,7 @@ import { reportPayResult } from 'service/game.svr' import { PriceSvr } from 'service/price.svr' import { OrderCacheSvr } from 'service/ordercache.svr' import { BaseController, role, ROLE_ANON, router, ZError } from 'zutils' -import { fromWei, toBigWei } from 'utils/number.util' +import { fromWei, toBigWei } from 'zutils/utils/bn.util' let errorRes = function (msg: string) { logger.info(`error res: ${msg}`) diff --git a/src/modules/Account.ts b/src/modules/Account.ts index de979ac..65821f5 100644 --- a/src/modules/Account.ts +++ b/src/modules/Account.ts @@ -2,7 +2,7 @@ import { getModelForClass, index, modelOptions, mongoose, prop, ReturnModelType, import { dbconn } from 'decorators/dbconn' import { Base, TimeStamps } from '@typegoose/typegoose/lib/defaultClasses' import { BaseModule } from './Base' -import { genRandomString, sha512 } from 'utils/security.util' +import { genRandomString, sha512 } from 'zutils/utils/security.util' export enum PlatEnum { GOOGLE = 0, diff --git a/src/modules/Base.ts b/src/modules/Base.ts index 9d42f79..f5d11d2 100644 --- a/src/modules/Base.ts +++ b/src/modules/Base.ts @@ -6,7 +6,7 @@ import { plugin, prop, ReturnModelType } from '@typegoose/typegoose' import findOrCreate from 'mongoose-findorcreate' import { Connection } from 'mongoose' import { ObjectId } from 'bson' -import { isTrue } from '../utils/string.util' +import { isTrue } from 'zutils/utils/string.util' import { AnyParamConstructor } from '@typegoose/typegoose/lib/types' const jsonExcludeKeys = ['updatedAt', '__v'] diff --git a/src/plugins/zReqParser.ts b/src/plugins/zReqParser.ts index b853d22..4883884 100644 --- a/src/plugins/zReqParser.ts +++ b/src/plugins/zReqParser.ts @@ -1,37 +1,26 @@ -import { - FastifyInstance, - FastifyPluginAsync, - FastifyReply, - FastifyRequest, -} from "fastify"; -import fastifyPlugin from "fastify-plugin"; +import { FastifyInstance, FastifyPluginAsync, FastifyReply, FastifyRequest } from 'fastify' +import fastifyPlugin from 'fastify-plugin' /** * 将post 和 get 的参数统一到 req.params */ -declare module "fastify" { +declare module 'fastify' { interface FastifyInstance { - zReqParser: (request: FastifyRequest, reply: FastifyReply) => {}; + zReqParser: (request: FastifyRequest, reply: FastifyReply) => {} } } -const zReqParserPlugin: FastifyPluginAsync = async function ( - fastify: FastifyInstance, - options?: any -) { - fastify.addHook( - "preValidation", - async (request: FastifyRequest, reply: FastifyReply) => { - let params = request.params || {}; - if (request.query) { - Object.assign(params, request.query); - } - if (request.body) { - Object.assign(params, request.body); - } - request.params = params; +const zReqParserPlugin: FastifyPluginAsync = async function (fastify: FastifyInstance, options?: any) { + fastify.addHook('preValidation', async (request: FastifyRequest, reply: FastifyReply) => { + let params = request.params || {} + if (request.query) { + Object.assign(params, request.query) } - ); - return; -}; + if (request.body) { + Object.assign(params, request.body) + } + request.params = params + }) + return +} -export default fastifyPlugin(zReqParserPlugin, "4.x"); +export default fastifyPlugin(zReqParserPlugin, '4.x') diff --git a/src/plugins/zTokenParser.ts b/src/plugins/zTokenParser.ts index 223194c..184dba1 100644 --- a/src/plugins/zTokenParser.ts +++ b/src/plugins/zTokenParser.ts @@ -1,73 +1,62 @@ -import { - FastifyInstance, - FastifyPluginAsync, - FastifyReply, - FastifyRequest, -} from "fastify"; -import fastifyPlugin from "fastify-plugin"; +import { FastifyInstance, FastifyPluginAsync, FastifyReply, FastifyRequest } from 'fastify' +import fastifyPlugin from 'fastify-plugin' const getTokenFromHeader = function (request) { - let token: string | undefined; + let token: string | undefined if (request.headers && request.headers.authorization) { - const parts = request.headers.authorization.split(" "); + const parts = request.headers.authorization.split(' ') if (parts.length === 2) { - const scheme = parts[0]; + const scheme = parts[0] if (/^Bearer$/i.test(scheme)) { - token = parts[1]; + token = parts[1] } } } - return token; -}; + return token +} const getTokenFromCookie = function (request) { - let token: string | undefined; + let token: string | undefined if (request.cookies) { - if (request.cookies["token"]) { - token = request.cookies["token"]; + if (request.cookies['token']) { + token = request.cookies['token'] } } - return token; -}; + return token +} const getTokenFromParams = function (request) { - let token: string | undefined; - token = request.params && request.params.token; - return token; -}; + let token: string | undefined + token = request.params && request.params.token + return token +} const getTokenFromQuery = function (request) { - let token: string | undefined; - token = request.query && request.query.token; - return token; -}; + let token: string | undefined + token = request.query && request.query.token + return token +} const getTokenFromBody = function (request) { - let token: string | undefined; - token = request.body && request.body.token; - return token; -}; + let token: string | undefined + token = request.body && request.body.token + return token +} -const zTokenParserPlugin: FastifyPluginAsync = async function ( - fastify: FastifyInstance, - options?: any -) { - fastify.addHook( - "preValidation", - async (request: FastifyRequest, reply: FastifyReply) => { - request["token"] = - getTokenFromHeader(request) || - getTokenFromCookie(request) || - getTokenFromParams(request) || - getTokenFromQuery(request) || - getTokenFromBody(request); - } - ); - return; -}; +const zTokenParserPlugin: FastifyPluginAsync = async function (fastify: FastifyInstance, options?: any) { + fastify.addHook('preValidation', async (request: FastifyRequest, reply: FastifyReply) => { + request['token'] = + getTokenFromHeader(request) || + getTokenFromCookie(request) || + getTokenFromParams(request) || + getTokenFromQuery(request) || + getTokenFromBody(request) + }) + return +} /** * 依次从request的header, cookie, params, query和body中获取token, 加入到request.token中 * header中的字段key为authorization, 格式为 Bearer xxxx * 其他位置的key都为 token */ -export default fastifyPlugin(zTokenParserPlugin, "4.x"); +export default fastifyPlugin(zTokenParserPlugin, '4.x') diff --git a/src/providers/facebook.provider.ts b/src/providers/facebook.provider.ts index 259ca1b..6b17559 100644 --- a/src/providers/facebook.provider.ts +++ b/src/providers/facebook.provider.ts @@ -1,19 +1,19 @@ -import {NetClient} from "net/NetClient"; +import { NetClient } from 'net/NetClient' const FACEBOOK_API_HOST = 'https://graph.facebook.com' -export const FACEBOOK_APP_ID = '1204701000119770'; -const FACEBOOK_APP_SECRET = '5a1deba64b30c7326f497fc52691207f'; +export const FACEBOOK_APP_ID = '1204701000119770' +const FACEBOOK_APP_SECRET = '5a1deba64b30c7326f497fc52691207f' export async function getAppAccessToken() { - const url = `${FACEBOOK_API_HOST}/oauth/access_token?client_id=${FACEBOOK_APP_ID}&clent_secret=${FACEBOOK_APP_SECRET}&grant_type=client_credentials`; - return new NetClient().httpGet(url); -} -export async function verifyFbUserAccessToken(accessToken: string){ - const url = `${FACEBOOK_API_HOST}/debug_token?input_token=${accessToken}&access_token=GG|${FACEBOOK_APP_ID}|${FACEBOOK_APP_SECRET}`; - return new NetClient().httpGet(url); + const url = `${FACEBOOK_API_HOST}/oauth/access_token?client_id=${FACEBOOK_APP_ID}&clent_secret=${FACEBOOK_APP_SECRET}&grant_type=client_credentials` + return new NetClient().httpGet(url) +} +export async function verifyFbUserAccessToken(accessToken: string) { + const url = `${FACEBOOK_API_HOST}/debug_token?input_token=${accessToken}&access_token=GG|${FACEBOOK_APP_ID}|${FACEBOOK_APP_SECRET}` + return new NetClient().httpGet(url) } export async function fetchUserInfo(accessToken: string) { - const url = `${FACEBOOK_API_HOST}/me?fields=["email","id", "name"]&access_token=${accessToken}`; - return new NetClient().httpGet(url); + const url = `${FACEBOOK_API_HOST}/me?fields=["email","id", "name"]&access_token=${accessToken}` + return new NetClient().httpGet(url) } diff --git a/src/service/alchemy.svr.ts b/src/service/alchemy.svr.ts index 8510cd7..615832b 100644 --- a/src/service/alchemy.svr.ts +++ b/src/service/alchemy.svr.ts @@ -1,10 +1,10 @@ import axios from 'axios' -import { hmacsha256, md5, sha1 } from 'utils/security.util' +import { hmacSha256, md5, sha1 } from 'zutils/utils/security.util' import crypto from 'crypto' -import { generateKVStr } from 'utils/net.util' +import { generateKVStr } from 'zutils/utils/net.util' import logger from 'logger/logger' import { GasSvr } from './gas.svr' -import { toBigInt, toBigWei } from 'utils/number.util' +import { toBigInt, toBigWei } from 'zutils/utils/bn.util' import { PriceSvr } from './price.svr' export function createSimpleSign(data: any) { @@ -17,7 +17,7 @@ export function createSimpleSign(data: any) { .sort() .map(key => `${key}=${signData[key]}`) .join('&') - let sign = hmacsha256(signStr, secret) + let sign = hmacSha256(signStr, secret).toLowerCase() return { appid, timestamp, @@ -85,7 +85,7 @@ export function checkSimpleSign(headers: any, data: any) { .sort() .map(key => `${key}=${signData[key]}`) .join('&') - const expectedSign = hmacsha256(signStr, process.env.ALCHEMY_APP_SECRET) + const expectedSign = hmacSha256(signStr, process.env.ALCHEMY_APP_SECRET).toLowerCase() logger.info('compare sign: ', sign, expectedSign) // const expectedSign = sha1(appIdToCheck + process.env.ALCHEMY_APP_SECRET + timestamp) return sign === expectedSign diff --git a/src/service/bridge.svr.ts b/src/service/bridge.svr.ts index d247a85..ebe706c 100644 --- a/src/service/bridge.svr.ts +++ b/src/service/bridge.svr.ts @@ -1,4 +1,4 @@ -import { shortUuid, uuid } from 'utils/security.util' +import { shortUuid } from 'zutils/utils/security.util' import { ZError, singleton } from 'zutils' export interface IQrData { diff --git a/src/service/game.svr.ts b/src/service/game.svr.ts index 6f3f343..9e001a2 100644 --- a/src/service/game.svr.ts +++ b/src/service/game.svr.ts @@ -1,7 +1,7 @@ import axios from 'axios' import { PayRecordClass } from 'modules/PayRecord' import { DocumentType } from '@typegoose/typegoose' -import { hmacsha256 } from 'utils/security.util' +import { hmacSha256 } from 'zutils/utils/security.util' import { NetClient } from 'net/NetClient' import logger from 'logger/logger' import { ReportQueue } from 'modules/ReportQueue' @@ -47,7 +47,7 @@ export function assembleGameData(data: DocumentType, mini = true export function checkGameSign({ id, timestamp, sign }: { id: string; timestamp: string; sign: string }) { const signStr = `id=${id}×tamp=${timestamp}` - const hash = hmacsha256(signStr, process.env.HASH_SALT) + const hash = hmacSha256(signStr, process.env.HASH_SALT).toLowerCase() return sign === hash } @@ -57,7 +57,7 @@ export async function reportPayResult(data: DocumentType) { .sort() .map(key => `${key}=${encodeURIComponent(repData[key])}`) .join('&') - const sign = hmacsha256(signStr, process.env.HASH_SALT) + const sign = hmacSha256(signStr, process.env.HASH_SALT).toLowerCase() const url = `${process.env.GAME_PAY_CB_URL}?c=Shop&a=buyGoodsDirect&${signStr}&sign=${sign}` const reqConfig: any = { method: 'get', @@ -92,7 +92,7 @@ export async function reportPurchaseResult(records: IPayResult[], channel: strin .join('&'), ) .join('&') - const sign = hmacsha256(signStr, process.env.HASH_SALT) + const sign = hmacSha256(signStr, process.env.HASH_SALT).toLowerCase() reportData.sign = sign const reqData = { url, diff --git a/src/service/okxmarket.svr.ts b/src/service/okxmarket.svr.ts index 7d165fb..ce1e40a 100644 --- a/src/service/okxmarket.svr.ts +++ b/src/service/okxmarket.svr.ts @@ -1,7 +1,7 @@ import axios from 'axios' import { HTTP_GET, HTTP_POST } from 'common/Constants' import logger from 'logger/logger' -import { generateKVStr } from 'utils/net.util' +import { generateKVStr } from 'zutils/utils/net.util' import { prepareOkxReqCfg } from 'utils/okx.utils' const OKX_BASE = 'https://www.okx.com/api/v5/mktplace' diff --git a/src/test.ts b/src/test.ts index 8d38017..97426b0 100644 --- a/src/test.ts +++ b/src/test.ts @@ -1,6 +1,6 @@ import { GasSvr } from 'service/gas.svr' import { PriceSvr } from 'service/price.svr' -import { fromWei, toBigInt, toBigWei } from 'utils/number.util' +import { fromWei, toBigInt, toBigWei } from 'zutils/utils/bn.util' async function main() { let cryptoPrice = '0.1' diff --git a/src/utils/net.util.ts b/src/utils/net.util.ts deleted file mode 100644 index 0555091..0000000 --- a/src/utils/net.util.ts +++ /dev/null @@ -1,182 +0,0 @@ -const TIMEOUT_ERROR = new Error('timeout') - -const hexRe = /^[0-9A-Fa-f]+$/gu - -/** - * Execute fetch and verify that the response was successful. - * - * @param request - Request information. - * @param options - Fetch options. - * @returns The fetch response. - */ -export async function successfulFetch(request: string, options?: RequestInit) { - const response = await fetch(request, options) - if (!response.ok) { - throw new Error(`Fetch failed with status '${response.status}' for request '${request}'`) - } - return response -} - -/** - * Execute fetch and return object response. - * - * @param request - The request information. - * @param options - The fetch options. - * @returns The fetch response JSON data. - */ -export async function handleFetch(request: string, options?: RequestInit) { - const response = await successfulFetch(request, options) - const object = await response.json() - return object -} - -/** - * Execute fetch and return object response, log if known error thrown, otherwise rethrow error. - * - * @param request - the request options object - * @param request.url - The request url to query. - * @param request.options - The fetch options. - * @param request.timeout - Timeout to fail request - * @param request.errorCodesToCatch - array of error codes for errors we want to catch in a particular context - * @returns The fetch response JSON data or undefined (if error occurs). - */ -export async function fetchWithErrorHandling({ - url, - options, - timeout, - errorCodesToCatch, -}: { - url: string - options?: RequestInit - timeout?: number - errorCodesToCatch?: number[] -}) { - let result - try { - if (timeout) { - result = Promise.race([ - await handleFetch(url, options), - new Promise((_, reject) => - setTimeout(() => { - reject(TIMEOUT_ERROR) - }, timeout), - ), - ]) - } else { - result = await handleFetch(url, options) - } - } catch (e) { - logOrRethrowError(e, errorCodesToCatch) - } - return result -} - -/** - * Fetch that fails after timeout. - * - * @param url - Url to fetch. - * @param options - Options to send with the request. - * @param timeout - Timeout to fail request. - * @returns Promise resolving the request. - */ -export async function timeoutFetch(url: string, options?: RequestInit, timeout = 500): Promise { - return Promise.race([ - successfulFetch(url, options), - new Promise((_, reject) => - setTimeout(() => { - reject(TIMEOUT_ERROR) - }, timeout), - ), - ]) -} - -/** - * Utility method to log if error is a common fetch error and otherwise rethrow it. - * - * @param error - Caught error that we should either rethrow or log to console - * @param codesToCatch - array of error codes for errors we want to catch and log in a particular context - */ -function logOrRethrowError(error: any, codesToCatch: number[] = []) { - if (!error) { - return - } - - const includesErrorCodeToCatch = codesToCatch.some(code => - error.message.includes(`Fetch failed with status '${code}'`), - ) - - if ( - error instanceof Error && - (includesErrorCodeToCatch || error.message.includes('Failed to fetch') || error === TIMEOUT_ERROR) - ) { - console.error(error) - } else { - throw error - } -} - -/** - * 生成 key1=val1&key2=val2的字符串 - * @param {object} data 需要处理的对象 - * @param {boolean} sort 是否按key生序重排 - * @param {boolean} ignoreNull 是否过滤空值(空格或者null值不参与拼接) - * @param splitChar 连接的字符, 默认是& - * @param equalChar = - */ -export function generateKVStr({ - data = {}, - sort = false, - encode = false, - ignoreNull = true, - splitChar = '&', - equalChar = '=', - uri = '', -}: { - data?: any - sort?: boolean - encode?: boolean - ignoreNull?: boolean - splitChar?: string - equalChar?: string - uri?: string -}) { - const keys = Object.keys(data) - sort && keys.sort() - let result = '' - let i = 0 - for (let key of keys) { - if (ignoreNull && !data[key]) { - continue - } - if (i++ > 0) result += splitChar - if (encode) { - result += `${key}${equalChar}${encodeURIComponent(data[key])}` - } else { - result += `${key}${equalChar}${data[key]}` - } - } - if (uri) { - const joinChar = uri.search(/\?/) === -1 ? '?' : '&' - result = uri + joinChar + result - } - return result -} - -/** - * 将key1=val&key2=val的字符串组装成对象 - * @param str key1=val&key2=val的字符串 - * @param splitChar 连接的字符, 默认是& - * @param equalChar = - */ -export function keyValToObject(str: string, splitChar: string = '&', equalChar = '='): {} { - let result: any = {} - if (!str) { - return result - } - let arrs = str.split(splitChar) - for (let sub of arrs) { - let subArr = sub.split(equalChar) - result[subArr[0]] = subArr[1] - } - return result -} diff --git a/src/utils/number.util.ts b/src/utils/number.util.ts deleted file mode 100644 index cd5733f..0000000 --- a/src/utils/number.util.ts +++ /dev/null @@ -1,218 +0,0 @@ -export declare type HexString = string -export declare type Numbers = number | bigint | string | HexString - -const isHexStrict = hex => typeof hex === 'string' && /^((-)?0x[0-9a-f]+|(0x))$/i.test(hex) -export declare type ValidInputTypes = Uint8Array | bigint | string | number | boolean -export const isHex = (hex: ValidInputTypes): boolean => - typeof hex === 'number' || - typeof hex === 'bigint' || - (typeof hex === 'string' && /^((-0x|0x|-)?[0-9a-f]+|(0x))$/i.test(hex)) -const base = BigInt(10) -const expo10 = (expo: number) => base ** BigInt(expo) - -export const ethUnitMap = { - noether: BigInt('0'), - wei: BigInt(1), - kwei: expo10(3), - Kwei: expo10(3), - babbage: expo10(3), - femtoether: expo10(3), - mwei: expo10(6), - Mwei: expo10(6), - lovelace: expo10(6), - picoether: expo10(6), - gwei: expo10(9), - Gwei: expo10(9), - shannon: expo10(9), - nanoether: expo10(9), - nano: expo10(9), - szabo: expo10(12), - microether: expo10(12), - micro: expo10(12), - finney: expo10(15), - milliether: expo10(15), - milli: expo10(15), - ether: expo10(18), - kether: expo10(21), - grand: expo10(21), - mether: expo10(24), - gether: expo10(27), - tether: expo10(30), -} - -export type EtherUnits = keyof typeof ethUnitMap - -/** - * Converts value to it's number representation - */ -export const hexToNumber = (value: string): bigint | number => { - if (!isHexStrict(value)) { - throw new Error('Invalid hex string') - } - - const [negative, hexValue] = value.startsWith('-') ? [true, value.slice(1)] : [false, value] - const num = BigInt(hexValue) - - if (num > Number.MAX_SAFE_INTEGER) { - return negative ? -num : num - } - - if (num < Number.MIN_SAFE_INTEGER) { - return num - } - - return negative ? -1 * Number(num) : Number(num) -} - -export const toNumber = (value: Numbers): number | bigint => { - if (typeof value === 'number') { - return value - } - - if (typeof value === 'bigint') { - return value >= Number.MIN_SAFE_INTEGER && value <= Number.MAX_SAFE_INTEGER ? Number(value) : value - } - - if (typeof value === 'string' && isHexStrict(value)) { - return hexToNumber(value) - } - - try { - return toNumber(BigInt(value)) - } catch { - throw new Error('ivalid number: ' + value) - } -} - -/** - * Auto converts any given value into it's bigint representation - * - * @param value - The value to convert - * @returns - Returns the value in bigint representation - - * @example - * ```ts - * console.log(web3.utils.toBigInt(1)); - * > 1n - * ``` - */ -export const toBigInt = (value: unknown): bigint => { - if (typeof value === 'number') { - return BigInt(value) - } - - if (typeof value === 'bigint') { - return value - } - - // isHex passes for dec, too - if (typeof value === 'string' && isHex(value)) { - return BigInt(value) - } - - if (typeof value === 'string' && value.indexOf(',') >= 0) { - return BigInt(value.replace(/,/g, '')) - } - - throw new Error('invalid number' + value) -} - -export const toBigWei = (number: Numbers, unit: EtherUnits = 'ether'): bigint => { - return toBigInt(toWei(number, unit)) -} - -export const toWei = (number: Numbers, unit: EtherUnits = 'ether'): string => { - const denomination = ethUnitMap[unit] - - if (!denomination) { - throw new Error('error unit: ' + unit) - } - - // if value is decimal e.g. 24.56 extract `integer` and `fraction` part - // to avoid `fraction` to be null use `concat` with empty string - typeof number === 'string' && number.indexOf(',') >= 0 && (number = number.replace(/,/g, '')) - const [integer, fraction] = String(typeof number === 'string' && !isHexStrict(number) ? number : toNumber(number)) - .split('.') - .concat('') - - // join the value removing `.` from - // 24.56 -> 2456 - const value = BigInt(`${integer}${fraction}`) - - // multiply value with denomination - // 2456 * 1000000 -> 2456000000 - const updatedValue = value * denomination - - // count number of zeros in denomination - const numberOfZerosInDenomination = denomination.toString().length - 1 - - // check which either `fraction` or `denomination` have lower number of zeros - const decimals = Math.min(fraction.length, numberOfZerosInDenomination) - - if (decimals === 0) { - return updatedValue.toString() - } - - // Add zeros to make length equal to required decimal points - // If string is larger than decimal points required then remove last zeros - return updatedValue.toString().padStart(decimals, '0').slice(0, -decimals) -} - -/** - * Takes a number of wei and converts it to any other ether unit. - * @param number - The value in wei - * @param unit - The unit to convert to - * @returns - Returns the converted value in the given unit - * - * @example - * ```ts - * console.log(web3.utils.fromWei("1", "ether")); - * > 0.000000000000000001 - * - * console.log(web3.utils.fromWei("1", "shannon")); - * > 0.000000001 - * ``` - */ -export const fromWei = (number: Numbers, unit: EtherUnits = 'ether'): string => { - const denomination = ethUnitMap[unit] - - if (!denomination) { - throw new Error('invalid unit: ' + unit) - } - - // value in wei would always be integer - // 13456789, 1234 - const value = String(toNumber(number)) - - // count number of zeros in denomination - // 1000000 -> 6 - const numberOfZerosInDenomination = denomination.toString().length - 1 - - if (numberOfZerosInDenomination <= 0) { - return value.toString() - } - - // pad the value with required zeros - // 13456789 -> 13456789, 1234 -> 001234 - const zeroPaddedValue = value.padStart(numberOfZerosInDenomination, '0') - - // get the integer part of value by counting number of zeros from start - // 13456789 -> '13' - // 001234 -> '' - const integer = zeroPaddedValue.slice(0, -numberOfZerosInDenomination) - - // get the fraction part of value by counting number of zeros backward - // 13456789 -> '456789' - // 001234 -> '001234' - const fraction = zeroPaddedValue.slice(-numberOfZerosInDenomination).replace(/\.?0+$/, '') - - if (integer === '') { - return `0.${fraction}` - } - - if (fraction === '') { - return integer - } - - return `${integer}.${fraction}` -} diff --git a/src/utils/promise.util.ts b/src/utils/promise.util.ts deleted file mode 100644 index 1cb6ebe..0000000 --- a/src/utils/promise.util.ts +++ /dev/null @@ -1,47 +0,0 @@ -/** - * - * @param {Function} cb - * @param {number} maxRetries - * @param {any[]} errorWhiteList - * @param {number} retries - * @return {Promise} - */ -export function retry(cb: Function, maxRetries: number = 3, errorWhiteList: any[] = [], retries: number = 0) { - return new Promise((resolve, reject) => { - cb() - .then(resolve) - .catch(e => { - if (errorWhiteList.indexOf(e.constructor) !== -1 && retries++ < maxRetries) { - setTimeout(() => { - retry(cb, maxRetries, errorWhiteList, retries) - .then(resolve) - .catch(e2 => reject(e2)) - }, Math.floor(Math.random() * Math.pow(2, retries) * 400)) - } else { - reject(e) - } - }) - }) -} - -export class Deferred { - public promise: Promise - - public resolve: Function - public reject: Function - - constructor() { - this.promise = new Promise((resolve, reject) => { - this.resolve = resolve - this.reject = reject - }) - } - - public then(func: (value: T) => any) { - return this.promise.then.apply(this.promise, arguments) - } - - public catch(func: (value: any) => any) { - return this.promise.catch(func) - } -} diff --git a/src/utils/security.util.ts b/src/utils/security.util.ts deleted file mode 100644 index 5d21ccf..0000000 --- a/src/utils/security.util.ts +++ /dev/null @@ -1,74 +0,0 @@ -import crypto from 'crypto' -import { compressUuid } from './string.util' -const ENCODER = 'base64' -const REG_KEY = /^[0-9a-fA-F]{63,64}$/ - -export function isEncrypt(msg: string) { - return !REG_KEY.test(msg) -} - -export function aesEncrypt(text: string, password: string, iv: string) { - var md5 = crypto.createHash('md5') - const key = md5.update(password).digest('hex') - let cipher = crypto.createCipheriv('aes-256-cbc', key, iv) - let encrypted = cipher.update(text, 'utf8', ENCODER) - encrypted += cipher.final(ENCODER) - return encrypted -} - -export function aesDecrypt(encryptedText: string, password: string, iv: string) { - var md5 = crypto.createHash('md5') - const key = md5.update(password).digest('hex') - let decipher = crypto.createDecipheriv('aes-256-cbc', key, iv) - let decrypted = decipher.update(encryptedText, ENCODER, 'utf8') - return decrypted + decipher.final('utf8') -} - -export function hmacsha256(text: string, secret: string) { - const mac = crypto.createHmac('sha256', secret) - const data = mac.update(text).digest('hex').toLowerCase() - console.log(`HmacSHA256 rawContent is [${text}], key is [${secret}], hash result is [${data}]`) - return data -} - -export function sha512(password: string, salt: string) { - let hash = crypto.createHmac('sha512', salt) - hash.update(password) - let value = hash.digest('hex') - return { - salt: salt, - passwordHash: value, - } -} - -export function sha3_256(str: string) { - let hash = crypto.createHash('sha3-256') - hash.update(str) - return hash.digest('hex') -} - -export function genRandomString(length: number) { - return crypto - .randomBytes(Math.ceil(length / 2)) - .toString('hex') - .slice(0, length) -} - -export function uuid() { - return crypto.randomUUID() -} - -export function shortUuid() { - let uid = uuid() - return compressUuid(uid) -} - -export function md5(content: string) { - var md5 = crypto.createHash('md5') - return md5.update(content).digest('hex') -} - -export function sha1(content: string) { - var md5 = crypto.createHash('sha1') - return md5.update(content).digest('hex') -} diff --git a/src/utils/string.util.ts b/src/utils/string.util.ts deleted file mode 100644 index 19bdd13..0000000 --- a/src/utils/string.util.ts +++ /dev/null @@ -1,137 +0,0 @@ -/** - * 根据key升序生成 key1=val1&key2=val2的字符串 - * @param {object} data 需要处理的对象 - * @param {boolean} ignoreNull 是否过滤空值(空格或者null值不参与拼接) - * @param splitChar 连接的字符, 默认是& - * @param equalChar = - */ -export function generateKeyValStr(data: Record, ignoreNull = true, splitChar = '&', equalChar = '=') { - const keys = Object.keys(data) - keys.sort() - let result = '' - let i = 0 - for (let key of keys) { - if (ignoreNull && !data[key]) { - return - } - if (i++ > 0) result += splitChar - result += `${key}${equalChar}${data[key]}` - } - return result -} - -/** - * 将key1=val&key2=val的字符串组装成对象 - * @param str key1=val&key2=val的字符串 - * @param splitChar 连接的字符, 默认是& - * @param equalChar = - */ -export function keyValToObject(str: string, splitChar: string = '&', equalChar = '='): {} { - let result = {} - if (!str) { - return result - } - let arrs = str.split(splitChar) - for (let sub of arrs) { - let subArr = sub.split(equalChar) - result[subArr[0]] = subArr[1] - } - return result -} - -/** - * 判断传入的值是否为true - * @param {Object} obj 传入值为'true','TRUE',1,'1','on','ON','YES','yes'时,返回true,其他值均返回false - * @return {boolean} - */ -export function isTrue(obj) { - return ( - obj === 'true' || - obj === 'TRUE' || - obj === 'True' || - obj === 'on' || - obj === 'ON' || - obj === true || - obj === 1 || - obj === '1' || - obj === 'YES' || - obj === 'yes' - ) -} - -/** - * 验证ObjectId格式是否正确 - * @param {string} id - * @return {boolean} - */ -export function isObjectId(id: string): boolean { - //mongoose.Types.ObjectId.isValid(id) - return /^[a-fA-F0-9]{24}$/.test(id) -} - -/** - * 10进制 -> 62进制 - * @param {string | number} number - * @return {string} - */ -export function string10to62(number: string | number) { - const chars = '0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ'.split('') - const radix = chars.length - let qutient = +number - const arr = [] - do { - const mod = qutient % radix - qutient = (qutient - mod) / radix - arr.unshift(chars[mod]) - } while (qutient) - return arr.join('') -} - -/** - * 62进制 -> 10 进制 - * @param {string} numberCode - * @return {number} - */ -export function string62to10(numberCode: string) { - const chars = '0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ' - const radix = chars.length - numberCode = numberCode + '' - const len = numberCode.length - let i = 0 - let originNumber = 0 - while (i < len) { - originNumber += Math.pow(radix, i++) * (chars.indexOf(numberCode.charAt(len - i)) || 0) - } - return originNumber -} - -const reNormalUUID = /^[0-9a-fA-F-]{36}$/ -const reLongUUID = /^[0-9a-fA-F]{32}$/ -const reShortUUID = /^[0-9a-zA-Z+/]{22,23}$/ -const n = /-/g - -export function compressUuid(e: string, t: boolean = false) { - if (reNormalUUID.test(e)) { - e = e.replace(n, '') - } else if (!reLongUUID.test(e)) { - return e - } - var r = !0 === t ? 2 : 5 - return compressHex(e, r) -} - -const CHARS_BASE64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' -export function compressHex(e: string, r: number) { - var i, - n = e.length - i = void 0 !== r ? r : n % 3 - for (var s = e.slice(0, i), o = []; i < n; ) { - var u = parseInt(e[i], 16), - a = parseInt(e[i + 1], 16), - c = parseInt(e[i + 2], 16) - o.push(CHARS_BASE64[(u << 2) | (a >> 2)]) - o.push(CHARS_BASE64[((3 & a) << 4) | c]) - i += 3 - } - return s + o.join('') -}