@gataca/qr 4.0.3 → 4.1.1

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 (57) hide show
  1. package/dist/cjs/gataca-autoqr.cjs.entry.js +1 -1
  2. package/dist/cjs/gataca-qr_3.cjs.entry.js +130 -26
  3. package/dist/cjs/gataca-qrws.cjs.entry.js +142 -22
  4. package/dist/cjs/gataca-ssibuttonws.cjs.entry.js +1 -1
  5. package/dist/cjs/gatacaqr.cjs.js +2 -2
  6. package/dist/cjs/{index-1332a8ce.js → index-d8d3dfde.js} +32 -0
  7. package/dist/cjs/index.cjs.js +6 -1
  8. package/dist/cjs/loader.cjs.js +2 -2
  9. package/dist/cjs/utils-04522aa4.js +117 -0
  10. package/dist/collection/components/gataca-qr/components/qr/QR.js +9 -1
  11. package/dist/collection/components/gataca-qr/components/retryButton/RetryButton.js +5 -2
  12. package/dist/collection/components/gataca-qr/gataca-qr.css +6 -0
  13. package/dist/collection/components/gataca-qr/gataca-qr.js +87 -17
  14. package/dist/collection/components/gataca-qrdisplay/gataca-qrdisplay.js +28 -4
  15. package/dist/collection/components/gataca-qrws/components/qr/QR.js +9 -1
  16. package/dist/collection/components/gataca-qrws/components/retryButton/RetryButton.js +5 -2
  17. package/dist/collection/components/gataca-qrws/gataca-qrws.css +7 -0
  18. package/dist/collection/components/gataca-qrws/gataca-qrws.js +126 -18
  19. package/dist/collection/components/gataca-ssibutton/gataca-ssibutton.js +2 -2
  20. package/dist/collection/utils/utils.js +84 -0
  21. package/dist/components/gat-icon-check.js +85 -1
  22. package/dist/components/gataca-qr2.js +106 -20
  23. package/dist/components/gataca-qrdisplay2.js +25 -4
  24. package/dist/components/gataca-qrws2.js +145 -21
  25. package/dist/components/gataca-ssibutton2.js +2 -2
  26. package/dist/components/index.js +1 -1
  27. package/dist/esm/gataca-autoqr.entry.js +1 -1
  28. package/dist/esm/gataca-qr_3.entry.js +131 -27
  29. package/dist/esm/gataca-qrws.entry.js +142 -22
  30. package/dist/esm/gataca-ssibuttonws.entry.js +1 -1
  31. package/dist/esm/gatacaqr.js +2 -2
  32. package/dist/esm/{index-055790a7.js → index-dca2ab22.js} +32 -0
  33. package/dist/esm/index.js +1 -1
  34. package/dist/esm/loader.js +2 -2
  35. package/dist/esm/utils-cf9db2bd.js +109 -0
  36. package/dist/gatacaqr/gatacaqr.esm.js +1 -1
  37. package/dist/gatacaqr/index.esm.js +1 -1
  38. package/dist/gatacaqr/{p-49cf321c.entry.js → p-2e8accf9.entry.js} +1 -1
  39. package/dist/gatacaqr/p-3db0f74d.entry.js +1 -0
  40. package/dist/gatacaqr/p-775c90cf.entry.js +1 -0
  41. package/dist/gatacaqr/{p-0501e224.js → p-7b6fa63b.js} +1 -1
  42. package/dist/gatacaqr/p-85af64b1.js +2 -0
  43. package/dist/gatacaqr/{p-c65f810b.entry.js → p-d27dabe4.entry.js} +1 -1
  44. package/dist/types/components/gataca-qr/components/qr/QR.d.ts +1 -0
  45. package/dist/types/components/gataca-qr/components/retryButton/RetryButton.d.ts +0 -2
  46. package/dist/types/components/gataca-qr/gataca-qr.d.ts +5 -2
  47. package/dist/types/components/gataca-qrdisplay/gataca-qrdisplay.d.ts +4 -0
  48. package/dist/types/components/gataca-qrws/components/qr/QR.d.ts +1 -0
  49. package/dist/types/components/gataca-qrws/components/retryButton/RetryButton.d.ts +0 -2
  50. package/dist/types/components/gataca-qrws/gataca-qrws.d.ts +8 -2
  51. package/dist/types/utils/utils.d.ts +10 -0
  52. package/package.json +1 -1
  53. package/dist/cjs/utils-c6edb275.js +0 -28
  54. package/dist/esm/utils-22df0ce4.js +0 -25
  55. package/dist/gatacaqr/p-2083dd06.entry.js +0 -1
  56. package/dist/gatacaqr/p-f5a4f65c.entry.js +0 -1
  57. package/dist/gatacaqr/p-fccf9d4d.js +0 -2
@@ -213,6 +213,13 @@ img {
213
213
  justify-content: center;
214
214
  }
215
215
 
216
+ .qr-placeholder-slot,
217
+ .qr-loading-slot {
218
+ box-sizing: border-box;
219
+ border-radius: 12px;
220
+ background: rgba(0, 0, 0, 0.04);
221
+ }
222
+
216
223
  #qrwait,
217
224
  #notify {
218
225
  width: 100%;
@@ -1,7 +1,7 @@
1
1
  import { h } from '@stencil/core';
2
2
  import logoGataca from '../../assets/images/logo_gataca.svg';
3
3
  import '../gataca-qrdisplay/gataca-qrdisplay';
4
- import { base64UrlEncode, checkMobile, RESULT_STATUS } from '../../utils/utils';
4
+ import { assignWindowLocationIfAllowed, base64UrlEncode, checkMobile, RESULT_STATUS, shortenUrlIfPossible } from '../../utils/utils';
5
5
  import { Success } from './components/success/Success';
6
6
  import { RetryButton } from './components/retryButton/RetryButton';
7
7
  import { QR } from './components/qr/QR';
@@ -10,7 +10,54 @@ const DEEP_LINK_PREFIX = 'https://api.gataca.io/qr/redirect.html';
10
10
  const DEFAULT_SESSION_TIMEOUT = 300;
11
11
  const QR_ROLE_CONNECT = 'connect';
12
12
  export class GatacaQRWS {
13
- constructor() { this.successCallback = undefined; this.errorCallback = undefined; this.qrRole = undefined; this.qrType = 'svg'; this.callbackServer = undefined; this.socketEndpoint = undefined; this.sessionTimeout = DEFAULT_SESSION_TIMEOUT; this.wsOnOpen = undefined; this.wsOnMessage = undefined; this.autostart = true; this.autorefresh = false; this.v = '3'; this.qrModalTitle = 'Quick Access'; this.modalTitleColor = '#4745B7'; this.qrModalDescription = 'Sign up or sign in by scanning the QR Code with the Gataca Wallet'; this.hideModalTexts = false; this.hideModalBoxShadow = false; this.hideBrandTitle = false; this.logoSize = 0; this.logoSrc = logoGataca; this.qrSize = 300; this.modalWidth = 300; this.modalHeight = undefined; this.qrCodeExpiredLabel = 'QR Code expired'; this.credentialsNotValidatedLabel = 'User credentials not validated'; this.clickInsideBoxLabel = 'Click inside the box to'; this.refreshQrLabel = 'Refresh QR Code'; this.scanQrLabel = 'Scan QR Code'; this.userNotScanInTimeErrorLabel = 'User did not scan the QR in the allowed time'; this.credsNotValidatedErrorLabel = "Provided user credentials couldn't be validated"; this.failedLoginErrorLabel = 'No successful login'; this.successLoginLabel = 'Successful Connection!'; this.byBrandLabel = 'by Gataca'; this.waitingStartSessionLabel = 'waiting to start a session'; this.readQrTitle = 'Processing...'; this.readQrDescription = 'Please wait a moment'; this.hideQrModalDescription = false; this.dynamicLink = true; this.sessionId = undefined; this.authenticationRequest = undefined; this.sessionData = undefined; this.result = RESULT_STATUS.NOT_STARTED; }
13
+ constructor() {
14
+ this.qrRefreshGeneration = 0;
15
+ this.lastShortenRaw = null;
16
+ this.successCallback = undefined;
17
+ this.errorCallback = undefined;
18
+ this.qrRole = undefined;
19
+ this.qrType = 'svg';
20
+ this.callbackServer = undefined;
21
+ this.socketEndpoint = undefined;
22
+ this.sessionTimeout = DEFAULT_SESSION_TIMEOUT;
23
+ this.wsOnOpen = undefined;
24
+ this.wsOnMessage = undefined;
25
+ this.autostart = true;
26
+ this.autorefresh = false;
27
+ this.v = '3';
28
+ this.qrModalTitle = 'Quick Access';
29
+ this.modalTitleColor = '#4745B7';
30
+ this.qrModalDescription = 'Sign up or sign in by scanning the QR Code with the Gataca Wallet';
31
+ this.hideModalTexts = false;
32
+ this.hideModalBoxShadow = false;
33
+ this.hideBrandTitle = false;
34
+ this.logoSize = 0;
35
+ this.logoSrc = logoGataca;
36
+ this.qrSize = 300;
37
+ this.modalWidth = 300;
38
+ this.modalHeight = undefined;
39
+ this.qrCodeExpiredLabel = 'QR Code expired';
40
+ this.credentialsNotValidatedLabel = 'User credentials not validated';
41
+ this.clickInsideBoxLabel = 'Click inside the box to';
42
+ this.refreshQrLabel = 'Refresh QR Code';
43
+ this.scanQrLabel = 'Scan QR Code';
44
+ this.userNotScanInTimeErrorLabel = 'User did not scan the QR in the allowed time';
45
+ this.credsNotValidatedErrorLabel = "Provided user credentials couldn't be validated";
46
+ this.failedLoginErrorLabel = 'No successful login';
47
+ this.successLoginLabel = 'Successful Connection!';
48
+ this.byBrandLabel = 'by Gataca';
49
+ this.waitingStartSessionLabel = 'waiting to start a session';
50
+ this.readQrTitle = 'Processing...';
51
+ this.readQrDescription = 'Please wait a moment';
52
+ this.hideQrModalDescription = false;
53
+ this.dynamicLink = true;
54
+ this.sessionId = undefined;
55
+ this.authenticationRequest = undefined;
56
+ this.sessionData = undefined;
57
+ this.result = RESULT_STATUS.NOT_STARTED;
58
+ this.qrHref = '';
59
+ this.qrShortenPending = false;
60
+ }
14
61
  disconnectedCallback() {
15
62
  this.stop();
16
63
  }
@@ -23,6 +70,10 @@ export class GatacaQRWS {
23
70
  * Force manually the display of a QR
24
71
  */
25
72
  async display() {
73
+ this.qrHref = '';
74
+ this.qrShortenPending = false;
75
+ this.lastShortenRaw = null;
76
+ this.qrRefreshGeneration++;
26
77
  let socket = new WebSocket(this.socketEndpoint);
27
78
  setTimeout(() => {
28
79
  this.socket.close(1000, '');
@@ -66,7 +117,7 @@ export class GatacaQRWS {
66
117
  }
67
118
  };
68
119
  if (checkMobile() && this.dynamicLink) {
69
- window.location.href = this.getLink();
120
+ assignWindowLocationIfAllowed(this.getLink(), true);
70
121
  }
71
122
  }
72
123
  sessionMsgReceived(event) {
@@ -77,10 +128,16 @@ export class GatacaQRWS {
77
128
  this.result = wsresp.result;
78
129
  switch (wsresp.result) {
79
130
  case RESULT_STATUS.ONGOING:
80
- case RESULT_STATUS.READ:
131
+ case RESULT_STATUS.READ: {
81
132
  this.sessionId = wsresp.sessionId;
82
133
  this.authenticationRequest = wsresp.authenticationRequest;
134
+ const raw = this.buildRawLink();
135
+ if (raw === null || raw === void 0 ? void 0 : raw.trim()) {
136
+ this.qrShortenPending = true;
137
+ void this.refreshQrHref();
138
+ }
83
139
  break;
140
+ }
84
141
  case RESULT_STATUS.SUCCESS:
85
142
  this.sessionData = wsresp.authenticatedUserData;
86
143
  this.gatacaLoginCompleted.emit(wsresp.authenticatedUserData);
@@ -111,6 +168,9 @@ export class GatacaQRWS {
111
168
  async stop() {
112
169
  this.sessionData = undefined;
113
170
  this.sessionId = undefined;
171
+ this.qrHref = '';
172
+ this.qrShortenPending = false;
173
+ this.lastShortenRaw = null;
114
174
  this.socket.close(1000, 'Client stopped the connection');
115
175
  }
116
176
  /**
@@ -119,19 +179,56 @@ export class GatacaQRWS {
119
179
  async getSessionData() {
120
180
  return this.sessionData ? Promise.resolve(this.sessionData) : Promise.reject(new Error('No successful login'));
121
181
  }
122
- getLink() {
182
+ buildRawLink() {
183
+ var _a;
123
184
  if (this.v === '2' && this.qrRole == QR_ROLE_CONNECT) {
124
- return this.authenticationRequest;
185
+ return (_a = this.authenticationRequest) !== null && _a !== void 0 ? _a : '';
125
186
  }
126
187
  const authRequestEncoded = '?dl=' + base64UrlEncode(this.authenticationRequest);
127
188
  return DEEP_LINK_PREFIX + authRequestEncoded;
128
189
  }
190
+ async refreshQrHref() {
191
+ var _a, _b, _c;
192
+ const raw = this.buildRawLink();
193
+ if (!(raw === null || raw === void 0 ? void 0 : raw.trim())) {
194
+ this.qrShortenPending = false;
195
+ return;
196
+ }
197
+ if (raw === this.lastShortenRaw && ((_a = this.qrHref) === null || _a === void 0 ? void 0 : _a.trim())) {
198
+ this.qrShortenPending = false;
199
+ return;
200
+ }
201
+ if (this.qrShortenPending && raw === this.lastShortenRaw && !((_b = this.qrHref) === null || _b === void 0 ? void 0 : _b.trim())) {
202
+ return;
203
+ }
204
+ const gen = ++this.qrRefreshGeneration;
205
+ this.lastShortenRaw = raw;
206
+ try {
207
+ const shortened = await shortenUrlIfPossible(raw);
208
+ const now = this.buildRawLink();
209
+ if (now === raw) {
210
+ this.qrHref = shortened;
211
+ }
212
+ else if (!((_c = this.qrHref) === null || _c === void 0 ? void 0 : _c.trim())) {
213
+ this.qrHref = now;
214
+ }
215
+ }
216
+ finally {
217
+ if (gen === this.qrRefreshGeneration) {
218
+ this.qrShortenPending = false;
219
+ }
220
+ }
221
+ }
222
+ getLink() {
223
+ return this.qrHref || this.buildRawLink();
224
+ }
129
225
  renderQRSection() {
226
+ var _a, _b, _c;
130
227
  switch (this.result) {
131
228
  case RESULT_STATUS.NOT_STARTED:
132
229
  return this.renderRetryButton();
133
230
  case RESULT_STATUS.ONGOING:
134
- return this.renderQR(this.getLink(), true);
231
+ return this.qrShortenPending || !((_a = this.qrHref) === null || _a === void 0 ? void 0 : _a.trim()) ? this.renderQrLoadingSlot() : this.renderQR(this.getLink(), true, undefined, !!((_b = this.qrHref) === null || _b === void 0 ? void 0 : _b.trim()));
135
232
  case RESULT_STATUS.EXPIRED:
136
233
  return this.renderRetryButton(this.qrCodeExpiredLabel);
137
234
  case RESULT_STATUS.FAILED:
@@ -139,26 +236,35 @@ export class GatacaQRWS {
139
236
  case RESULT_STATUS.SUCCESS:
140
237
  return this.renderSuccess();
141
238
  case RESULT_STATUS.READ:
142
- return this.renderReadQR({
143
- title: this === null || this === void 0 ? void 0 : this.readQrTitle,
144
- description: this === null || this === void 0 ? void 0 : this.readQrDescription
145
- });
239
+ return this.qrShortenPending || !((_c = this.qrHref) === null || _c === void 0 ? void 0 : _c.trim())
240
+ ? this.renderQrLoadingSlot()
241
+ : this.renderReadQR({
242
+ title: this === null || this === void 0 ? void 0 : this.readQrTitle,
243
+ description: this === null || this === void 0 ? void 0 : this.readQrDescription
244
+ });
146
245
  }
147
246
  }
148
247
  renderSuccess() {
149
248
  return h(Success, { modalHeight: this === null || this === void 0 ? void 0 : this.modalHeight, successLoginLabel: this === null || this === void 0 ? void 0 : this.successLoginLabel });
150
249
  }
151
250
  renderRetryButton(errorMessage) {
152
- return (h(RetryButton, { errorMessage: errorMessage, modalWidth: this === null || this === void 0 ? void 0 : this.modalWidth, clickInsideBoxLabel: this === null || this === void 0 ? void 0 : this.clickInsideBoxLabel, refreshQrLabel: this === null || this === void 0 ? void 0 : this.refreshQrLabel, scanQrLabel: this === null || this === void 0 ? void 0 : this.scanQrLabel, waitingStartSessionLabel: this === null || this === void 0 ? void 0 : this.waitingStartSessionLabel, display: this.display.bind(this), renderRetryQR: this.renderRetryQR.bind(this) }));
251
+ return (h(RetryButton, { errorMessage: errorMessage, modalWidth: this === null || this === void 0 ? void 0 : this.modalWidth, clickInsideBoxLabel: this === null || this === void 0 ? void 0 : this.clickInsideBoxLabel, refreshQrLabel: this === null || this === void 0 ? void 0 : this.refreshQrLabel, scanQrLabel: this === null || this === void 0 ? void 0 : this.scanQrLabel, display: this.display.bind(this) }));
153
252
  }
154
253
  renderReadQR(readQrMessages) {
155
- return h(ReadQR, { modalWidth: this === null || this === void 0 ? void 0 : this.modalWidth, readQrMessages: readQrMessages, url: this.getLink(), sizeQR: (this === null || this === void 0 ? void 0 : this.qrSize) ? (this === null || this === void 0 ? void 0 : this.qrSize) - 50 : undefined, renderQR: this.renderQR.bind(this) });
254
+ var _a;
255
+ const linkReady = !!((_a = this.qrHref) === null || _a === void 0 ? void 0 : _a.trim());
256
+ return (h(ReadQR, { modalWidth: this === null || this === void 0 ? void 0 : this.modalWidth, readQrMessages: readQrMessages, url: this.getLink(), sizeQR: (this === null || this === void 0 ? void 0 : this.qrSize) ? (this === null || this === void 0 ? void 0 : this.qrSize) - 50 : undefined, renderQR: (url, useLogo, size) => this.renderQR(url, useLogo, size, linkReady) }));
156
257
  }
157
- renderQR(value, useLogo, sizeQR) {
158
- return h(QR, { value: value, qrType: this.qrType, useLogo: useLogo && this.logoSize !== 0, size: sizeQR || (this === null || this === void 0 ? void 0 : this.qrSize) || undefined, logoSrc: this === null || this === void 0 ? void 0 : this.logoSrc });
258
+ renderQR(value, useLogo, sizeQR, linkReady = true) {
259
+ return h(QR, { value: value, qrType: this.qrType, useLogo: useLogo && this.logoSize !== 0, size: sizeQR || (this === null || this === void 0 ? void 0 : this.qrSize) || undefined, logoSrc: this === null || this === void 0 ? void 0 : this.logoSrc, linkReady: linkReady });
159
260
  }
160
- renderRetryQR(value, useLogo) {
161
- return h(QR, { value: value, qrType: this.qrType, useLogo: useLogo && this.logoSize !== 0, size: (this === null || this === void 0 ? void 0 : this.qrSize) ? (this === null || this === void 0 ? void 0 : this.qrSize) - 50 : undefined, logoSrc: this === null || this === void 0 ? void 0 : this.logoSrc });
261
+ renderQrLoadingSlot() {
262
+ const s = this.qrSize || 300;
263
+ return (h("div", { class: "qr-loading-slot", style: {
264
+ width: s + 'px',
265
+ height: s + 'px',
266
+ margin: '0 auto'
267
+ } }));
162
268
  }
163
269
  render() {
164
270
  var _a, _b;
@@ -883,7 +989,9 @@ export class GatacaQRWS {
883
989
  "sessionId": {},
884
990
  "authenticationRequest": {},
885
991
  "sessionData": {},
886
- "result": {}
992
+ "result": {},
993
+ "qrHref": {},
994
+ "qrShortenPending": {}
887
995
  };
888
996
  }
889
997
  static get events() {
@@ -1,6 +1,6 @@
1
1
  import { h } from '@stencil/core';
2
2
  import '../gataca-qrdisplay/gataca-qrdisplay';
3
- import { RESULT_STATUS } from '../../utils/utils';
3
+ import { assignWindowLocationIfAllowed, RESULT_STATUS } from '../../utils/utils';
4
4
  const PHONE_ICON = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAYAAACN1PRVAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAHvSURBVHgB3ZZPTttAFMbfe3YjL7qYLopcpZXSG7Q3CDfIsqrSJpyg5QQtJ2h7glgUdVs4AeEE5AYEQSDAgtnw357Hm0hAQDaeIRFCfFKyeKPxzzPzvc+DUKCZN80GEv1ABgWOQgSdGbOwv7u0nDueV4zjTzUIKhuAZna4vdQFR828azbI0K/TI/qodaLvjlP+tLDGDCs+IKv9Lbsi7kcv0w9541Q0EREPYcoieEQ9KiyECRXHzbpBUOcnYTfPFOOaaGVx9WsLiDrSIp0iU0wFNgIx/AQyc9I/OmOjy+Y8aBvHQcDUYebewc6/Xtk8J5htcg5efEPGhk0JtqkyBjo7DuZcnuO2sqCyKv8rUDmfTS9IBURqBAL+I6CkzBjOMOs22TLY21n8fl17KzXR3uDvb/CQk0GEdfvN07QvpnAOaGfYaRT25JzU6+rnG2tTpcWAy+Cp0m3U/URLms8HWfg/rn6RFaGSs9KQkZMpvGBWNs2Vandt46ac6YNBuc0fDLMaOU5DFybQ8039p/KJ4bq4rwPewtqoM/1gsCm/NfBXvWjgHhhuDAeLyd3qVSifHQULeZkou9EqemLhmUmav8qrZ4GEMGA7ivzjKvfeqGptFV2YdWPMPHHq0cCh3DdpVdLl/XCY9J1gVvbCiWa6N+JLocPFjCsx9cAAAAAASUVORK5CYII=';
5
5
  //Default values
6
6
  const DEFAULT_SESSION_TIMEOUT = 300; //5mins as in connect
@@ -185,7 +185,7 @@ export class GatacaSSIButton {
185
185
  let timeout;
186
186
  let detected = false;
187
187
  if (appScheme === null || appScheme === void 0 ? void 0 : appScheme.length) {
188
- window.location.href = appScheme;
188
+ assignWindowLocationIfAllowed(appScheme, true);
189
189
  }
190
190
  const waitTimeToCheckApp = this.checkAppTimeout * 1000;
191
191
  timeout = setTimeout(() => {
@@ -20,4 +20,88 @@ export var RESULT_STATUS;
20
20
  RESULT_STATUS[RESULT_STATUS["EXPIRED"] = 3] = "EXPIRED";
21
21
  RESULT_STATUS[RESULT_STATUS["READ"] = 5] = "READ";
22
22
  })(RESULT_STATUS || (RESULT_STATUS = {}));
23
+ const GATACA_SHORTEN_API = 'https://links.gataca.io/api/v1/short';
24
+ /** URL schemes before assigning window.location. */
25
+ export const ALLOWED_APP_REDIRECT_PROTOCOLS = [
26
+ 'openid-gatc-vp',
27
+ 'openid-vp',
28
+ 'openid4vp',
29
+ 'haip-vp',
30
+ 'openid',
31
+ 'openid-gatc-credential-offer',
32
+ 'haip-vci',
33
+ 'openid-credential-offer',
34
+ 'digital-credentials'
35
+ ];
36
+ const ALLOWED_APP_REDIRECT_PROTOCOL_SET = new Set(ALLOWED_APP_REDIRECT_PROTOCOLS);
37
+ function extractRedirectProtocol(url) {
38
+ var _a;
39
+ if (typeof url !== 'string') {
40
+ return undefined;
41
+ }
42
+ const trimmed = url.trim();
43
+ if (!trimmed || /[\u0000-\u001F\u007F\\]/.test(trimmed)) {
44
+ return undefined;
45
+ }
46
+ const match = /^([a-z][a-z0-9+.-]*):/i.exec(trimmed);
47
+ return (_a = match === null || match === void 0 ? void 0 : match[1]) === null || _a === void 0 ? void 0 : _a.toLowerCase();
48
+ }
49
+ export function isAllowedAppRedirect(url) {
50
+ const protocol = extractRedirectProtocol(url);
51
+ return !!protocol && ALLOWED_APP_REDIRECT_PROTOCOL_SET.has(protocol);
52
+ }
53
+ export function isAllowedNavigationRedirect(url) {
54
+ const protocol = extractRedirectProtocol(url);
55
+ return protocol === 'https' || isAllowedAppRedirect(url);
56
+ }
57
+ export function assignWindowLocationIfAllowed(url, allowHttps = false) {
58
+ const allowed = allowHttps ? isAllowedNavigationRedirect(url) : isAllowedAppRedirect(url);
59
+ if (!allowed || typeof url !== 'string') {
60
+ return false;
61
+ }
62
+ window.location.href = url.trim();
63
+ return true;
64
+ }
65
+ function extractShortUrlFromResponse(body) {
66
+ if (!body || typeof body !== 'object') {
67
+ return null;
68
+ }
69
+ const o = body;
70
+ for (const key of ['url', 'shortUrl', 'short_url', 'link']) {
71
+ const v = o[key];
72
+ if (typeof v === 'string' && v.trim() !== '') {
73
+ return v;
74
+ }
75
+ }
76
+ return null;
77
+ }
78
+ /**
79
+ * POSTs the link to shortener. On success with a non-empty url in the body, returns that url;
80
+ * otherwise returns the original link.
81
+ */
82
+ export async function shortenUrlIfPossible(link) {
83
+ const trimmedLink = (link === null || link === void 0 ? void 0 : link.trim()) || '';
84
+ const linkHasLength = trimmedLink === null || trimmedLink === void 0 ? void 0 : trimmedLink.length;
85
+ if (!linkHasLength) {
86
+ return link !== null && link !== void 0 ? link : '';
87
+ }
88
+ try {
89
+ const res = await fetch(GATACA_SHORTEN_API, {
90
+ method: 'POST',
91
+ mode: 'cors',
92
+ credentials: 'omit',
93
+ headers: { 'Content-Type': 'application/json' },
94
+ body: JSON.stringify({ url: trimmedLink })
95
+ });
96
+ if (res.status !== 200 && res.status !== 201) {
97
+ return link;
98
+ }
99
+ const data = await res.json().catch(() => null);
100
+ const short = extractShortUrlFromResponse(data);
101
+ return short !== null && short !== void 0 ? short : link;
102
+ }
103
+ catch (_a) {
104
+ return link;
105
+ }
106
+ }
23
107
  //
@@ -20,10 +20,94 @@ var RESULT_STATUS;
20
20
  RESULT_STATUS[RESULT_STATUS["EXPIRED"] = 3] = "EXPIRED";
21
21
  RESULT_STATUS[RESULT_STATUS["READ"] = 5] = "READ";
22
22
  })(RESULT_STATUS || (RESULT_STATUS = {}));
23
+ const GATACA_SHORTEN_API = 'https://links.gataca.io/api/v1/short';
24
+ /** URL schemes before assigning window.location. */
25
+ const ALLOWED_APP_REDIRECT_PROTOCOLS = [
26
+ 'openid-gatc-vp',
27
+ 'openid-vp',
28
+ 'openid4vp',
29
+ 'haip-vp',
30
+ 'openid',
31
+ 'openid-gatc-credential-offer',
32
+ 'haip-vci',
33
+ 'openid-credential-offer',
34
+ 'digital-credentials'
35
+ ];
36
+ const ALLOWED_APP_REDIRECT_PROTOCOL_SET = new Set(ALLOWED_APP_REDIRECT_PROTOCOLS);
37
+ function extractRedirectProtocol(url) {
38
+ var _a;
39
+ if (typeof url !== 'string') {
40
+ return undefined;
41
+ }
42
+ const trimmed = url.trim();
43
+ if (!trimmed || /[\u0000-\u001F\u007F\\]/.test(trimmed)) {
44
+ return undefined;
45
+ }
46
+ const match = /^([a-z][a-z0-9+.-]*):/i.exec(trimmed);
47
+ return (_a = match === null || match === void 0 ? void 0 : match[1]) === null || _a === void 0 ? void 0 : _a.toLowerCase();
48
+ }
49
+ function isAllowedAppRedirect(url) {
50
+ const protocol = extractRedirectProtocol(url);
51
+ return !!protocol && ALLOWED_APP_REDIRECT_PROTOCOL_SET.has(protocol);
52
+ }
53
+ function isAllowedNavigationRedirect(url) {
54
+ const protocol = extractRedirectProtocol(url);
55
+ return protocol === 'https' || isAllowedAppRedirect(url);
56
+ }
57
+ function assignWindowLocationIfAllowed(url, allowHttps = false) {
58
+ const allowed = allowHttps ? isAllowedNavigationRedirect(url) : isAllowedAppRedirect(url);
59
+ if (!allowed || typeof url !== 'string') {
60
+ return false;
61
+ }
62
+ window.location.href = url.trim();
63
+ return true;
64
+ }
65
+ function extractShortUrlFromResponse(body) {
66
+ if (!body || typeof body !== 'object') {
67
+ return null;
68
+ }
69
+ const o = body;
70
+ for (const key of ['url', 'shortUrl', 'short_url', 'link']) {
71
+ const v = o[key];
72
+ if (typeof v === 'string' && v.trim() !== '') {
73
+ return v;
74
+ }
75
+ }
76
+ return null;
77
+ }
78
+ /**
79
+ * POSTs the link to shortener. On success with a non-empty url in the body, returns that url;
80
+ * otherwise returns the original link.
81
+ */
82
+ async function shortenUrlIfPossible(link) {
83
+ const trimmedLink = (link === null || link === void 0 ? void 0 : link.trim()) || '';
84
+ const linkHasLength = trimmedLink === null || trimmedLink === void 0 ? void 0 : trimmedLink.length;
85
+ if (!linkHasLength) {
86
+ return link !== null && link !== void 0 ? link : '';
87
+ }
88
+ try {
89
+ const res = await fetch(GATACA_SHORTEN_API, {
90
+ method: 'POST',
91
+ mode: 'cors',
92
+ credentials: 'omit',
93
+ headers: { 'Content-Type': 'application/json' },
94
+ body: JSON.stringify({ url: trimmedLink })
95
+ });
96
+ if (res.status !== 200 && res.status !== 201) {
97
+ return link;
98
+ }
99
+ const data = await res.json().catch(() => null);
100
+ const short = extractShortUrlFromResponse(data);
101
+ return short !== null && short !== void 0 ? short : link;
102
+ }
103
+ catch (_a) {
104
+ return link;
105
+ }
106
+ }
23
107
  //
24
108
 
25
109
  const gatIconAlertSvg = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEwLjI5MDggMy44NjAyTDEuODIwNzUgMTguMDAwMkMxLjY0NjEyIDE4LjMwMjYgMS41NTM3MiAxOC42NDU1IDEuNTUyNzQgMTguOTk0N0MxLjU1MTc2IDE5LjM0MzkgMS42NDIyNCAxOS42ODczIDEuODE1MTggMTkuOTkwN0MxLjk4ODEyIDIwLjI5NDEgMi4yMzc0OCAyMC41NDcgMi41Mzg0NiAyMC43MjQxQzIuODM5NDQgMjAuOTAxMiAzLjE4MTU1IDIwLjk5NjQgMy41MzA3NSAyMS4wMDAySDIwLjQ3MDhDMjAuODIgMjAuOTk2NCAyMS4xNjIxIDIwLjkwMTIgMjEuNDYzIDIwLjcyNDFDMjEuNzY0IDIwLjU0NyAyMi4wMTM0IDIwLjI5NDEgMjIuMTg2MyAxOS45OTA3QzIyLjM1OTMgMTkuNjg3MyAyMi40NDk3IDE5LjM0MzkgMjIuNDQ4OCAxOC45OTQ3QzIyLjQ0NzggMTguNjQ1NSAyMi4zNTU0IDE4LjMwMjYgMjIuMTgwOCAxOC4wMDAyTDEzLjcxMDggMy44NjAyQzEzLjUzMjUgMy41NjYzMSAxMy4yODE1IDMuMzIzMzIgMTIuOTgxOSAzLjE1NDY5QzEyLjY4MjQgMi45ODYwNSAxMi4zNDQ1IDIuODk3NDYgMTIuMDAwOCAyLjg5NzQ2QzExLjY1NyAyLjg5NzQ2IDExLjMxOTEgMi45ODYwNSAxMS4wMTk2IDMuMTU0NjlDMTAuNzIgMy4zMjMzMiAxMC40NjkgMy41NjYzMSAxMC4yOTA4IDMuODYwMlYzLjg2MDJaIiBzdHJva2U9IiNDRDJCMzEiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+CjxwYXRoIGQ9Ik0xMiA5VjEzIiBzdHJva2U9IiNDRDJCMzEiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+CjxwYXRoIGQ9Ik0xMiAxN0gxMi4wMSIgc3Ryb2tlPSIjQ0QyQjMxIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPgo8L3N2Zz4K';
26
110
 
27
111
  const gatIconCheckSvg = 'data:image/svg+xml;base64,Cjxzdmcgd2lkdGg9IjUyIiBoZWlnaHQ9IjUzIiB2aWV3Qm94PSIwIDAgNTIgNTMiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxjaXJjbGUgY3g9IjI2IiBjeT0iMjYuNjcxOSIgcj0iMjYiIGZpbGw9IiMzRDlBNTAiLz4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0zOC41MiAxNy43NDk1QzM5LjU4MDUgMTguODA5OSAzOS41ODA1IDIwLjUyOTMgMzguNTIgMjEuNTg5OEwyMy41ODQ2IDM2LjUyNTFDMjIuNTI0MiAzNy41ODU2IDIwLjgwNDggMzcuNTg1NiAxOS43NDQzIDM2LjUyNTFMMTIuOTU1NSAyOS43MzYzQzExLjg5NSAyOC42NzU5IDExLjg5NSAyNi45NTY1IDEyLjk1NTUgMjUuODk2QzE0LjAxNiAyNC44MzU1IDE1LjczNTQgMjQuODM1NSAxNi43OTU4IDI1Ljg5NkwyMS42NjQ1IDMwLjc2NDdMMzQuNjc5NyAxNy43NDk1QzM1Ljc0MDIgMTYuNjg5IDM3LjQ1OTUgMTYuNjg5IDM4LjUyIDE3Ljc0OTVaIiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K';
28
112
 
29
- export { RESULT_STATUS as R, gatIconCheckSvg as a, base64UrlEncode as b, checkMobile as c, gatIconAlertSvg as g };
113
+ export { ALLOWED_APP_REDIRECT_PROTOCOLS as A, RESULT_STATUS as R, isAllowedNavigationRedirect as a, base64UrlEncode as b, checkMobile as c, assignWindowLocationIfAllowed as d, gatIconCheckSvg as e, gatIconAlertSvg as g, isAllowedAppRedirect as i, shortenUrlIfPossible as s };