@mytmpvpn/mytmpvpn-common 9.0.0 → 10.0.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.
@@ -4,3 +4,7 @@ export const testMatch: string[];
4
4
  export const transform: {
5
5
  '^.+\\.tsx?$': string;
6
6
  };
7
+ export const collectCoverage: boolean;
8
+ export const coverageDirectory: string;
9
+ export const collectCoverageFrom: string[];
10
+ export const coverageReporters: string[];
@@ -5,5 +5,12 @@ module.exports = {
5
5
  testMatch: ['**/*.test.ts'],
6
6
  transform: {
7
7
  '^.+\\.tsx?$': 'ts-jest'
8
- }
8
+ },
9
+ collectCoverage: true,
10
+ coverageDirectory: 'coverage',
11
+ collectCoverageFrom: [
12
+ 'src/**/*.ts',
13
+ '!src/**/*.d.ts'
14
+ ],
15
+ coverageReporters: ['text', 'lcov', 'html'],
9
16
  };
@@ -1,3 +1,5 @@
1
1
  export * as vpn from './vpn';
2
2
  export * as uservpn from './uservpn';
3
3
  export * as referral from './referral';
4
+ export * as peanuts from './peanuts';
5
+ export * as location from './location';
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.referral = exports.uservpn = exports.vpn = void 0;
3
+ exports.location = exports.peanuts = exports.referral = exports.uservpn = exports.vpn = void 0;
4
4
  exports.vpn = require("./vpn");
5
5
  exports.uservpn = require("./uservpn");
6
6
  exports.referral = require("./referral");
7
+ exports.peanuts = require("./peanuts");
8
+ exports.location = require("./location");
@@ -0,0 +1,40 @@
1
+ export declare enum InfrastructureProvider {
2
+ Aws = "Aws",
3
+ GoogleCloud = "GoogleCloud",
4
+ Azure = "Azure"
5
+ }
6
+ /**
7
+ * Instance types define the bandwidth capabilities of VPN instances
8
+ */
9
+ export declare enum InstanceType {
10
+ Ultra = "Ultra",
11
+ Fast = "Fast",
12
+ Eco = "Eco"
13
+ }
14
+ export interface PricingRate {
15
+ peanutsPerMinuteMax: number;
16
+ peanutsPerMinuteMin: number;
17
+ }
18
+ export type PricingRates = Partial<Record<InstanceType, PricingRate>>;
19
+ export interface InfraDetails {
20
+ ipv6Supported: boolean;
21
+ }
22
+ export interface ProviderInfo {
23
+ infraDetails: InfraDetails;
24
+ pricingRates: PricingRates;
25
+ }
26
+ export type ProvidersInfo = Partial<Record<InfrastructureProvider, ProviderInfo>>;
27
+ export interface Location {
28
+ geonamesId: number;
29
+ city: string;
30
+ country: string;
31
+ countryCode: string;
32
+ coordinates: {
33
+ latitude: number;
34
+ longitude: number;
35
+ };
36
+ }
37
+ export interface LocationWithProvidersInfo extends Location {
38
+ providersInfo: ProvidersInfo;
39
+ }
40
+ export type ListLocationsResponse = LocationWithProvidersInfo[];
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InstanceType = exports.InfrastructureProvider = void 0;
4
+ var InfrastructureProvider;
5
+ (function (InfrastructureProvider) {
6
+ InfrastructureProvider["Aws"] = "Aws";
7
+ InfrastructureProvider["GoogleCloud"] = "GoogleCloud";
8
+ InfrastructureProvider["Azure"] = "Azure";
9
+ })(InfrastructureProvider = exports.InfrastructureProvider || (exports.InfrastructureProvider = {}));
10
+ /**
11
+ * Instance types define the bandwidth capabilities of VPN instances
12
+ */
13
+ var InstanceType;
14
+ (function (InstanceType) {
15
+ InstanceType["Ultra"] = "Ultra";
16
+ InstanceType["Fast"] = "Fast";
17
+ InstanceType["Eco"] = "Eco";
18
+ })(InstanceType = exports.InstanceType || (exports.InstanceType = {}));
@@ -1,23 +1,30 @@
1
1
  import * as vpn from './vpn';
2
+ import { VpnConfig } from './vpnConfig';
3
+ export declare enum UserVpnVersion {
4
+ INITIAL = 0,
5
+ LOCATIONS = 1
6
+ }
2
7
  export interface UserVpn {
3
8
  userId: string;
4
- version: number;
9
+ version: UserVpnVersion;
5
10
  vpn: vpn.Vpn;
6
11
  }
7
- export interface newUserVpnParams {
12
+ export interface NewUserVpnParams {
8
13
  userId: string;
9
- region: string;
10
- version?: number;
11
- config: vpn.VpnConfig;
14
+ geonamesId: number;
15
+ version?: UserVpnVersion;
16
+ config: VpnConfig;
12
17
  state: vpn.VpnState;
13
18
  }
14
- export interface getUserVpnFromParams {
19
+ export interface GetUserVpnFromParams {
15
20
  userId: string;
16
21
  vpnId: string;
17
- version?: number;
18
- config: vpn.VpnConfig;
22
+ createdAt?: Date;
23
+ geonamesId: number;
24
+ version?: UserVpnVersion;
25
+ config: VpnConfig;
19
26
  state: vpn.VpnState;
20
27
  }
21
- export declare function newUserVpn({ userId, region, version, ...rest }: newUserVpnParams): UserVpn;
22
- export declare function getUserVpnFrom({ userId, vpnId, version, ...rest }: getUserVpnFromParams): UserVpn;
28
+ export declare function newUserVpn({ userId, geonamesId, version, ...rest }: NewUserVpnParams): UserVpn;
29
+ export declare function getUserVpnFrom({ userId, vpnId, geonamesId, createdAt, version, ...rest }: GetUserVpnFromParams): UserVpn;
23
30
  export declare function jsonToUserVpn(jsonString: any): UserVpn;
@@ -1,21 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.jsonToUserVpn = exports.getUserVpnFrom = exports.newUserVpn = void 0;
3
+ exports.jsonToUserVpn = exports.getUserVpnFrom = exports.newUserVpn = exports.UserVpnVersion = void 0;
4
4
  const vpn = require("./vpn");
5
- const INITIAL_VERSION = 0;
6
- function newUserVpn({ userId, region, version = INITIAL_VERSION, ...rest }) {
5
+ var UserVpnVersion;
6
+ (function (UserVpnVersion) {
7
+ UserVpnVersion[UserVpnVersion["INITIAL"] = 0] = "INITIAL";
8
+ UserVpnVersion[UserVpnVersion["LOCATIONS"] = 1] = "LOCATIONS"; // This version introduces locations (geonames)
9
+ })(UserVpnVersion = exports.UserVpnVersion || (exports.UserVpnVersion = {}));
10
+ function newUserVpn({ userId, geonamesId, version = UserVpnVersion.LOCATIONS, ...rest }) {
7
11
  return {
8
12
  userId,
9
13
  version,
10
- vpn: vpn.newVpn(region, rest.config, rest.state)
14
+ vpn: vpn.newVpn(geonamesId, rest.config, rest.state)
11
15
  };
12
16
  }
13
17
  exports.newUserVpn = newUserVpn;
14
- function getUserVpnFrom({ userId, vpnId, version = INITIAL_VERSION, ...rest }) {
18
+ function getUserVpnFrom({ userId, vpnId, geonamesId, createdAt, version = UserVpnVersion.LOCATIONS, ...rest }) {
15
19
  return {
16
20
  userId,
17
21
  version,
18
- vpn: vpn.getVpnFrom(vpnId, rest.state, rest.config)
22
+ vpn: vpn.getVpnFrom(vpnId, createdAt, geonamesId, rest.state, rest.config)
19
23
  };
20
24
  }
21
25
  exports.getUserVpnFrom = getUserVpnFrom;
@@ -1,4 +1,6 @@
1
- import { UserVpn } from "./uservpn";
1
+ import { UserVpn, UserVpnVersion } from "./uservpn";
2
+ import { VpnConfig } from "./vpnConfig";
3
+ import { Location } from './location';
2
4
  export declare enum VpnState {
3
5
  Failed = "Failed",
4
6
  Creating = "Creating",
@@ -14,21 +16,6 @@ export declare function fromRank(rank: number): VpnState;
14
16
  export declare enum VpnType {
15
17
  WireGuard = "wireguard"
16
18
  }
17
- export interface VpnConfigLimits {
18
- deleteAfterFieldMinValue: number;
19
- deleteAfterFieldMaxValue: number;
20
- maxPeanutsFieldMinValue: number;
21
- maxPeanutsFieldMaxValue: number;
22
- }
23
- export interface ValidDeleteAfterConfig {
24
- min: number;
25
- max: number;
26
- }
27
- export interface VpnConfig {
28
- type: VpnType;
29
- maxPeanuts: number;
30
- deleteAfter?: number;
31
- }
32
19
  export interface VpnMetrics {
33
20
  duration: number;
34
21
  bytes: number;
@@ -37,11 +24,10 @@ export interface VpnMetrics {
37
24
  export interface Vpn {
38
25
  vpnId: string;
39
26
  createdAt: Date;
40
- region: string;
27
+ geonamesId: number;
41
28
  config: VpnConfig;
42
29
  state: VpnState;
43
30
  }
44
- export type GetVpnConfigLimitsResponse = VpnConfigLimits;
45
31
  export type ListVpnsResponse = Vpn[];
46
32
  export interface DeleteVpnResponse {
47
33
  vpn: {
@@ -59,33 +45,43 @@ export interface GetVpnResponse {
59
45
  vpn: Vpn;
60
46
  metrics: VpnMetrics;
61
47
  }
62
- export interface RegionInfo {
63
- name: string;
64
- city: string;
65
- country: string;
66
- cctld: string;
48
+ export declare enum ListVpnsSortByCriteria {
49
+ CreatedAt = "createdAt",
50
+ State = "state",
51
+ GeonamesId = "geonamesId",
52
+ VpnId = "vpnId",
53
+ City = "city",
54
+ Country = "country"
55
+ }
56
+ export declare enum ListVpnsSortOrder {
57
+ Asc = "asc",
58
+ Desc = "desc"
67
59
  }
68
- export type GetVpnConfigResponse = string;
69
- export type ListRegionsResponse = string[];
70
- export type ListRegionsDetailedResponse = RegionInfo[];
71
60
  export type ListVpnsPagingParams = {
72
- pageSize: Number;
73
- nextPageToken: string | undefined;
61
+ pageSize: number;
62
+ nextPageToken?: string;
63
+ filterCity?: string;
64
+ filterCountry?: string;
65
+ sortBy?: ListVpnsSortByCriteria;
66
+ sortOrder?: ListVpnsSortOrder;
74
67
  };
75
68
  export type ListVpnsPaginatedResponse = {
76
- totalVpns: number;
77
- totalPages: number;
78
69
  vpns: Vpn[];
79
70
  nextPageToken: string | undefined;
80
71
  };
81
- export declare function getVpnConfigTypes(): VpnType[];
72
+ export declare function validateVpnId(vpnId: string): UserVpnVersion;
82
73
  export declare function vpnAgainstQuotaPredicate(uservpn: UserVpn): boolean;
83
74
  export declare function validateVpnNbAgainstQuota(vpnNb: number, quota: number): number;
84
- export declare function checkValidConfig(userId: string, currentBalance: number, vpnConfigLimits: VpnConfigLimits, vpnConfig: any): VpnConfig;
85
- export declare function newVpn(region: string, config: VpnConfig, state: VpnState): Vpn;
86
- export declare function getVpnFrom(vpnId: string, state: VpnState, config: VpnConfig): Vpn;
87
- export declare function vpnIdToWgFileName(vpnId: string): string;
75
+ export type GetLocationByGeonamesId = (geonamesId: number) => Location | undefined;
76
+ export declare function filterVpns(vpns: Vpn[], getLocationByGeonamesId: GetLocationByGeonamesId, filterCity?: string, filterCountry?: string): Vpn[];
77
+ export declare function sortVpns(vpns: Vpn[], getCityByGeonamesId: GetLocationByGeonamesId, sortBy?: ListVpnsSortByCriteria, sortOrder?: ListVpnsSortOrder): Vpn[];
78
+ export declare function newVpn(geonamesId: number, config: VpnConfig, state: VpnState): Vpn;
79
+ export declare function getVpnFrom(vpnId: string, createdAt: Date | undefined, geonamesId: number, state: VpnState, config: VpnConfig): Vpn;
80
+ export declare function dateToId(date: Date): string;
81
+ export declare function idToDate(id: string): Date;
82
+ export declare function vpnIdToWgFileName(vpn: Vpn): string;
88
83
  export declare function vpnToClient(vpn: Vpn): Vpn;
84
+ export declare function vpnFromServer(vpn: any): Vpn;
89
85
  export declare function metricsToClient(metrics: VpnMetrics | undefined): VpnMetrics;
90
86
  /**
91
87
  * Extract the creation date from a VPN ID
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getCreationDateFromVpnId = exports.metricsToClient = exports.vpnToClient = exports.vpnIdToWgFileName = exports.getVpnFrom = exports.newVpn = exports.checkValidConfig = exports.validateVpnNbAgainstQuota = exports.vpnAgainstQuotaPredicate = exports.getVpnConfigTypes = exports.VpnType = exports.fromRank = exports.toRank = exports.VpnState = void 0;
3
+ exports.getCreationDateFromVpnId = exports.metricsToClient = exports.vpnFromServer = exports.vpnToClient = exports.vpnIdToWgFileName = exports.idToDate = exports.dateToId = exports.getVpnFrom = exports.newVpn = exports.sortVpns = exports.filterVpns = exports.validateVpnNbAgainstQuota = exports.vpnAgainstQuotaPredicate = exports.validateVpnId = exports.ListVpnsSortOrder = exports.ListVpnsSortByCriteria = exports.VpnType = exports.fromRank = exports.toRank = exports.VpnState = void 0;
4
+ const uuid_1 = require("uuid");
4
5
  const errors_1 = require("../errors");
5
6
  const peanuts_1 = require("./peanuts");
6
- const loglevel_1 = require("loglevel");
7
+ const uservpn_1 = require("./uservpn");
8
+ const LEGACY_VPN_ID_FORMAT_REGEX = /\d{4}[01]\d[0-3]\d[0-2]\d[0-5]\d[0-5]\d\d{3}@[a-z]{2}-[a-z]+-\d/;
7
9
  var VpnState;
8
10
  (function (VpnState) {
9
11
  VpnState["Failed"] = "Failed";
@@ -28,52 +30,29 @@ var VpnType;
28
30
  (function (VpnType) {
29
31
  VpnType["WireGuard"] = "wireguard";
30
32
  })(VpnType = exports.VpnType || (exports.VpnType = {}));
31
- function getVpnConfigTypes() {
32
- return Object.values(VpnType).filter((item) => {
33
- return isNaN(Number(item));
34
- });
35
- }
36
- exports.getVpnConfigTypes = getVpnConfigTypes;
33
+ var ListVpnsSortByCriteria;
34
+ (function (ListVpnsSortByCriteria) {
35
+ ListVpnsSortByCriteria["CreatedAt"] = "createdAt";
36
+ ListVpnsSortByCriteria["State"] = "state";
37
+ ListVpnsSortByCriteria["GeonamesId"] = "geonamesId";
38
+ ListVpnsSortByCriteria["VpnId"] = "vpnId";
39
+ ListVpnsSortByCriteria["City"] = "city";
40
+ ListVpnsSortByCriteria["Country"] = "country";
41
+ })(ListVpnsSortByCriteria = exports.ListVpnsSortByCriteria || (exports.ListVpnsSortByCriteria = {}));
42
+ var ListVpnsSortOrder;
43
+ (function (ListVpnsSortOrder) {
44
+ ListVpnsSortOrder["Asc"] = "asc";
45
+ ListVpnsSortOrder["Desc"] = "desc";
46
+ })(ListVpnsSortOrder = exports.ListVpnsSortOrder || (exports.ListVpnsSortOrder = {}));
37
47
  function validateVpnId(vpnId) {
38
- // e.g: YYYYMMDDHHmmssmss@az-test-7
39
- if (!/\d{4}[01]\d[0-3]\d[0-2]\d[0-5]\d[0-5]\d\d{3}@[a-z]{2}-[a-z]+-\d/.test(vpnId)) {
40
- throw new errors_1.MyTmpVpnError(`Incorrect vpnId: \'${vpnId}\'`);
41
- }
42
- return vpnId;
43
- }
44
- function validateMaxPeanuts(peanuts, currentBalance, vpnConfigLimits) {
45
- // No matter what, if currentBalance is negative, we fail
46
- if (currentBalance <= 0) {
47
- throw new errors_1.NegativeBalanceError(currentBalance);
48
- }
49
- if (peanuts <= 0) {
50
- // result = Math.min(currentBalance, vpnConfigLimits.maxPeanutsFieldMaxValue)
51
- // This is always safe as it means run as long as there are enough peanuts
52
- return -1;
53
- }
54
- if (peanuts > currentBalance) {
55
- throw new errors_1.NotEnoughPeanutsError(peanuts, currentBalance);
56
- }
57
- if (peanuts < vpnConfigLimits.maxPeanutsFieldMinValue) {
58
- throw new errors_1.MinPeanutsError(vpnConfigLimits.maxPeanutsFieldMinValue, peanuts, currentBalance);
59
- }
60
- if (peanuts > vpnConfigLimits.maxPeanutsFieldMaxValue) {
61
- throw new errors_1.MaxPeanutsError(vpnConfigLimits.maxPeanutsFieldMaxValue, peanuts, currentBalance);
62
- }
63
- return peanuts;
64
- }
65
- function validateDeleteAfter(deleteAfter, vpnConfigLimits) {
66
- if (deleteAfter === undefined) {
67
- return vpnConfigLimits.deleteAfterFieldMaxValue;
68
- }
69
- if (deleteAfter < vpnConfigLimits.deleteAfterFieldMinValue) {
70
- throw new errors_1.MinDeleteAfterError(vpnConfigLimits.deleteAfterFieldMinValue, deleteAfter);
71
- }
72
- if (deleteAfter > vpnConfigLimits.deleteAfterFieldMaxValue) {
73
- throw new errors_1.MaxDeleteAfterError(vpnConfigLimits.deleteAfterFieldMaxValue, deleteAfter);
74
- }
75
- return deleteAfter;
48
+ // Parse the string as a uuid
49
+ if ((0, uuid_1.validate)(vpnId))
50
+ return uservpn_1.UserVpnVersion.LOCATIONS;
51
+ if (LEGACY_VPN_ID_FORMAT_REGEX.test(vpnId))
52
+ return uservpn_1.UserVpnVersion.INITIAL;
53
+ throw new errors_1.MyTmpVpnError(`Invalid vpnId format: \'${vpnId}\'`);
76
54
  }
55
+ exports.validateVpnId = validateVpnId;
77
56
  // Return whether the given vpn should be taken into account when computing
78
57
  // whether a given user has reached its quota or not
79
58
  function vpnAgainstQuotaPredicate(uservpn) {
@@ -90,79 +69,113 @@ function validateVpnNbAgainstQuota(vpnNb, quota) {
90
69
  return vpnNb;
91
70
  }
92
71
  exports.validateVpnNbAgainstQuota = validateVpnNbAgainstQuota;
93
- // vpnConfig is of type any here because it could come from user input such as json
94
- function checkValidConfig(userId, currentBalance, vpnConfigLimits, vpnConfig) {
95
- const maxPeanuts = checkValidMaxPeanuts(userId, currentBalance, vpnConfig.maxPeanuts, vpnConfigLimits);
96
- const type = checkValidVpnType(vpnConfig.type);
97
- const deleteAfter = checkValidDeleteAfter(vpnConfig.deleteAfter, vpnConfigLimits);
98
- const result = {
99
- maxPeanuts,
100
- type,
101
- deleteAfter
102
- };
103
- return result;
104
- }
105
- exports.checkValidConfig = checkValidConfig;
106
- function checkValidMaxPeanuts(userId, currentBalance, maxPeanuts, vpnConfigLimits) {
107
- const peanuts = maxPeanuts ? Number.parseFloat(maxPeanuts) : -1;
108
- if (Number.isNaN(peanuts) || !Number.isFinite(peanuts)) {
109
- throw new errors_1.InvalidVpnConfigError(`Config maxPeanuts is invalid: ${maxPeanuts}`);
110
- }
111
- loglevel_1.default.debug(`Validating peanuts for ${userId}, peanuts: ${peanuts}, currentBalance: ${currentBalance}`);
112
- return validateMaxPeanuts(peanuts, currentBalance, vpnConfigLimits);
113
- }
114
- function checkValidVpnType(jsonType) {
115
- if (!jsonType) {
116
- throw new errors_1.InvalidVpnConfigError(`Config type is null or undefined: ${jsonType}`);
117
- }
118
- const type = jsonType;
119
- if (!type || !Object.values(VpnType).includes(type)) {
120
- throw new errors_1.InvalidVpnConfigError(`Config type is invalid: ${jsonType}`);
121
- }
122
- return type;
72
+ function filterVpns(vpns, getLocationByGeonamesId, filterCity, filterCountry) {
73
+ let filtered = vpns;
74
+ return filtered.filter(vpn => {
75
+ const cityLocation = getLocationByGeonamesId(vpn.geonamesId);
76
+ if (!cityLocation)
77
+ return false;
78
+ // If no filters are applied, include all VPNs
79
+ if (!filterCity && !filterCountry)
80
+ return true;
81
+ const cityMatch = filterCity && cityLocation.city.toLowerCase().includes(filterCity);
82
+ const countryMatch = filterCountry && cityLocation.country.toLowerCase().includes(filterCountry);
83
+ // FilterCity | FilterCountry
84
+ // undefined | undefined -> true (handled above)
85
+ // match | undefined -> cityMatch
86
+ // unmatch | undefined -> false
87
+ // undefined | match -> countryMatch
88
+ // undefined | unmatch -> false
89
+ // match | match -> cityMatch && countryMatch
90
+ // match | unmatch -> cityMatch && false
91
+ // unmatch | match -> false && countryMatch
92
+ // unmatch | unmatch -> false && false
93
+ const bothMatch = cityMatch && countryMatch;
94
+ // Either both city and country match the filter
95
+ // or one of them is undefined and the other matches
96
+ return bothMatch || (!filterCountry && cityMatch) || (!filterCity && countryMatch);
97
+ });
123
98
  }
124
- function checkValidDeleteAfter(jsonDeleteAfter, vpnConfigLimits) {
125
- if (jsonDeleteAfter === undefined) {
126
- return validateDeleteAfter(undefined, vpnConfigLimits);
127
- }
128
- const deleteAfter = Number.parseInt(jsonDeleteAfter);
129
- if (Number.isNaN(deleteAfter)) {
130
- throw new errors_1.InvalidVpnConfigError(`Config deleteAfter is invalid: ${jsonDeleteAfter}`);
99
+ exports.filterVpns = filterVpns;
100
+ function sortVpns(vpns, getCityByGeonamesId, sortBy = ListVpnsSortByCriteria.CreatedAt, sortOrder = ListVpnsSortOrder.Desc) {
101
+ if (!sortBy) {
102
+ return vpns;
131
103
  }
132
- return validateDeleteAfter(deleteAfter, vpnConfigLimits);
104
+ const sorted = [...vpns].sort((a, b) => {
105
+ let compareResult = 0;
106
+ const aCityLocation = getCityByGeonamesId(a.geonamesId);
107
+ const bCityLocation = getCityByGeonamesId(b.geonamesId);
108
+ switch (sortBy) {
109
+ case ListVpnsSortByCriteria.City:
110
+ compareResult = aCityLocation.city.localeCompare(bCityLocation.city);
111
+ break;
112
+ case ListVpnsSortByCriteria.Country:
113
+ compareResult = aCityLocation.country.localeCompare(bCityLocation.country);
114
+ break;
115
+ case ListVpnsSortByCriteria.GeonamesId:
116
+ compareResult = a.geonamesId - b.geonamesId;
117
+ break;
118
+ case ListVpnsSortByCriteria.State:
119
+ compareResult = toRank(a.state) - toRank(b.state);
120
+ break;
121
+ case ListVpnsSortByCriteria.CreatedAt:
122
+ default:
123
+ compareResult = a.createdAt.getTime() - b.createdAt.getTime();
124
+ break;
125
+ }
126
+ return sortOrder === ListVpnsSortOrder.Desc ? -compareResult : compareResult;
127
+ });
128
+ return sorted;
133
129
  }
134
- function newVpn(region, config, state) {
135
- // e.g: ap-northeast-3
136
- if (!/[a-z]{2}-[a-z]+-[1-9]+/.test(region)) {
137
- throw new errors_1.MyTmpVpnError(`Incorrect region: \'${region}\'`);
130
+ exports.sortVpns = sortVpns;
131
+ function newVpn(geonamesId, config, state) {
132
+ if (!Number.isInteger(geonamesId) || geonamesId <= 0) {
133
+ throw new errors_1.MyTmpVpnError(`Incorrect geonamesId: \'${geonamesId}\'`);
138
134
  }
139
135
  const createdAt = new Date();
140
- const vpnId = `${dateToId(createdAt)}@${region}`;
136
+ const vpnId = (0, uuid_1.v4)();
141
137
  // Assert we will be able to deserialize later on...
142
138
  validateVpnId(vpnId);
143
139
  return {
144
140
  vpnId,
145
141
  createdAt,
146
- region,
142
+ geonamesId,
147
143
  config,
148
144
  state
149
145
  };
150
146
  }
151
147
  exports.newVpn = newVpn;
152
- function getVpnFrom(vpnId, state, config) {
153
- validateVpnId(vpnId);
154
- const tokens = vpnId.split('@');
155
- if (tokens.length !== 2) {
156
- throw new errors_1.MyTmpVpnError(`Incorrect vpnId: ${vpnId}`);
148
+ function getVpnFrom(vpnId, createdAt, geonamesId, state, config) {
149
+ const version = validateVpnId(vpnId);
150
+ let finalCreatedAt;
151
+ switch (version) {
152
+ case uservpn_1.UserVpnVersion.INITIAL:
153
+ // Legacy vpnId format, the createdAt is given from the vpnId itself
154
+ if (createdAt !== undefined) {
155
+ throw new errors_1.MyTmpVpnError(`Invalid parameter: createdAt must be undefined when vpnId version is INITIAL: vpnId=${vpnId}; createdAt=${createdAt}`);
156
+ }
157
+ const tokens = vpnId.split('@');
158
+ if (tokens.length !== 2) {
159
+ throw new errors_1.MyTmpVpnError(`Incorrect vpnId: ${vpnId}`);
160
+ }
161
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
162
+ finalCreatedAt = idToDate(tokens[0]);
163
+ /* eslint-enable @typescript-eslint/no-non-null-assertion */
164
+ break;
165
+ case uservpn_1.UserVpnVersion.LOCATIONS:
166
+ // New vpnId format
167
+ if (createdAt === undefined) {
168
+ throw new errors_1.MyTmpVpnError(`Invalid parameter: createdAt can't be undefined: vpnId=${vpnId}`);
169
+ }
170
+ finalCreatedAt = createdAt;
171
+ break;
172
+ default:
173
+ throw new errors_1.MyTmpVpnError(`Incorrect version: \'${version}\'`);
157
174
  }
158
- /* eslint-disable @typescript-eslint/no-non-null-assertion */
159
- const createdAt = idToDate(tokens[0]);
160
- const region = tokens[1];
161
- /* eslint-enable @typescript-eslint/no-non-null-assertion */
162
175
  return {
163
176
  vpnId,
164
- createdAt,
165
- region,
177
+ createdAt: finalCreatedAt,
178
+ geonamesId,
166
179
  config,
167
180
  state
168
181
  };
@@ -176,6 +189,7 @@ function dateToId(date) {
176
189
  // YYYY-MM-DDTHH:mm:ss.uuuZ -> YYYYMMDDHHmmssuuu
177
190
  return date.toISOString().replace(/[^\d]/g, '');
178
191
  }
192
+ exports.dateToId = dateToId;
179
193
  function idToDate(id) {
180
194
  // YYYYMMDDHHmmssuuu -> YYYY-MM-DDTHH:mm:ss.uuuZ
181
195
  const year = id.substring(0, 4);
@@ -187,60 +201,25 @@ function idToDate(id) {
187
201
  const millis = id.substring(14);
188
202
  return new Date(`${year}-${month}-${day}T${hour}:${minute}:${second}.${millis}Z`);
189
203
  }
204
+ exports.idToDate = idToDate;
190
205
  // The WireGuard Mobile Application has requirements for the wireguard configuration file:
191
206
  // 1. must have extension '.conf'
192
207
  // 2. file name must match the following regexp: "[a-zA-Z0-9_=+.-]{1,15}")
193
208
  // https://git.zx2c4.com/wireguard-android/tree/tunnel/src/main/java/com/wireguard/android/backend/Tunnel.java#n19
194
- // This function is to transform from vpnIn to Wireguard mobile application requirements
195
- function vpnIdToWgFileName(vpnId) {
196
- validateVpnId(vpnId);
197
- // The vpnId is made of YYYYMMDDHHmmssmss@region
198
- // Let's keep it simple: vpn is mostly temporary, so keeping
199
- // the year is useless.
200
- // Also the milliseconds are useless.
201
- // Finally, the region itself is of the following format: ap-northeast-3
202
- // We can compressing with something like:
203
- // MMDDHHmmssapne3.conf
204
- const ddhhmmss = vpnId.substring(4, 14);
205
- const seps = vpnId.substring(18).split(/-/);
206
- const ccld = seps[0];
207
- let location;
208
- switch (seps[1]) {
209
- case 'north':
210
- location = 'n';
211
- break;
212
- case 'northeast':
213
- location = 'ne';
214
- break;
215
- case 'east':
216
- location = 'e';
217
- break;
218
- case 'southeast':
219
- location = 'se';
220
- break;
221
- case 'south':
222
- location = 's';
223
- break;
224
- case 'southwest':
225
- location = 'sw';
226
- break;
227
- case 'west':
228
- location = 'w';
229
- break;
230
- case 'northwest':
231
- location = 'nw';
232
- break;
233
- case 'central':
234
- location = 'c';
235
- break;
236
- default:
237
- '';
238
- break;
239
- }
240
- const number = seps[2];
241
- // Let's make sure the end file is of 15 char max
242
- const result = `${ddhhmmss}${ccld}${location}${number}`.substring(0, 15);
243
- loglevel_1.default.info(`Transforming ${vpnId} to ${result}`);
209
+ // This function is to transform from vpnId to Wireguard mobile application requirements
210
+ function vpnIdToWgFileName(vpn) {
211
+ const version = validateVpnId(vpn.vpnId);
212
+ // We will create a file name from the createdAt field and the location so for the end-user
213
+ // it will be easier to distinguish. Also the vpnId is to big anyway.
214
+ // Note that using the createdAt field makes it simpler across versions as
215
+ // all versions must have this field.
216
+ // Let's keep it simple: vpn is mostly temporary, so keeping
217
+ // the year is useless. Also the milliseconds are useless.
218
+ // Return an id from the vpn.createdAt Date object with the following format
219
+ // MMDDHHmmss.conf
220
+ const result = vpn.createdAt.toISOString() // This will create YYYY-MM-DDThh:mm:ss....
221
+ .replace(/[^\d]/g, '') // Remove meanless characters: YYYYMMDDhhmmss
222
+ .substring(4, 14); // Use only MMDDhhmmss
244
223
  return result;
245
224
  }
246
225
  exports.vpnIdToWgFileName = vpnIdToWgFileName;
@@ -248,20 +227,27 @@ function vpnToClient(vpn) {
248
227
  return {
249
228
  vpnId: vpn.vpnId,
250
229
  state: vpn.state,
251
- region: vpn.region,
230
+ geonamesId: vpn.geonamesId,
252
231
  createdAt: vpn.createdAt,
253
232
  config: {
254
233
  type: vpn.config.type,
255
234
  deleteAfter: vpn.config.deleteAfter,
256
235
  maxPeanuts: (0, peanuts_1.peanutsToClient)(vpn.config.maxPeanuts),
257
- // terminationReason: userVpn.vpn.config.terminationReason,
258
- // terminationMessage: userVpn.vpn.config.terminationMessage,
259
- // terminationCode: userVpn.vpn.config.terminationCode,
260
- // terminationType: userVpn.vpn.config.terminationType,
261
236
  }
262
237
  };
263
238
  }
264
239
  exports.vpnToClient = vpnToClient;
240
+ function vpnFromServer(vpn) {
241
+ // Transform from JSON to Plain object, especially Date object are not de-serialized automatically
242
+ return {
243
+ vpnId: vpn.vpnId,
244
+ createdAt: new Date(vpn.createdAt),
245
+ geonamesId: vpn.geonamesId,
246
+ config: vpn.config,
247
+ state: vpn.state,
248
+ };
249
+ }
250
+ exports.vpnFromServer = vpnFromServer;
265
251
  function metricsToClient(metrics) {
266
252
  return (metrics != null)
267
253
  ? {
@@ -0,0 +1,22 @@
1
+ export declare enum VpnType {
2
+ WireGuard = "wireguard"
3
+ }
4
+ export interface VpnConfigLimits {
5
+ deleteAfterFieldMinValue: number;
6
+ deleteAfterFieldMaxValue: number;
7
+ maxPeanutsFieldMinValue: number;
8
+ maxPeanutsFieldMaxValue: number;
9
+ }
10
+ export interface ValidDeleteAfterConfig {
11
+ min: number;
12
+ max: number;
13
+ }
14
+ export interface VpnConfig {
15
+ type: VpnType;
16
+ maxPeanuts: number;
17
+ deleteAfter?: number;
18
+ }
19
+ export type GetVpnConfigLimitsResponse = VpnConfigLimits;
20
+ export type GetVpnConfigResponse = string;
21
+ export declare function getVpnConfigTypes(): VpnType[];
22
+ export declare function checkValidConfig(userId: string, currentBalance: number, vpnConfigLimits: VpnConfigLimits, vpnConfig: any): VpnConfig;
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkValidConfig = exports.getVpnConfigTypes = exports.VpnType = void 0;
4
+ const errors_1 = require("../errors");
5
+ const loglevel_1 = require("loglevel");
6
+ var VpnType;
7
+ (function (VpnType) {
8
+ VpnType["WireGuard"] = "wireguard";
9
+ })(VpnType = exports.VpnType || (exports.VpnType = {}));
10
+ function getVpnConfigTypes() {
11
+ return Object.values(VpnType).filter((item) => {
12
+ return isNaN(Number(item));
13
+ });
14
+ }
15
+ exports.getVpnConfigTypes = getVpnConfigTypes;
16
+ function validateMaxPeanuts(peanuts, currentBalance, vpnConfigLimits) {
17
+ // No matter what, if currentBalance is negative, we fail
18
+ if (currentBalance <= 0) {
19
+ throw new errors_1.NegativeBalanceError(currentBalance);
20
+ }
21
+ if (peanuts <= 0) {
22
+ // result = Math.min(currentBalance, vpnConfigLimits.maxPeanutsFieldMaxValue)
23
+ // This is always safe as it means run as long as there are enough peanuts
24
+ return -1;
25
+ }
26
+ if (peanuts > currentBalance) {
27
+ throw new errors_1.NotEnoughPeanutsError(peanuts, currentBalance);
28
+ }
29
+ if (peanuts < vpnConfigLimits.maxPeanutsFieldMinValue) {
30
+ throw new errors_1.MinPeanutsError(vpnConfigLimits.maxPeanutsFieldMinValue, peanuts, currentBalance);
31
+ }
32
+ if (peanuts > vpnConfigLimits.maxPeanutsFieldMaxValue) {
33
+ throw new errors_1.MaxPeanutsError(vpnConfigLimits.maxPeanutsFieldMaxValue, peanuts, currentBalance);
34
+ }
35
+ return peanuts;
36
+ }
37
+ function validateDeleteAfter(deleteAfter, vpnConfigLimits) {
38
+ if (deleteAfter === undefined) {
39
+ return vpnConfigLimits.deleteAfterFieldMaxValue;
40
+ }
41
+ if (deleteAfter < vpnConfigLimits.deleteAfterFieldMinValue) {
42
+ throw new errors_1.MinDeleteAfterError(vpnConfigLimits.deleteAfterFieldMinValue, deleteAfter);
43
+ }
44
+ if (deleteAfter > vpnConfigLimits.deleteAfterFieldMaxValue) {
45
+ throw new errors_1.MaxDeleteAfterError(vpnConfigLimits.deleteAfterFieldMaxValue, deleteAfter);
46
+ }
47
+ return deleteAfter;
48
+ }
49
+ // vpnConfig is of type any here because it could come from user input such as json
50
+ function checkValidConfig(userId, currentBalance, vpnConfigLimits, vpnConfig) {
51
+ const maxPeanuts = checkValidMaxPeanuts(userId, currentBalance, vpnConfig.maxPeanuts, vpnConfigLimits);
52
+ const type = checkValidVpnType(vpnConfig.type);
53
+ const deleteAfter = checkValidDeleteAfter(vpnConfig.deleteAfter, vpnConfigLimits);
54
+ const result = {
55
+ maxPeanuts,
56
+ type,
57
+ deleteAfter
58
+ };
59
+ return result;
60
+ }
61
+ exports.checkValidConfig = checkValidConfig;
62
+ function checkValidMaxPeanuts(userId, currentBalance, maxPeanuts, vpnConfigLimits) {
63
+ const peanuts = maxPeanuts ? Number.parseFloat(maxPeanuts) : -1;
64
+ if (Number.isNaN(peanuts) || !Number.isFinite(peanuts)) {
65
+ throw new errors_1.InvalidVpnConfigError(`Config maxPeanuts is invalid: ${maxPeanuts}`);
66
+ }
67
+ loglevel_1.default.debug(`Validating peanuts for ${userId}, peanuts: ${peanuts}, currentBalance: ${currentBalance}`);
68
+ return validateMaxPeanuts(peanuts, currentBalance, vpnConfigLimits);
69
+ }
70
+ function checkValidVpnType(jsonType) {
71
+ if (!jsonType) {
72
+ throw new errors_1.InvalidVpnConfigError(`Config type is null or undefined: ${jsonType}`);
73
+ }
74
+ const type = jsonType;
75
+ if (!type || !Object.values(VpnType).includes(type)) {
76
+ throw new errors_1.InvalidVpnConfigError(`Config type is invalid: ${jsonType}`);
77
+ }
78
+ return type;
79
+ }
80
+ function checkValidDeleteAfter(jsonDeleteAfter, vpnConfigLimits) {
81
+ if (jsonDeleteAfter === undefined) {
82
+ return validateDeleteAfter(undefined, vpnConfigLimits);
83
+ }
84
+ const deleteAfter = Number.parseInt(jsonDeleteAfter);
85
+ if (Number.isNaN(deleteAfter)) {
86
+ throw new errors_1.InvalidVpnConfigError(`Config deleteAfter is invalid: ${jsonDeleteAfter}`);
87
+ }
88
+ return validateDeleteAfter(deleteAfter, vpnConfigLimits);
89
+ }
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ const uuid_1 = require("uuid");
3
4
  const uservpn_1 = require("../src/models/uservpn");
4
5
  const errors_1 = require("../src/errors");
5
6
  const vpn_1 = require("../src/models/vpn");
7
+ const vpnConfig_1 = require("../src/models/vpnConfig");
6
8
  describe('Testing VpnState', () => {
7
9
  it('should check that all VpnState are ordered properly', async () => {
8
10
  expect((0, vpn_1.toRank)(vpn_1.VpnState.Creating) <= (0, vpn_1.toRank)(vpn_1.VpnState.Created)).toBe(true);
@@ -19,69 +21,77 @@ describe('Testing VpnState', () => {
19
21
  });
20
22
  });
21
23
  describe('Testing Vpn constructors', () => {
22
- it('Should shout when regions is empty', async () => {
23
- expect(() => (0, vpn_1.newVpn)('', { maxPeanuts: -1, type: vpn_1.VpnType.WireGuard }, vpn_1.VpnState.Created))
24
- .toThrow(new errors_1.MyTmpVpnError("Incorrect region: \'\'"));
24
+ it('Should shout when geonamesId is zero', async () => {
25
+ expect(() => (0, vpn_1.newVpn)(0, { maxPeanuts: -1, type: vpn_1.VpnType.WireGuard }, vpn_1.VpnState.Created))
26
+ .toThrow(new errors_1.MyTmpVpnError("Incorrect geonamesId: \'0\'"));
25
27
  });
26
- it('Should shout when regions is bad format', async () => {
27
- expect(() => (0, vpn_1.newVpn)('foo', { maxPeanuts: -1, type: vpn_1.VpnType.WireGuard }, vpn_1.VpnState.Created))
28
- .toThrow(new errors_1.MyTmpVpnError("Incorrect region: \'foo\'"));
28
+ it('Should shout when geonamesId is negative', async () => {
29
+ expect(() => (0, vpn_1.newVpn)(-1, { maxPeanuts: -1, type: vpn_1.VpnType.WireGuard }, vpn_1.VpnState.Created))
30
+ .toThrow(new errors_1.MyTmpVpnError("Incorrect geonamesId: \'-1\'"));
29
31
  });
30
32
  it('Should create vpn with all mandatory fields set', async () => {
31
- const vpn = (0, vpn_1.newVpn)('az-test-7', { maxPeanuts: -1, type: vpn_1.VpnType.WireGuard }, vpn_1.VpnState.Created);
33
+ const vpn = (0, vpn_1.newVpn)(4140963, { maxPeanuts: -1, type: vpn_1.VpnType.WireGuard }, vpn_1.VpnState.Created);
32
34
  expect(vpn.createdAt).toBeDefined();
33
- expect(vpn.region).toEqual('az-test-7');
35
+ expect(vpn.geonamesId).toEqual(4140963);
34
36
  expect(vpn.state).toEqual(vpn_1.VpnState.Created);
35
37
  expect(vpn.config).toEqual({ maxPeanuts: -1, type: vpn_1.VpnType.WireGuard });
36
38
  expect(vpn.vpnId).toBeDefined();
39
+ expect((0, vpn_1.validateVpnId)(vpn.vpnId)).toEqual(uservpn_1.UserVpnVersion.LOCATIONS);
37
40
  });
38
41
  it('Should create vpn with optional fields set', async () => {
39
- const vpn = (0, vpn_1.newVpn)('az-test-7', {
42
+ const vpn = (0, vpn_1.newVpn)(4140963, {
40
43
  maxPeanuts: -1,
41
44
  type: vpn_1.VpnType.WireGuard,
42
45
  deleteAfter: 37,
43
46
  }, vpn_1.VpnState.Created);
44
47
  expect(vpn.createdAt).toBeDefined();
45
- expect(vpn.region).toEqual('az-test-7');
48
+ expect(vpn.geonamesId).toEqual(4140963);
46
49
  expect(vpn.state).toEqual(vpn_1.VpnState.Created);
47
50
  expect(vpn.config).toEqual({ maxPeanuts: -1, type: vpn_1.VpnType.WireGuard, deleteAfter: 37 });
48
51
  expect(vpn.vpnId).toBeDefined();
49
52
  });
50
53
  it('Should create vpn with deleteAfter set to NaN', async () => {
51
54
  const deleteAfter = Number.NaN;
52
- const vpn = (0, vpn_1.newVpn)('az-test-7', {
55
+ const vpn = (0, vpn_1.newVpn)(4140963, {
53
56
  maxPeanuts: -1,
54
57
  type: vpn_1.VpnType.WireGuard,
55
58
  deleteAfter: deleteAfter
56
59
  }, vpn_1.VpnState.Created);
57
60
  expect(vpn.createdAt).toBeDefined();
58
- expect(vpn.region).toEqual('az-test-7');
61
+ expect(vpn.geonamesId).toEqual(4140963);
59
62
  expect(vpn.state).toEqual(vpn_1.VpnState.Created);
60
63
  expect(vpn.config).toEqual({ maxPeanuts: -1, type: vpn_1.VpnType.WireGuard, deleteAfter: deleteAfter });
61
64
  expect(vpn.vpnId).toBeDefined();
62
65
  });
63
- it('Should deserialize a vpn with all mandatory fields set', async () => {
64
- const vpn = (0, vpn_1.getVpnFrom)('20030902012345678@az-test-7', vpn_1.VpnState.Created, { maxPeanuts: -1, type: vpn_1.VpnType.WireGuard, deleteAfter: 37 });
65
- expect(vpn.createdAt).toEqual(new Date('2003-09-02T01:23:45.678Z'));
66
- expect(vpn.region).toEqual('az-test-7');
66
+ it('Should deserialize a vpn with new format (geonamesId)', async () => {
67
+ const vpnId = (0, uuid_1.v4)();
68
+ const createdAt = new Date();
69
+ const vpn = (0, vpn_1.getVpnFrom)(vpnId, createdAt, 4140963, vpn_1.VpnState.Created, { maxPeanuts: -1, type: vpn_1.VpnType.WireGuard, deleteAfter: 37 });
70
+ expect(vpn.createdAt).toEqual(createdAt);
71
+ expect(vpn.geonamesId).toEqual(4140963);
67
72
  expect(vpn.state).toEqual(vpn_1.VpnState.Created);
68
73
  expect(vpn.config).toEqual({ maxPeanuts: -1, type: vpn_1.VpnType.WireGuard, deleteAfter: 37 });
69
- expect(vpn.vpnId).toBeDefined();
74
+ expect((0, vpn_1.validateVpnId)(vpn.vpnId)).toEqual(uservpn_1.UserVpnVersion.LOCATIONS);
75
+ expect(vpn.vpnId).toEqual(vpnId);
70
76
  });
71
77
  it('Should deserialize a vpn with deleteAfter set to NaN', async () => {
72
78
  const deleteAfter = Number.NaN;
73
- const vpn = (0, vpn_1.getVpnFrom)('20030902012345678@az-test-7', vpn_1.VpnState.Created, { maxPeanuts: -1, type: vpn_1.VpnType.WireGuard, deleteAfter: deleteAfter });
74
- expect(vpn.createdAt).toEqual(new Date('2003-09-02T01:23:45.678Z'));
75
- expect(vpn.region).toEqual('az-test-7');
79
+ const vpnId = (0, uuid_1.v4)();
80
+ const createdAt = new Date();
81
+ const vpn = (0, vpn_1.getVpnFrom)(vpnId, createdAt, 4140963, vpn_1.VpnState.Created, { maxPeanuts: -1, type: vpn_1.VpnType.WireGuard, deleteAfter: deleteAfter });
82
+ expect(vpn.createdAt).toEqual(createdAt);
83
+ expect(vpn.geonamesId).toEqual(4140963);
76
84
  expect(vpn.state).toEqual(vpn_1.VpnState.Created);
77
85
  expect(vpn.config).toEqual({ maxPeanuts: -1, type: vpn_1.VpnType.WireGuard, deleteAfter: deleteAfter });
78
86
  expect(vpn.vpnId).toBeDefined();
87
+ expect((0, vpn_1.validateVpnId)(vpn.vpnId)).toEqual(uservpn_1.UserVpnVersion.LOCATIONS);
88
+ expect(vpn.vpnId).toEqual(vpnId);
79
89
  });
80
90
  it('Should deserialize a json vpn with all fields set', async () => {
81
91
  const originalVpn = (0, uservpn_1.newUserVpn)({
82
92
  userId: 'myId',
83
- region: 'az-test-7',
84
- version: 1,
93
+ geonamesId: 4140963,
94
+ version: uservpn_1.UserVpnVersion.LOCATIONS,
85
95
  config: {
86
96
  maxPeanuts: -1,
87
97
  type: vpn_1.VpnType.WireGuard,
@@ -94,35 +104,33 @@ describe('Testing Vpn constructors', () => {
94
104
  expect(userVpn).toEqual(originalVpn);
95
105
  });
96
106
  it('Should shout when vpnId is empty', async () => {
97
- expect(() => (0, vpn_1.getVpnFrom)('', vpn_1.VpnState.Created, { maxPeanuts: -1, type: vpn_1.VpnType.WireGuard }))
98
- .toThrow(new errors_1.MyTmpVpnError("Incorrect vpnId: \'\'"));
107
+ expect(() => (0, vpn_1.getVpnFrom)('', new Date(), 4140963, vpn_1.VpnState.Created, { maxPeanuts: -1, type: vpn_1.VpnType.WireGuard }))
108
+ .toThrow(new errors_1.MyTmpVpnError("Invalid vpnId format: \'\'"));
99
109
  });
100
110
  it('Should shout when vpnId has bad format', async () => {
101
- expect(() => (0, vpn_1.getVpnFrom)('foo', vpn_1.VpnState.Created, { maxPeanuts: -1, type: vpn_1.VpnType.WireGuard }))
102
- .toThrow(new errors_1.MyTmpVpnError("Incorrect vpnId: \'foo\'"));
111
+ expect(() => (0, vpn_1.getVpnFrom)('foo', new Date(), 4140963, vpn_1.VpnState.Created, { maxPeanuts: -1, type: vpn_1.VpnType.WireGuard }))
112
+ .toThrow(new errors_1.MyTmpVpnError("Invalid vpnId format: \'foo\'"));
103
113
  });
104
- it('Should shout when vpnId does not hold a region in good format', async () => {
105
- expect(() => (0, vpn_1.getVpnFrom)('20030902012345678@test', vpn_1.VpnState.Created, { maxPeanuts: -1, type: vpn_1.VpnType.WireGuard }))
106
- .toThrow(new errors_1.MyTmpVpnError("Incorrect vpnId: \'20030902012345678@test\'"));
114
+ it('Should accept legacy vpnId format with AWS region', async () => {
115
+ const vpn = (0, vpn_1.getVpnFrom)('20030902012345678@us-east-1', undefined, 4140963, vpn_1.VpnState.Created, { maxPeanuts: -1, type: vpn_1.VpnType.WireGuard });
116
+ expect(vpn.vpnId).toEqual('20030902012345678@us-east-1');
117
+ expect(vpn.geonamesId).toEqual(4140963);
107
118
  });
108
119
  });
109
120
  describe('Testing vpnId to Wireguard file name functions ', () => {
110
- it('Should shout when vpnId is empty', async () => {
111
- expect(() => (0, vpn_1.vpnIdToWgFileName)(''))
112
- .toThrow(new errors_1.MyTmpVpnError("Incorrect vpnId: \'\'"));
113
- });
114
- it('Should shout when vpnId is bad format', async () => {
115
- expect(() => (0, vpn_1.vpnIdToWgFileName)('foo'))
116
- .toThrow(new errors_1.MyTmpVpnError("Incorrect vpnId: \'foo\'"));
117
- });
118
- it('Should shout when region has bad format', async () => {
119
- expect(() => (0, vpn_1.vpnIdToWgFileName)('20030902012345678@test'))
120
- .toThrow(new errors_1.MyTmpVpnError("Incorrect vpnId: \'20030902012345678@test\'"));
121
+ it('Should handle new format with GeoNames ID', async () => {
122
+ const vpn = (0, vpn_1.newVpn)(4140963, {
123
+ maxPeanuts: -1,
124
+ type: vpn_1.VpnType.WireGuard,
125
+ }, vpn_1.VpnState.Created);
126
+ const fileName = (0, vpn_1.vpnIdToWgFileName)(vpn);
127
+ expect(fileName).toBeDefined();
128
+ expect(fileName.length).toBeLessThanOrEqual(15);
121
129
  });
122
130
  });
123
131
  describe('Testing vpn config', () => {
124
132
  it('Should keep maxPeanuts to -1 when specified', async () => {
125
- const validatedConfig = (0, vpn_1.checkValidConfig)('userId', 2, {
133
+ const validatedConfig = (0, vpnConfig_1.checkValidConfig)('userId', 2, {
126
134
  maxPeanutsFieldMinValue: 0,
127
135
  maxPeanutsFieldMaxValue: 1,
128
136
  deleteAfterFieldMinValue: 1,
@@ -139,7 +147,7 @@ describe('Testing vpn config', () => {
139
147
  });
140
148
  });
141
149
  it('Should set maxPeanuts to -1 when null', async () => {
142
- const validatedConfig = (0, vpn_1.checkValidConfig)('userId', 2, {
150
+ const validatedConfig = (0, vpnConfig_1.checkValidConfig)('userId', 2, {
143
151
  maxPeanutsFieldMinValue: 0,
144
152
  maxPeanutsFieldMaxValue: 1,
145
153
  deleteAfterFieldMinValue: 1,
@@ -156,7 +164,7 @@ describe('Testing vpn config', () => {
156
164
  });
157
165
  });
158
166
  it('Should set maxPeanuts to -1 when undefined', async () => {
159
- const validatedConfig = (0, vpn_1.checkValidConfig)('userId', 2, {
167
+ const validatedConfig = (0, vpnConfig_1.checkValidConfig)('userId', 2, {
160
168
  maxPeanutsFieldMinValue: 0,
161
169
  maxPeanutsFieldMaxValue: 1,
162
170
  deleteAfterFieldMinValue: 1,
@@ -173,7 +181,7 @@ describe('Testing vpn config', () => {
173
181
  });
174
182
  });
175
183
  it('Should shout when currentBalance is negative', async () => {
176
- expect(() => (0, vpn_1.checkValidConfig)('userId', -1, {
184
+ expect(() => (0, vpnConfig_1.checkValidConfig)('userId', -1, {
177
185
  maxPeanutsFieldMinValue: 2,
178
186
  maxPeanutsFieldMaxValue: 3,
179
187
  deleteAfterFieldMinValue: 1,
@@ -185,7 +193,7 @@ describe('Testing vpn config', () => {
185
193
  })).toThrow(new errors_1.NegativeBalanceError(-1));
186
194
  });
187
195
  it('Should shout when currentBalance is zero', async () => {
188
- expect(() => (0, vpn_1.checkValidConfig)('userId', 0, {
196
+ expect(() => (0, vpnConfig_1.checkValidConfig)('userId', 0, {
189
197
  maxPeanutsFieldMinValue: 2,
190
198
  maxPeanutsFieldMaxValue: 3,
191
199
  deleteAfterFieldMinValue: 1,
@@ -197,7 +205,7 @@ describe('Testing vpn config', () => {
197
205
  })).toThrow(new errors_1.NegativeBalanceError(0));
198
206
  });
199
207
  it('Should shout when maxPeanuts is Infinity', async () => {
200
- expect(() => (0, vpn_1.checkValidConfig)('userId', 2, {
208
+ expect(() => (0, vpnConfig_1.checkValidConfig)('userId', 2, {
201
209
  maxPeanutsFieldMinValue: 2,
202
210
  maxPeanutsFieldMaxValue: 3,
203
211
  deleteAfterFieldMinValue: 1,
@@ -209,7 +217,7 @@ describe('Testing vpn config', () => {
209
217
  })).toThrow(new errors_1.InvalidVpnConfigError('Config maxPeanuts is invalid: Infinity'));
210
218
  });
211
219
  it('Should shout when maxPeanuts is -Infinity', async () => {
212
- expect(() => (0, vpn_1.checkValidConfig)('userId', 2, {
220
+ expect(() => (0, vpnConfig_1.checkValidConfig)('userId', 2, {
213
221
  maxPeanutsFieldMinValue: 2,
214
222
  maxPeanutsFieldMaxValue: 3,
215
223
  deleteAfterFieldMinValue: 1,
@@ -221,7 +229,7 @@ describe('Testing vpn config', () => {
221
229
  })).toThrow(new errors_1.InvalidVpnConfigError('Config maxPeanuts is invalid: -Infinity'));
222
230
  });
223
231
  it('Should shout when maxPeanuts is not a number', async () => {
224
- expect(() => (0, vpn_1.checkValidConfig)('userId', 2, {
232
+ expect(() => (0, vpnConfig_1.checkValidConfig)('userId', 2, {
225
233
  maxPeanutsFieldMinValue: 2,
226
234
  maxPeanutsFieldMaxValue: 3,
227
235
  deleteAfterFieldMinValue: 1,
@@ -233,7 +241,7 @@ describe('Testing vpn config', () => {
233
241
  })).toThrow(new errors_1.InvalidVpnConfigError('Config maxPeanuts is invalid: Not a number'));
234
242
  });
235
243
  it('Should shout when maxPeanuts is below the validPeanutsConfig minimum', async () => {
236
- expect(() => (0, vpn_1.checkValidConfig)('userId', 2, {
244
+ expect(() => (0, vpnConfig_1.checkValidConfig)('userId', 2, {
237
245
  maxPeanutsFieldMinValue: 2,
238
246
  maxPeanutsFieldMaxValue: 3,
239
247
  deleteAfterFieldMinValue: 1,
@@ -245,7 +253,7 @@ describe('Testing vpn config', () => {
245
253
  })).toThrow(new errors_1.MinPeanutsError(2, 1, 2));
246
254
  });
247
255
  it('Should shout when maxPeanuts is above the validPeanutsConfig maximum', async () => {
248
- expect(() => (0, vpn_1.checkValidConfig)('userId', 10, {
256
+ expect(() => (0, vpnConfig_1.checkValidConfig)('userId', 10, {
249
257
  maxPeanutsFieldMinValue: 2,
250
258
  maxPeanutsFieldMaxValue: 3,
251
259
  deleteAfterFieldMinValue: 1,
@@ -257,7 +265,7 @@ describe('Testing vpn config', () => {
257
265
  })).toThrow(new errors_1.MaxPeanutsError(3, 5, 10));
258
266
  });
259
267
  it('Should shout when deleteAfter is below the validPeanutsConfig minimum', async () => {
260
- expect(() => (0, vpn_1.checkValidConfig)('userId', 2, {
268
+ expect(() => (0, vpnConfig_1.checkValidConfig)('userId', 2, {
261
269
  maxPeanutsFieldMinValue: 1,
262
270
  maxPeanutsFieldMaxValue: 3,
263
271
  deleteAfterFieldMinValue: 3,
@@ -269,7 +277,7 @@ describe('Testing vpn config', () => {
269
277
  })).toThrow(new errors_1.MinDeleteAfterError(3, 1));
270
278
  });
271
279
  it('Should shout when deleteAfter is greater the validPeanutsConfig maximum', async () => {
272
- expect(() => (0, vpn_1.checkValidConfig)('userId', 2, {
280
+ expect(() => (0, vpnConfig_1.checkValidConfig)('userId', 2, {
273
281
  maxPeanutsFieldMinValue: 1,
274
282
  maxPeanutsFieldMaxValue: 3,
275
283
  deleteAfterFieldMinValue: 3,
@@ -281,7 +289,7 @@ describe('Testing vpn config', () => {
281
289
  })).toThrow(new errors_1.MaxDeleteAfterError(5, 7));
282
290
  });
283
291
  it('Should shout when deleteAfter is positive infinity', async () => {
284
- expect(() => (0, vpn_1.checkValidConfig)('userId', 2, {
292
+ expect(() => (0, vpnConfig_1.checkValidConfig)('userId', 2, {
285
293
  maxPeanutsFieldMinValue: 1,
286
294
  maxPeanutsFieldMaxValue: 3,
287
295
  deleteAfterFieldMinValue: 3,
@@ -293,7 +301,7 @@ describe('Testing vpn config', () => {
293
301
  })).toThrow(new errors_1.InvalidVpnConfigError('Config deleteAfter is invalid: Infinity'));
294
302
  });
295
303
  it('Should shout when deleteAfter is negative infinity', async () => {
296
- expect(() => (0, vpn_1.checkValidConfig)('userId', 2, {
304
+ expect(() => (0, vpnConfig_1.checkValidConfig)('userId', 2, {
297
305
  maxPeanutsFieldMinValue: 1,
298
306
  maxPeanutsFieldMaxValue: 3,
299
307
  deleteAfterFieldMinValue: 3,
@@ -305,7 +313,7 @@ describe('Testing vpn config', () => {
305
313
  })).toThrow(new errors_1.InvalidVpnConfigError('Config deleteAfter is invalid: -Infinity'));
306
314
  });
307
315
  it('Should shout when deleteAfter is not a number', async () => {
308
- expect(() => (0, vpn_1.checkValidConfig)('userId', 2, {
316
+ expect(() => (0, vpnConfig_1.checkValidConfig)('userId', 2, {
309
317
  maxPeanutsFieldMinValue: 1,
310
318
  maxPeanutsFieldMaxValue: 3,
311
319
  deleteAfterFieldMinValue: 3,
@@ -317,7 +325,7 @@ describe('Testing vpn config', () => {
317
325
  })).toThrow(new errors_1.InvalidVpnConfigError('Config deleteAfter is invalid: Not a number'));
318
326
  });
319
327
  it('Should not shout when deleteAfter is undefined', async () => {
320
- expect((0, vpn_1.checkValidConfig)('userId', 2, {
328
+ expect((0, vpnConfig_1.checkValidConfig)('userId', 2, {
321
329
  maxPeanutsFieldMinValue: 1,
322
330
  maxPeanutsFieldMaxValue: 3,
323
331
  deleteAfterFieldMinValue: 3,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mytmpvpn/mytmpvpn-common",
3
- "version": "9.0.0",
3
+ "version": "10.0.2",
4
4
  "description": "Common library for all MyTmpVpn related projects",
5
5
  "types": "dist/src/index.d.ts",
6
6
  "files": [
@@ -44,6 +44,7 @@
44
44
  "typescript": "^4.9.5"
45
45
  },
46
46
  "dependencies": {
47
- "loglevel": "^1.9.2"
47
+ "loglevel": "^1.9.2",
48
+ "uuid": "^11.1.0"
48
49
  }
49
50
  }
@@ -1 +0,0 @@
1
- {"root":["../.eslintrc.js","../jest.config.js","../src/errors.ts","../src/index.ts","../src/utils.ts","../src/models/index.ts","../src/models/peanuts.ts","../src/models/referral.ts","../src/models/uservpn.ts","../src/models/vpn.ts","../test/models.test.ts"],"version":"5.9.3"}