squarefi-bff-api-module 1.32.1 → 1.32.2
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/api/auth.d.ts +29 -0
- package/dist/api/auth.js +59 -0
- package/dist/api/bank-data.d.ts +4 -0
- package/dist/api/bank-data.js +6 -0
- package/dist/api/counterparties.d.ts +14 -0
- package/dist/api/counterparties.js +16 -0
- package/dist/api/developer.d.ts +12 -0
- package/dist/api/developer.js +12 -0
- package/dist/api/exchange.d.ts +14 -0
- package/dist/api/exchange.js +20 -0
- package/dist/api/frontend.d.ts +11 -0
- package/dist/api/frontend.js +11 -0
- package/dist/api/index.d.ts +38 -0
- package/dist/api/index.js +36 -0
- package/dist/api/issuing.d.ts +64 -0
- package/dist/api/issuing.js +140 -0
- package/dist/api/kyc.d.ts +21 -0
- package/dist/api/kyc.js +21 -0
- package/dist/api/list.d.ts +16 -0
- package/dist/api/list.js +16 -0
- package/dist/api/orders.d.ts +49 -0
- package/dist/api/orders.js +84 -0
- package/dist/api/persona.d.ts +7 -0
- package/dist/api/persona.js +7 -0
- package/dist/api/storage.d.ts +8 -0
- package/dist/api/storage.js +16 -0
- package/dist/api/tenants.d.ts +6 -0
- package/dist/api/tenants.js +6 -0
- package/dist/api/totp.d.ts +17 -0
- package/dist/api/totp.js +45 -0
- package/{src/api/types/autogen/apiV2.types.ts → dist/api/types/autogen/apiV2.types.d.ts} +0 -1
- package/dist/api/types/autogen/apiV2.types.js +5 -0
- package/dist/api/types/types.d.ts +2258 -0
- package/dist/api/types/types.js +1 -0
- package/dist/api/user.d.ts +18 -0
- package/dist/api/user.js +18 -0
- package/dist/api/virtual-accounts.d.ts +9 -0
- package/dist/api/virtual-accounts.js +9 -0
- package/dist/api/wallets.d.ts +24 -0
- package/dist/api/wallets.js +30 -0
- package/dist/constants.d.ts +303 -0
- package/dist/constants.js +332 -0
- package/dist/hooks/index.js +3 -0
- package/dist/hooks/useCalc.d.ts +25 -0
- package/dist/hooks/useCalc.js +115 -0
- package/dist/hooks/useFileUpload.d.ts +49 -0
- package/dist/hooks/useFileUpload.js +100 -0
- package/dist/hooks/useSupabaseSubscription/config.d.ts +2 -0
- package/dist/hooks/useSupabaseSubscription/config.js +5 -0
- package/dist/hooks/useSupabaseSubscription/index.js +2 -0
- package/dist/hooks/useSupabaseSubscription/specialized.d.ts +5 -0
- package/{src/hooks/useSupabaseSubscription/specialized.ts → dist/hooks/useSupabaseSubscription/specialized.js} +2 -5
- package/dist/hooks/useSupabaseSubscription/types.d.ts +16 -0
- package/dist/hooks/useSupabaseSubscription/types.js +1 -0
- package/dist/hooks/useSupabaseSubscription/useSupabaseSubscription.d.ts +5 -0
- package/dist/hooks/useSupabaseSubscription/useSupabaseSubscription.js +37 -0
- package/dist/index.d.ts +7 -0
- package/dist/utils/apiClientFactory.d.ts +31 -0
- package/dist/utils/apiClientFactory.js +138 -0
- package/dist/utils/converters.d.ts +1 -0
- package/dist/utils/converters.js +1 -0
- package/dist/utils/encrypt.d.ts +10 -0
- package/dist/utils/encrypt.js +77 -0
- package/dist/utils/fileStorage.d.ts +120 -0
- package/dist/utils/fileStorage.js +292 -0
- package/dist/utils/storage.d.ts +3 -0
- package/dist/utils/storage.js +24 -0
- package/dist/utils/supabase.d.ts +1 -0
- package/dist/utils/supabase.js +12 -0
- package/dist/utils/tokensFactory.d.ts +12 -0
- package/dist/utils/tokensFactory.js +42 -0
- package/package.json +4 -1
- package/.env.example +0 -1
- package/.husky/pre-commit +0 -2
- package/.prettierignore +0 -6
- package/.prettierrc +0 -7
- package/CHANGELOG.md +0 -1415
- package/FIXED_RLS_ERROR.md +0 -146
- package/QUICK_TEST.md +0 -127
- package/STORAGE_MODULE_SUMMARY.md +0 -228
- package/TEST_INSTRUCTIONS.md +0 -122
- package/docs/AUTH_TOKEN_USAGE.md +0 -290
- package/docs/BACKEND_SERVICE_URL.md +0 -334
- package/docs/FRONTEND_STORAGE_GUIDE.md +0 -529
- package/docs/STORAGE_MODULE.md +0 -490
- package/docs/STORAGE_QUICK_START.md +0 -76
- package/scripts/generate-openapi-types.ts +0 -41
- package/scripts/supabase-storage-setup.sql +0 -223
- package/src/api/auth.ts +0 -78
- package/src/api/bank-data.ts +0 -11
- package/src/api/counterparties.ts +0 -73
- package/src/api/developer.ts +0 -20
- package/src/api/exchange.ts +0 -44
- package/src/api/frontend.ts +0 -20
- package/src/api/index.ts +0 -57
- package/src/api/issuing.ts +0 -214
- package/src/api/kyc.ts +0 -41
- package/src/api/list.ts +0 -26
- package/src/api/orders.ts +0 -255
- package/src/api/persona.ts +0 -16
- package/src/api/storage.ts +0 -24
- package/src/api/tenants.ts +0 -8
- package/src/api/totp.ts +0 -51
- package/src/api/types/types.ts +0 -2820
- package/src/api/user.ts +0 -27
- package/src/api/virtual-accounts.ts +0 -15
- package/src/api/wallets.ts +0 -65
- package/src/constants.ts +0 -343
- package/src/hooks/useCalc.ts +0 -181
- package/src/hooks/useFileUpload.ts +0 -129
- package/src/hooks/useSupabaseSubscription/config.ts +0 -7
- package/src/hooks/useSupabaseSubscription/types.ts +0 -18
- package/src/hooks/useSupabaseSubscription/useSupabaseSubscription.ts +0 -53
- package/src/utils/apiClientFactory.ts +0 -194
- package/src/utils/converters.ts +0 -1
- package/src/utils/encrypt.ts +0 -96
- package/src/utils/fileStorage.ts +0 -353
- package/src/utils/storage.ts +0 -29
- package/src/utils/supabase.ts +0 -16
- package/src/utils/tokensFactory.ts +0 -59
- package/tsconfig.json +0 -15
- package/types.d.ts +0 -11
- /package/{src/hooks/index.ts → dist/hooks/index.d.ts} +0 -0
- /package/{src/hooks/useSupabaseSubscription/index.ts → dist/hooks/useSupabaseSubscription/index.d.ts} +0 -0
- /package/{src/index.ts → dist/index.js} +0 -0
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import { useState, useCallback } from 'react';
|
|
2
|
-
import { uploadFile, UploadFileOptions, UploadFileResult } from '../utils/fileStorage';
|
|
3
|
-
|
|
4
|
-
interface UseFileUploadOptions {
|
|
5
|
-
bucket: string;
|
|
6
|
-
folder?: string; // Папка внутри бакета (например, 'documents', 'images/avatars'). Создается автоматически, если не существует
|
|
7
|
-
authToken?: string; // JWT token для авторизации
|
|
8
|
-
onSuccess?: (result: UploadFileResult) => void;
|
|
9
|
-
onError?: (error: string) => void;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
interface UseFileUploadReturn {
|
|
13
|
-
upload: (file: File, fileName?: string) => Promise<UploadFileResult>;
|
|
14
|
-
uploading: boolean;
|
|
15
|
-
progress: number;
|
|
16
|
-
error: string | null;
|
|
17
|
-
result: UploadFileResult | null;
|
|
18
|
-
reset: () => void;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* React хук для загрузки файлов в Supabase Storage
|
|
23
|
-
*
|
|
24
|
-
* Папки создаются автоматически при загрузке файла, если их не существует.
|
|
25
|
-
*
|
|
26
|
-
* @example
|
|
27
|
-
* ```tsx
|
|
28
|
-
* // Загрузка в корень бакета
|
|
29
|
-
* const { upload, uploading, error, result } = useFileUpload({
|
|
30
|
-
* bucket: 'user-files',
|
|
31
|
-
* onSuccess: (result) => console.log('Загружено:', result.path),
|
|
32
|
-
* });
|
|
33
|
-
*
|
|
34
|
-
* // Загрузка в конкретную папку (папка создастся автоматически)
|
|
35
|
-
* const { upload } = useFileUpload({
|
|
36
|
-
* bucket: 'documents',
|
|
37
|
-
* folder: 'invoices', // файл будет загружен в invoices/
|
|
38
|
-
* });
|
|
39
|
-
*
|
|
40
|
-
* // Загрузка во вложенную папку (все папки создадутся автоматически)
|
|
41
|
-
* const { upload } = useFileUpload({
|
|
42
|
-
* bucket: 'images',
|
|
43
|
-
* folder: 'avatars/2024', // файл будет загружен в avatars/2024/
|
|
44
|
-
* });
|
|
45
|
-
*
|
|
46
|
-
* const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
47
|
-
* const file = e.target.files?.[0];
|
|
48
|
-
* if (file) await upload(file);
|
|
49
|
-
* };
|
|
50
|
-
* ```
|
|
51
|
-
*/
|
|
52
|
-
export const useFileUpload = (options: UseFileUploadOptions): UseFileUploadReturn => {
|
|
53
|
-
const { bucket, folder, authToken, onSuccess, onError } = options;
|
|
54
|
-
|
|
55
|
-
const [uploading, setUploading] = useState(false);
|
|
56
|
-
const [progress, setProgress] = useState(0);
|
|
57
|
-
const [error, setError] = useState<string | null>(null);
|
|
58
|
-
const [result, setResult] = useState<UploadFileResult | null>(null);
|
|
59
|
-
|
|
60
|
-
const upload = useCallback(
|
|
61
|
-
async (file: File, customFileName?: string): Promise<UploadFileResult> => {
|
|
62
|
-
setUploading(true);
|
|
63
|
-
setProgress(0);
|
|
64
|
-
setError(null);
|
|
65
|
-
setResult(null);
|
|
66
|
-
|
|
67
|
-
try {
|
|
68
|
-
// Симулируем прогресс (Supabase не предоставляет реальный progress)
|
|
69
|
-
const progressInterval = setInterval(() => {
|
|
70
|
-
setProgress((prev) => Math.min(prev + 10, 90));
|
|
71
|
-
}, 100);
|
|
72
|
-
|
|
73
|
-
const uploadOptions: UploadFileOptions = {
|
|
74
|
-
file,
|
|
75
|
-
fileName: customFileName || `${Date.now()}-${file.name}`,
|
|
76
|
-
bucket,
|
|
77
|
-
folder,
|
|
78
|
-
contentType: file.type,
|
|
79
|
-
authToken,
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
const uploadResult = await uploadFile(uploadOptions);
|
|
83
|
-
|
|
84
|
-
clearInterval(progressInterval);
|
|
85
|
-
setProgress(100);
|
|
86
|
-
setResult(uploadResult);
|
|
87
|
-
|
|
88
|
-
if (uploadResult.success) {
|
|
89
|
-
onSuccess?.(uploadResult);
|
|
90
|
-
} else {
|
|
91
|
-
const errorMsg = uploadResult.error || 'Ошибка загрузки файла';
|
|
92
|
-
setError(errorMsg);
|
|
93
|
-
onError?.(errorMsg);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return uploadResult;
|
|
97
|
-
} catch (err) {
|
|
98
|
-
const errorMsg = err instanceof Error ? err.message : 'Непредвиденная ошибка';
|
|
99
|
-
setError(errorMsg);
|
|
100
|
-
onError?.(errorMsg);
|
|
101
|
-
setProgress(0);
|
|
102
|
-
|
|
103
|
-
return {
|
|
104
|
-
success: false,
|
|
105
|
-
error: errorMsg,
|
|
106
|
-
};
|
|
107
|
-
} finally {
|
|
108
|
-
setUploading(false);
|
|
109
|
-
}
|
|
110
|
-
},
|
|
111
|
-
[bucket, folder, authToken, onSuccess, onError],
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
const reset = useCallback(() => {
|
|
115
|
-
setUploading(false);
|
|
116
|
-
setProgress(0);
|
|
117
|
-
setError(null);
|
|
118
|
-
setResult(null);
|
|
119
|
-
}, []);
|
|
120
|
-
|
|
121
|
-
return {
|
|
122
|
-
upload,
|
|
123
|
-
uploading,
|
|
124
|
-
progress,
|
|
125
|
-
error,
|
|
126
|
-
result,
|
|
127
|
-
reset,
|
|
128
|
-
};
|
|
129
|
-
};
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export interface SubscriptionConfig {
|
|
2
|
-
channelName: string;
|
|
3
|
-
table: string;
|
|
4
|
-
schema?: string;
|
|
5
|
-
event?: 'INSERT' | 'UPDATE' | 'DELETE' | '*';
|
|
6
|
-
filter?: string;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface UseSupabaseSubscriptionProps {
|
|
10
|
-
config: SubscriptionConfig;
|
|
11
|
-
callback: (payload?: unknown) => void;
|
|
12
|
-
enabled?: boolean;
|
|
13
|
-
key?: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface UseWalletTransactionsSubscriptionProps extends Omit<UseSupabaseSubscriptionProps, 'config'> {
|
|
17
|
-
walletId: string | undefined;
|
|
18
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useEffect, useRef } from 'react';
|
|
4
|
-
|
|
5
|
-
import { UseSupabaseSubscriptionProps } from './types';
|
|
6
|
-
|
|
7
|
-
import { supabaseClient } from '../../utils/supabase';
|
|
8
|
-
|
|
9
|
-
export const useSupabaseSubscription = ({ config, callback, enabled = true, key }: UseSupabaseSubscriptionProps) => {
|
|
10
|
-
const subscriptionRef = useRef<any>(null);
|
|
11
|
-
const callbackRef = useRef(callback);
|
|
12
|
-
|
|
13
|
-
callbackRef.current = callback;
|
|
14
|
-
|
|
15
|
-
useEffect(() => {
|
|
16
|
-
if (!enabled || !supabaseClient) {
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (subscriptionRef.current) {
|
|
21
|
-
supabaseClient.removeChannel(subscriptionRef.current);
|
|
22
|
-
subscriptionRef.current = null;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const subscription = supabaseClient
|
|
26
|
-
.channel(key || config.channelName)
|
|
27
|
-
.on(
|
|
28
|
-
'postgres_changes' as any,
|
|
29
|
-
{
|
|
30
|
-
event: config.event || '*',
|
|
31
|
-
schema: config.schema || 'public',
|
|
32
|
-
table: config.table,
|
|
33
|
-
...(config.filter && { filter: config.filter }),
|
|
34
|
-
},
|
|
35
|
-
(payload) => callbackRef.current(payload),
|
|
36
|
-
)
|
|
37
|
-
.subscribe();
|
|
38
|
-
|
|
39
|
-
subscriptionRef.current = subscription;
|
|
40
|
-
|
|
41
|
-
return () => {
|
|
42
|
-
if (subscriptionRef.current && supabaseClient) {
|
|
43
|
-
supabaseClient.removeChannel(subscriptionRef.current);
|
|
44
|
-
subscriptionRef.current = null;
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
}, [enabled, config.channelName, config.table, config.schema, config.event, config.filter, supabaseClient, key]);
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
isConnected: !!subscriptionRef.current,
|
|
51
|
-
isClientAvailable: !!supabaseClient,
|
|
52
|
-
};
|
|
53
|
-
};
|
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
import { isTMA } from '@telegram-apps/sdk-react';
|
|
3
|
-
import axios, { AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
|
|
4
|
-
|
|
5
|
-
import { telegramSignUpPath, telegramSignInPath, refreshTokenPath } from '../api/auth';
|
|
6
|
-
|
|
7
|
-
import { AppEnviroment, ResponseStatus } from '../constants';
|
|
8
|
-
|
|
9
|
-
import { deleteTokens, getTokens, refreshTokens } from './tokensFactory';
|
|
10
|
-
|
|
11
|
-
// eslint-disable-next-line no-constant-condition
|
|
12
|
-
|
|
13
|
-
const apiV1BaseURL = process.env.API_URL ?? 'ENV variable API_URL is not defined';
|
|
14
|
-
const apiV2BaseURL = process.env.API_V2_URL ?? 'ENV variable API_V2_URL is not defined';
|
|
15
|
-
const apiTOTPBaseURL = process.env.API_TOTP_URL ?? 'ENV variable API_TOTP_URL is not defined';
|
|
16
|
-
const envTenantId = process.env.TENANT_ID ?? 'ENV variable TENANT_ID is not defined';
|
|
17
|
-
const envLogoutURL = process.env.LOGOUT_URL ?? '/auth/logout';
|
|
18
|
-
|
|
19
|
-
type AxiosError = {
|
|
20
|
-
response: AxiosResponse;
|
|
21
|
-
config: InternalAxiosRequestConfig;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
type CreateApiClientOptions = {
|
|
25
|
-
baseURL: string;
|
|
26
|
-
tenantId: string;
|
|
27
|
-
isBearerToken?: boolean;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
type RequestQueueItem = {
|
|
31
|
-
resolve: Function;
|
|
32
|
-
reject: Function;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
let isTokenRefreshing = false;
|
|
36
|
-
let requestQueue: RequestQueueItem[] = [];
|
|
37
|
-
|
|
38
|
-
export const createApiClient = ({ baseURL, isBearerToken, tenantId }: CreateApiClientOptions) => {
|
|
39
|
-
const instance = axios.create({
|
|
40
|
-
baseURL,
|
|
41
|
-
timeout: 60000,
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
instance.interceptors.request.use((config) => {
|
|
45
|
-
const { access_token } = getTokens();
|
|
46
|
-
|
|
47
|
-
const modifiedHeaders = {
|
|
48
|
-
...config.headers,
|
|
49
|
-
'x-tenant-id': tenantId,
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
if (access_token) {
|
|
53
|
-
const authHeader = isBearerToken ? `Bearer ${access_token}` : access_token;
|
|
54
|
-
modifiedHeaders.Authorization = authHeader;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
config.context = {
|
|
58
|
-
...config.context,
|
|
59
|
-
appEnvironment: isTMA() ? AppEnviroment.TELEGRAM : AppEnviroment.WEB,
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
return {
|
|
63
|
-
...config,
|
|
64
|
-
headers: modifiedHeaders,
|
|
65
|
-
} as unknown as InternalAxiosRequestConfig;
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
instance.interceptors.response.use(
|
|
69
|
-
(response) => response,
|
|
70
|
-
(error: AxiosError) => {
|
|
71
|
-
if (typeof window === 'undefined') {
|
|
72
|
-
return Promise.reject(error);
|
|
73
|
-
}
|
|
74
|
-
if (
|
|
75
|
-
error?.response?.status === ResponseStatus.UNAUTHORIZED &&
|
|
76
|
-
!error?.response?.config.context?.bypassUnauthorizedHandler
|
|
77
|
-
) {
|
|
78
|
-
const { response, config: failedRequestConfig } = error;
|
|
79
|
-
const { refresh_token } = getTokens();
|
|
80
|
-
const isRetryRequest = failedRequestConfig.context?.isRetryRequest;
|
|
81
|
-
|
|
82
|
-
const isRefreshTokenRequest = failedRequestConfig.url?.includes(refreshTokenPath);
|
|
83
|
-
const isTelegramSignInRequest = failedRequestConfig.url?.includes(telegramSignInPath);
|
|
84
|
-
const isTelegramSignUpRequest = failedRequestConfig.url?.includes(telegramSignUpPath);
|
|
85
|
-
const isRefreshNotRequired = !refresh_token && !isTMA();
|
|
86
|
-
const isLogoutNeccesary =
|
|
87
|
-
isRefreshNotRequired ||
|
|
88
|
-
isTelegramSignInRequest ||
|
|
89
|
-
isTelegramSignUpRequest ||
|
|
90
|
-
isRefreshTokenRequest ||
|
|
91
|
-
isRetryRequest;
|
|
92
|
-
|
|
93
|
-
const isRefreshAvailable = !isTokenRefreshing && !isRefreshNotRequired;
|
|
94
|
-
|
|
95
|
-
if (isLogoutNeccesary) {
|
|
96
|
-
if (typeof window !== 'undefined') {
|
|
97
|
-
window.location.href = envLogoutURL;
|
|
98
|
-
deleteTokens();
|
|
99
|
-
}
|
|
100
|
-
requestQueue = [];
|
|
101
|
-
return Promise.reject(response);
|
|
102
|
-
}
|
|
103
|
-
if (isRefreshAvailable) {
|
|
104
|
-
isTokenRefreshing = true;
|
|
105
|
-
refreshTokens()
|
|
106
|
-
.then((data) => {
|
|
107
|
-
if (data?.access_token) {
|
|
108
|
-
requestQueue.forEach((request) => request.resolve());
|
|
109
|
-
requestQueue = [];
|
|
110
|
-
}
|
|
111
|
-
})
|
|
112
|
-
.catch((tokenRefreshError) => {
|
|
113
|
-
if (typeof window !== 'undefined') {
|
|
114
|
-
window.location.href = envLogoutURL;
|
|
115
|
-
deleteTokens();
|
|
116
|
-
}
|
|
117
|
-
requestQueue = [];
|
|
118
|
-
return Promise.reject(tokenRefreshError);
|
|
119
|
-
})
|
|
120
|
-
.finally(() => {
|
|
121
|
-
isTokenRefreshing = false;
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
return new Promise((res, rej) => {
|
|
125
|
-
requestQueue.push({
|
|
126
|
-
resolve: () => {
|
|
127
|
-
failedRequestConfig.context = {
|
|
128
|
-
...failedRequestConfig.context,
|
|
129
|
-
isRetryRequest: true,
|
|
130
|
-
};
|
|
131
|
-
return res(instance(failedRequestConfig));
|
|
132
|
-
},
|
|
133
|
-
reject: () => rej(instance(failedRequestConfig)),
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
console.error('Axios error', error);
|
|
139
|
-
|
|
140
|
-
return Promise.reject(error);
|
|
141
|
-
},
|
|
142
|
-
);
|
|
143
|
-
|
|
144
|
-
const patchRequest = async <T>(url: string, config?: AxiosRequestConfig): Promise<T> => {
|
|
145
|
-
const { data = {}, ...restConfig } = config ?? {};
|
|
146
|
-
|
|
147
|
-
const res = await instance.patch(url, data, restConfig);
|
|
148
|
-
|
|
149
|
-
return res.data;
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
const postRequest = async <T>(url: string, config?: AxiosRequestConfig): Promise<T> => {
|
|
153
|
-
const { data = {}, ...restConfig } = config ?? {};
|
|
154
|
-
|
|
155
|
-
const res = await instance.post(url, data, restConfig);
|
|
156
|
-
|
|
157
|
-
return res.data;
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
const deleteRequest = async (url: string, config?: AxiosRequestConfig) => {
|
|
161
|
-
const { data = {}, ...restConfig } = config ?? {};
|
|
162
|
-
|
|
163
|
-
const res = await instance.delete(url, { data, ...restConfig });
|
|
164
|
-
|
|
165
|
-
return res.data;
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
const getRequest = async <T>(url: string, config?: AxiosRequestConfig): Promise<T> => {
|
|
169
|
-
const { params = {}, ...restConfig } = config ?? {};
|
|
170
|
-
|
|
171
|
-
const res = await instance.get(url, { params, ...restConfig });
|
|
172
|
-
|
|
173
|
-
return res.data;
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
return { patchRequest, postRequest, deleteRequest, getRequest };
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
export const apiClientV1 = createApiClient({
|
|
180
|
-
baseURL: apiV1BaseURL,
|
|
181
|
-
tenantId: envTenantId,
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
export const apiClientV2 = createApiClient({
|
|
185
|
-
baseURL: apiV2BaseURL,
|
|
186
|
-
isBearerToken: true,
|
|
187
|
-
tenantId: envTenantId,
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
export const apiClientTOTP = createApiClient({
|
|
191
|
-
baseURL: apiTOTPBaseURL,
|
|
192
|
-
isBearerToken: true,
|
|
193
|
-
tenantId: envTenantId,
|
|
194
|
-
});
|
package/src/utils/converters.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const convertPhoneToSupabaseFormat = (phone: string) => phone.replace(/\D/g, '');
|
package/src/utils/encrypt.ts
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import crypto, { CipherKey } from 'crypto';
|
|
2
|
-
import NodeRSA from 'node-rsa';
|
|
3
|
-
|
|
4
|
-
import { API } from '../api/types/types';
|
|
5
|
-
|
|
6
|
-
type MakeSecureRequestParams = {
|
|
7
|
-
callback: (props: API.Common.Encrypted.Request) => Promise<API.Common.Encrypted.Response>;
|
|
8
|
-
publicKey: string;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export const generateSecretKey = () => {
|
|
12
|
-
const secretKey = crypto.randomBytes(32);
|
|
13
|
-
return secretKey;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export const decryptAESData = async (encryptedData: string, iv: string, secretKey: CipherKey) => {
|
|
17
|
-
const decipher = crypto.createDecipheriv('aes-256-cbc', secretKey, Buffer.from(iv, 'base64'));
|
|
18
|
-
let decrypted = decipher.update(encryptedData, 'base64', 'utf8');
|
|
19
|
-
decrypted += decipher.final('utf8');
|
|
20
|
-
return JSON.parse(decrypted);
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Очищает и валидирует публичный RSA ключ
|
|
25
|
-
* Исправляет ошибку InvalidAsn1Error: encoding too long
|
|
26
|
-
* путем удаления лишних символов и нормализации переносов строк
|
|
27
|
-
*/
|
|
28
|
-
const cleanAndValidatePublicKey = (publicKey: string): string => {
|
|
29
|
-
try {
|
|
30
|
-
// Декодируем base64 ключ
|
|
31
|
-
const publicKeyBase64 = Buffer.from(publicKey, 'base64').toString('utf8');
|
|
32
|
-
|
|
33
|
-
// Удаляем лишние символы (переносы строк, пробелы в начале и конце)
|
|
34
|
-
// Нормализуем переносы строк для корректной обработки ASN.1
|
|
35
|
-
const cleanedKey = publicKeyBase64.trim().replace(/\r?\n|\r/g, '\n');
|
|
36
|
-
|
|
37
|
-
// Проверяем, что ключ содержит необходимые маркеры
|
|
38
|
-
if (!cleanedKey.includes('BEGIN') || !cleanedKey.includes('END')) {
|
|
39
|
-
throw new Error('Invalid public key format: missing BEGIN/END markers');
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return cleanedKey;
|
|
43
|
-
} catch (error) {
|
|
44
|
-
throw new Error(`Invalid public key format: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Автоматически определяет формат RSA ключа по заголовку
|
|
50
|
-
* Помогает избежать ошибок импорта при неправильном указании формата
|
|
51
|
-
*/
|
|
52
|
-
const detectKeyFormat = (key: string): 'pkcs1' | 'pkcs8' => {
|
|
53
|
-
if (key.includes('BEGIN RSA PUBLIC KEY')) {
|
|
54
|
-
return 'pkcs1';
|
|
55
|
-
} else if (key.includes('BEGIN PUBLIC KEY')) {
|
|
56
|
-
return 'pkcs8';
|
|
57
|
-
}
|
|
58
|
-
// По умолчанию возвращаем pkcs8, как было ранее
|
|
59
|
-
return 'pkcs8';
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
export const makeSecureRequest = async <T>({ callback, publicKey }: MakeSecureRequestParams): Promise<T> => {
|
|
63
|
-
const clientRsa = new NodeRSA();
|
|
64
|
-
|
|
65
|
-
try {
|
|
66
|
-
// Очищаем и валидируем публичный ключ
|
|
67
|
-
const cleanedPublicKey = cleanAndValidatePublicKey(publicKey);
|
|
68
|
-
|
|
69
|
-
// Определяем формат ключа автоматически
|
|
70
|
-
const keyFormat = detectKeyFormat(cleanedPublicKey);
|
|
71
|
-
|
|
72
|
-
// Импортируем ключ с правильным форматом
|
|
73
|
-
clientRsa.importKey(cleanedPublicKey, `${keyFormat}-public-pem`);
|
|
74
|
-
} catch (error) {
|
|
75
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
76
|
-
throw new Error(`Failed to import RSA public key: ${errorMessage}`);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const clientSecretKey = generateSecretKey();
|
|
80
|
-
const clientPayload = {
|
|
81
|
-
key: clientSecretKey.toString('base64'),
|
|
82
|
-
timestamp: Date.now(),
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
const encrypted_key = clientRsa.encrypt(JSON.stringify(clientPayload), 'base64');
|
|
86
|
-
|
|
87
|
-
const { success, encrypted, data, iv } = await callback({ encrypted_key });
|
|
88
|
-
|
|
89
|
-
if (success && encrypted && data && iv) {
|
|
90
|
-
const decryptedData = await decryptAESData(data, iv, clientSecretKey);
|
|
91
|
-
|
|
92
|
-
return decryptedData.data;
|
|
93
|
-
} else {
|
|
94
|
-
throw new Error('Failed to get encrypted secret key');
|
|
95
|
-
}
|
|
96
|
-
};
|