@queue-it/fastly 3.6.0 → 4.4.3-beta.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 (39) hide show
  1. package/README.md +156 -58
  2. package/package.json +23 -16
  3. package/src/contextProvider.ts +175 -0
  4. package/src/fastlyCryptoProvider.ts +8 -0
  5. package/src/helper.ts +11 -0
  6. package/{assembly/sdk → src}/helpers/crypto.ts +338 -340
  7. package/src/index.ts +3 -0
  8. package/src/integrationConfigProvider.ts +199 -0
  9. package/src/requestResponseHandler.ts +200 -0
  10. package/README-INTERNAL.md +0 -21
  11. package/asconfig.json +0 -17
  12. package/assembly/__tests__/CustomerIntegrationDecodingHandler.spec.ts +0 -1086
  13. package/assembly/__tests__/IntegrationConfigHelpersTest.spec.ts +0 -574
  14. package/assembly/__tests__/KnownUserTest.spec.ts +0 -1894
  15. package/assembly/__tests__/Mocks.ts +0 -321
  16. package/assembly/__tests__/QueueParameterHelper.spec.ts +0 -59
  17. package/assembly/__tests__/UserInQueueService.spec.ts +0 -418
  18. package/assembly/__tests__/UserInQueueStateCookieRepository.spec.ts +0 -337
  19. package/assembly/__tests__/as-pect.config.js +0 -57
  20. package/assembly/__tests__/as-pect.d.ts +0 -1
  21. package/assembly/contextProvider.ts +0 -123
  22. package/assembly/helper.ts +0 -23
  23. package/assembly/index.ts +0 -10
  24. package/assembly/integrationConfigProvider.ts +0 -32
  25. package/assembly/requestResponseHandler.ts +0 -92
  26. package/assembly/sdk/HttpContextProvider.ts +0 -24
  27. package/assembly/sdk/IntegrationConfig/CustomerIntegrationDecodingHandler.ts +0 -198
  28. package/assembly/sdk/IntegrationConfig/IntegrationConfigHelpers.ts +0 -232
  29. package/assembly/sdk/IntegrationConfig/IntegrationConfigModel.ts +0 -93
  30. package/assembly/sdk/KnownUser.ts +0 -396
  31. package/assembly/sdk/Models.ts +0 -105
  32. package/assembly/sdk/QueueITHelpers.ts +0 -263
  33. package/assembly/sdk/UserInQueueService.ts +0 -245
  34. package/assembly/sdk/UserInQueueStateCookieRepository.ts +0 -189
  35. package/assembly/sdk/helpers/Date.ts +0 -194
  36. package/assembly/sdk/helpers/Uri.ts +0 -308
  37. package/assembly/tsconfig.json +0 -6
  38. package/index.js +0 -5
  39. package/pipelines/ci.yaml +0 -28
@@ -1,263 +0,0 @@
1
- //@ts-ignore
2
- import {RegExp} from "assemblyscript-regex";
3
- import {KeyValuePair, RequestValidationResult} from "./Models";
4
- import {IDateTimeProvider} from "./HttpContextProvider";
5
- import {Date as WasiDate} from "as-wasi";
6
- import {encodeURIComponent, decodeURIComponent} from "./helpers/Uri";
7
- import {KnownUser} from "./KnownUser";
8
- import {Response} from "@fastly/as-compute";
9
- import {UserInQueueService} from "./UserInQueueService";
10
-
11
- export class QueueUrlParams {
12
- public timeStamp: i64 = 0;
13
- public eventId: string = "";
14
- public hashCode: string = "";
15
- public extendableCookie: bool = false;
16
- public cookieValidityMinutes: i64 = 0;
17
- public queueITToken: string = "";
18
- public queueITTokenWithoutHash: string = "";
19
- public queueId: string = "";
20
- public redirectType: string = "";
21
- }
22
-
23
-
24
- export class Utils {
25
-
26
- static encodeUrl(url: string): string {
27
- if (url.length == 0)
28
- return "";
29
- let decoded = encodeURIComponent(url);
30
- decoded = decoded.replaceAll('!', '%' + '!'.charCodeAt(0).toString(16));
31
- decoded = decoded.replaceAll('\'', '%' + '\''.charCodeAt(0).toString(16));
32
- decoded = decoded.replaceAll('(', '%' + '('.charCodeAt(0).toString(16));
33
- decoded = decoded.replaceAll(')', '%' + ')'.charCodeAt(0).toString(16));
34
- decoded = decoded.replaceAll('*', '%' + '*'.charCodeAt(0).toString(16));
35
-
36
- return decoded;
37
- }
38
-
39
- static decodeUrl(url: string): string {
40
- return decodeURIComponent(url);
41
- }
42
-
43
- static generateSHA256Hash: (a: string, b: string) => string = (secretKey: string, stringToHash: string): string => "";
44
-
45
- static endsWith(str: string, search: string): bool {
46
- if (str == search)
47
- return true;
48
- if (str.length == 0 || search.length == 0)
49
- return false;
50
- return str.substring(str.length - search.length, str.length) == search;
51
- }
52
-
53
- static getCurrentTime(): i64 {
54
- return Math.floor((WasiDate.now() / 1000) as f64) as i64;
55
- }
56
-
57
- private static _hex2bin: u8[] = [
58
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
59
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
60
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
61
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // 0-9
62
- 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A-F
63
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
64
- 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // a-f
65
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
66
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
67
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
68
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
69
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
70
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
71
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
72
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
73
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
74
- ];
75
-
76
- static hex2bin(str: string): string {
77
- let len = str.length;
78
- let rv = '';
79
- let i = 0;
80
-
81
- let c1: i32;
82
- let c2: i32;
83
-
84
- while (len > 1) {
85
- let h1 = str.charAt(i++);
86
- c1 = h1.charCodeAt(0);
87
- let h2 = str.charAt(i++);
88
- c2 = h2.charCodeAt(0);
89
-
90
- rv += String.fromCharCode((Utils._hex2bin[c1] << 4) + Utils._hex2bin[c2]);
91
- len -= 2;
92
- }
93
-
94
- return rv;
95
- }
96
-
97
- static addNoCacheHeaders(res: Response): void {
98
- res.headers.set('Cache-Control', 'no-cache, no-store, must-revalidate, max-age=0');
99
- res.headers.set('Pragma', 'no-cache');
100
- res.headers.set('Expires', 'Fri, 01 Jan 1990 00:00:00 GMT');
101
- }
102
-
103
- static getParameterByName(url: string, name: string): string {
104
- const namePart = new RegExp(`[\[\]]`, 'g')
105
- let match = namePart.exec(name);
106
- while (match != null) {
107
- let rxmatch = match.matches[0];
108
- name = name.replaceAll(rxmatch, '\\$&')
109
- match = namePart.exec(name);
110
- }
111
- const regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)');
112
- const results = regex.exec(url);
113
- if (results == null) return '';
114
- if (results.matches.length < 3) {
115
- return '';
116
- }
117
-
118
- return decodeURIComponent(results.matches[2].replaceAll('+', ' '));
119
- }
120
-
121
- static removeQueueItToken(url: string): string {
122
- const pattern = new RegExp("([\?&])(" + KnownUser.QueueITTokenKey + "=[^&]*)", 'gi');
123
- const match = pattern.exec(url);
124
- if (match == null) return url;
125
-
126
- url = url.replaceAll(match.matches[0], '')
127
- return url;
128
- }
129
- }
130
-
131
- export class QueueParameterHelper {
132
- public static readonly TimeStampKey: string = "ts";
133
- public static readonly ExtendableCookieKey: string = "ce";
134
- public static readonly CookieValidityMinutesKey: string = "cv";
135
- public static readonly HashKey: string = "h";
136
- public static readonly EventIdKey: string = "e";
137
- public static readonly QueueIdKey: string = "q";
138
- public static readonly RedirectTypeKey: string = "rt";
139
- public static readonly KeyValueSeparatorChar: string = '_';
140
- public static readonly KeyValueSeparatorGroupChar: string = '~';
141
-
142
- public static extractQueueParams(queueitToken: string): QueueUrlParams | null {
143
- if (queueitToken.length == 0) {
144
- return null;
145
- }
146
-
147
- const result = new QueueUrlParams();
148
- result.queueITToken = queueitToken;
149
-
150
- const paramList = result.queueITToken.split(QueueParameterHelper.KeyValueSeparatorGroupChar);
151
- for (let i = 0; i < paramList.length; i++) {
152
- let paramKeyValue = paramList[i];
153
-
154
- let keyValueArr = paramKeyValue.split(QueueParameterHelper.KeyValueSeparatorChar);
155
- if (keyValueArr.length != 2) {
156
- continue;
157
- }
158
-
159
- if (keyValueArr[0] == QueueParameterHelper.HashKey) {
160
- result.hashCode = keyValueArr[1];
161
- } else if (keyValueArr[0] == QueueParameterHelper.TimeStampKey) {
162
- result.timeStamp = I64.parseInt(keyValueArr[1]);
163
- } else if (keyValueArr[0] == QueueParameterHelper.CookieValidityMinutesKey) {
164
- result.cookieValidityMinutes = I64.parseInt(keyValueArr[1]);
165
- } else if (keyValueArr[0] == QueueParameterHelper.EventIdKey) {
166
- result.eventId = keyValueArr[1];
167
- } else if (keyValueArr[0] == QueueParameterHelper.ExtendableCookieKey) {
168
- let extendCookie = (keyValueArr[1].length > 0 ? keyValueArr[1] : "false").toLowerCase();
169
- result.extendableCookie = extendCookie == "true";
170
- } else if (keyValueArr[0] == QueueParameterHelper.QueueIdKey) {
171
- result.queueId = keyValueArr[1];
172
-
173
- } else if (keyValueArr[0] == QueueParameterHelper.RedirectTypeKey) {
174
- result.redirectType = keyValueArr[1];
175
- }
176
- }
177
-
178
- const hashWithPrefix = QueueParameterHelper.KeyValueSeparatorGroupChar +
179
- QueueParameterHelper.HashKey +
180
- QueueParameterHelper.KeyValueSeparatorChar +
181
- result.hashCode;
182
- result.queueITTokenWithoutHash = result.queueITToken.replaceAll(hashWithPrefix, "");
183
- return result;
184
- }
185
- }
186
-
187
- export class CookieHelper {
188
- public static toMapFromValue(cookieValue: string): Map<string, string> {
189
- const items: string[] = cookieValue.split('&');
190
- let result = new Map<string, string>();
191
- for (let i = 0; i < items.length; i++) {
192
- let item: string = items[i];
193
- let keyValue = item.split('=');
194
- if (keyValue.length == 2) {
195
- result.set(keyValue[0], keyValue[1]);
196
- }
197
- }
198
- return result;
199
- }
200
-
201
- public static toValueFromKeyValueCollection(cookieValues: Array<KeyValuePair>): string {
202
- let values = new Array<string>();
203
-
204
- for (let i = 0; i < cookieValues.length; i++) {
205
- let kvp: KeyValuePair = cookieValues[i];
206
- values.push(kvp.key + "=" + kvp.value);
207
- }
208
-
209
- return values.join("&");
210
- }
211
- }
212
-
213
- export class ConnectorDiagnostics {
214
- public isEnabled: bool = false;
215
- public hasError: bool = false;
216
- public validationResult: RequestValidationResult | null
217
-
218
- private setStateWithTokenError(customerId: string, errorCode: string): void {
219
- this.hasError = true;
220
- const redirectUrl = "https://" + customerId + ".api2.queue-it.net/" + customerId + "/diagnostics/connector/error/?code=" + errorCode;
221
- this.validationResult = new RequestValidationResult("ConnectorDiagnosticsRedirect", "",
222
- "", redirectUrl, "", "")
223
- }
224
-
225
- private setStateWithSetupError(): void {
226
- this.hasError = true;
227
- this.validationResult = new RequestValidationResult("ConnectorDiagnosticsRedirect", "", "",
228
- "https://api2.queue-it.net/diagnostics/connector/error/?code=setup", "", "")
229
- }
230
-
231
- public static verify(customerId: string, secretKey: string, queueitToken: string): ConnectorDiagnostics {
232
- const diagnostics = new ConnectorDiagnostics();
233
- const qParams = QueueParameterHelper.extractQueueParams(queueitToken);
234
-
235
- if (qParams == null)
236
- return diagnostics;
237
- if (qParams.redirectType == null)
238
- return diagnostics;
239
- if (qParams.redirectType != "debug")
240
- return diagnostics;
241
- if (!(customerId != "" && secretKey != "")) {
242
- diagnostics.setStateWithSetupError();
243
- return diagnostics;
244
- }
245
- if (Utils.generateSHA256Hash(secretKey, qParams.queueITTokenWithoutHash) != qParams.hashCode) {
246
- diagnostics.setStateWithTokenError(customerId, "hash");
247
- return diagnostics;
248
- }
249
- if (qParams.timeStamp < Utils.getCurrentTime()) {
250
- diagnostics.setStateWithTokenError(customerId, "timestamp");
251
- return diagnostics;
252
- }
253
- diagnostics.isEnabled = true;
254
-
255
- return diagnostics;
256
- }
257
- }
258
-
259
- export class DateTimeProvider implements IDateTimeProvider {
260
- getCurrentTime(): Date {
261
- return new Date(i64(WasiDate.now()));
262
- }
263
- }
@@ -1,245 +0,0 @@
1
- import {Utils, QueueUrlParams, QueueParameterHelper} from './QueueITHelpers'
2
- import {ActionTypes, RequestValidationResult, QueueEventConfig, CancelEventConfig, ValidationResult} from './Models'
3
- import {StateInfo, UserInQueueStateCookieRepository} from './UserInQueueStateCookieRepository'
4
-
5
- export class UserInQueueService {
6
- static readonly SDK_VERSION: string = "v3-asmscrpt-" + "3.6.0";
7
-
8
- constructor(private userInQueueStateRepository: UserInQueueStateCookieRepository) {
9
- }
10
-
11
- private getValidTokenResult(
12
- config: QueueEventConfig,
13
- queueParams: QueueUrlParams,
14
- secretKey: string)
15
- : RequestValidationResult {
16
-
17
- this.userInQueueStateRepository.store(
18
- config.eventId,
19
- queueParams.queueId,
20
- queueParams.cookieValidityMinutes,
21
- config.cookieDomain,
22
- queueParams.redirectType,
23
- secretKey);
24
-
25
- return new RequestValidationResult(
26
- ActionTypes.QueueAction,
27
- config.eventId,
28
- queueParams.queueId,
29
- "",
30
- queueParams.redirectType,
31
- config.actionName,
32
- );
33
- }
34
-
35
- private getErrorResult(
36
- customerId: string,
37
- targetUrl: string,
38
- config: QueueEventConfig,
39
- qParams: QueueUrlParams,
40
- errorCode: string)
41
- : RequestValidationResult {
42
-
43
- let query = this.getQueryString(customerId, config.eventId, config.version, config.culture, config.layoutName, config.actionName) +
44
- "&queueittoken=" + qParams.queueITToken +
45
- "&ts=" + Utils.getCurrentTime().toString() +
46
- (targetUrl.length > 0 ? "&t=" + Utils.encodeUrl(targetUrl) : "");
47
- const uriPath = "error/" + errorCode + "/";
48
- const redirectUrl = this.generateRedirectUrl(config.queueDomain, uriPath, query);
49
-
50
- return new RequestValidationResult(
51
- ActionTypes.QueueAction,
52
- config.eventId,
53
- "",
54
- redirectUrl,
55
- "",
56
- config.actionName
57
- );
58
- }
59
-
60
- private getQueueResult(
61
- targetUrl: string,
62
- config: QueueEventConfig,
63
- customerId: string)
64
- : RequestValidationResult {
65
-
66
- let query = this.getQueryString(customerId, config.eventId, config.version, config.culture, config.layoutName, config.actionName) +
67
- (targetUrl.length > 0 ? "&t=" + Utils.encodeUrl(targetUrl) : "");
68
-
69
- const redirectUrl = this.generateRedirectUrl(config.queueDomain, "", query);
70
-
71
- return new RequestValidationResult(
72
- ActionTypes.QueueAction,
73
- config.eventId,
74
- "",
75
- redirectUrl,
76
- "",
77
- config.actionName
78
- );
79
- }
80
-
81
- private getQueryString(
82
- customerId: string,
83
- eventId: string,
84
- configVersion: i64,
85
- culture: string,
86
- layoutName: string,
87
- actionName: string)
88
- : string {
89
- const queryStringList = new Array<string>();
90
- queryStringList.push("c=" + Utils.encodeUrl(customerId));
91
- queryStringList.push("e=" + Utils.encodeUrl(eventId));
92
- queryStringList.push("ver=" + UserInQueueService.SDK_VERSION);
93
- queryStringList.push("cver=" + configVersion.toString());
94
- queryStringList.push("man=" + Utils.encodeUrl(actionName));
95
-
96
- if (culture.length > 0) {
97
- queryStringList.push("cid=" + Utils.encodeUrl(culture));
98
- }
99
-
100
-
101
- if (layoutName.length > 0) {
102
- queryStringList.push("l=" + Utils.encodeUrl(layoutName));
103
- }
104
-
105
- return queryStringList.join("&");
106
- }
107
-
108
-
109
- private generateRedirectUrl(queueDomain: string, uriPath: string, query: string): string {
110
- if (!Utils.endsWith(queueDomain, "/"))
111
- queueDomain = queueDomain + "/";
112
-
113
- return "https://".concat(queueDomain).concat(uriPath).concat("?").concat(query);
114
- }
115
-
116
- public validateQueueRequest(
117
- targetUrl: string,
118
- queueitToken: string,
119
- config: QueueEventConfig,
120
- customerId: string,
121
- secretKey: string): ValidationResult {
122
- const state: StateInfo = this.userInQueueStateRepository.getState(config.eventId,
123
- config.cookieValidityMinute, secretKey, true);
124
- if (state.isValid) {
125
- if (state.isStateExtendable() && config.extendCookieValidity) {
126
- this.userInQueueStateRepository.store(config.eventId,
127
- state.queueId,
128
- 0,
129
- config.cookieDomain,
130
- state.redirectType,
131
- secretKey);
132
- }
133
- return new ValidationResult(new RequestValidationResult(
134
- ActionTypes.QueueAction,
135
- config.eventId,
136
- state.queueId,
137
- "",
138
- state.redirectType,
139
- config.actionName
140
- ), null);
141
- }
142
-
143
- const queueParams = QueueParameterHelper.extractQueueParams(queueitToken);
144
-
145
- let requestValidationResult: RequestValidationResult | null;
146
- let isTokenValid: bool = false;
147
-
148
- if (queueParams != null) {
149
- const tokenValidationResult = this.validateToken(config, queueParams, secretKey);
150
- isTokenValid = tokenValidationResult.isValid;
151
-
152
- if (isTokenValid) {
153
- requestValidationResult = this.getValidTokenResult(config, queueParams, secretKey);
154
- } else {
155
- requestValidationResult = this.getErrorResult(customerId, targetUrl, config, queueParams, tokenValidationResult.errorCode);
156
- }
157
- } else {
158
- requestValidationResult = this.getQueueResult(targetUrl, config, customerId);
159
- }
160
-
161
- if (state.isFound && !isTokenValid) {
162
- this.userInQueueStateRepository.cancelQueueCookie(config.eventId, config.cookieDomain);
163
- }
164
-
165
- return new ValidationResult(requestValidationResult, null);
166
- }
167
-
168
- public validateCancelRequest(
169
- targetUrl: string,
170
- config: CancelEventConfig,
171
- customerId: string,
172
- secretKey: string): ValidationResult {
173
- //we do not care how long cookie is valid while canceling cookie
174
- const state = this.userInQueueStateRepository.getState(config.eventId, -1, secretKey, false);
175
-
176
- if (state.isValid) {
177
-
178
- this.userInQueueStateRepository.cancelQueueCookie(config.eventId, config.cookieDomain);
179
- const query = this.getQueryString(customerId, config.eventId, config.version, '', '', config.actionName) +
180
- (targetUrl.length > 0 ? "&r=" + Utils.encodeUrl(targetUrl) : "");
181
-
182
- const uriPath = "cancel/" + customerId + "/" + config.eventId + "/";
183
- const redirectUrl = this.generateRedirectUrl(config.queueDomain, uriPath, query);
184
- return new ValidationResult(new RequestValidationResult(
185
- ActionTypes.CancelAction,
186
- config.eventId,
187
- state.queueId,
188
- redirectUrl,
189
- state.redirectType,
190
- config.actionName), null);
191
- } else {
192
- return new ValidationResult(new RequestValidationResult(
193
- ActionTypes.CancelAction,
194
- config.eventId,
195
- "",
196
- "",
197
- "",
198
- config.actionName), null);
199
- }
200
- }
201
-
202
- public extendQueueCookie(
203
- eventId: string,
204
- cookieValidityMinutes: i64,
205
- cookieDomain: string,
206
- secretKey: string): void {
207
- this.userInQueueStateRepository.reissueQueueCookie(eventId, cookieValidityMinutes, cookieDomain, secretKey)
208
- }
209
-
210
- public getIgnoreResult(
211
- actionName: string): RequestValidationResult {
212
- return new RequestValidationResult(ActionTypes.IgnoreAction, "", "", "", "", actionName);
213
- }
214
-
215
- private validateToken(
216
- config: QueueEventConfig,
217
- queueParams: QueueUrlParams,
218
- secretKey: string): TokenValidationResult {
219
-
220
- const calculatedHash = Utils.generateSHA256Hash(secretKey, queueParams.queueITTokenWithoutHash);
221
-
222
- if (calculatedHash != queueParams.hashCode) {
223
- return new TokenValidationResult(false, "hash");
224
- }
225
-
226
-
227
- if (queueParams.eventId != config.eventId)
228
- return new TokenValidationResult(false, "eventid");
229
-
230
- if (queueParams.timeStamp < Utils.getCurrentTime())
231
- return new TokenValidationResult(false, "timestamp");
232
-
233
- return new TokenValidationResult(true, "");
234
- }
235
-
236
- }
237
-
238
- class TokenValidationResult {
239
- constructor(
240
- public isValid: bool,
241
- public errorCode: string) {
242
-
243
- }
244
-
245
- }
@@ -1,189 +0,0 @@
1
- import {IHttpContextProvider} from './HttpContextProvider'
2
- import {Utils, CookieHelper} from './QueueITHelpers'
3
- import {Date as WasiDate} from "as-wasi";
4
- import {KeyValuePair} from "./Models";
5
-
6
- export class UserInQueueStateCookieRepository {
7
- private static readonly _QueueITDataKey: string = "QueueITAccepted-SDFrts345E-V3";
8
- private static readonly _HashKey: string = "Hash";
9
- private static readonly _IssueTimeKey: string = "IssueTime";
10
- private static readonly _QueueIdKey: string = "QueueId";
11
- private static readonly _EventIdKey: string = "EventId";
12
- private static readonly _RedirectTypeKey: string = "RedirectType";
13
- private static readonly _FixedCookieValidityMinutesKey: string = "FixedValidityMins";
14
-
15
- constructor(private httpContextProvider: IHttpContextProvider) {
16
- }
17
-
18
- public static getCookieKey(eventId: string): string {
19
- return UserInQueueStateCookieRepository._QueueITDataKey + "_" + eventId;
20
- }
21
-
22
- public store(eventId: string, queueId: string, fixedCookieValidityMinutes: i64,
23
- cookieDomain: string, redirectType: string, secretKey: string): void {
24
- this.createCookie(
25
- eventId, queueId,
26
- fixedCookieValidityMinutes > 0 ? fixedCookieValidityMinutes.toString() : "",
27
- redirectType, cookieDomain, secretKey);
28
- }
29
-
30
- private createCookie(
31
- eventId: string,
32
- queueId: string,
33
- fixedCookieValidityMinutes: string,
34
- redirectType: string,
35
- cookieDomain: string,
36
- secretKey: string): void {
37
- let cookieKey = UserInQueueStateCookieRepository.getCookieKey(eventId);
38
-
39
- let issueTime = Utils.getCurrentTime().toString();
40
-
41
- let cookieValues = new Array<KeyValuePair>();
42
- cookieValues.push(new KeyValuePair(UserInQueueStateCookieRepository._EventIdKey, eventId));
43
- cookieValues.push(new KeyValuePair(UserInQueueStateCookieRepository._QueueIdKey, queueId));
44
- if (fixedCookieValidityMinutes != '') {
45
- cookieValues.push(new KeyValuePair(
46
- UserInQueueStateCookieRepository._FixedCookieValidityMinutesKey, fixedCookieValidityMinutes
47
- ));
48
- }
49
- cookieValues.push(new KeyValuePair(UserInQueueStateCookieRepository._RedirectTypeKey, redirectType.toLowerCase()));
50
- cookieValues.push(new KeyValuePair(UserInQueueStateCookieRepository._IssueTimeKey, issueTime));
51
- cookieValues.push(new KeyValuePair(
52
- UserInQueueStateCookieRepository._HashKey,
53
- this.generateHash(eventId.toLowerCase(), queueId, fixedCookieValidityMinutes, redirectType.toLowerCase(), issueTime, secretKey)
54
- ));
55
- const tomorrow: Date = new Date(i64(WasiDate.now()) + 1000 * 60 * 60 * 24);
56
- const expire: i32 = Math.floor((tomorrow.getTime() / 1000) as f64) as i32;
57
- let cookieValue = CookieHelper.toValueFromKeyValueCollection(cookieValues);
58
-
59
- this.httpContextProvider.getHttpResponse().setCookie(cookieKey,
60
- cookieValue,
61
- cookieDomain, expire);
62
- }
63
-
64
- public getState(eventId: string, cookieValidityMinutes: i64, secretKey: string, validateTime: bool): StateInfo {
65
- const cookieKey = UserInQueueStateCookieRepository.getCookieKey(eventId);
66
- const cookie = this.httpContextProvider.getHttpRequest().getCookieValue(cookieKey);
67
-
68
- if (cookie == "") {
69
- return new StateInfo(false, false, "", 0, "");
70
- }
71
- const cookieValues = CookieHelper.toMapFromValue(cookie);
72
-
73
- if (!this.isCookieValid(secretKey, cookieValues, eventId, cookieValidityMinutes, validateTime)) {
74
- return new StateInfo(true, false, "", 0, "");
75
- }
76
-
77
- const fixedCookieValidity: i64 = cookieValues.has(UserInQueueStateCookieRepository._FixedCookieValidityMinutesKey)
78
- ? I64.parseInt(cookieValues.get(UserInQueueStateCookieRepository._FixedCookieValidityMinutesKey))
79
- : 0;
80
-
81
- return new StateInfo(
82
- true,
83
- true,
84
- cookieValues.get(UserInQueueStateCookieRepository._QueueIdKey),
85
- fixedCookieValidity,
86
- cookieValues.get(UserInQueueStateCookieRepository._RedirectTypeKey));
87
- }
88
-
89
- private isCookieValid(
90
- secretKey: string,
91
- cookieValueMap: Map<string, string>,
92
- eventId: string,
93
- cookieValidityMinutes: i64,
94
- validateTime: bool): bool {
95
-
96
- const storedHash = cookieValueMap.has(UserInQueueStateCookieRepository._HashKey) ?
97
- cookieValueMap.get(UserInQueueStateCookieRepository._HashKey) : "";
98
- const issueTimeString = cookieValueMap.has(UserInQueueStateCookieRepository._IssueTimeKey) ?
99
- cookieValueMap.get(UserInQueueStateCookieRepository._IssueTimeKey) : "";
100
- const queueId = cookieValueMap.has(UserInQueueStateCookieRepository._QueueIdKey) ?
101
- cookieValueMap.get(UserInQueueStateCookieRepository._QueueIdKey) : "";
102
- const eventIdFromCookie = cookieValueMap.has(UserInQueueStateCookieRepository._EventIdKey) ?
103
- cookieValueMap.get(UserInQueueStateCookieRepository._EventIdKey) : "";
104
- const redirectType = cookieValueMap.has(UserInQueueStateCookieRepository._RedirectTypeKey) ?
105
- cookieValueMap.get(UserInQueueStateCookieRepository._RedirectTypeKey) : "";
106
- let fixedCookieValidityMinutes = cookieValueMap.has(UserInQueueStateCookieRepository._FixedCookieValidityMinutesKey) ?
107
- cookieValueMap.get(UserInQueueStateCookieRepository._FixedCookieValidityMinutesKey) : "";
108
-
109
- const expectedHash = this.generateHash(
110
- eventIdFromCookie,
111
- queueId,
112
- fixedCookieValidityMinutes,
113
- redirectType,
114
- issueTimeString,
115
- secretKey);
116
- if (expectedHash.length == 0) {
117
- return false
118
- }
119
-
120
- if (expectedHash != storedHash)
121
- return false;
122
-
123
- if (eventId.toLowerCase() != eventIdFromCookie.toLowerCase())
124
- return false;
125
-
126
- if (validateTime) {
127
- let validity: i64 = fixedCookieValidityMinutes.length > 0 ? I64.parseInt(fixedCookieValidityMinutes) : cookieValidityMinutes;
128
- let expirationTime: i64 = I64.parseInt(issueTimeString) + validity * 60;
129
-
130
- if (expirationTime < Utils.getCurrentTime())
131
- return false;
132
- }
133
- return true;
134
- }
135
-
136
- public cancelQueueCookie(eventId: string, cookieDomain: string): void {
137
- const cookieKey = UserInQueueStateCookieRepository.getCookieKey(eventId);
138
- this.httpContextProvider.getHttpResponse().setCookie(cookieKey, "", cookieDomain, 0);
139
- }
140
-
141
- public reissueQueueCookie(eventId: string, cookieValidityMinutes: i64, cookieDomain: string, secretKey: string): void {
142
- const cookieKey = UserInQueueStateCookieRepository.getCookieKey(eventId);
143
- const cookie = this.httpContextProvider.getHttpRequest().getCookieValue(cookieKey);
144
-
145
- if (cookie == '')
146
- return;
147
-
148
- const cookieValues = CookieHelper.toMapFromValue(cookie);
149
-
150
- if (!this.isCookieValid(secretKey, cookieValues, eventId, cookieValidityMinutes, true))
151
- return;
152
-
153
- let fixedCookieValidityMinutes = "";
154
- if (cookieValues.has(UserInQueueStateCookieRepository._FixedCookieValidityMinutesKey)) {
155
- fixedCookieValidityMinutes = cookieValues.get(UserInQueueStateCookieRepository._FixedCookieValidityMinutesKey).toString();
156
- }
157
-
158
- this.createCookie(
159
- eventId,
160
- cookieValues.get(UserInQueueStateCookieRepository._QueueIdKey),
161
- fixedCookieValidityMinutes,
162
- cookieValues.get(UserInQueueStateCookieRepository._RedirectTypeKey),
163
- cookieDomain, secretKey);
164
- }
165
-
166
- private generateHash(
167
- eventId: string,
168
- queueId: string,
169
- fixedCookieValidityMinutes: string,
170
- redirectType: string,
171
- issueTime: string,
172
- secretKey: string): string {
173
- let valueToHash = eventId + queueId + fixedCookieValidityMinutes + redirectType + issueTime;
174
- return Utils.generateSHA256Hash(secretKey, valueToHash);
175
- }
176
- }
177
-
178
- export class StateInfo {
179
- constructor(public isFound: bool,
180
- public isValid: bool,
181
- public queueId: string,
182
- public fixedCookieValidityMinutes: i64,
183
- public redirectType: string) {
184
- }
185
-
186
- isStateExtendable(): bool {
187
- return this.isValid && !this.fixedCookieValidityMinutes;
188
- }
189
- }