From c32e60076a9118a54d543973b1f153d6b46fd399 Mon Sep 17 00:00:00 2001 From: cebgcontract <99630598+cebgcontract@users.noreply.github.com> Date: Fri, 28 Oct 2022 17:50:14 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0native=20=E7=9A=84rpc?= =?UTF-8?q?=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/WalletApi.ts | 27 ++++++++++++ src/common/WalletEvent.ts | 40 +++++++++++------- src/config/WalletEnv.ts | 9 ++++ src/config/chain_config.ts | 40 +++++++++++------- src/config/constants.ts | 4 +- src/index.ts | 84 ++++++++++++++++++------------------- src/lib/Http.ts | 70 +++++++++++++++++++++++++++++-- src/manage/DataManage.ts | 44 +++++++++++-------- src/manage/WalletManage.ts | 76 ++++++++++++++++++++++++++------- src/services/NativeSvr.ts | 44 +++++++++++++++++++ src/standards/JCStandard.ts | 1 + src/util/crypto.util.ts | 34 +++++++++------ 12 files changed, 352 insertions(+), 121 deletions(-) create mode 100644 src/api/WalletApi.ts create mode 100644 src/config/WalletEnv.ts create mode 100644 src/services/NativeSvr.ts diff --git a/src/api/WalletApi.ts b/src/api/WalletApi.ts new file mode 100644 index 0000000..8db72e1 --- /dev/null +++ b/src/api/WalletApi.ts @@ -0,0 +1,27 @@ +import { WALLET_API_HOST } from "../config/constants"; +import { GET_JSON, POST_JSON } from "../lib/Http"; + +export function googleAuth(idToken: string) { + const url = `${WALLET_API_HOST}/wallet/login/google`; + return POST_JSON(url, { token: idToken }); +} + +export function getWalletInfo() { + const url = `${WALLET_API_HOST}/wallet/info`; + return GET_JSON(url); +} + +export function uploadWalletInfo(data) { + const url = `${WALLET_API_HOST}/wallet/info`; + return POST_JSON(url, data); +} + +export function fetchUserCollection() { + const url = `${WALLET_API_HOST}/wallet/collection`; + return GET_JSON(url); +} + +export function uploadUserCollection(data) { + const url = `${WALLET_API_HOST}/wallet/collection`; + return POST_JSON(url, data); +} diff --git a/src/common/WalletEvent.ts b/src/common/WalletEvent.ts index 9a49f9d..d2fab98 100644 --- a/src/common/WalletEvent.ts +++ b/src/common/WalletEvent.ts @@ -1,24 +1,36 @@ -let createWalletEvents = () => ({ +var createWalletEvents = () => ({ events: {}, - emit (event, ...args) { + emit(event, ...args) { for (let i of this.events[event] || []) { - i(...args) + i(...args); } }, - on (event, cb) { - ;(this.events[event] = this.events[event] || []).push(cb) - return () => (this.events[event] = this.events[event].filter(i => i !== cb)) + on(event, cb) { + (this.events[event] = this.events[event] || []).push(cb); + return () => + (this.events[event] = this.events[event].filter((i) => i !== cb)); + }, + once(event, cb) { + var callback = (...args) => { + this.events[event] = this.events[event].filter((i) => i !== callback); + cb(...args); + }; + (this.events[event] = this.events[event] || []).push(callback); }, listen(event, cb) { - ;(this.events[event] = this.events[event] || []).push(cb) - return () => (this.events[event] = this.events[event].filter(i => i !== cb)) - } -}) + (this.events[event] = this.events[event] || []).push(cb); + return () => + (this.events[event] = this.events[event].filter((i) => i !== cb)); + }, + remove(event, cb) { + this.events[event] = this.events[event].filter((i) => i !== cb); + }, +}); -export { createWalletEvents } +export { createWalletEvents }; -export const WALLET_CHAIN_CHANGE = 'wallet_chain_change' +export const WALLET_CHAIN_CHANGE = "wallet_chain_change"; -export const WALLET_ACCOUNT_CHANGE = 'wallet_account_change' +export const WALLET_ACCOUNT_CHANGE = "wallet_account_change"; -export const WALLET_TOKEN_TYPE_CHANGE = 'wallet_token_type_change' +export const WALLET_TOKEN_TYPE_CHANGE = "wallet_token_type_change"; diff --git a/src/config/WalletEnv.ts b/src/config/WalletEnv.ts new file mode 100644 index 0000000..e1c2aa8 --- /dev/null +++ b/src/config/WalletEnv.ts @@ -0,0 +1,9 @@ +import { createWalletEvents } from "../common/WalletEvent"; +import { singleton } from "../decorator/singleton.decorator"; + +@singleton +export class WalletEnv { + public idToken: string; + public token: string; + public handler = createWalletEvents(); +} diff --git a/src/config/chain_config.ts b/src/config/chain_config.ts index b91d0e0..a0f12f3 100644 --- a/src/config/chain_config.ts +++ b/src/config/chain_config.ts @@ -114,53 +114,61 @@ export const DEFAULT_NFT_TYPES = { }, 137: { hero: { - address: "0x0EB362BD40F2288fF25A6Ee1b487cB0cb4638e0D", + address: "0xaE08adb5278B107D2501e7c61907e41FEf3887D7", type: "erc721", }, weapon: { - address: "0x29F67A372AC1c6AcF478A564992D421FE20F2cc8", + address: "0xee0044BF2ACEf7C3D7f6781d8f5DC4d2Dd1CE64c", type: "erc721", }, chip: { - address: "0x54B6ED7EDe9355b471985439421Aa1DC7Da6Dc20", + address: "0xc058411B15E544291765F15B13c88582b7bceaD0", type: "erc1155", }, shard: { - address: "0x54B6ED7EDe9355b471985439421Aa1DC7Da6Dc20", + address: "0x1d4c7908E6a6795aE4335D0F072B0A129AAFFdc1", type: "erc1155", }, }, 80001: { hero: { - address: "0x0EB362BD40F2288fF25A6Ee1b487cB0cb4638e0D", + address: "0xaE08adb5278B107D2501e7c61907e41FEf3887D7", type: "erc721", }, weapon: { - address: "0x29F67A372AC1c6AcF478A564992D421FE20F2cc8", + address: "0xee0044BF2ACEf7C3D7f6781d8f5DC4d2Dd1CE64c", type: "erc721", }, chip: { - address: "0x54B6ED7EDe9355b471985439421Aa1DC7Da6Dc20", + address: "0xc058411B15E544291765F15B13c88582b7bceaD0", type: "erc1155", }, shard: { - address: "0x54B6ED7EDe9355b471985439421Aa1DC7Da6Dc20", + address: "0x1d4c7908E6a6795aE4335D0F072B0A129AAFFdc1", type: "erc1155", }, }, }; export const JC_CONTRACTS = { - 321: {}, - 322: {}, + 321: { + nftMall: "0xa44927698D0aC8EF29e91508839cd6e10f773EE0", + evolveFactory: "0x07Bad070e403a4Bad2Eec3BA3894c4524d3d2674", + minterFactory: "0x5ecEFA2707e3f09B9A169ae696B36Df8dB7410ED", + }, + 322: { + nftMall: "0xa44927698D0aC8EF29e91508839cd6e10f773EE0", + evolveFactory: "0x07Bad070e403a4Bad2Eec3BA3894c4524d3d2674", + minterFactory: "0x5ecEFA2707e3f09B9A169ae696B36Df8dB7410ED", + }, 137: { - nftMall: "", - evolveFactory: "", - minterFactory: "", + nftMall: "0xa44927698D0aC8EF29e91508839cd6e10f773EE0", + evolveFactory: "0x07Bad070e403a4Bad2Eec3BA3894c4524d3d2674", + minterFactory: "0x5ecEFA2707e3f09B9A169ae696B36Df8dB7410ED", }, 80001: { - nftMall: "", - evolveFactory: "", - minterFactory: "", + nftMall: "0xa44927698D0aC8EF29e91508839cd6e10f773EE0", + evolveFactory: "0x07Bad070e403a4Bad2Eec3BA3894c4524d3d2674", + minterFactory: "0x5ecEFA2707e3f09B9A169ae696B36Df8dB7410ED", }, }; diff --git a/src/config/constants.ts b/src/config/constants.ts index 8490971..bca8c0e 100644 --- a/src/config/constants.ts +++ b/src/config/constants.ts @@ -1 +1,3 @@ -export const WALLET_STORAGE_KEY_NAME = 'jc_wallet_data' \ No newline at end of file +export const WALLET_STORAGE_KEY_NAME = "jc_wallet_data"; + +export const WALLET_API_HOST = "http://10.0.1.3:3007"; diff --git a/src/index.ts b/src/index.ts index bb43dcd..d4b16c9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,12 +19,14 @@ import { IAccount, INFT, initAccount, initNFT } from "./data/DataModel"; import { checkPassword, loadData, + loadToken, saveData, savePassword, } from "./manage/DataManage"; import { WALLET_STORAGE_KEY_NAME } from "./config/constants"; import { DEFALUT_TOKENS, JC_CONTRACTS } from "./config/chain_config"; import { + loadInternalWallet, newAccount, newMnemonic, restoreWalletByMnemonic, @@ -35,6 +37,7 @@ import { ERC1155Standard } from "./standards/ERC1155Standard"; import { ZWalletConnect } from "./comp/ZWalletConnect"; import { getJCErc721Info, getTypeByAddress, UNKNOW } from "./util/chain.util"; import { JCStandard } from "./standards/JCStandard"; +import { NativeSvr } from "./services/NativeSvr"; var global = (typeof globalThis !== "undefined" && globalThis) || @@ -80,6 +83,7 @@ export default class JCWallet { public erc721Standard: ERC721Standard; public erc1155Standard: ERC1155Standard; public jcStandard: JCStandard; + public nativeSvr: NativeSvr; public wConnect: ZWalletConnect; public mainHandlers = createWalletEvents(); public data: IAccount[] = []; @@ -89,15 +93,8 @@ export default class JCWallet { private rpcUrl: string = ""; public rpc: any = {}; - constructor({ - type, - chain, - password, - }: { - type: number; - chain: number; - password: string; - }) { + constructor({ type, chain }: { type: number; chain: number }) { + this.nativeSvr = new NativeSvr(); this.walletType = type; chain = chain || 80001; let data = AllChains.find((o) => o.id === chain); @@ -108,38 +105,40 @@ export default class JCWallet { this.rpcUrl = data.rpc; console.log(`rpc url: ${this.rpcUrl}`); if (this.walletType === WalletType.INTERNAL) { - if (!password) { - throw new Error("need password"); - } - if (!checkPassword(password)) { - throw new Error("password error"); - } - this.password = password; - savePassword(password); - this.initInternalWallet(); + this.prepareInternalWallet(); } this.init({ chains: [80001], password: this.password }); window.jc = { wallet: this }; } - private initInternalWallet() { - var start = Date.now(); - this.web3 = new Web3(this.rpcUrl); - console.log(`init web3 cost: ${(Date.now() - start) / 1000}`); - this.erc20Standard = new ERC20Standard(this.web3); - this.erc721Standard = new ERC721Standard(this.web3); - this.erc1155Standard = new ERC1155Standard(this.web3); - this.jcStandard = new JCStandard(this.web3); + private prepareInternalWallet() { + let token = loadToken(); + if (!token) { + // check if token expired + } else { + // to goole login + } + } - start = Date.now(); - this.wallet = this.web3.eth.accounts.wallet.load( - this.password, - WALLET_STORAGE_KEY_NAME - ); - console.log(`load wallet cost: ${(Date.now() - start) / 1000}`); - start = Date.now(); - this.data = loadData(); - console.log(`init wallet ext data cost: ${(Date.now() - start) / 1000}`); + public async initInternalWallet() { + await loadInternalWallet(); + // var start = Date.now(); + // this.web3 = new Web3(this.rpcUrl); + // console.log(`init web3 cost: ${(Date.now() - start) / 1000}`); + // this.erc20Standard = new ERC20Standard(this.web3); + // this.erc721Standard = new ERC721Standard(this.web3); + // this.erc1155Standard = new ERC1155Standard(this.web3); + // this.jcStandard = new JCStandard(this.web3); + + // start = Date.now(); + // this.wallet = this.web3.eth.accounts.wallet.load( + // this.password, + // WALLET_STORAGE_KEY_NAME + // ); + // console.log(`load wallet cost: ${(Date.now() - start) / 1000}`); + // start = Date.now(); + // this.data = loadData(); + // console.log(`init wallet ext data cost: ${(Date.now() - start) / 1000}`); } /** * init wallet connect @@ -189,13 +188,14 @@ export default class JCWallet { } } } - if (this.walletType !== WalletType.INTERNAL) { - return; - } - if (!this.wallet || this.wallet.length === 0) { - // this.createAccount(); - this.newWallet(password); - } + return; + // if (this.walletType !== WalletType.INTERNAL) { + // return; + // } + // if (!this.wallet || this.wallet.length === 0) { + // // this.createAccount(); + // this.newWallet(password); + // } } public newWallet(password: string) { diff --git a/src/lib/Http.ts b/src/lib/Http.ts index c4f12a5..8de6477 100644 --- a/src/lib/Http.ts +++ b/src/lib/Http.ts @@ -1,9 +1,71 @@ -import 'whatwg-fetch' +import "whatwg-fetch"; +import { WalletEnv } from "../config/WalletEnv"; + +export async function request(url, option) { + let headers = new Headers(); + headers.append("Content-Type", "application/json"); + let walletEnv = new WalletEnv(); + if (walletEnv.token) { + headers.append("Authorization", `Bearer ${walletEnv.token}`); + } + let optionInt: any = { + method: "GET", + mode: "cors", + headers, + cache: "no-cache", + }; + Object.assign(optionInt, option); + // console.log("request option", JSON.stringify(optionInt)); + return fetch(url, optionInt); +} export async function GET(url: string) { - return fetch(url) + return request(url, {}); } export async function GET_JSON(url: string) { - return fetch(url).then(res => {return res.json()}) -} \ No newline at end of file + return GET(url).then((res) => { + return res.json(); + }); +} + +export async function POST(url, data) { + let option = { + method: "POST", + body: JSON.stringify(data), + }; + return request(url, option); +} + +export async function POST_JSON(url, data) { + return POST(url, data).then((res) => { + return res.json(); + }); +} +/** + * var headers = new Headers(); + headers.append("Content-Type", "application/json"); + if (window.chain.logined) { + formData.token = window.chain.token; + } + try { + let data = await fetch( + FORM_URL, + { + method: 'POST', + headers, + mode: 'cors', + cache: 'no-cache', + body: JSON.stringify(formData) + }, + ) + .then(res => { + return res.json() + }) + if (!data.errcode) { + showSuccess(); + } + } catch (err) { + console.log('error post data', err); + } + */ diff --git a/src/manage/DataManage.ts b/src/manage/DataManage.ts index 6e82f39..5bb94a1 100644 --- a/src/manage/DataManage.ts +++ b/src/manage/DataManage.ts @@ -1,37 +1,45 @@ import { IAccount } from "../data/DataModel"; import { aesDecrypt, aesEncrypt } from "../util/crypto.util"; -import sha256 from 'crypto-js/sha256' +import sha256 from "crypto-js/sha256"; -const LOCAL_ACCOUNT_DATAS = 'local_account_datas' -const LOCAL_WALLET_MNEMONIC = 'local_wallet_mnemonic' -const LOCAL_WALLET_PASSWORD = 'local_wallet_password'; -const LOCAL_PASSWORD_SALT = '_jcwallet'; +const LOCAL_ACCOUNT_DATAS = "local_account_datas"; +const LOCAL_WALLET_TOKEN = "local_wallet_token"; +const LOCAL_WALLET_MNEMONIC = "local_wallet_mnemonic"; +const LOCAL_WALLET_PASSWORD = "local_wallet_password"; +const LOCAL_PASSWORD_SALT = "_jcwallet"; +export function loadToken() { + return localStorage.getItem(LOCAL_WALLET_TOKEN); +} -export function loadData(){ - const dataStr = localStorage.getItem(LOCAL_ACCOUNT_DATAS) - let result: IAccount[] = [] +export function saveToken(token: string) { + localStorage.setItem(LOCAL_WALLET_TOKEN, token); +} + +export function loadData() { + const dataStr = localStorage.getItem(LOCAL_ACCOUNT_DATAS); + let result: IAccount[] = []; if (dataStr) { try { - result = JSON.parse(dataStr) + result = JSON.parse(dataStr); } catch (err) { - console.log('load local data error') + console.log("load local data error"); } } - return result + return result; } export function saveData(datas: IAccount[]) { - const dataStr = JSON.stringify(datas) - localStorage.setItem(LOCAL_ACCOUNT_DATAS, dataStr) + const dataStr = JSON.stringify(datas); + localStorage.setItem(LOCAL_ACCOUNT_DATAS, dataStr); } export function loadMnemonic(password: string) { - let dataStr: string = localStorage.getItem(LOCAL_WALLET_MNEMONIC) + let dataStr: string = localStorage.getItem(LOCAL_WALLET_MNEMONIC); if (dataStr) { - dataStr = aesDecrypt(dataStr, password) - } - return dataStr + dataStr = aesDecrypt(dataStr, password); + } + return dataStr; } export function saveMnemonic(mnemonic: string, password: string) { @@ -48,4 +56,4 @@ export function checkPassword(password: string) { export function savePassword(password: string) { const dataStr = sha256(password + LOCAL_PASSWORD_SALT).toString(); localStorage.setItem(LOCAL_WALLET_PASSWORD, dataStr); -} \ No newline at end of file +} diff --git a/src/manage/WalletManage.ts b/src/manage/WalletManage.ts index fff6f3c..07297bc 100644 --- a/src/manage/WalletManage.ts +++ b/src/manage/WalletManage.ts @@ -1,23 +1,71 @@ -import { hdkey } from 'ethereumjs-wallet' +import { hdkey } from "ethereumjs-wallet"; import { generateMnemonic, mnemonicToSeedSync } from "bip39"; -import { loadMnemonic, saveMnemonic } from './DataManage'; - +import { loadMnemonic, saveMnemonic } from "./DataManage"; +import { NativeSvr } from "../services/NativeSvr"; +import { getWalletInfo, googleAuth, uploadWalletInfo } from "../api/WalletApi"; +import { WalletEnv } from "../config/WalletEnv"; +import { md5Hash, sha1Hash } from "../util/crypto.util"; export function newAccount(password: string, index: number) { - const mnemonic = loadMnemonic(password) - const seed = mnemonicToSeedSync(mnemonic) - const hdWallet = hdkey.fromMasterSeed(seed) - const keyPair1 = hdWallet.derivePath(`m/44'/60'/0'/0/${index}`) - const w1 = keyPair1.getWallet() - return {address: w1.getAddressString(), privateKey: w1.getPrivateKeyString()} + const mnemonic = loadMnemonic(password); + const seed = mnemonicToSeedSync(mnemonic); + const hdWallet = hdkey.fromMasterSeed(seed); + const keyPair1 = hdWallet.derivePath(`m/44'/60'/0'/0/${index}`); + const w1 = keyPair1.getWallet(); + return { + address: w1.getAddressString(), + privateKey: w1.getPrivateKeyString(), + }; } export function newMnemonic(password: string) { - let mnemonic = generateMnemonic() - saveMnemonic(mnemonic, password) - return mnemonic + let mnemonic = generateMnemonic(); + saveMnemonic(mnemonic, password); + return mnemonic; } export function restoreWalletByMnemonic(mnemonic: string, password: string) { - saveMnemonic(mnemonic, password) -} \ No newline at end of file + saveMnemonic(mnemonic, password); +} + +export async function loadInternalWallet() { + let res: any = await new NativeSvr().signWithGoogle(); + console.log("native res: " + res); + let tokenRes = await googleAuth(res); + console.log("wallet token: " + tokenRes.data?.token); + if (tokenRes.errcode || !tokenRes.data?.token) { + return; + } + + new WalletEnv().token = tokenRes.data.token; + let infoRes = await getWalletInfo(); + if (infoRes.errcode) { + return; + } + console.log("wallet info: " + JSON.stringify(infoRes.data)); + let seed = infoRes.data.oid + infoRes.data.is + infoRes.data.salt; + let seedHash = md5Hash(seed); + let idHash = md5Hash(infoRes.data.oid); + if (!infoRes.data.key) { + let time = Date.now(); + //@ts-ignore + let strWallwt = jsb.generateWallet(idHash, seedHash); + console.log("generate wallet cost: " + (Date.now() - time) / 1000); + let walletInfo = JSON.parse(strWallwt); + console.log(strWallwt); + setImmediate(function () { + uploadWalletInfo({ key: walletInfo.master }); + }); + } else { + //@ts-ignore + jsb.prepareWallet(idHash, seedHash, infoRes.data.key); + } + let signStr = walletSign("111"); + console.log("sign str: " + signStr); +} + +export function walletSign(str: string) { + //@ts-ignore + let result = jsb.walletSign(str); + return result; +} diff --git a/src/services/NativeSvr.ts b/src/services/NativeSvr.ts new file mode 100644 index 0000000..edb2a4e --- /dev/null +++ b/src/services/NativeSvr.ts @@ -0,0 +1,44 @@ +import { payloadId } from "@walletconnect/utils"; +import { createWalletEvents } from "../common/WalletEvent"; +import { singleton } from "../decorator/singleton.decorator"; + +@singleton +export class NativeSvr { + _event = createWalletEvents(); + + _subscribeToResponse(id: string, callback) { + this._event.on(`response:${id}`, callback); + } + + _subscribeToCallResponse(id) { + return new Promise((resolve, reject) => { + this._subscribeToResponse(id, (result) => { + if (result.errcode) { + reject(result.errcode); + return; + } + resolve(result.data); + }); + }); + } + + public handleNativeCallback(...args) { + let id = args[0]; + let result = JSON.parse(args[1]); + this._event.emit(`response:${id}`, result); + } + + public signWithGoogle() { + let id = payloadId(); + //@ts-ignore + jsb.signWithGoogle(id); + return this._subscribeToCallResponse(id); + } + + public signOutGoogle() { + let id = payloadId(); + //@ts-ignore + jsb.signOutGoogle(id); + return this._subscribeToCallResponse(id); + } +} diff --git a/src/standards/JCStandard.ts b/src/standards/JCStandard.ts index 5da483a..0d5caeb 100644 --- a/src/standards/JCStandard.ts +++ b/src/standards/JCStandard.ts @@ -22,6 +22,7 @@ export class JCStandard { }) { let address = JC_CONTRACTS[window.jc.wallet.currentChain.id].nftMall; const contract = new this.web3.eth.Contract(abiNftMall, address); + //TODO:: increaseAllowance before call let gas = await contract.methods .buy721NFT(addresses, values, signature) .estimateGas({ gas: 1000000 }); diff --git a/src/util/crypto.util.ts b/src/util/crypto.util.ts index ec1d189..1ea4ed7 100644 --- a/src/util/crypto.util.ts +++ b/src/util/crypto.util.ts @@ -1,5 +1,15 @@ -import { AES, enc, mode, pad } from 'crypto-js'; -import sha256 from 'crypto-js/sha256' +import { AES, enc, mode, pad } from "crypto-js"; +import sha256 from "crypto-js/sha256"; +import sha1 from "crypto-js/sha1"; +import md5 from "crypto-js/md5"; + +export function sha1Hash(str: string) { + return sha1(str).toString(); +} + +export function md5Hash(str: string) { + return md5(str).toString(); +} function generateIV(password: string) { const key = sha256(password).toString(); @@ -7,26 +17,26 @@ function generateIV(password: string) { const ivHex = keyHex.clone(); ivHex.sigBytes = 16; ivHex.words.splice(4); - return {keyHex,ivHex} + return { keyHex, ivHex }; } export function aesEncrypt(text: string, password: string) { - const {keyHex, ivHex} = generateIV(password); + const { keyHex, ivHex } = generateIV(password); const messageHex = enc.Utf8.parse(text); const encrypted = AES.encrypt(messageHex, keyHex, { - "iv": ivHex, - "mode": mode.CBC, - "padding": pad.Pkcs7 + iv: ivHex, + mode: mode.CBC, + padding: pad.Pkcs7, }); return encrypted.toString(); } export function aesDecrypt(encryptedText: string, password: string) { - const {keyHex, ivHex} = generateIV(password); + const { keyHex, ivHex } = generateIV(password); const decrypt = AES.decrypt(encryptedText, keyHex, { - "iv": ivHex, - "mode": mode.CBC, - "padding": pad.Pkcs7 + iv: ivHex, + mode: mode.CBC, + padding: pad.Pkcs7, }); return enc.Utf8.stringify(decrypt); -} \ No newline at end of file +}