Skip to content

Commit

Permalink
Merge commit '4d2706e3ffe74a6d01deb880ac865a1ede9f11ac' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
gicha committed Jun 15, 2024
2 parents 7aa25ea + 4d2706e commit 54fd336
Show file tree
Hide file tree
Showing 13 changed files with 1,031 additions and 221 deletions.
2 changes: 1 addition & 1 deletion ignore_step.sh
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ else
# Don't build
echo "🛑 - Build cancelled"
exit 0;
fi
fi
11 changes: 8 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@
"react": "18.2.0",
"react-dom": "18.2.0",
"react-switch": "^7.0.0",
"styled-components": "^6.1.11"
"styled-components": "^6.1.11",
"telegram-webapps-types": "^1.0.5",
"@types/telegram-web-app": "^7.2.1",
"jsrsasign": "10.8.2",
"jsrsasign-util": "^1.0.5"
},
"devDependencies": {
"@next/bundle-analyzer": "^13.0.2",
Expand All @@ -50,10 +54,11 @@
"prisma": "^5.15.0",
"tailwindcss": "^3.4.3",
"telegram-webapps-types": "^1.0.5",
"typescript": "4.8.4"
"typescript": "4.8.4",
"@types/jsrsasign": "^10.5.14"
},
"lint-staged": {
"**/*.(ts|tsx)": "bash -c 'pnpm tsc --noEmit'",
"**/*.(ts|tsx|js)": "eslint --fix"
}
}
}
46 changes: 43 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions public/toncoin.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 8 additions & 8 deletions src/components/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,6 @@ const Navigation: React.FC = () => {
<Image src="/icon-home.svg" alt="Home" width={40} height={40} />
<span className="text-bottomBar">Главная</span>
</button>
<button
onClick={() => router.push('/earn')}
className={`flex flex-col items-center ${
router.pathname === '/earn' ? 'text-blue-500' : 'text-gray-500'
}`}>
<Image src="/icon-earn.svg" alt="Earn" width={40} height={40} />
<span className="text-bottomBar">Заработать</span>
</button>
<button
onClick={() => router.push('/calendar')}
className={`flex flex-col items-center ${
Expand All @@ -31,6 +23,14 @@ const Navigation: React.FC = () => {
<Image src="/icon-calendar.svg" alt="Calendar" width={40} height={40} />
<span className="text-bottomBar">Календарь</span>
</button>
<button
onClick={() => router.push('/earn')}
className={`flex flex-col items-center ${
router.pathname === '/earn' ? 'text-blue-500' : 'text-gray-500'
}`}>
<Image src="/toncoin.svg" alt="Earn" width={30} height={30} />
<span className="mt-0.5 text-bottomBar">TON</span>
</button>
</footer>
);
};
Expand Down
51 changes: 51 additions & 0 deletions src/hooks/useTelegramStorage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
function canUseStorage(version: string) {
return versionCompare(version, '6.9') >= 0;
}

function versionCompare(v1: string, v2: string): number {
if (typeof v1 !== 'string') v1 = '';
if (typeof v2 !== 'string') v2 = '';
const _v1 = v1.replace(/^\s+|\s+$/g, '').split('.');
const _v2 = v2.replace(/^\s+|\s+$/g, '').split('.');
let a = Math.max(_v1.length, _v2.length),
i,
p1,
p2;
for (i = 0; i < a; i++) {
p1 = parseInt(_v1[i], 10) || 0;
p2 = parseInt(_v2[i], 10) || 0;
if (p1 === p2) continue;
if (p1 > p2) return 1;
return -1;
}
return 0;
}

export function saveToTelegramStorage(window: Window, key: string, value: string) {
if (canUseStorage(window.Telegram.WebApp.version)) {
window.Telegram.WebApp.CloudStorage.setItem(key, value);
} else {
localStorage.setItem(key, value);
}
}

export function getFromTelegramStorage(window: Window, key: string): string | null {
if (canUseStorage(window.Telegram.WebApp.version)) {
return window.Telegram.WebApp.CloudStorage.getItem(key);
}
return localStorage.getItem(key);
}

export function isUseApi(): boolean {
const type = getFromTelegramStorage(window, 'dataStorageType');
return type === 'backend+ton' || type === 'backend';
}

export function isUseTon(): boolean {
const type = getFromTelegramStorage(window, 'dataStorageType');
return type === 'backend+ton' || type === 'ton';
}

export function getUserTonPrivateKey(): string | null {
return getFromTelegramStorage(window, 'privateKey');
}
32 changes: 32 additions & 0 deletions src/pages/api/contracts/encryption.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { KEYUTIL, KJUR, RSAKey } from 'jsrsasign';

export function generatePrivateKey(): string {
// Generate an RSA key pair
const rsaKey = KEYUTIL.generateKeypair('RSA', 1024);

// Export the keys to PEM format
return KEYUTIL.getPEM(rsaKey.prvKeyObj, 'PKCS8PRV');
}

export function derivePublicKey(privateKeyPEM: string) {
const privKey = KEYUTIL.getKey(privateKeyPEM) as RSAKey;
const privKeyJWK = KEYUTIL.getJWKFromKey(privKey);
let pubKeyJWK;
{
const { e, kty, n } = privKeyJWK;
pubKeyJWK = { e, kty, n };
}
const pubKey = KEYUTIL.getKey(pubKeyJWK);
const pubKeyPEMText = KEYUTIL.getPEM(pubKey);
return pubKeyPEMText;
}

export function encryptData(data: string, publicKeyPEM: string): string {
const publicKey = KEYUTIL.getKey(publicKeyPEM) as RSAKey;
return KJUR.crypto.Cipher.encrypt(data, publicKey, 'RSAOAEP');
}

export function decryptData(data: string, privateKeyPEM: string): string {
const privateKey = KEYUTIL.getKey(privateKeyPEM) as RSAKey;
return KJUR.crypto.Cipher.decrypt(data, privateKey, 'RSAOAEP');
}
32 changes: 21 additions & 11 deletions src/pages/api/contracts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { KeyPair, mnemonicToPrivateKey } from '@ton/crypto';
import { Address, Sender, TonClient, WalletContractV3R2, toNano } from '@ton/ton';
import assert from 'assert';

import { Account } from 'src/ton_client/tact_Account';
import { Account, HealthDataState } from 'src/ton_client/tact_Account';
import { HealthDataRecord } from 'src/ton_client/tact_HealthDataRecord';

const tonClient = new TonClient({
Expand All @@ -11,6 +11,7 @@ const tonClient = new TonClient({
});

async function getBotKeyPair(): Promise<KeyPair> {
// const mnemonics = process.env.REACT_APP_WALLET_MNEMONIC?.split(' ');
const mnemonics = [
'conduct',
'insect',
Expand All @@ -37,6 +38,7 @@ async function getBotKeyPair(): Promise<KeyPair> {
'faint',
'tail',
];
assert(mnemonics, 'Mnemonic is not provided');
return await mnemonicToPrivateKey(mnemonics);
}

Expand Down Expand Up @@ -75,14 +77,17 @@ export function isBlockchainLogicInited() {
return blockchainLogicInited;
}

export async function isContractDeployed(userAddress: string) {
const contract = await Account.fromInit(userAddress);
return await tonClient.isContractDeployed(contract.address);
}

export async function initBlockchainLogic(userAddress: string, publicKey: string) {
if (!blockchainLogicInited) {
if (initing) return;
initing = true;
try {
const sender = await getBotSender();
const contract = await Account.fromInit(userAddress);
const openedContract = tonClient.open(contract);
const deployed = await tonClient.isContractDeployed(contract.address);
if (!deployed) {
await createAccount(userAddress, publicKey);
Expand Down Expand Up @@ -135,7 +140,11 @@ export async function getPublicKey(userAddress: string): Promise<string> {
return publicKey;
}

export async function addHealthData(userAddress: string, encryptedData: string) {
export async function addHealthData(
userAddress: string,
encryptedPeriodDateStart: string,
encryptedPeriodDateEnd: string
) {
assert(
blockchainLogicInited,
'Blockchain logic is not initialized. Run initBlockchainLogic first'
Expand All @@ -152,8 +161,9 @@ export async function addHealthData(userAddress: string, encryptedData: string)
{ value: toNano('0.02') },
{
$$type: 'AddHealthData',
encryptedData,
accessedAddress: dataOwnerAddress,
encryptedPeriodDateStart,
encryptedPeriodDateEnd,
}
);
await waitForAction(
Expand All @@ -179,23 +189,23 @@ export async function getRecordsCount(userAddress: string): Promise<bigint> {
const contract = await Account.fromInit(userAddress);
const openedContract = tonClient.open(contract);
const recordsCount = await openedContract.getNumHealthDataRecords();
console.log(recordsCount);
return recordsCount;
}

export async function getHealthDataAddress(userAddress: string, seqno: bigint): Promise<string> {
export async function getHealthRecordState(
userAddress: string,
seqno: bigint
): Promise<HealthDataState> {
assert(
blockchainLogicInited,
'Blockchain logic is not initialized. Run initBlockchainLogic first'
);
const dataOwnerAddress = Address.parse(userAddress);
// const dataOwnerAddress = Address.parse('UQDKbjIcfM6ezt8KjKJJLshZJJSqX7XOA4ff-W72r5gqPuwA');
const contract = await Account.fromInit(userAddress);
const openedContract = tonClient.open(contract);
const recordContractAddress = await openedContract.getHealthDataAddress(seqno, dataOwnerAddress);
const recordContract = HealthDataRecord.fromAddress(recordContractAddress);
const openedRecordContract = tonClient.open(recordContract);
const encryptedData = await openedRecordContract.getEncryptedData();
console.log(encryptedData);
return encryptedData;
const recordState = await openedRecordContract.getHealthDataState();
return recordState;
}
Loading

0 comments on commit 54fd336

Please sign in to comment.