@0xtld/tair-node
Version:
A Node.js package for Tair functionality with configuration, core, and helper modules.
211 lines (172 loc) • 6.09 kB
text/typescript
import axios, { AxiosInstance, AxiosResponse } from 'axios';
import { UrbanProxyElement } from '../types';
import { HttpsProxyAgent } from 'https-proxy-agent';
class UrbanProxyConfig {
static clientAppName = 'URBAN_VPN_BROWSER_EXTENSION';
static headers = {
'accept': '*/*',
'accept-language': 'en-GB,en-US;q=0.9,en;q=0.8,vi;q=0.7,cs;q=0.6,th;q=0.5',
'authorization': 'Bearer wBgfw5JK1K24wpo01S5wSbtNi5MEIMjI',
'cache-control': 'no-cache',
'content-type': 'application/json',
'origin': 'chrome-extension://eppiocemhmnlbhjplcgkofciiegomcon',
'pragma': 'no-cache',
'priority': 'u=1, i',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'none',
'sec-fetch-storage-access': 'active',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36',
};
static urls = {
accessToken: 'https://api-pro.falais.com/rest/v1/security/tokens/accs',
getProxy: 'https://api-pro.falais.com/rest/v1/security/tokens/accs-proxy',
getProxyList: 'https://stats.falais.com/api/rest/v2/entrypoints/countries',
};
}
class UrbanProxy {
private proxyList: UrbanProxyElement[] = [];
private proxy: UrbanProxyElement | null = null;
private accessToken: string | null = null;
private session: AxiosInstance;
constructor() {
this.session = axios.create({
headers: UrbanProxyConfig.headers,
});
this.session.interceptors.response.use(
(response) => response,
async (error) => {
if (error.response) {
this.reset();
}
return Promise.reject(error);
}
)
}
private async getAccessToken(): Promise<string | null> {
const response = await this.session.post(UrbanProxyConfig.urls.accessToken, {
type: 'accs',
clientApp: {
name: UrbanProxyConfig.clientAppName,
},
});
if (response.status === 200) {
this.accessToken = response.data.value;
return this.accessToken;
}
return null;
}
private async handleBeforeRequest(): Promise<void> {
if (!this.accessToken) {
await this.getAccessToken();
}
}
private isExpired(proxy: UrbanProxyElement): boolean {
return proxy.expiration_time! < Date.now();
}
private async handleAfterResponse(response: AxiosResponse): Promise<void> {
if (response.status === 401) {
await this.refreshSession();
} else if (response.status !== 200) {
console.error(`Error: ${response.status} - ${response.data}`);
this.reset();
}
}
private reset(): void {
this.proxy = null;
this.proxyList = [];
this.accessToken = null;
}
private async refreshSession(): Promise<void> {
this.session = axios.create({
headers: UrbanProxyConfig.headers,
});
await this.getAccessToken();
}
private async authProxy(proxy: UrbanProxyElement): Promise<UrbanProxyElement> {
await this.handleBeforeRequest();
const headers = {
...UrbanProxyConfig.headers,
authorization: `Bearer ${this.accessToken}`,
'x-client-app': UrbanProxyConfig.clientAppName,
};
const body = {
type: 'accs-proxy',
clientApp: {
name: UrbanProxyConfig.clientAppName,
},
signature: proxy.signature,
};
const response = await this.session.post(UrbanProxyConfig.urls.getProxy, body, { headers });
if (response.status !== 200) {
await this.handleAfterResponse(response);
throw new Error(`Auth proxy failed -> ${response.status} : ${response.data}`);
}
const resp = response.data;
proxy.username = resp.value;
proxy.creation_time = resp.creationTime;
proxy.expiration_time = resp.expirationTime;
proxy.auth_str = `http://${proxy.username}:${proxy.password}@${proxy.host}:${proxy.port}`;
this.proxyList = this.proxyList.filter((p) => p !== proxy);
this.proxyList.push(proxy);
return proxy;
}
public async getProxy(proxy: UrbanProxyElement | null = null): Promise<UrbanProxyElement> {
if (this.proxyList.length === 0) {
await this.getProxyList();
}
if (proxy && !this.isExpired(proxy)) {
return proxy;
}
const element = this.proxyList[Math.floor(Math.random() * this.proxyList.length)];
if (!element) {
throw new Error('Proxy not found');
}
if (element.expiration_time && element.expiration_time > Date.now()) {
return element;
}
return this.authProxy(element);
}
public async getProxyList(): Promise<UrbanProxyElement[]> {
await this.handleBeforeRequest();
const headers = {
...UrbanProxyConfig.headers,
authorization: `Bearer ${this.accessToken}`,
'x-client-app': UrbanProxyConfig.clientAppName,
};
const response = await this.session.get(UrbanProxyConfig.urls.getProxyList, { headers });
if (response.status !== 200) {
await this.handleAfterResponse(response);
throw new Error(`Get proxy list failed -> ${response.status} : ${response.data}`);
}
const resp = response.data;
for (const country of resp.countries.elements) {
const servers = country.servers.elements || [];
for (const element of servers) {
this.proxyList.push({
...element,
host: element.address.primary.host,
port: element.address.primary.port,
ip: element.address.primary.ip,
password: element.password || '1',
});
}
}
console.log(`Proxy list available: ${this.proxyList.length}`);
return this.proxyList;
}
public getHttpsAgent(proxy: UrbanProxyElement): HttpsProxyAgent<string> {
return new HttpsProxyAgent(proxy
.auth_str);
}
public async getIp(proxy: UrbanProxyElement): Promise<string> {
const agent = this.getHttpsAgent(proxy);
const response = await axios.get('https://ifconfig.co/json', {
httpsAgent: agent,
timeout: 10000,
});
return response.data;
}
}
export { UrbanProxy, UrbanProxyElement, UrbanProxyConfig };
export default UrbanProxy;