perimeterx-js-core 0.7.0 → 0.8.0

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.
Files changed (216) hide show
  1. package/lib/action/utils.js +1 -1
  2. package/lib/activities/HttpActivityClient.d.ts +5 -5
  3. package/lib/activities/HttpActivityClient.js +28 -39
  4. package/lib/activities/HttpBatchedActivityClient.d.ts +2 -2
  5. package/lib/activities/HttpBatchedActivityClient.js +19 -32
  6. package/lib/activities/model/AsyncActivity.d.ts +14 -0
  7. package/lib/activities/model/{ActivityDetails.d.ts → AsyncActivityDetails.d.ts} +6 -23
  8. package/lib/activities/model/CommonActivityDetails.d.ts +40 -0
  9. package/lib/activities/model/CommonActivityDetails.js +1 -0
  10. package/lib/activities/model/HeaderEntry.d.ts +4 -0
  11. package/lib/activities/model/HeaderEntry.js +1 -0
  12. package/lib/activities/model/index.d.ts +4 -2
  13. package/lib/activities/model/index.js +4 -2
  14. package/lib/activities/utils.d.ts +6071 -9
  15. package/lib/activities/utils.js +111 -35
  16. package/lib/additional_activity_handler/AdditionalActivityHandler.d.ts +1 -1
  17. package/lib/additional_activity_handler/AdditionalActivityHandlerUtils.js +4 -12
  18. package/lib/config/ConfigurationParams.d.ts +2 -1
  19. package/lib/config/DefaultConfigurations.js +1 -0
  20. package/lib/config/IConfiguration.d.ts +5 -1
  21. package/lib/config/StaticConfigurationBase.d.ts +2 -1
  22. package/lib/config/StaticConfigurationBase.js +6 -1
  23. package/lib/context/DefaultContext.d.ts +1 -1
  24. package/lib/context/DefaultContext.js +40 -8
  25. package/lib/context/interfaces/RiskApiData.d.ts +4 -0
  26. package/lib/cors/DefaultCors.js +21 -31
  27. package/lib/custom_parameters/CustomParametersUtils.js +3 -12
  28. package/lib/enforcer/EnforcerBase.d.ts +2 -1
  29. package/lib/enforcer/EnforcerBase.js +56 -57
  30. package/lib/enforcer/options/EnforcerBaseOptions.d.ts +2 -0
  31. package/lib/graphql/DefaultGraphQLParser.js +30 -39
  32. package/lib/http/index.d.ts +0 -1
  33. package/lib/http/index.js +0 -1
  34. package/lib/http/interfaces/IBody.d.ts +3 -2
  35. package/lib/http/interfaces/IIncomingRequest.d.ts +4 -0
  36. package/lib/http/interfaces/IURL.d.ts +3 -0
  37. package/lib/http/interfaces/IURLSearchParams.d.ts +9 -0
  38. package/lib/http/interfaces/IURLSearchParams.js +1 -0
  39. package/lib/http/interfaces/index.d.ts +1 -0
  40. package/lib/http/interfaces/index.js +1 -0
  41. package/lib/http/{impl → utils}/FormDataImpl.js +4 -4
  42. package/lib/http/{impl → utils}/MinimalResponseImpl.js +3 -0
  43. package/lib/http/utils/MinimalResponseUtils.js +5 -7
  44. package/lib/http/utils/MultipartFormDataUtils.js +4 -5
  45. package/lib/http/{impl → utils}/OutgoingRequestImpl.d.ts +1 -1
  46. package/lib/http/{impl → utils}/OutgoingRequestImpl.js +5 -1
  47. package/lib/http/utils/URLUtils.d.ts +7 -0
  48. package/lib/http/utils/URLUtils.js +62 -0
  49. package/lib/http/utils/UrlImpl.d.ts +18 -0
  50. package/lib/http/utils/UrlImpl.js +54 -0
  51. package/lib/http/utils/UrlSearchParamsImpl.d.ts +19 -0
  52. package/lib/http/utils/UrlSearchParamsImpl.js +116 -0
  53. package/lib/http/utils/index.d.ts +6 -0
  54. package/lib/http/utils/index.js +6 -0
  55. package/lib/{utils → impl}/base64/AtobBase64Utils.d.ts +1 -1
  56. package/lib/{utils → impl}/base64/BufferBase64Utils.d.ts +1 -1
  57. package/lib/{utils → impl}/base64/BufferBase64Utils.js +1 -1
  58. package/lib/{utils → impl}/base64/JSBase64Base64Utils.d.ts +1 -1
  59. package/lib/{utils → impl}/cipher/CryptoCipherUtils.d.ts +1 -1
  60. package/lib/impl/cipher/CryptoCipherUtils.js +18 -0
  61. package/lib/{utils → impl}/cipher/SubtleCryptoCipherUtils.d.ts +1 -2
  62. package/lib/impl/cipher/SubtleCryptoCipherUtils.js +38 -0
  63. package/lib/{utils → impl}/hash/CryptoHashUtils.d.ts +1 -2
  64. package/lib/impl/hash/CryptoHashUtils.js +10 -0
  65. package/lib/{utils → impl}/hash/CryptoJSHashUtils.d.ts +1 -2
  66. package/lib/{utils → impl}/hash/CryptoJSHashUtils.js +1 -1
  67. package/lib/{utils → impl}/hash/SubtleCryptoHashUtils.d.ts +1 -2
  68. package/lib/impl/hash/SubtleCryptoHashUtils.js +21 -0
  69. package/lib/{utils → impl}/hmac/CryptoHmacUtils.d.ts +1 -2
  70. package/lib/{utils → impl}/hmac/CryptoHmacUtils.js +2 -1
  71. package/lib/{utils → impl}/hmac/CryptoJSHmacUtils.d.ts +1 -2
  72. package/lib/{utils → impl}/hmac/CryptoJSHmacUtils.js +1 -1
  73. package/lib/{http/impl → impl/http}/phin/PhinHttpClient.d.ts +1 -1
  74. package/lib/impl/http/phin/PhinHttpClient.js +31 -0
  75. package/lib/{http/impl → impl/http}/phin/PhinIncomingResponse.d.ts +2 -2
  76. package/lib/impl/http/phin/PhinIncomingResponse.js +23 -0
  77. package/lib/{utils → impl}/ip_range_checker/DefaultIpRangeChecker.d.ts +1 -1
  78. package/lib/{utils → impl}/request_id_generator/UuidRequestIdGenerator.d.ts +1 -1
  79. package/lib/{utils → impl}/url_parser/DefaultUrlParser.d.ts +4 -4
  80. package/lib/{utils → impl}/url_parser/DefaultUrlParser.js +9 -2
  81. package/lib/logger/HttpLogServiceClient.d.ts +17 -0
  82. package/lib/logger/HttpLogServiceClient.js +52 -0
  83. package/lib/logger/ILogServiceClient.d.ts +6 -0
  84. package/lib/logger/ILogServiceClient.js +1 -0
  85. package/lib/logger/ILogger.d.ts +6 -0
  86. package/lib/logger/LoggerBase.d.ts +6 -2
  87. package/lib/logger/LoggerBase.js +14 -1
  88. package/lib/logger/constants.d.ts +2 -0
  89. package/lib/logger/constants.js +2 -0
  90. package/lib/logger/index.d.ts +4 -0
  91. package/lib/logger/index.js +3 -0
  92. package/lib/logger/model/EnrichedLogRecord.d.ts +3 -0
  93. package/lib/logger/model/EnrichedLogRecord.js +1 -0
  94. package/lib/logger/model/LogMetadata.d.ts +9 -0
  95. package/lib/logger/model/LogMetadata.js +1 -0
  96. package/lib/logger/model/LogRecord.d.ts +6 -0
  97. package/lib/logger/model/LogRecord.js +1 -0
  98. package/lib/logger/model/index.d.ts +3 -0
  99. package/lib/logger/model/index.js +3 -0
  100. package/lib/phase/flow/EndEnforcerFlow.d.ts +6 -0
  101. package/lib/phase/flow/EndEnforcerFlow.js +10 -0
  102. package/lib/phase/flow/index.d.ts +1 -0
  103. package/lib/phase/flow/index.js +1 -0
  104. package/lib/phase/impl/AdditionalActivityHandlerPhase.js +4 -15
  105. package/lib/phase/impl/CompositePhase.js +9 -19
  106. package/lib/phase/impl/CreateBlockResponsePhase.js +24 -35
  107. package/lib/phase/impl/DecideActionPhase.js +11 -21
  108. package/lib/phase/impl/EnrichContextFromRequestPhase.js +28 -45
  109. package/lib/phase/impl/EnrichContextFromResponsePhase.js +12 -23
  110. package/lib/phase/impl/FilterPhase.js +3 -13
  111. package/lib/phase/impl/FirstPartyPhase.js +21 -32
  112. package/lib/phase/impl/ModifyIncomingRequestPhase.js +4 -14
  113. package/lib/phase/impl/ModifyOutgoingResponsePhase.js +7 -18
  114. package/lib/phase/impl/ParseTokenPhase.js +5 -15
  115. package/lib/phase/impl/PreflightPhase.js +12 -20
  116. package/lib/phase/impl/RiskApiPhase.js +24 -36
  117. package/lib/phase/impl/SendAsyncActivitiesOnRequestPhase.js +8 -20
  118. package/lib/phase/impl/SendAsyncActivitiesOnResponsePhase.js +4 -14
  119. package/lib/phase/impl/SendLogsPhase.d.ts +11 -0
  120. package/lib/phase/impl/SendLogsPhase.js +16 -0
  121. package/lib/phase/impl/TelemetryPhase.js +9 -21
  122. package/lib/phase/impl/index.d.ts +1 -0
  123. package/lib/phase/impl/index.js +1 -0
  124. package/lib/products/account_defender/AccountDefender.js +16 -35
  125. package/lib/products/bot_defender/BotDefender.js +51 -72
  126. package/lib/products/bot_defender/BotDefenderActionData.js +2 -0
  127. package/lib/products/bot_defender/block/DefaultBotDefenderBlocker.d.ts +4 -4
  128. package/lib/products/bot_defender/block/DefaultBotDefenderBlocker.js +5 -3
  129. package/lib/products/bot_defender/block/captcha/CaptchaBlocker.d.ts +7 -4
  130. package/lib/products/bot_defender/block/captcha/CaptchaBlocker.js +12 -8
  131. package/lib/products/bot_defender/block/captcha/HtmlCaptchaBlocker.d.ts +1 -1
  132. package/lib/products/bot_defender/block/captcha/HtmlCaptchaBlocker.js +1 -0
  133. package/lib/products/bot_defender/block/captcha/JsonCaptchaBlocker.d.ts +1 -1
  134. package/lib/products/bot_defender/block/captcha/JsonCaptchaBlocker.js +5 -4
  135. package/lib/products/bot_defender/block/captcha/MobileCaptchaBlocker.d.ts +2 -2
  136. package/lib/products/bot_defender/block/captcha/MobileCaptchaBlocker.js +2 -0
  137. package/lib/products/bot_defender/block/utils.js +1 -2
  138. package/lib/products/bot_defender/filter/DefaultBotDefenderFilter.js +7 -1
  139. package/lib/products/bot_defender/first_party/DefaultBotDefenderFirstParty.js +51 -68
  140. package/lib/products/bot_defender/first_party/constants.d.ts +0 -4
  141. package/lib/products/bot_defender/first_party/constants.js +0 -7
  142. package/lib/products/credential_intelligence/CredentialIntelligence.js +42 -63
  143. package/lib/products/credential_intelligence/endpoint/CredentialEndpoint.js +15 -23
  144. package/lib/products/credential_intelligence/endpoint/CredentialEndpointManager.js +9 -22
  145. package/lib/products/credential_intelligence/endpoint/extractor/BodyCredentialExtractor.d.ts +5 -5
  146. package/lib/products/credential_intelligence/endpoint/extractor/BodyCredentialExtractor.js +22 -33
  147. package/lib/products/credential_intelligence/endpoint/extractor/CustomCredentialExtractor.js +8 -18
  148. package/lib/products/credential_intelligence/endpoint/extractor/HeaderCredentialExtractor.js +2 -0
  149. package/lib/products/credential_intelligence/endpoint/extractor/QueryParamCredentialExtractor.d.ts +1 -1
  150. package/lib/products/credential_intelligence/endpoint/extractor/QueryParamCredentialExtractor.js +11 -16
  151. package/lib/products/credential_intelligence/endpoint/hash_protocol/MultistepHashProtocol.js +11 -21
  152. package/lib/products/credential_intelligence/endpoint/hash_protocol/SingleStepAndMultistepHashProtocol.js +9 -18
  153. package/lib/products/credential_intelligence/endpoint/hash_protocol/SingleStepHashProtocol.js +13 -25
  154. package/lib/products/credential_intelligence/endpoint/login_successful/BodyLoginSuccessfulParser.js +4 -14
  155. package/lib/products/credential_intelligence/endpoint/login_successful/CustomLoginSuccessfulParser.js +10 -20
  156. package/lib/products/credential_intelligence/endpoint/login_successful/HeaderLoginSuccessfulParser.js +7 -16
  157. package/lib/products/credential_intelligence/endpoint/login_successful/LoginSuccessfulParserFactory.js +7 -6
  158. package/lib/products/credential_intelligence/endpoint/login_successful/StatusLoginSuccessfulParser.js +3 -13
  159. package/lib/products/credential_intelligence/endpoint/matcher/ExactPathEndpointMatcher.js +2 -0
  160. package/lib/products/credential_intelligence/endpoint/matcher/RegexPathEndpointMatcher.js +2 -0
  161. package/lib/pxde/DefaultDataEnrichment.js +47 -61
  162. package/lib/pxhd/PXHDUtils.js +2 -2
  163. package/lib/risk_api/client/PostRiskApiClientBase.d.ts +7 -12
  164. package/lib/risk_api/client/PostRiskApiClientBase.js +70 -171
  165. package/lib/risk_api/model/RiskActivity.d.ts +5 -45
  166. package/lib/risk_api/risk_response/IRiskResponse.d.ts +1 -0
  167. package/lib/risk_api/risk_response/RiskResponseBase.d.ts +1 -0
  168. package/lib/risk_api/risk_response/RiskResponseBase.js +20 -33
  169. package/lib/risk_api/risk_response/v2/DefaultRiskResponseV2.d.ts +1 -1
  170. package/lib/risk_api/risk_response/v2/DefaultRiskResponseV2.js +3 -5
  171. package/lib/risk_api/risk_response/v2/RiskResponseV2Payload.d.ts +1 -0
  172. package/lib/risk_api/risk_response/v3/DefaultRiskResponseV3.js +2 -4
  173. package/lib/risk_api/risk_response/v3/RiskResponseV3Payload.d.ts +1 -0
  174. package/lib/risk_token/parser/TokenParserBase.js +25 -36
  175. package/lib/risk_token/token/TokenBase.js +24 -29
  176. package/lib/risk_token/token/v2/DefaultTokenV2.js +34 -49
  177. package/lib/risk_token/token/v3/DefaultTokenV3.js +63 -77
  178. package/lib/telemetry/DefaultTelemetry.js +46 -58
  179. package/lib/utils/base64/index.d.ts +0 -3
  180. package/lib/utils/base64/index.js +0 -3
  181. package/lib/utils/cipher/index.d.ts +1 -3
  182. package/lib/utils/cipher/index.js +1 -2
  183. package/lib/utils/constants.d.ts +2 -1
  184. package/lib/utils/constants.js +2 -1
  185. package/lib/utils/hash/index.d.ts +0 -3
  186. package/lib/utils/hash/index.js +0 -3
  187. package/lib/utils/hmac/index.d.ts +0 -2
  188. package/lib/utils/hmac/index.js +0 -2
  189. package/lib/utils/ip_range_checker/index.d.ts +1 -2
  190. package/lib/utils/ip_range_checker/index.js +1 -1
  191. package/lib/utils/request_id_generator/index.d.ts +1 -2
  192. package/lib/utils/request_id_generator/index.js +1 -1
  193. package/lib/utils/url_parser/index.d.ts +0 -1
  194. package/lib/utils/url_parser/index.js +0 -1
  195. package/lib/utils/utils.d.ts +1 -7
  196. package/lib/utils/utils.js +3 -25
  197. package/package.json +12 -6
  198. package/lib/activities/model/Activity.d.ts +0 -13
  199. package/lib/http/impl/index.d.ts +0 -4
  200. package/lib/http/impl/index.js +0 -4
  201. package/lib/http/impl/phin/PhinHttpClient.js +0 -41
  202. package/lib/http/impl/phin/PhinIncomingResponse.js +0 -38
  203. package/lib/utils/cipher/CryptoCipherUtils.js +0 -28
  204. package/lib/utils/cipher/SubtleCryptoCipherUtils.js +0 -47
  205. package/lib/utils/hash/CryptoHashUtils.js +0 -20
  206. package/lib/utils/hash/SubtleCryptoHashUtils.js +0 -31
  207. /package/lib/activities/model/{Activity.js → AsyncActivity.js} +0 -0
  208. /package/lib/activities/model/{ActivityDetails.js → AsyncActivityDetails.js} +0 -0
  209. /package/lib/http/{impl → utils}/FormDataImpl.d.ts +0 -0
  210. /package/lib/http/{impl → utils}/MinimalResponseImpl.d.ts +0 -0
  211. /package/lib/{utils → impl}/base64/AtobBase64Utils.js +0 -0
  212. /package/lib/{utils → impl}/base64/JSBase64Base64Utils.js +0 -0
  213. /package/lib/{http/impl → impl/http}/phin/index.d.ts +0 -0
  214. /package/lib/{http/impl → impl/http}/phin/index.js +0 -0
  215. /package/lib/{utils → impl}/ip_range_checker/DefaultIpRangeChecker.js +0 -0
  216. /package/lib/{utils → impl}/request_id_generator/UuidRequestIdGenerator.js +0 -0
@@ -1,19 +1,11 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { ProductName } from '../../products';
11
1
  import { AUTHORIZATION_HEADER_NAME, CONTENT_TYPE_HEADER_NAME, ContentType, HttpMethod, OutgoingRequestImpl, } from '../../http';
12
- import { EnforcerErrorName, getAuthorizationHeader, ModuleMode, removeSensitiveHeaders, transferExistingProperties, } from '../../utils';
2
+ import { EnforcerErrorName, getAuthorizationHeader, removeSensitiveHeaders, } from '../../utils';
3
+ import { createCommonActivityDetails, toHeaderEntryArray } from '../../activities';
13
4
  import { RISK_API_ENDPOINT } from '../constants';
14
5
  import { RiskApiCallResult, RiskStatus, S2SErrorReason } from '../model';
15
- import { TokenParseResult } from '../../risk_token';
16
6
  export class PostRiskApiClientBase {
7
+ config;
8
+ httpClient;
17
9
  constructor(config, httpClient) {
18
10
  this.config = config;
19
11
  this.httpClient = httpClient;
@@ -23,32 +15,30 @@ export class PostRiskApiClientBase {
23
15
  * @param context
24
16
  * @returns Promise<RiskApiData>
25
17
  */
26
- executeRiskApi(context) {
27
- return __awaiter(this, void 0, void 0, function* () {
28
- let response, riskResponse;
29
- const riskApiData = { riskApiCallResult: RiskApiCallResult.NONE };
30
- try {
31
- const riskActivity = this.createRiskActivity(context);
32
- response = yield this.sendRiskActivity(riskActivity, riskApiData);
33
- if ((response === null || response === void 0 ? void 0 : response.status) !== 200) {
34
- return yield this.handleS2SError(riskApiData, response);
35
- }
36
- riskResponse = this.createRiskResponse(response);
37
- riskApiData.riskResponse = riskResponse;
38
- if (!(yield riskResponse.validate())) {
39
- return yield this.handleS2SError(riskApiData, response);
40
- }
41
- this.config.logger.debug(`received risk response, score: ${riskResponse.score}, rtt: ${riskApiData.riskRtt}`);
42
- return riskApiData;
18
+ async executeRiskApi(context) {
19
+ let response, riskResponse;
20
+ const riskApiData = { riskApiCallResult: RiskApiCallResult.NONE };
21
+ try {
22
+ const riskActivity = this.createRiskActivity(context);
23
+ response = await this.sendRiskActivity(riskActivity, riskApiData);
24
+ if (response?.status !== 200) {
25
+ return await this.handleS2SError(riskApiData, response);
43
26
  }
44
- catch (err) {
45
- if (err.name === EnforcerErrorName.ENFORCER_TIMEOUT_ERROR) {
46
- return this.handleS2STimeout(riskApiData);
47
- }
48
- this.config.logger.error(`caught error in risk api: ${err} - ${JSON.stringify(context.requestData.url)}`);
49
- return yield this.handleS2SError(riskApiData, response, err);
27
+ riskResponse = this.createRiskResponse(response);
28
+ riskApiData.riskResponse = riskResponse;
29
+ if (!(await riskResponse.validate())) {
30
+ return await this.handleS2SError(riskApiData, response);
50
31
  }
51
- });
32
+ this.config.logger.debug(`received risk response, score: ${riskResponse.score}, rtt: ${riskApiData.riskRtt}`);
33
+ return riskApiData;
34
+ }
35
+ catch (err) {
36
+ if (err.name === EnforcerErrorName.ENFORCER_TIMEOUT_ERROR) {
37
+ return this.handleS2STimeout(riskApiData);
38
+ }
39
+ this.config.logger.error(`caught error in risk api: ${err} - ${JSON.stringify(context.requestData.url)}`);
40
+ return await this.handleS2SError(riskApiData, response, err);
41
+ }
52
42
  }
53
43
  /**
54
44
  * Creates the RiskActivity payload
@@ -57,26 +47,20 @@ export class PostRiskApiClientBase {
57
47
  * @protected
58
48
  */
59
49
  createRiskActivity(context) {
60
- var _a, _b, _c;
61
50
  const riskActivity = {
51
+ vid: context.vid,
52
+ client_uuid: context.uuid,
53
+ pxhd: context.pxhd?.value,
62
54
  request: {
63
- ip: context.requestData.ip,
55
+ socket_ip: context.requestData.ip,
64
56
  headers: this.formatRiskHeadersField(context.requestData.headers),
65
57
  url: context.requestData.rawUrl,
66
58
  },
67
59
  additional: {
68
- s2s_call_reason: ((_a = context.reasons) === null || _a === void 0 ? void 0 : _a[ProductName.BOT_DEFENDER]) ||
69
- ((_b = context.reasons) === null || _b === void 0 ? void 0 : _b[ProductName.CREDENTIAL_INTELLIGENCE]),
70
- module_version: this.config.moduleVersion,
71
- http_method: context.requestData.method,
72
- http_version: context.requestData.httpVersion,
73
- risk_mode: ((_c = context.productData.bd) === null || _c === void 0 ? void 0 : _c.isMonitoredRequest) ? ModuleMode.MONITOR : ModuleMode.ACTIVE_BLOCKING,
74
- cookie_origin: context.tokenOrigin,
75
- request_cookie_names: context.requestData.requestCookieNames.concat(),
76
- request_id: context.requestId,
60
+ ...createCommonActivityDetails(this.config, context),
61
+ s2s_call_reason: context.riskApiData.s2sCallReason,
77
62
  },
78
63
  };
79
- this.addOptionalRiskFields(riskActivity, context);
80
64
  return this.finalizeRiskActivity(riskActivity);
81
65
  }
82
66
  /**
@@ -88,105 +72,23 @@ export class PostRiskApiClientBase {
88
72
  finalizeRiskActivity(riskActivity) {
89
73
  return riskActivity;
90
74
  }
91
- addOptionalRiskFields(riskActivity, context) {
92
- this.addOptionalRiskFieldsToRoot(riskActivity, context);
93
- this.addOptionalRiskFieldsToAdditional(riskActivity, context);
94
- this.addProductDataToAdditional(riskActivity, context.productData);
95
- this.addTokenDataToAdditional(riskActivity, context.tokenData);
96
- this.addCustomParamsToAdditional(riskActivity, context);
97
- }
98
- addOptionalRiskFieldsToRoot(riskActivity, context) {
99
- var _a;
100
- transferExistingProperties(context, riskActivity, {
101
- vid: 'vid',
102
- uuid: 'uuid',
103
- });
104
- if ((_a = context.pxhd) === null || _a === void 0 ? void 0 : _a.value) {
105
- riskActivity.pxhd = context.pxhd.value;
106
- }
107
- }
108
- addOptionalRiskFieldsToAdditional(riskActivity, context) {
109
- transferExistingProperties(context, riskActivity.additional, {
110
- vidSource: 'enforcer_vid_source',
111
- graphqlData: 'graphql_operations',
112
- });
113
- transferExistingProperties(context.serverData, riskActivity.additional, {
114
- region: 'server_info_region',
115
- datacenter: 'server_info_datacenter',
116
- });
117
- transferExistingProperties(context.tlsData, riskActivity.additional, {
118
- tlsProtocol: 'tls_protocol',
119
- tlsServer: 'tls_server',
120
- tlsCipher: 'tls_cipher',
121
- tlsCiphersSha: 'tls_ciphers_sha',
122
- tlsExtensionSha: 'tls_extension_sha',
123
- tlsPreferredCiphers: 'tls_preferred_ciphers',
124
- tlsJa3Fingerprint: 'tls_ja3_fingerprint',
125
- });
126
- }
127
- addProductDataToAdditional(riskActivity, productData) {
128
- transferExistingProperties(productData.ad, riskActivity.additional, {
129
- appUserId: 'app_user_id',
130
- additionalFields: 'jwt_additional_fields',
131
- crossTabSession: 'cross_tab_session',
132
- });
133
- transferExistingProperties(productData.ci, riskActivity.additional, {
134
- hashedUsername: 'user',
135
- hashedPassword: 'pass',
136
- ciVersion: 'ci_version',
137
- ssoStep: 'sso_step',
138
- });
139
- }
140
- addCustomParamsToAdditional(riskActivity, context) {
141
- if (context.customParameters) {
142
- Object.assign(riskActivity.additional, context.customParameters);
143
- }
144
- }
145
- addTokenDataToAdditional(riskActivity, { token, mobileData }) {
146
- if (token) {
147
- if (token.isValid()) {
148
- riskActivity.additional.px_cookie = token.getPayloadString();
149
- riskActivity.additional.px_cookie_hmac = token.hmac;
150
- }
151
- else {
152
- riskActivity.additional.px_orig_cookie = token.getTokenString();
153
- }
154
- }
155
- if (mobileData) {
156
- transferExistingProperties(mobileData, riskActivity.additional, {
157
- originalToken: 'original_token',
158
- decodedOriginalToken: 'px_decoded_original_token',
159
- });
160
- if (mobileData.originalTokenParseResult === TokenParseResult.DECRYPTION_FAILED) {
161
- riskActivity.additional.original_token_error = 'cookie_decryption_failed';
162
- }
163
- else if (mobileData.originalTokenParseResult === TokenParseResult.VALIDATION_FAILED) {
164
- riskActivity.additional.original_token_error = 'cookie_validation_failed';
165
- }
166
- }
167
- }
168
75
  formatRiskHeadersField(headers) {
169
76
  const headersWithoutSensitive = removeSensitiveHeaders(headers, this.config.sensitiveHeaders);
170
- return Object.entries(headersWithoutSensitive).flatMap(([key, values]) => values.map((value) => ({
171
- name: key,
172
- value: value,
173
- })));
174
- }
175
- sendRiskActivity(riskActivity, riskApiData) {
176
- return __awaiter(this, void 0, void 0, function* () {
177
- const url = this.getRiskUrl();
178
- const headers = this.getRiskHeaders();
179
- const body = JSON.stringify(riskActivity);
180
- const method = HttpMethod.POST;
181
- const riskRequest = new OutgoingRequestImpl({ url, method, headers, body });
182
- this.config.logger.debug(`sending risk api to ${url}`);
183
- const startTime = Date.now();
184
- const response = yield this.httpClient.send(riskRequest, { timeoutMs: this.config.s2sTimeout });
185
- const endTime = Date.now();
186
- riskApiData.riskApiCallResult = RiskApiCallResult.SUCCESSFUL;
187
- riskApiData.riskRtt = endTime - startTime;
188
- return response;
189
- });
77
+ return toHeaderEntryArray(headersWithoutSensitive);
78
+ }
79
+ async sendRiskActivity(riskActivity, riskApiData) {
80
+ const url = this.getRiskUrl();
81
+ const headers = this.getRiskHeaders();
82
+ const body = JSON.stringify(riskActivity);
83
+ const method = HttpMethod.POST;
84
+ const riskRequest = new OutgoingRequestImpl({ url, method, headers, body });
85
+ this.config.logger.debug(`sending risk api to ${url}`);
86
+ const startTime = Date.now();
87
+ const response = await this.httpClient.send(riskRequest, { timeoutMs: this.config.s2sTimeout });
88
+ const endTime = Date.now();
89
+ riskApiData.riskApiCallResult = RiskApiCallResult.SUCCESSFUL;
90
+ riskApiData.riskRtt = endTime - startTime;
91
+ return response;
190
92
  }
191
93
  getRiskUrl() {
192
94
  return `${this.config.backendScoreApiUrl}${RISK_API_ENDPOINT}`;
@@ -201,35 +103,32 @@ export class PostRiskApiClientBase {
201
103
  riskApiData.riskApiCallResult = RiskApiCallResult.TIMEOUT;
202
104
  return riskApiData;
203
105
  }
204
- handleS2SError(riskApiData, response, error) {
205
- var _a, _b, _c;
206
- return __awaiter(this, void 0, void 0, function* () {
207
- riskApiData.riskApiCallResult = RiskApiCallResult.ERROR;
208
- riskApiData.errorReason = S2SErrorReason.UNKNOWN_ERROR;
209
- if (response || riskApiData.riskResponse) {
210
- riskApiData.errorHttpStatus = response.status;
211
- riskApiData.errorMessage = ((_a = riskApiData.riskResponse) === null || _a === void 0 ? void 0 : _a.message) || `response body: ${yield response.text()}`;
212
- if (response.status === 200) {
213
- if (((_b = riskApiData.riskResponse) === null || _b === void 0 ? void 0 : _b.status) === RiskStatus.FAILURE) {
214
- riskApiData.errorReason = S2SErrorReason.REQUEST_FAILED_ON_SERVER;
215
- }
216
- else if (!(yield ((_c = riskApiData.riskResponse) === null || _c === void 0 ? void 0 : _c.validate()))) {
217
- riskApiData.errorReason = S2SErrorReason.INVALID_RESPONSE;
218
- }
219
- }
220
- else if (response.status >= 400 && response.status < 500) {
221
- riskApiData.errorReason = S2SErrorReason.BAD_REQUEST;
106
+ async handleS2SError(riskApiData, response, error) {
107
+ riskApiData.riskApiCallResult = RiskApiCallResult.ERROR;
108
+ riskApiData.errorReason = S2SErrorReason.UNKNOWN_ERROR;
109
+ if (response || riskApiData.riskResponse) {
110
+ riskApiData.errorHttpStatus = response.status;
111
+ riskApiData.errorMessage = riskApiData.riskResponse?.message || `response body: ${await response.text()}`;
112
+ if (response.status === 200) {
113
+ if (riskApiData.riskResponse?.status === RiskStatus.FAILURE) {
114
+ riskApiData.errorReason = S2SErrorReason.REQUEST_FAILED_ON_SERVER;
222
115
  }
223
- else if (response.status >= 500 && response.status < 600) {
224
- riskApiData.errorReason = S2SErrorReason.SERVER_ERROR;
116
+ else if (!(await riskApiData.riskResponse?.validate())) {
117
+ riskApiData.errorReason = S2SErrorReason.INVALID_RESPONSE;
225
118
  }
226
119
  }
227
- if (error) {
228
- const errorMessage = `${error}`;
229
- const existingMessage = riskApiData.errorMessage;
230
- riskApiData.errorMessage = existingMessage ? `${existingMessage}, ${errorMessage}` : errorMessage;
120
+ else if (response.status >= 400 && response.status < 500) {
121
+ riskApiData.errorReason = S2SErrorReason.BAD_REQUEST;
231
122
  }
232
- return riskApiData;
233
- });
123
+ else if (response.status >= 500 && response.status < 600) {
124
+ riskApiData.errorReason = S2SErrorReason.SERVER_ERROR;
125
+ }
126
+ }
127
+ if (error) {
128
+ const errorMessage = `${error}`;
129
+ const existingMessage = riskApiData.errorMessage;
130
+ riskApiData.errorMessage = existingMessage ? `${existingMessage}, ${errorMessage}` : errorMessage;
131
+ }
132
+ return riskApiData;
234
133
  }
235
134
  }
@@ -1,56 +1,16 @@
1
- import { ModuleMode, VidSource } from '../../utils';
2
- import { TokenOrigin } from '../../risk_token';
3
- import { CustomParameters } from '../../custom_parameters';
4
- import { GraphQLData } from '../../graphql/';
5
- import { CredentialIntelligenceVersion, SsoStep } from '../../products';
6
- export type HeaderEntry = {
7
- name: string;
8
- value: string;
9
- };
1
+ import { HeaderEntry, CommonActivityDetails } from '../../activities';
10
2
  export type RiskRequestData = {
11
- ip: string;
3
+ socket_ip: string;
12
4
  url: string;
13
5
  headers: HeaderEntry[];
14
6
  };
15
7
  export type RiskAdditionalData = {
16
- request_id: string;
17
- module_version: string;
18
8
  s2s_call_reason: string;
19
- risk_mode: ModuleMode;
20
- http_method: string;
21
- http_version?: string;
22
- px_orig_cookie?: string;
23
- px_cookie?: string;
24
- px_cookie_hmac?: string;
25
- tls_protocol?: string;
26
- tls_server?: string;
27
- tls_cipher?: string;
28
- tls_ciphers_sha?: string;
29
- tls_extension_sha?: string;
30
- tls_preferred_ciphers?: string;
31
- tls_ja3_fingerprint?: string;
32
- enforcer_vid_source?: VidSource;
33
- original_uuid?: string;
34
- original_token_error?: string;
35
- original_token?: string;
36
- px_decoded_original_token?: string;
37
- cookie_origin?: TokenOrigin;
38
- request_cookie_names?: string[];
39
- server_info_region?: string;
40
- server_info_datacenter?: string;
41
- cross_tab_session?: string;
42
- app_user_id?: string;
43
- jwt_additional_fields?: Record<string, any>;
44
- graphql_operations?: GraphQLData[];
45
- user?: string;
46
- pass?: string;
47
- ci_version?: CredentialIntelligenceVersion;
48
- sso_step?: SsoStep;
49
- } & CustomParameters;
9
+ };
50
10
  export type RiskActivity = {
51
11
  vid?: string;
52
- uuid?: string;
12
+ client_uuid?: string;
53
13
  pxhd?: string;
54
14
  request: RiskRequestData;
55
- additional: RiskAdditionalData;
15
+ additional: RiskAdditionalData & CommonActivityDetails;
56
16
  };
@@ -11,5 +11,6 @@ export interface IRiskResponse {
11
11
  readonly pxhdDomain?: string;
12
12
  readonly message?: string;
13
13
  readonly dataEnrichment?: PXDE;
14
+ readonly additionalRiskInfo?: string;
14
15
  validate(): AsyncOrSync<boolean>;
15
16
  }
@@ -19,4 +19,5 @@ export declare abstract class RiskResponseBase<TokenV extends TokenVersion> impl
19
19
  get uuid(): string;
20
20
  get dataEnrichment(): PXDE;
21
21
  get pxhdDomain(): string;
22
+ get additionalRiskInfo(): string;
22
23
  }
@@ -1,54 +1,41 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  import { RiskStatus } from '../model';
11
2
  export class RiskResponseBase {
3
+ response;
4
+ riskResponse;
12
5
  constructor(response) {
13
6
  this.response = response;
14
7
  }
15
- validate() {
16
- return __awaiter(this, void 0, void 0, function* () {
17
- try {
18
- this.riskResponse = (yield this.response.json());
19
- return this.status === RiskStatus.SUCCESS && this.validateRiskResponseScore();
20
- }
21
- catch (e) {
22
- return false;
23
- }
24
- });
8
+ async validate() {
9
+ try {
10
+ this.riskResponse = (await this.response.json());
11
+ return this.status === RiskStatus.SUCCESS && this.validateRiskResponseScore();
12
+ }
13
+ catch (e) {
14
+ return false;
15
+ }
25
16
  }
26
17
  get status() {
27
- var _a;
28
- return (_a = this.riskResponse) === null || _a === void 0 ? void 0 : _a.status;
18
+ return this.riskResponse?.status;
29
19
  }
30
20
  get action() {
31
- var _a;
32
- return (_a = this.riskResponse) === null || _a === void 0 ? void 0 : _a.action;
21
+ return this.riskResponse?.action;
33
22
  }
34
23
  get message() {
35
- var _a;
36
- return (_a = this.riskResponse) === null || _a === void 0 ? void 0 : _a.message;
24
+ return this.riskResponse?.message;
37
25
  }
38
26
  get pxhd() {
39
- var _a;
40
- return (_a = this.riskResponse) === null || _a === void 0 ? void 0 : _a.pxhd;
27
+ return this.riskResponse?.pxhd;
41
28
  }
42
29
  get uuid() {
43
- var _a;
44
- return (_a = this.riskResponse) === null || _a === void 0 ? void 0 : _a.uuid;
30
+ return this.riskResponse?.uuid;
45
31
  }
46
32
  get dataEnrichment() {
47
- var _a;
48
- return (_a = this.riskResponse) === null || _a === void 0 ? void 0 : _a.data_enrichment;
33
+ return this.riskResponse?.data_enrichment;
49
34
  }
50
35
  get pxhdDomain() {
51
- var _a;
52
- return (_a = this.riskResponse) === null || _a === void 0 ? void 0 : _a.pxhdDomain;
36
+ return this.riskResponse?.pxhdDomain;
37
+ }
38
+ get additionalRiskInfo() {
39
+ return this.riskResponse?.additional_risk_info;
53
40
  }
54
41
  }
@@ -1,6 +1,6 @@
1
1
  import { IIncomingResponse } from '../../../http';
2
- import { RiskResponseBase } from '../RiskResponseBase';
3
2
  import { TokenVersion } from '../../../risk_token';
3
+ import { RiskResponseBase } from '../RiskResponseBase';
4
4
  export declare class DefaultRiskResponseV2 extends RiskResponseBase<TokenVersion.V2> {
5
5
  constructor(response: IIncomingResponse);
6
6
  get score(): number;
@@ -4,15 +4,13 @@ export class DefaultRiskResponseV2 extends RiskResponseBase {
4
4
  super(response);
5
5
  }
6
6
  get score() {
7
- var _a, _b;
8
- return typeof ((_a = this.riskResponse) === null || _a === void 0 ? void 0 : _a.cookie_cfg_block_result) === 'undefined'
7
+ return typeof this.riskResponse?.cookie_cfg_block_result === 'undefined'
9
8
  ? undefined
10
- : ((_b = this.riskResponse) === null || _b === void 0 ? void 0 : _b.cookie_cfg_block_result) === '1'
9
+ : this.riskResponse?.cookie_cfg_block_result === '1'
11
10
  ? 100
12
11
  : 0;
13
12
  }
14
13
  validateRiskResponseScore() {
15
- var _a;
16
- return ['0', '1'].includes((_a = this.riskResponse) === null || _a === void 0 ? void 0 : _a.cookie_cfg_block_result);
14
+ return ['0', '1'].includes(this.riskResponse?.cookie_cfg_block_result);
17
15
  }
18
16
  }
@@ -10,4 +10,5 @@ export type RiskResponseV2Payload = {
10
10
  pxhdDomain?: string;
11
11
  message?: string;
12
12
  data_enrichment?: PXDE;
13
+ additional_risk_info?: string;
13
14
  };
@@ -4,11 +4,9 @@ export class DefaultRiskResponseV3 extends RiskResponseBase {
4
4
  super(response);
5
5
  }
6
6
  get score() {
7
- var _a;
8
- return (_a = this.riskResponse) === null || _a === void 0 ? void 0 : _a.score;
7
+ return this.riskResponse?.score;
9
8
  }
10
9
  validateRiskResponseScore() {
11
- var _a;
12
- return typeof ((_a = this.riskResponse) === null || _a === void 0 ? void 0 : _a.score) === 'number';
10
+ return typeof this.riskResponse?.score === 'number';
13
11
  }
14
12
  }
@@ -10,4 +10,5 @@ export type RiskResponseV3Payload = {
10
10
  pxhdDomain?: string;
11
11
  message?: string;
12
12
  data_enrichment?: PXDE;
13
+ additional_risk_info?: string;
13
14
  };
@@ -1,38 +1,29 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  import { X_PX_AUTHORIZATION_HEADER_NAME, X_PX_BYPASS_REASON_HEADER_NAME, X_PX_ORIGINAL_TOKEN_HEADER_NAME, } from '../../utils';
11
2
  import { TokenParseResult } from '../TokenParseResult';
12
3
  import { COOKIE_SPLIT_DELIMITER } from '../constants';
13
4
  import { convertMobileTokenVersionToCookieName } from '../utils';
14
5
  export class TokenParserBase {
6
+ config;
7
+ options;
15
8
  constructor(config, options) {
16
9
  this.config = config;
17
10
  this.options = options;
18
11
  }
19
- parseToken(context) {
20
- return __awaiter(this, void 0, void 0, function* () {
21
- const tokenData = this.initializeToken(context);
22
- try {
23
- if (!tokenData.token) {
24
- this.config.logger.debug('no token found');
25
- yield this.handleMobileErrorIfNeeded(context, tokenData);
26
- return tokenData;
27
- }
28
- tokenData.tokenParseResult = yield tokenData.token.verify(context);
29
- }
30
- catch (e) {
31
- this.config.logger.debug(`could not parse token - ${e}`);
32
- tokenData.tokenParseResult = tokenData.token ? TokenParseResult.DECRYPTION_FAILED : TokenParseResult.NONE;
12
+ async parseToken(context) {
13
+ const tokenData = this.initializeToken(context);
14
+ try {
15
+ if (!tokenData.token) {
16
+ this.config.logger.debug('no token found');
17
+ await this.handleMobileErrorIfNeeded(context, tokenData);
18
+ return tokenData;
33
19
  }
34
- return tokenData;
35
- });
20
+ tokenData.tokenParseResult = await tokenData.token.verify(context);
21
+ }
22
+ catch (e) {
23
+ this.config.logger.debug(`could not parse token - ${e}`);
24
+ tokenData.tokenParseResult = tokenData.token ? TokenParseResult.DECRYPTION_FAILED : TokenParseResult.NONE;
25
+ }
26
+ return tokenData;
36
27
  }
37
28
  initializeToken({ requestData, isMobile }) {
38
29
  if (isMobile) {
@@ -59,7 +50,7 @@ export class TokenParserBase {
59
50
  }
60
51
  getMobileToken(mobileToken) {
61
52
  try {
62
- if (!mobileToken || (mobileToken === null || mobileToken === void 0 ? void 0 : mobileToken.indexOf(COOKIE_SPLIT_DELIMITER)) === -1) {
53
+ if (!mobileToken || mobileToken?.indexOf(COOKIE_SPLIT_DELIMITER) === -1) {
63
54
  return null;
64
55
  }
65
56
  const [tokenVersion, ...cookieString] = mobileToken.split(COOKIE_SPLIT_DELIMITER);
@@ -80,15 +71,13 @@ export class TokenParserBase {
80
71
  token: this.createToken(this.config, cookies, this.options),
81
72
  };
82
73
  }
83
- handleMobileErrorIfNeeded(context, { mobileData }) {
84
- return __awaiter(this, void 0, void 0, function* () {
85
- if (!mobileData || !mobileData.mobileError || !mobileData.originalToken) {
86
- return;
87
- }
88
- mobileData.originalTokenParseResult = yield mobileData.originalToken.verify(context);
89
- if (mobileData.originalTokenParseResult === TokenParseResult.SUCCESSFUL) {
90
- mobileData.decodedOriginalToken = mobileData.originalToken.getPayloadString();
91
- }
92
- });
74
+ async handleMobileErrorIfNeeded(context, { mobileData }) {
75
+ if (!mobileData || !mobileData.mobileError || !mobileData.originalToken) {
76
+ return;
77
+ }
78
+ mobileData.originalTokenParseResult = await mobileData.originalToken.verify(context);
79
+ if (mobileData.originalTokenParseResult === TokenParseResult.SUCCESSFUL) {
80
+ mobileData.decodedOriginalToken = mobileData.originalToken.getPayloadString();
81
+ }
93
82
  }
94
83
  }
@@ -1,14 +1,11 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  import { TokenParseResult } from '../TokenParseResult';
11
2
  export class TokenBase {
3
+ logger;
4
+ payload;
5
+ cookieString;
6
+ cookieSecret;
7
+ cookieMaxLength;
8
+ isValidated;
12
9
  constructor(config, cookieString) {
13
10
  this.logger = config.logger;
14
11
  this.cookieSecret = config.cookieSecret;
@@ -16,27 +13,25 @@ export class TokenBase {
16
13
  this.cookieString = cookieString;
17
14
  this.isValidated = false;
18
15
  }
19
- verify(context) {
20
- return __awaiter(this, void 0, void 0, function* () {
21
- if (!this.cookieString) {
22
- return TokenParseResult.NONE;
23
- }
24
- if (this.isValid()) {
25
- return TokenParseResult.SUCCESSFUL;
26
- }
27
- if (this.cookieString.length > this.cookieMaxLength) {
28
- return TokenParseResult.DECRYPTION_FAILED;
29
- }
30
- this.payload = this.payload || (yield this.decrypt(context));
31
- if (!this.payload) {
32
- return TokenParseResult.DECRYPTION_FAILED;
33
- }
34
- if (!(yield this.validate(context))) {
35
- return TokenParseResult.VALIDATION_FAILED;
36
- }
37
- this.isValidated = true;
16
+ async verify(context) {
17
+ if (!this.cookieString) {
18
+ return TokenParseResult.NONE;
19
+ }
20
+ if (this.isValid()) {
38
21
  return TokenParseResult.SUCCESSFUL;
39
- });
22
+ }
23
+ if (this.cookieString.length > this.cookieMaxLength) {
24
+ return TokenParseResult.DECRYPTION_FAILED;
25
+ }
26
+ this.payload = this.payload || (await this.decrypt(context));
27
+ if (!this.payload) {
28
+ return TokenParseResult.DECRYPTION_FAILED;
29
+ }
30
+ if (!(await this.validate(context))) {
31
+ return TokenParseResult.VALIDATION_FAILED;
32
+ }
33
+ this.isValidated = true;
34
+ return TokenParseResult.SUCCESSFUL;
40
35
  }
41
36
  isValid() {
42
37
  return this.isValidated;