@tonconnect/sdk 3.3.0-beta.2 → 3.3.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/tonconnect-sdk.min.js +1 -1
- package/dist/tonconnect-sdk.min.js.map +1 -1
- package/lib/cjs/index.cjs +319 -132
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/esm/index.mjs +316 -133
- package/lib/esm/index.mjs.map +1 -1
- package/lib/types/index.d.ts +33 -3
- package/package.json +2 -1
package/lib/cjs/index.cjs
CHANGED
|
@@ -1476,22 +1476,6 @@ function getWindow() {
|
|
|
1476
1476
|
}
|
|
1477
1477
|
return window;
|
|
1478
1478
|
}
|
|
1479
|
-
/**
|
|
1480
|
-
* The function try to get window keys, if it is not available it returns empty array.
|
|
1481
|
-
* As an example, for Safari's private mode it returns empty array, because the browser does not allow to get window keys.
|
|
1482
|
-
*/
|
|
1483
|
-
function tryGetWindowKeys() {
|
|
1484
|
-
const window = getWindow();
|
|
1485
|
-
if (!window) {
|
|
1486
|
-
return [];
|
|
1487
|
-
}
|
|
1488
|
-
try {
|
|
1489
|
-
return Object.keys(window);
|
|
1490
|
-
}
|
|
1491
|
-
catch (_a) {
|
|
1492
|
-
return [];
|
|
1493
|
-
}
|
|
1494
|
-
}
|
|
1495
1479
|
function getDocument() {
|
|
1496
1480
|
if (typeof document === 'undefined') {
|
|
1497
1481
|
return undefined;
|
|
@@ -1536,6 +1520,43 @@ function isLocalStorageAvailable() {
|
|
|
1536
1520
|
function isNodeJs() {
|
|
1537
1521
|
return (typeof process !== 'undefined' && process.versions != null && process.versions.node != null);
|
|
1538
1522
|
}
|
|
1523
|
+
/**
|
|
1524
|
+
* Returns the current domain (hostname) if available.
|
|
1525
|
+
* In browser environment, returns window.location.hostname.
|
|
1526
|
+
* In Node.js environment or when window is not available, returns null.
|
|
1527
|
+
*/
|
|
1528
|
+
function getDomain() {
|
|
1529
|
+
try {
|
|
1530
|
+
// In browser environment
|
|
1531
|
+
if (typeof window !== 'undefined' && window.location) {
|
|
1532
|
+
return window.location.hostname;
|
|
1533
|
+
}
|
|
1534
|
+
else {
|
|
1535
|
+
// In Node.js environment, skip domain validation
|
|
1536
|
+
return null;
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
catch (_a) {
|
|
1540
|
+
return null;
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
/**
|
|
1544
|
+
* Returns an array of [key, value] pairs from window object if available.
|
|
1545
|
+
* In browser environment, returns Object.entries(window).
|
|
1546
|
+
* In Node.js environment or when window is not available, returns empty array.
|
|
1547
|
+
*/
|
|
1548
|
+
function getWindowEntries() {
|
|
1549
|
+
const window = getWindow();
|
|
1550
|
+
if (!window) {
|
|
1551
|
+
return [];
|
|
1552
|
+
}
|
|
1553
|
+
try {
|
|
1554
|
+
return Object.entries(window);
|
|
1555
|
+
}
|
|
1556
|
+
catch (_a) {
|
|
1557
|
+
return [];
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1539
1560
|
|
|
1540
1561
|
class InjectedProvider {
|
|
1541
1562
|
static fromStorage(storage) {
|
|
@@ -1558,8 +1579,8 @@ class InjectedProvider {
|
|
|
1558
1579
|
if (!this.window) {
|
|
1559
1580
|
return [];
|
|
1560
1581
|
}
|
|
1561
|
-
const
|
|
1562
|
-
const wallets =
|
|
1582
|
+
const windowEntries = getWindowEntries();
|
|
1583
|
+
const wallets = windowEntries.filter(([_key, value]) => isJSBridgeWithMetadata(value));
|
|
1563
1584
|
return wallets.map(([jsBridgeKey, wallet]) => ({
|
|
1564
1585
|
name: wallet.tonconnect.walletInfo.name,
|
|
1565
1586
|
appName: wallet.tonconnect.walletInfo.app_name,
|
|
@@ -2105,11 +2126,6 @@ function enableQaMode() {
|
|
|
2105
2126
|
function isQaModeEnabled() {
|
|
2106
2127
|
return qaModeEnabled;
|
|
2107
2128
|
}
|
|
2108
|
-
function logValidationError(message) {
|
|
2109
|
-
if (isQaModeEnabled()) {
|
|
2110
|
-
console.error(`[QA Mode] Validation failed: ${message}`);
|
|
2111
|
-
}
|
|
2112
|
-
}
|
|
2113
2129
|
function showQaModeBanner() {
|
|
2114
2130
|
if (typeof window === 'undefined')
|
|
2115
2131
|
return;
|
|
@@ -2210,8 +2226,8 @@ function startBannerObserver() {
|
|
|
2210
2226
|
class WalletsListManager {
|
|
2211
2227
|
constructor(options) {
|
|
2212
2228
|
var _a;
|
|
2213
|
-
this.
|
|
2214
|
-
this.
|
|
2229
|
+
this.walletsListDTOCache = null;
|
|
2230
|
+
this.walletsListDTOCacheCreationTimestamp = null;
|
|
2215
2231
|
if (isQaModeEnabled()) {
|
|
2216
2232
|
this.walletsListSource =
|
|
2217
2233
|
'https://raw.githubusercontent.com/ton-connect/wallets-list-staging/refs/heads/main/wallets-v2.json';
|
|
@@ -2224,23 +2240,11 @@ class WalletsListManager {
|
|
|
2224
2240
|
}
|
|
2225
2241
|
getWallets() {
|
|
2226
2242
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2227
|
-
|
|
2228
|
-
this.
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
if (!this.walletsListCache) {
|
|
2233
|
-
this.walletsListCache = this.fetchWalletsList();
|
|
2234
|
-
this.walletsListCache
|
|
2235
|
-
.then(() => {
|
|
2236
|
-
this.walletsListCacheCreationTimestamp = Date.now();
|
|
2237
|
-
})
|
|
2238
|
-
.catch(() => {
|
|
2239
|
-
this.walletsListCache = null;
|
|
2240
|
-
this.walletsListCacheCreationTimestamp = null;
|
|
2241
|
-
});
|
|
2242
|
-
}
|
|
2243
|
-
return this.walletsListCache;
|
|
2243
|
+
const [walletsListDTO, currentlyInjectedWallets] = yield Promise.all([
|
|
2244
|
+
this.fetchWalletsListDTO(),
|
|
2245
|
+
this.getCurrentlyInjectedWallets()
|
|
2246
|
+
]);
|
|
2247
|
+
return this.mergeWalletsLists(this.walletConfigDTOListToWalletConfigList(walletsListDTO), currentlyInjectedWallets);
|
|
2244
2248
|
});
|
|
2245
2249
|
}
|
|
2246
2250
|
getEmbeddedWallet() {
|
|
@@ -2250,7 +2254,28 @@ class WalletsListManager {
|
|
|
2250
2254
|
return embeddedWallets.length === 1 ? embeddedWallets[0] : null;
|
|
2251
2255
|
});
|
|
2252
2256
|
}
|
|
2253
|
-
|
|
2257
|
+
fetchWalletsListDTO() {
|
|
2258
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2259
|
+
if (this.cacheTTLMs &&
|
|
2260
|
+
this.walletsListDTOCacheCreationTimestamp &&
|
|
2261
|
+
Date.now() > this.walletsListDTOCacheCreationTimestamp + this.cacheTTLMs) {
|
|
2262
|
+
this.walletsListDTOCache = null;
|
|
2263
|
+
}
|
|
2264
|
+
if (!this.walletsListDTOCache) {
|
|
2265
|
+
this.walletsListDTOCache = this.fetchWalletsListFromSource();
|
|
2266
|
+
this.walletsListDTOCache
|
|
2267
|
+
.then(() => {
|
|
2268
|
+
this.walletsListDTOCacheCreationTimestamp = Date.now();
|
|
2269
|
+
})
|
|
2270
|
+
.catch(() => {
|
|
2271
|
+
this.walletsListDTOCache = null;
|
|
2272
|
+
this.walletsListDTOCacheCreationTimestamp = null;
|
|
2273
|
+
});
|
|
2274
|
+
}
|
|
2275
|
+
return this.walletsListDTOCache;
|
|
2276
|
+
});
|
|
2277
|
+
}
|
|
2278
|
+
fetchWalletsListFromSource() {
|
|
2254
2279
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2255
2280
|
let walletsList = [];
|
|
2256
2281
|
try {
|
|
@@ -2271,16 +2296,21 @@ class WalletsListManager {
|
|
|
2271
2296
|
logError(e);
|
|
2272
2297
|
walletsList = FALLBACK_WALLETS_LIST;
|
|
2273
2298
|
}
|
|
2274
|
-
|
|
2275
|
-
try {
|
|
2276
|
-
currentlyInjectedWallets = InjectedProvider.getCurrentlyInjectedWallets();
|
|
2277
|
-
}
|
|
2278
|
-
catch (e) {
|
|
2279
|
-
logError(e);
|
|
2280
|
-
}
|
|
2281
|
-
return this.mergeWalletsLists(this.walletConfigDTOListToWalletConfigList(walletsList), currentlyInjectedWallets);
|
|
2299
|
+
return walletsList;
|
|
2282
2300
|
});
|
|
2283
2301
|
}
|
|
2302
|
+
getCurrentlyInjectedWallets() {
|
|
2303
|
+
if (!isQaModeEnabled()) {
|
|
2304
|
+
return [];
|
|
2305
|
+
}
|
|
2306
|
+
try {
|
|
2307
|
+
return InjectedProvider.getCurrentlyInjectedWallets();
|
|
2308
|
+
}
|
|
2309
|
+
catch (e) {
|
|
2310
|
+
logError(e);
|
|
2311
|
+
return [];
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2284
2314
|
walletConfigDTOListToWalletConfigList(walletConfigDTO) {
|
|
2285
2315
|
return walletConfigDTO.map(walletConfigDTO => {
|
|
2286
2316
|
const walletConfig = {
|
|
@@ -2923,8 +2953,9 @@ class TonConnectTracker {
|
|
|
2923
2953
|
}
|
|
2924
2954
|
}
|
|
2925
2955
|
|
|
2926
|
-
const tonConnectSdkVersion = "3.3.0-beta.
|
|
2956
|
+
const tonConnectSdkVersion = "3.3.0-beta.3";
|
|
2927
2957
|
|
|
2958
|
+
const bounceableTag = 0x11;
|
|
2928
2959
|
const noBounceableTag = 0x51;
|
|
2929
2960
|
const testOnlyTag = 0x80;
|
|
2930
2961
|
/**
|
|
@@ -2994,25 +3025,40 @@ function parseUserFriendlyAddress(address) {
|
|
|
2994
3025
|
throw new WrongAddressError(`Invalid address length: ${address}`);
|
|
2995
3026
|
}
|
|
2996
3027
|
const addr = decoded.slice(0, 34);
|
|
2997
|
-
const checksum = decoded.slice(34);
|
|
3028
|
+
const checksum = decoded.slice(34, 36);
|
|
2998
3029
|
const calculatedChecksum = crc16(addr);
|
|
2999
3030
|
if (!checksum.every((byte, i) => byte === calculatedChecksum[i])) {
|
|
3000
3031
|
throw new WrongAddressError(`Invalid checksum in address: ${address}`);
|
|
3001
3032
|
}
|
|
3002
|
-
|
|
3003
|
-
|
|
3033
|
+
let tag = addr[0];
|
|
3034
|
+
let isTestOnly = false;
|
|
3035
|
+
let isBounceable = false;
|
|
3036
|
+
if (tag & testOnlyTag) {
|
|
3037
|
+
isTestOnly = true;
|
|
3038
|
+
tag = tag ^ testOnlyTag;
|
|
3039
|
+
}
|
|
3040
|
+
if (tag !== bounceableTag && tag !== noBounceableTag) {
|
|
3041
|
+
throw new WrongAddressError(`Unknown address tag: ${tag}`);
|
|
3042
|
+
}
|
|
3043
|
+
isBounceable = tag === bounceableTag;
|
|
3044
|
+
let wc = null;
|
|
3045
|
+
if (addr[1] === 0xff) {
|
|
3046
|
+
// TODO we should read signed integer here
|
|
3047
|
+
wc = -1;
|
|
3048
|
+
}
|
|
3049
|
+
else {
|
|
3050
|
+
wc = addr[1];
|
|
3051
|
+
}
|
|
3004
3052
|
const hex = addr.slice(2);
|
|
3005
3053
|
if (wc !== 0 && wc !== -1) {
|
|
3006
3054
|
throw new WrongAddressError(`Invalid workchain: ${wc}`);
|
|
3007
3055
|
}
|
|
3008
|
-
const testOnly = (tag & testOnlyTag) !== 0;
|
|
3009
|
-
const isBounceable = (tag & 0x40) !== 0;
|
|
3010
3056
|
return {
|
|
3011
3057
|
wc,
|
|
3012
3058
|
hex: Array.from(hex)
|
|
3013
3059
|
.map(b => b.toString(16).padStart(2, '0'))
|
|
3014
3060
|
.join(''),
|
|
3015
|
-
testOnly,
|
|
3061
|
+
testOnly: isTestOnly,
|
|
3016
3062
|
isBounceable
|
|
3017
3063
|
};
|
|
3018
3064
|
}
|
|
@@ -3089,12 +3135,21 @@ const BASE64_REGEX = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{
|
|
|
3089
3135
|
const BOC_PREFIX = 'te6cc';
|
|
3090
3136
|
const INTEGER_REGEX = /^-?\d+$/;
|
|
3091
3137
|
const POSITIVE_INTEGER_REGEX = /^\d+$/;
|
|
3138
|
+
const MAX_DOMAIN_BYTES = 128;
|
|
3139
|
+
const MAX_PAYLOAD_BYTES = 128;
|
|
3140
|
+
const MAX_TOTAL_BYTES = 222;
|
|
3092
3141
|
function isValidNumber(value) {
|
|
3093
3142
|
return typeof value === 'number' && !isNaN(value);
|
|
3094
3143
|
}
|
|
3095
3144
|
function isValidString(value) {
|
|
3096
3145
|
return typeof value === 'string' && value.length > 0;
|
|
3097
3146
|
}
|
|
3147
|
+
function isValidAddress(value) {
|
|
3148
|
+
return isValidString(value) && (isValidRawAddress(value) || isValidUserFriendlyAddress(value));
|
|
3149
|
+
}
|
|
3150
|
+
function isValidNetwork(value) {
|
|
3151
|
+
return isValidString(value) && /^-?\d+$/.test(value);
|
|
3152
|
+
}
|
|
3098
3153
|
function isValidBoc(value) {
|
|
3099
3154
|
return typeof value === 'string' && BASE64_REGEX.test(value) && value.startsWith(BOC_PREFIX);
|
|
3100
3155
|
}
|
|
@@ -3108,52 +3163,33 @@ function hasExtraProperties(obj, allowedKeys) {
|
|
|
3108
3163
|
return Object.keys(obj).some(key => !allowedKeys.includes(key));
|
|
3109
3164
|
}
|
|
3110
3165
|
function validateSendTransactionRequest(data) {
|
|
3111
|
-
// eslint-disable-next-line no-console
|
|
3112
|
-
console.log('[Validation Debug] validateSendTransactionRequest called');
|
|
3113
|
-
// eslint-disable-next-line no-console
|
|
3114
|
-
console.log('[Validation Debug] isQaModeEnabled():', isQaModeEnabled());
|
|
3115
3166
|
if (!isValidObject(data)) {
|
|
3116
|
-
|
|
3117
|
-
logValidationError(error);
|
|
3118
|
-
const shouldReturnNull = isQaModeEnabled();
|
|
3119
|
-
// eslint-disable-next-line no-console
|
|
3120
|
-
console.log('[Validation Debug] Should return null:', shouldReturnNull);
|
|
3121
|
-
return shouldReturnNull ? null : error;
|
|
3167
|
+
return 'Request must be an object';
|
|
3122
3168
|
}
|
|
3123
3169
|
const allowedKeys = ['validUntil', 'network', 'from', 'messages'];
|
|
3124
3170
|
if (hasExtraProperties(data, allowedKeys)) {
|
|
3125
|
-
|
|
3126
|
-
logValidationError(error);
|
|
3127
|
-
return isQaModeEnabled() ? null : error;
|
|
3128
|
-
}
|
|
3129
|
-
if (!isValidNumber(data.validUntil)) {
|
|
3130
|
-
const error = "Incorrect 'validUntil'";
|
|
3131
|
-
logValidationError(error);
|
|
3132
|
-
return isQaModeEnabled() ? null : error;
|
|
3171
|
+
return 'Request contains extra properties';
|
|
3133
3172
|
}
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3173
|
+
if (data.validUntil) {
|
|
3174
|
+
if (!isValidNumber(data.validUntil)) {
|
|
3175
|
+
return "Incorrect 'validUntil'";
|
|
3176
|
+
}
|
|
3177
|
+
const now = Math.floor(Date.now() / 1000);
|
|
3178
|
+
const fiveMinutesFromNow = now + 300;
|
|
3179
|
+
if (data.validUntil > fiveMinutesFromNow) {
|
|
3180
|
+
console.warn(`validUntil (${data.validUntil}) is more than 5 minutes from now (${now})`);
|
|
3181
|
+
}
|
|
3138
3182
|
}
|
|
3139
3183
|
if (data.network !== undefined) {
|
|
3140
|
-
if (!
|
|
3141
|
-
|
|
3142
|
-
logValidationError(error);
|
|
3143
|
-
return isQaModeEnabled() ? null : error;
|
|
3184
|
+
if (!isValidNetwork(data.network)) {
|
|
3185
|
+
return "Invalid 'network' format";
|
|
3144
3186
|
}
|
|
3145
3187
|
}
|
|
3146
|
-
if (data.from !== undefined) {
|
|
3147
|
-
|
|
3148
|
-
const error = "Invalid 'from' address format";
|
|
3149
|
-
logValidationError(error);
|
|
3150
|
-
return isQaModeEnabled() ? null : error;
|
|
3151
|
-
}
|
|
3188
|
+
if (data.from !== undefined && !isValidAddress(data.from)) {
|
|
3189
|
+
return "Invalid 'from' address format";
|
|
3152
3190
|
}
|
|
3153
3191
|
if (!isValidArray(data.messages) || data.messages.length === 0) {
|
|
3154
|
-
|
|
3155
|
-
logValidationError(error);
|
|
3156
|
-
return isQaModeEnabled() ? null : error;
|
|
3192
|
+
return "'messages' is required";
|
|
3157
3193
|
}
|
|
3158
3194
|
for (let i = 0; i < data.messages.length; i++) {
|
|
3159
3195
|
const message = data.messages[i];
|
|
@@ -3216,8 +3252,34 @@ function validateConnectAdditionalRequest(data) {
|
|
|
3216
3252
|
if (hasExtraProperties(data, allowedKeys)) {
|
|
3217
3253
|
return 'Request contains extra properties';
|
|
3218
3254
|
}
|
|
3219
|
-
if (data.tonProof !== undefined
|
|
3220
|
-
|
|
3255
|
+
if (data.tonProof !== undefined) {
|
|
3256
|
+
if (typeof data.tonProof !== 'string') {
|
|
3257
|
+
return "Invalid 'tonProof'";
|
|
3258
|
+
}
|
|
3259
|
+
const payload = data.tonProof;
|
|
3260
|
+
if (payload.length === 0) {
|
|
3261
|
+
return "Empty 'tonProof' payload";
|
|
3262
|
+
}
|
|
3263
|
+
// Get current domain for validation first
|
|
3264
|
+
const domain = getDomain();
|
|
3265
|
+
if (!domain) {
|
|
3266
|
+
// In Node.js environment, skip domain validation
|
|
3267
|
+
return null;
|
|
3268
|
+
}
|
|
3269
|
+
// Validate domain size (max 128 bytes)
|
|
3270
|
+
const domainBytes = new TextEncoder().encode(domain).length;
|
|
3271
|
+
if (domainBytes > MAX_DOMAIN_BYTES) {
|
|
3272
|
+
return 'Current domain exceeds 128 bytes limit';
|
|
3273
|
+
}
|
|
3274
|
+
// Validate payload size (max 128 bytes)
|
|
3275
|
+
const payloadBytes = new TextEncoder().encode(payload).length;
|
|
3276
|
+
if (payloadBytes > MAX_PAYLOAD_BYTES) {
|
|
3277
|
+
return "'tonProof' payload exceeds 128 bytes limit";
|
|
3278
|
+
}
|
|
3279
|
+
// Validate total size (domain + payload <= 222 bytes)
|
|
3280
|
+
if (domainBytes + payloadBytes > MAX_TOTAL_BYTES) {
|
|
3281
|
+
return "'tonProof' domain + payload exceeds 222 bytes limit";
|
|
3282
|
+
}
|
|
3221
3283
|
}
|
|
3222
3284
|
return null;
|
|
3223
3285
|
}
|
|
@@ -3248,11 +3310,11 @@ function validateSignDataPayloadText(data) {
|
|
|
3248
3310
|
return "'text' is required";
|
|
3249
3311
|
}
|
|
3250
3312
|
if (data.network !== undefined) {
|
|
3251
|
-
if (!
|
|
3313
|
+
if (!isValidNetwork(data.network)) {
|
|
3252
3314
|
return "Invalid 'network' format";
|
|
3253
3315
|
}
|
|
3254
3316
|
}
|
|
3255
|
-
if (data.from !== undefined && !
|
|
3317
|
+
if (data.from !== undefined && !isValidAddress(data.from)) {
|
|
3256
3318
|
return "Invalid 'from'";
|
|
3257
3319
|
}
|
|
3258
3320
|
return null;
|
|
@@ -3266,11 +3328,11 @@ function validateSignDataPayloadBinary(data) {
|
|
|
3266
3328
|
return "'bytes' is required";
|
|
3267
3329
|
}
|
|
3268
3330
|
if (data.network !== undefined) {
|
|
3269
|
-
if (!
|
|
3331
|
+
if (!isValidNetwork(data.network)) {
|
|
3270
3332
|
return "Invalid 'network' format";
|
|
3271
3333
|
}
|
|
3272
3334
|
}
|
|
3273
|
-
if (data.from !== undefined && !
|
|
3335
|
+
if (data.from !== undefined && !isValidAddress(data.from)) {
|
|
3274
3336
|
return "Invalid 'from'";
|
|
3275
3337
|
}
|
|
3276
3338
|
return null;
|
|
@@ -3290,15 +3352,95 @@ function validateSignDataPayloadCell(data) {
|
|
|
3290
3352
|
return "Invalid 'cell' format (must be valid base64)";
|
|
3291
3353
|
}
|
|
3292
3354
|
if (data.network !== undefined) {
|
|
3293
|
-
if (!
|
|
3355
|
+
if (!isValidNetwork(data.network)) {
|
|
3294
3356
|
return "Invalid 'network' format";
|
|
3295
3357
|
}
|
|
3296
3358
|
}
|
|
3297
|
-
if (data.from !== undefined && !
|
|
3359
|
+
if (data.from !== undefined && !isValidAddress(data.from)) {
|
|
3298
3360
|
return "Invalid 'from'";
|
|
3299
3361
|
}
|
|
3300
3362
|
return null;
|
|
3301
3363
|
}
|
|
3364
|
+
/**
|
|
3365
|
+
* Validates ton_proof item received from wallet in connect event.
|
|
3366
|
+
*/
|
|
3367
|
+
// eslint-disable-next-line complexity
|
|
3368
|
+
function validateTonProofItemReply(data) {
|
|
3369
|
+
if (!isValidObject(data)) {
|
|
3370
|
+
return 'ton_proof item must be an object';
|
|
3371
|
+
}
|
|
3372
|
+
const allowedKeys = ['error', 'proof', 'name'];
|
|
3373
|
+
if (hasExtraProperties(data, allowedKeys)) {
|
|
3374
|
+
return 'ton_proof item contains extra properties';
|
|
3375
|
+
}
|
|
3376
|
+
const hasProof = Object.prototype.hasOwnProperty.call(data, 'proof');
|
|
3377
|
+
const hasError = Object.prototype.hasOwnProperty.call(data, 'error');
|
|
3378
|
+
if (!hasProof && !hasError) {
|
|
3379
|
+
return "'ton_proof' item must contain either 'proof' or 'error'";
|
|
3380
|
+
}
|
|
3381
|
+
if (hasProof && hasError) {
|
|
3382
|
+
return "'ton_proof' item must contain either 'proof' or 'error', not both";
|
|
3383
|
+
}
|
|
3384
|
+
if (hasProof) {
|
|
3385
|
+
const proof = data.proof;
|
|
3386
|
+
if (!isValidObject(proof)) {
|
|
3387
|
+
return "Invalid 'proof' object";
|
|
3388
|
+
}
|
|
3389
|
+
const allowedProofKeys = ['timestamp', 'domain', 'payload', 'signature'];
|
|
3390
|
+
if (hasExtraProperties(proof, allowedProofKeys)) {
|
|
3391
|
+
return 'ton_proof item contains extra properties';
|
|
3392
|
+
}
|
|
3393
|
+
if (!isValidNumber(proof.timestamp)) {
|
|
3394
|
+
return "Invalid 'proof.timestamp'";
|
|
3395
|
+
}
|
|
3396
|
+
const domain = proof.domain;
|
|
3397
|
+
if (!isValidObject(domain)) {
|
|
3398
|
+
return "Invalid 'proof.domain'";
|
|
3399
|
+
}
|
|
3400
|
+
if (!isValidNumber(domain.lengthBytes)) {
|
|
3401
|
+
return "Invalid 'proof.domain.lengthBytes'";
|
|
3402
|
+
}
|
|
3403
|
+
if (!isValidString(domain.value)) {
|
|
3404
|
+
return "Invalid 'proof.domain.value'";
|
|
3405
|
+
}
|
|
3406
|
+
// Try to verify that provided byte length matches actual byte length of value
|
|
3407
|
+
try {
|
|
3408
|
+
const encoderAvailable = typeof TextEncoder !== 'undefined';
|
|
3409
|
+
const actualLength = encoderAvailable
|
|
3410
|
+
? new TextEncoder().encode(domain.value).length
|
|
3411
|
+
: domain.value.length;
|
|
3412
|
+
if (actualLength !== domain.lengthBytes) {
|
|
3413
|
+
return "'proof.domain.lengthBytes' does not match 'proof.domain.value'";
|
|
3414
|
+
}
|
|
3415
|
+
}
|
|
3416
|
+
catch (_a) {
|
|
3417
|
+
// Ignore environment issues; best-effort validation
|
|
3418
|
+
}
|
|
3419
|
+
if (!isValidString(proof.payload)) {
|
|
3420
|
+
return "Invalid 'proof.payload'";
|
|
3421
|
+
}
|
|
3422
|
+
if (!isValidString(proof.signature) || !BASE64_REGEX.test(proof.signature)) {
|
|
3423
|
+
return "Invalid 'proof.signature' format";
|
|
3424
|
+
}
|
|
3425
|
+
}
|
|
3426
|
+
if (hasError) {
|
|
3427
|
+
const error = data.error;
|
|
3428
|
+
if (!isValidObject(error)) {
|
|
3429
|
+
return "Invalid 'error' object";
|
|
3430
|
+
}
|
|
3431
|
+
const allowedErrorKeys = ['code', 'message'];
|
|
3432
|
+
if (hasExtraProperties(error, allowedErrorKeys)) {
|
|
3433
|
+
return 'ton_proof error contains extra properties';
|
|
3434
|
+
}
|
|
3435
|
+
if (!isValidNumber(error.code)) {
|
|
3436
|
+
return "Invalid 'error.code'";
|
|
3437
|
+
}
|
|
3438
|
+
if (!isValidString(error.message)) {
|
|
3439
|
+
return "Invalid 'error.message'";
|
|
3440
|
+
}
|
|
3441
|
+
}
|
|
3442
|
+
return null;
|
|
3443
|
+
}
|
|
3302
3444
|
|
|
3303
3445
|
class TonConnect {
|
|
3304
3446
|
/**
|
|
@@ -3622,6 +3764,34 @@ class TonConnect {
|
|
|
3622
3764
|
prevAbortController === null || prevAbortController === void 0 ? void 0 : prevAbortController.abort();
|
|
3623
3765
|
});
|
|
3624
3766
|
}
|
|
3767
|
+
/**
|
|
3768
|
+
* Gets the current session ID if available.
|
|
3769
|
+
* @returns session ID string or null if not available.
|
|
3770
|
+
*/
|
|
3771
|
+
getSessionId() {
|
|
3772
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
3773
|
+
if (!this.provider || !this.connected) {
|
|
3774
|
+
return null;
|
|
3775
|
+
}
|
|
3776
|
+
try {
|
|
3777
|
+
const connection = yield this.bridgeConnectionStorage.getConnection();
|
|
3778
|
+
if (!connection || connection.type === 'injected') {
|
|
3779
|
+
return null;
|
|
3780
|
+
}
|
|
3781
|
+
if ('sessionCrypto' in connection) {
|
|
3782
|
+
// Pending connection
|
|
3783
|
+
return connection.sessionCrypto.sessionId;
|
|
3784
|
+
}
|
|
3785
|
+
else {
|
|
3786
|
+
// Established connection
|
|
3787
|
+
return connection.session.sessionCrypto.sessionId;
|
|
3788
|
+
}
|
|
3789
|
+
}
|
|
3790
|
+
catch (_a) {
|
|
3791
|
+
return null;
|
|
3792
|
+
}
|
|
3793
|
+
});
|
|
3794
|
+
}
|
|
3625
3795
|
/**
|
|
3626
3796
|
* Pause bridge HTTP connection. Might be helpful, if you want to pause connections while browser tab is unfocused,
|
|
3627
3797
|
* or if you use SDK with NodeJS and want to save server resources.
|
|
@@ -3711,46 +3881,59 @@ class TonConnect {
|
|
|
3711
3881
|
}
|
|
3712
3882
|
};
|
|
3713
3883
|
if (tonProofItem) {
|
|
3884
|
+
const validationError = validateTonProofItemReply(tonProofItem);
|
|
3714
3885
|
let tonProof = undefined;
|
|
3715
|
-
|
|
3716
|
-
if (
|
|
3717
|
-
|
|
3718
|
-
tonProof = {
|
|
3719
|
-
name: 'ton_proof',
|
|
3720
|
-
proof: {
|
|
3721
|
-
timestamp: tonProofItem.proof.timestamp,
|
|
3722
|
-
domain: {
|
|
3723
|
-
lengthBytes: tonProofItem.proof.domain.lengthBytes,
|
|
3724
|
-
value: tonProofItem.proof.domain.value
|
|
3725
|
-
},
|
|
3726
|
-
payload: tonProofItem.proof.payload,
|
|
3727
|
-
signature: tonProofItem.proof.signature
|
|
3728
|
-
}
|
|
3729
|
-
};
|
|
3730
|
-
}
|
|
3731
|
-
else if ('error' in tonProofItem) {
|
|
3732
|
-
// error
|
|
3733
|
-
tonProof = {
|
|
3734
|
-
name: 'ton_proof',
|
|
3735
|
-
error: {
|
|
3736
|
-
code: tonProofItem.error.code,
|
|
3737
|
-
message: tonProofItem.error.message
|
|
3738
|
-
}
|
|
3739
|
-
};
|
|
3740
|
-
}
|
|
3741
|
-
else {
|
|
3742
|
-
throw new TonConnectError('Invalid data format');
|
|
3886
|
+
if (validationError) {
|
|
3887
|
+
if (isQaModeEnabled()) {
|
|
3888
|
+
console.error('TonProofItem validation failed: ' + validationError);
|
|
3743
3889
|
}
|
|
3744
|
-
}
|
|
3745
|
-
catch (e) {
|
|
3746
3890
|
tonProof = {
|
|
3747
3891
|
name: 'ton_proof',
|
|
3748
3892
|
error: {
|
|
3749
3893
|
code: protocol.CONNECT_ITEM_ERROR_CODES.UNKNOWN_ERROR,
|
|
3750
|
-
message:
|
|
3894
|
+
message: validationError
|
|
3751
3895
|
}
|
|
3752
3896
|
};
|
|
3753
3897
|
}
|
|
3898
|
+
else {
|
|
3899
|
+
try {
|
|
3900
|
+
if ('proof' in tonProofItem) {
|
|
3901
|
+
tonProof = {
|
|
3902
|
+
name: 'ton_proof',
|
|
3903
|
+
proof: {
|
|
3904
|
+
timestamp: tonProofItem.proof.timestamp,
|
|
3905
|
+
domain: {
|
|
3906
|
+
lengthBytes: tonProofItem.proof.domain.lengthBytes,
|
|
3907
|
+
value: tonProofItem.proof.domain.value
|
|
3908
|
+
},
|
|
3909
|
+
payload: tonProofItem.proof.payload,
|
|
3910
|
+
signature: tonProofItem.proof.signature
|
|
3911
|
+
}
|
|
3912
|
+
};
|
|
3913
|
+
}
|
|
3914
|
+
else if ('error' in tonProofItem) {
|
|
3915
|
+
tonProof = {
|
|
3916
|
+
name: 'ton_proof',
|
|
3917
|
+
error: {
|
|
3918
|
+
code: tonProofItem.error.code,
|
|
3919
|
+
message: tonProofItem.error.message
|
|
3920
|
+
}
|
|
3921
|
+
};
|
|
3922
|
+
}
|
|
3923
|
+
else {
|
|
3924
|
+
throw new TonConnectError('Invalid data format');
|
|
3925
|
+
}
|
|
3926
|
+
}
|
|
3927
|
+
catch (e) {
|
|
3928
|
+
tonProof = {
|
|
3929
|
+
name: 'ton_proof',
|
|
3930
|
+
error: {
|
|
3931
|
+
code: protocol.CONNECT_ITEM_ERROR_CODES.UNKNOWN_ERROR,
|
|
3932
|
+
message: 'Invalid data format'
|
|
3933
|
+
}
|
|
3934
|
+
};
|
|
3935
|
+
}
|
|
3936
|
+
}
|
|
3754
3937
|
wallet.connectItems = { tonProof };
|
|
3755
3938
|
}
|
|
3756
3939
|
this.wallet = wallet;
|
|
@@ -3823,6 +4006,10 @@ Object.defineProperty(exports, "SIGN_DATA_ERROR_CODES", {
|
|
|
3823
4006
|
enumerable: true,
|
|
3824
4007
|
get: function () { return protocol.SIGN_DATA_ERROR_CODES; }
|
|
3825
4008
|
});
|
|
4009
|
+
Object.defineProperty(exports, "SessionCrypto", {
|
|
4010
|
+
enumerable: true,
|
|
4011
|
+
get: function () { return protocol.SessionCrypto; }
|
|
4012
|
+
});
|
|
3826
4013
|
exports.BadRequestError = BadRequestError;
|
|
3827
4014
|
exports.BrowserEventDispatcher = BrowserEventDispatcher;
|
|
3828
4015
|
exports.FetchWalletsError = FetchWalletsError;
|