@mytmpvpn/mytmpvpn-client
Version:
MyTmpVpn Client Library
341 lines (340 loc) • 14.2 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MyTmpVpnClientImpl = exports.MyTmpVpnClient = void 0;
const axios_1 = __importDefault(require("axios"));
const logging_1 = require("./logging");
const utils = __importStar(require("@mytmpvpn/mytmpvpn-common/utils"));
const errors = __importStar(require("@mytmpvpn/mytmpvpn-common/errors"));
const vpn_1 = require("@mytmpvpn/mytmpvpn-common/models/vpn");
const referral_1 = require("@mytmpvpn/mytmpvpn-common/models/referral");
const VPN_REST_PATH = '/v1/vpns';
// const REGIONS_REST_PATH = '/v1/regions'
// const REGIONSDETAILED_REST_PATH = '/v1/regionsDetailed'
const LOCATIONS_REST_PATH = '/v1/locations';
const PEANUTS_REST_PATH = '/v1/peanuts';
const PEANUTS_PACKS_REST_PATH = `${PEANUTS_REST_PATH}/packs`;
const REFERRAL_REST_PATH = '/v1/referral';
const USER_CONFIG_REST_PATH = '/v1/user/config';
function checkVpnId(vpnId) {
if (!vpnId) {
throw new errors.MyTmpVpnError(`Undefined vpnId: ${vpnId}`);
}
}
class MyTmpVpnClient {
getUser() {
return this.user;
}
getSession() {
return this.session;
}
setUserSession(user, session) {
this.user = user;
this.session = session;
}
async listVpns(pageSize = 1000) {
let response;
let vpns = [];
const pagingParams = { pageSize, nextPageToken: undefined };
do {
response = await this.listVpnsPaginated(pagingParams);
logging_1.logger.debug(`List response: ${JSON.stringify(response)}`);
vpns = vpns.concat(response.vpns);
pagingParams.nextPageToken = response.nextPageToken;
} while (response.nextPageToken);
return vpns;
}
async createVpnSync(geonamesId, config, timeout_s = 300) {
const vpn = await this.createVpn(geonamesId, config);
return await this.waitUntilVpnStateIs(vpn.vpnId, vpn_1.VpnState.Running, timeout_s);
}
// Helper method to get region info by city name
// async getRegionByCity(cityName: string): Promise<RegionInfo | undefined> {
// const regions = await this.listRegionsDetailed()
// return regions.find(r => r.city.toLowerCase() === cityName.toLowerCase())
// }
// Helper method to get location by city name
async getLocationByCity(cityName) {
const locations = await this.listLocations();
return locations.find(l => l.city.toLowerCase() === cityName.toLowerCase());
}
// Helper method to get region info by GeoNames ID
// async getRegionByGeonamesId(geonamesId: number): Promise<RegionInfo | undefined> {
// const regions = await this.listRegionsDetailed()
// return regions.find(r => r.geonamesId === geonamesId)
// }
// Helper method to get location by GeoNames ID
async getLocationByGeonamesId(geonamesId) {
const locations = await this.listLocations();
return locations.find(l => l.geonamesId === geonamesId);
}
/*
vpn\state Failed | Creating | Created | Provisioning | Running | Paused | Deprovisioning | Deleted
Failed return return return return return return return return
Creating wait return wait wait wait wait wait wait
Created wait return return wait wait wait wait wait
Provisioning wait return return return wait wait wait wait
Paused wait return return return wait return wait wait
Running wait return return return return wait wait wait
Deprovisioning wait return return return return return return wait
Deleted wait return return return return return return return
*/
async waitUntilVpnStateIs(vpnId, state, timeoutInSeconds = 300) {
checkVpnId(vpnId);
const exitAt = new Date();
exitAt.setSeconds(exitAt.getSeconds() + timeoutInSeconds);
while (true) {
const now = new Date();
if (now.getTime() >= exitAt.getTime())
throw new errors.MyTmpVpnError(`Timeout ${timeoutInSeconds} expires!`);
const { vpn } = await this.getVpn(vpnId);
if (vpn.state === null || vpn.state === undefined)
throw new errors.MyTmpVpnError(`No state found in vpn: ${JSON.stringify(vpn)}`);
if (vpn.state === vpn_1.VpnState.Failed)
return vpn;
if (state === vpn_1.VpnState.Created)
return vpn;
if (state === vpn.state)
return vpn;
if (vpn.state === vpn_1.VpnState.Paused && ((0, vpn_1.toRank)(state) < (0, vpn_1.toRank)(vpn_1.VpnState.Running)))
return vpn;
if ((0, vpn_1.toRank)(vpn.state) > (0, vpn_1.toRank)(state)) {
logging_1.logger.debug(`rank(${JSON.stringify(vpn)}) == ${(0, vpn_1.toRank)(vpn.state)} > ${(0, vpn_1.toRank)(state)} == rank(${state})`);
return vpn;
}
await utils.sleep(10000);
}
}
async waitAndDeleteVpn(vpnId) {
const response = await this.getVpn(vpnId);
if (response.vpn.state == vpn_1.VpnState.Deleted) {
logging_1.logger.debug(`${vpnId}: is already in Deleted state, returning`);
return;
}
if ((0, vpn_1.toRank)(response.vpn.state) <= (0, vpn_1.toRank)(vpn_1.VpnState.Running)) {
logging_1.logger.debug(`${vpnId}: waiting to reach Running state before deleting`);
await this.waitUntilVpnStateIs(vpnId, vpn_1.VpnState.Running);
}
return await this.deleteVpn(vpnId);
}
async waitAndDeleteVpnSync(vpnId, timeout_s = 300) {
await this.waitAndDeleteVpn(vpnId);
return await this.waitUntilVpnStateIs(vpnId, vpn_1.VpnState.Deleted);
}
async waitAndDeleteAll(vpnIds, timeout_s = vpnIds.length * 300) {
const promises = vpnIds.map(async (vpnId) => {
return this.waitAndDeleteVpn(vpnId);
});
return Promise.all(promises);
}
async waitAndDeleteAllSync(vpnIds, timeout_s = vpnIds.length * 300) {
const promises = vpnIds.map(async (vpnId) => {
return await this.waitAndDeleteVpnSync(vpnId);
});
return Promise.all(promises);
}
async validateReferralCode(code) {
// There is no need to call the backend if the code is not in the good format
try {
(0, referral_1.validateReferralCodeSyntax)(code);
}
catch (error) {
logging_1.logger.error(`Error detected on the client-side`, error);
return {
isValid: false,
error: error.message
};
}
return this.validateReferralCodeFromBackend(code);
}
async getVpnConfigLimits() {
return (await this.getUserConfig()).vpnConfigLimits;
}
}
exports.MyTmpVpnClient = MyTmpVpnClient;
class MyTmpVpnClientImpl extends MyTmpVpnClient {
constructor(apiUrl) {
super();
this.ax = axios_1.default.create({
baseURL: apiUrl
});
}
getDefaultAuthorizationHeaders() {
const session = this.getSession();
return {
Accept: 'application/json',
Authorization: session != null ? `${session.getIdToken().getJwtToken()}` : 'Unauthenticated'
};
}
getDefaultNonAuthorizationHeaders() {
return {
Accept: 'application/json'
};
}
async getUserConfig() {
const { data } = await this.ax.get(USER_CONFIG_REST_PATH, {
headers: this.getDefaultAuthorizationHeaders()
});
return data;
}
async patchUserConfig(updates) {
const { data } = await this.ax.patch(USER_CONFIG_REST_PATH, updates, {
headers: this.getDefaultAuthorizationHeaders()
});
return data;
}
async listVpnsPaginated(pagingParams) {
const { data } = await this.ax.get(`${VPN_REST_PATH}`, {
headers: this.getDefaultAuthorizationHeaders(),
params: pagingParams,
});
// log.debug(JSON.stringify(data, null, 4));
// 👇️ "response status is: 200"
// log.error('response status is: ', data);
return {
...data,
vpns: data.vpns.map(vpn => (0, vpn_1.vpnFromServer)(vpn))
};
}
async deleteVpn(vpnId) {
const { data, status } = await this.ax.delete(`${VPN_REST_PATH}/${vpnId}`, {
headers: this.getDefaultAuthorizationHeaders()
});
if (status !== 202 && status !== 204) {
throw new errors.MyTmpVpnError(`Error during deletion of vpn: ${vpnId}: ${JSON.stringify(data)}`);
}
return await this.getVpn(vpnId);
}
async createVpn(geonamesId, config) {
const { data, status } = await this.ax.post(`${VPN_REST_PATH}/`, { geonamesId, config }, {
headers: this.getDefaultAuthorizationHeaders()
});
if (status !== 202) {
throw new errors.MyTmpVpnError(`Error during creation of vpn for geonamesId: ${geonamesId}: ${JSON.stringify(data)}`);
}
const res = await this.getVpn(data.vpn.id);
// There is no need to return VpnMetrics here as creation takes time
return res.vpn;
}
async getVpn(vpnId) {
checkVpnId(vpnId);
const { data } = await this.ax.get(`${VPN_REST_PATH}/${vpnId}`, {
headers: this.getDefaultAuthorizationHeaders()
});
return {
...data,
vpn: (0, vpn_1.vpnFromServer)(data.vpn)
};
}
async getVpnConfig(vpnId, af) {
checkVpnId(vpnId);
const path = af === 'ipv6'
? `${VPN_REST_PATH}/${vpnId}/config?af=ipv6`
: `${VPN_REST_PATH}/${vpnId}/config`;
const { data, status } = await this.ax.get(path, {
headers: this.getDefaultAuthorizationHeaders(),
});
logging_1.logger.debug(`Returning ${JSON.stringify(data)}`);
return data;
}
async getVpnQrConfig(vpnId, af) {
checkVpnId(vpnId);
const path = af === 'ipv6'
? `${VPN_REST_PATH}/${vpnId}/qrconfig?af=ipv6`
: `${VPN_REST_PATH}/${vpnId}/qrconfig`;
const { data, status } = await this.ax.get(path, {
headers: this.getDefaultAuthorizationHeaders(),
});
logging_1.logger.debug(`Returning ${JSON.stringify(data)}`);
return data;
}
// override async listRegions(): Promise<ListRegionsResponse> {
// const { data } = await this.ax.get<ListRegionsResponse>(
// `${REGIONS_REST_PATH}/`,
// {
// headers: this.getDefaultNonAuthorizationHeaders(),
// }
// )
// return data
// }
async listLocations() {
const { data } = await this.ax.get(`${LOCATIONS_REST_PATH}/`, {
headers: this.getDefaultNonAuthorizationHeaders(),
});
return data;
}
async listPeanutsPacks() {
const { data } = await this.ax.get(`${PEANUTS_PACKS_REST_PATH}/`, {
headers: this.getDefaultNonAuthorizationHeaders()
});
return data;
}
async getPeanutsBalance() {
const { data } = await this.ax.get(`${PEANUTS_REST_PATH}`, {
headers: this.getDefaultAuthorizationHeaders()
});
return data;
}
async getReferralCode() {
const { data } = await this.ax.get(`${REFERRAL_REST_PATH}/referralCode`, {
headers: this.getDefaultAuthorizationHeaders()
});
return data;
}
async getReferrerCode() {
const { data } = await this.ax.get(`${REFERRAL_REST_PATH}/referrerCode`, {
headers: this.getDefaultAuthorizationHeaders()
});
return data;
}
async validateReferralCodeFromBackend(code) {
const { data } = await this.ax.post(`${REFERRAL_REST_PATH}/validate`, { referralCode: code }, {
headers: this.getDefaultAuthorizationHeaders()
});
return data;
}
async getReferralStats() {
const { data } = await this.ax.get(`${REFERRAL_REST_PATH}/stats`, {
headers: this.getDefaultAuthorizationHeaders()
});
return data;
}
async getReferralHistory(options) {
const params = {};
if (options?.limit)
params.limit = options.limit;
if (options?.nextToken)
params.nextToken = options.nextToken;
const { data } = await this.ax.get(`${REFERRAL_REST_PATH}/history`, {
headers: this.getDefaultAuthorizationHeaders(),
params
});
return data;
}
}
exports.MyTmpVpnClientImpl = MyTmpVpnClientImpl;