@paydock/client-sdk 1.144.0-beta → 1.145.0-beta
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.
- package/README.md +422 -31
- package/bundles/index.cjs +2476 -988
- package/bundles/index.cjs.d.ts +627 -431
- package/bundles/index.mjs +2476 -988
- package/bundles/index.mjs.d.ts +627 -431
- package/bundles/types/api/api-base.d.ts +15 -2
- package/bundles/types/api/api-base.d.ts.map +1 -1
- package/bundles/types/helper/browser.d.ts.map +1 -1
- package/bundles/types/helper/element-id.d.ts +3 -1
- package/bundles/types/helper/element-id.d.ts.map +1 -1
- package/bundles/types/helper/uuid.d.ts.map +1 -1
- package/bundles/types/open-wallets/apple-pay-open-wallet-button.d.ts +41 -0
- package/bundles/types/open-wallets/apple-pay-open-wallet-button.d.ts.map +1 -1
- package/bundles/types/open-wallets/base/open-wallet-buttons.d.ts +10 -0
- package/bundles/types/open-wallets/base/open-wallet-buttons.d.ts.map +1 -1
- package/bundles/types/open-wallets/base/service-config-cache.d.ts +23 -0
- package/bundles/types/open-wallets/base/service-config-cache.d.ts.map +1 -0
- package/bundles/types/open-wallets/google-pay-open-wallet-button.d.ts +33 -1
- package/bundles/types/open-wallets/google-pay-open-wallet-button.d.ts.map +1 -1
- package/bundles/types/open-wallets/index.d.ts +82 -1
- package/bundles/types/open-wallets/index.d.ts.map +1 -1
- package/bundles/types/open-wallets/interfaces/apple-pay/apple-pay-availability.interface.d.ts +41 -0
- package/bundles/types/open-wallets/interfaces/apple-pay/apple-pay-availability.interface.d.ts.map +1 -0
- package/bundles/types/open-wallets/interfaces/apple-pay/index.d.ts +1 -0
- package/bundles/types/open-wallets/interfaces/apple-pay/index.d.ts.map +1 -1
- package/bundles/types/open-wallets/interfaces/google-pay/google-pay-availability.interface.d.ts +25 -0
- package/bundles/types/open-wallets/interfaces/google-pay/google-pay-availability.interface.d.ts.map +1 -0
- package/bundles/types/open-wallets/interfaces/google-pay/index.d.ts +1 -0
- package/bundles/types/open-wallets/interfaces/google-pay/index.d.ts.map +1 -1
- package/bundles/types/open-wallets/interfaces/index.d.ts +3 -0
- package/bundles/types/open-wallets/interfaces/index.d.ts.map +1 -1
- package/bundles/types/open-wallets/interfaces/open-wallet-availability.interface.d.ts +31 -0
- package/bundles/types/open-wallets/interfaces/open-wallet-availability.interface.d.ts.map +1 -0
- package/bundles/types/open-wallets/services/apple-pay/apple-pay-availability.d.ts +58 -0
- package/bundles/types/open-wallets/services/apple-pay/apple-pay-availability.d.ts.map +1 -0
- package/bundles/types/open-wallets/services/apple-pay/apple-pay.open-wallet.service.d.ts +8 -10
- package/bundles/types/open-wallets/services/apple-pay/apple-pay.open-wallet.service.d.ts.map +1 -1
- package/bundles/types/open-wallets/services/apple-pay/index.d.ts +1 -0
- package/bundles/types/open-wallets/services/apple-pay/index.d.ts.map +1 -1
- package/bundles/types/open-wallets/services/google-pay/google-pay-availability.d.ts +53 -0
- package/bundles/types/open-wallets/services/google-pay/google-pay-availability.d.ts.map +1 -0
- package/bundles/types/open-wallets/services/google-pay/google-pay.open-wallet.service.d.ts.map +1 -1
- package/bundles/types/open-wallets/services/google-pay/index.d.ts +1 -0
- package/bundles/types/open-wallets/services/google-pay/index.d.ts.map +1 -1
- package/bundles/types/secure-remote-commerce/secure-remote-commerce.d.ts.map +1 -1
- package/bundles/widget.umd.js +2476 -988
- package/bundles/widget.umd.js.d.ts +627 -431
- package/bundles/widget.umd.js.min.d.ts +627 -431
- package/bundles/widget.umd.min.js +1 -1
- package/docs/open-wallet-buttons-examples.md +170 -2
- package/docs/open-wallet-buttons.md +252 -29
- package/package.json +15 -8
- package/slate.md +170 -2
package/bundles/index.cjs
CHANGED
|
@@ -830,16 +830,28 @@ var Browser = /*#__PURE__*/function () {
|
|
|
830
830
|
value: function getBrowserName() {
|
|
831
831
|
var sUsrAg = navigator.userAgent;
|
|
832
832
|
// "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0"
|
|
833
|
-
if (sUsrAg.indexOf('Firefox') > -1)
|
|
834
|
-
|
|
833
|
+
if (sUsrAg.indexOf('Firefox') > -1) {
|
|
834
|
+
return 'Mozilla Firefox';
|
|
835
|
+
}
|
|
836
|
+
if (sUsrAg.indexOf('Opera') > -1) {
|
|
837
|
+
return 'Opera';
|
|
838
|
+
}
|
|
835
839
|
// "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; Zoom 3.6.0; wbx 1.0.0; rv:11.0) like Gecko"
|
|
836
|
-
if (sUsrAg.indexOf('Trident') > -1)
|
|
840
|
+
if (sUsrAg.indexOf('Trident') > -1) {
|
|
841
|
+
return 'Microsoft Internet Explorer';
|
|
842
|
+
}
|
|
837
843
|
// "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299"
|
|
838
|
-
if (sUsrAg.indexOf('Edge') > -1)
|
|
844
|
+
if (sUsrAg.indexOf('Edge') > -1) {
|
|
845
|
+
return 'Microsoft Edge';
|
|
846
|
+
}
|
|
839
847
|
// "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/66.0.3359.181 Chrome/66.0.3359.181 Safari/537.36"
|
|
840
|
-
if (sUsrAg.indexOf('Chrome') > -1)
|
|
848
|
+
if (sUsrAg.indexOf('Chrome') > -1) {
|
|
849
|
+
return 'Google Chrome or Chromium';
|
|
850
|
+
}
|
|
841
851
|
// "Mozilla/5.0 (iPhone; CPU iPhone OS 11_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1 980x1306"
|
|
842
|
-
if (sUsrAg.indexOf('Safari') > -1)
|
|
852
|
+
if (sUsrAg.indexOf('Safari') > -1) {
|
|
853
|
+
return 'Apple Safari';
|
|
854
|
+
}
|
|
843
855
|
return 'unknown';
|
|
844
856
|
}
|
|
845
857
|
}, {
|
|
@@ -870,11 +882,13 @@ var Browser = /*#__PURE__*/function () {
|
|
|
870
882
|
}, {
|
|
871
883
|
key: "getBrowserInfo",
|
|
872
884
|
value: function getBrowserInfo() {
|
|
873
|
-
|
|
885
|
+
// Bound the user-agent length before running any regex to avoid
|
|
886
|
+
// pathological backtracking (ReDoS) on maliciously long inputs.
|
|
887
|
+
var ua = (navigator.userAgent || '').slice(0, 256);
|
|
874
888
|
var M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
|
|
875
|
-
var tem;
|
|
876
|
-
if (/trident/i.test(M[1])) {
|
|
877
|
-
tem = /\brv[ :](\d+)
|
|
889
|
+
var tem = null;
|
|
890
|
+
if (/trident/i.test(M[1] || '')) {
|
|
891
|
+
tem = ua.match(/\brv[ :](\d+)/) || [];
|
|
878
892
|
return {
|
|
879
893
|
name: 'IE',
|
|
880
894
|
version: tem[1] || ''
|
|
@@ -890,8 +904,8 @@ var Browser = /*#__PURE__*/function () {
|
|
|
890
904
|
}
|
|
891
905
|
}
|
|
892
906
|
M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, '-?'];
|
|
893
|
-
|
|
894
|
-
if (
|
|
907
|
+
tem = ua.match(/version\/(\d+)/i);
|
|
908
|
+
if (tem != null) {
|
|
895
909
|
M.splice(1, 1, tem[1]);
|
|
896
910
|
}
|
|
897
911
|
return {
|
|
@@ -956,246 +970,6 @@ var ApiCharge = /*#__PURE__*/function () {
|
|
|
956
970
|
}]);
|
|
957
971
|
}();
|
|
958
972
|
|
|
959
|
-
var ENV = {
|
|
960
|
-
SANDBOX: 'sandbox',
|
|
961
|
-
SANDBOX_KOVENA: 'sandbox-kovena',
|
|
962
|
-
SANDBOX_DEMO: 'sandbox-demo',
|
|
963
|
-
SANDBOX_DEMO_KOVENA: 'sandbox-demo-kovena',
|
|
964
|
-
PROD: 'production',
|
|
965
|
-
STAGING: 'staging',
|
|
966
|
-
STAGING_1: 'staging_1',
|
|
967
|
-
STAGING_2: 'staging_2',
|
|
968
|
-
STAGING_3: 'staging_3',
|
|
969
|
-
STAGING_4: 'staging_4',
|
|
970
|
-
STAGING_5: 'staging_5',
|
|
971
|
-
STAGING_6: 'staging_6',
|
|
972
|
-
STAGING_7: 'staging_7',
|
|
973
|
-
STAGING_8: 'staging_8',
|
|
974
|
-
STAGING_9: 'staging_9',
|
|
975
|
-
STAGING_10: 'staging_10',
|
|
976
|
-
STAGING_11: 'staging_11',
|
|
977
|
-
STAGING_12: 'staging_12',
|
|
978
|
-
STAGING_13: 'staging_13',
|
|
979
|
-
STAGING_14: 'staging_14',
|
|
980
|
-
STAGING_15: 'staging_15'
|
|
981
|
-
};
|
|
982
|
-
var WIDGET_URL = [{
|
|
983
|
-
env: ENV.SANDBOX,
|
|
984
|
-
url: 'https://widget-sandbox.'
|
|
985
|
-
}, {
|
|
986
|
-
env: ENV.SANDBOX_KOVENA,
|
|
987
|
-
url: 'https://widget-sandbox.'
|
|
988
|
-
}, {
|
|
989
|
-
env: ENV.SANDBOX_DEMO,
|
|
990
|
-
url: 'https://widget-sandbox-demo.'
|
|
991
|
-
}, {
|
|
992
|
-
env: ENV.SANDBOX_DEMO_KOVENA,
|
|
993
|
-
url: 'https://widget-sandbox-demo.'
|
|
994
|
-
}, {
|
|
995
|
-
env: ENV.PROD,
|
|
996
|
-
url: 'https://widget.'
|
|
997
|
-
}, {
|
|
998
|
-
env: ENV.STAGING,
|
|
999
|
-
url: 'https://widsta.'
|
|
1000
|
-
}, {
|
|
1001
|
-
env: ENV.STAGING_1,
|
|
1002
|
-
url: 'https://widsta-1.'
|
|
1003
|
-
}, {
|
|
1004
|
-
env: ENV.STAGING_2,
|
|
1005
|
-
url: 'https://widsta-2.'
|
|
1006
|
-
}, {
|
|
1007
|
-
env: ENV.STAGING_3,
|
|
1008
|
-
url: 'https://widsta-3.'
|
|
1009
|
-
}, {
|
|
1010
|
-
env: ENV.STAGING_4,
|
|
1011
|
-
url: 'https://widsta-4.'
|
|
1012
|
-
}, {
|
|
1013
|
-
env: ENV.STAGING_5,
|
|
1014
|
-
url: 'https://widsta-5.'
|
|
1015
|
-
}, {
|
|
1016
|
-
env: ENV.STAGING_6,
|
|
1017
|
-
url: 'https://widsta-6.'
|
|
1018
|
-
}, {
|
|
1019
|
-
env: ENV.STAGING_7,
|
|
1020
|
-
url: 'https://widsta-7.'
|
|
1021
|
-
}, {
|
|
1022
|
-
env: ENV.STAGING_8,
|
|
1023
|
-
url: 'https://widsta-8.'
|
|
1024
|
-
}, {
|
|
1025
|
-
env: ENV.STAGING_9,
|
|
1026
|
-
url: 'https://widsta-9.'
|
|
1027
|
-
}, {
|
|
1028
|
-
env: ENV.STAGING_10,
|
|
1029
|
-
url: 'https://widsta-10.'
|
|
1030
|
-
}, {
|
|
1031
|
-
env: ENV.STAGING_11,
|
|
1032
|
-
url: 'https://widsta-11.'
|
|
1033
|
-
}, {
|
|
1034
|
-
env: ENV.STAGING_12,
|
|
1035
|
-
url: 'https://widsta-12.'
|
|
1036
|
-
}, {
|
|
1037
|
-
env: ENV.STAGING_13,
|
|
1038
|
-
url: 'https://widsta-13.'
|
|
1039
|
-
}, {
|
|
1040
|
-
env: ENV.STAGING_14,
|
|
1041
|
-
url: 'https://widsta-14.'
|
|
1042
|
-
}, {
|
|
1043
|
-
env: ENV.STAGING_15,
|
|
1044
|
-
url: 'https://widsta-15.'
|
|
1045
|
-
}];
|
|
1046
|
-
var API_URL = [{
|
|
1047
|
-
env: ENV.SANDBOX,
|
|
1048
|
-
url: 'https://api-sandbox.'
|
|
1049
|
-
}, {
|
|
1050
|
-
env: ENV.PROD,
|
|
1051
|
-
url: 'https://api.'
|
|
1052
|
-
}, {
|
|
1053
|
-
env: ENV.STAGING,
|
|
1054
|
-
url: 'https://apista.'
|
|
1055
|
-
}, {
|
|
1056
|
-
env: ENV.STAGING_1,
|
|
1057
|
-
url: 'https://apista-1.'
|
|
1058
|
-
}, {
|
|
1059
|
-
env: ENV.STAGING_2,
|
|
1060
|
-
url: 'https://apista-2.'
|
|
1061
|
-
}, {
|
|
1062
|
-
env: ENV.STAGING_3,
|
|
1063
|
-
url: 'https://apista-3.'
|
|
1064
|
-
}, {
|
|
1065
|
-
env: ENV.STAGING_4,
|
|
1066
|
-
url: 'https://apista-4.'
|
|
1067
|
-
}, {
|
|
1068
|
-
env: ENV.STAGING_5,
|
|
1069
|
-
url: 'https://apista-5.'
|
|
1070
|
-
}, {
|
|
1071
|
-
env: ENV.STAGING_6,
|
|
1072
|
-
url: 'https://apista-6.'
|
|
1073
|
-
}, {
|
|
1074
|
-
env: ENV.STAGING_7,
|
|
1075
|
-
url: 'https://apista-7.'
|
|
1076
|
-
}, {
|
|
1077
|
-
env: ENV.STAGING_8,
|
|
1078
|
-
url: 'https://apista-8.'
|
|
1079
|
-
}, {
|
|
1080
|
-
env: ENV.STAGING_9,
|
|
1081
|
-
url: 'https://apista-9.'
|
|
1082
|
-
}, {
|
|
1083
|
-
env: ENV.STAGING_10,
|
|
1084
|
-
url: 'https://apista-10.'
|
|
1085
|
-
}, {
|
|
1086
|
-
env: ENV.STAGING_11,
|
|
1087
|
-
url: 'https://apista-11.'
|
|
1088
|
-
}, {
|
|
1089
|
-
env: ENV.STAGING_12,
|
|
1090
|
-
url: 'https://apista-12.'
|
|
1091
|
-
}, {
|
|
1092
|
-
env: ENV.STAGING_13,
|
|
1093
|
-
url: 'https://apista-13.'
|
|
1094
|
-
}, {
|
|
1095
|
-
env: ENV.STAGING_14,
|
|
1096
|
-
url: 'https://apista-14.'
|
|
1097
|
-
}, {
|
|
1098
|
-
env: ENV.STAGING_15,
|
|
1099
|
-
url: 'https://apista-15.'
|
|
1100
|
-
}];
|
|
1101
|
-
var ADDITIONAL_ENV = [ENV.SANDBOX_KOVENA, ENV.SANDBOX_DEMO_KOVENA];
|
|
1102
|
-
var REGEX_ALIAS = '^([a-zA-Z0-9](?:(?:[a-zA-Z0-9-.]*(?!-)\\.(?![-.]))*[a-zA-Z0-9]+)?)$';
|
|
1103
|
-
var DEFAULT_ENV = ENV.SANDBOX;
|
|
1104
|
-
var DEFAULT_ALIAS = {
|
|
1105
|
-
PAYDOCK: 'paydock.com',
|
|
1106
|
-
KOVENA: 'kovena.com'
|
|
1107
|
-
};
|
|
1108
|
-
// TODO @ingeniousraccoons we should take advantage of TypeScript mechanism for static environmentId checking and simplified runtime validation
|
|
1109
|
-
// TODO @ingeniousraccoons unify `environment.paydock.ts` and `environment.cba.ts` making them configuration driven
|
|
1110
|
-
var Env = /*#__PURE__*/function () {
|
|
1111
|
-
function Env(configs) {
|
|
1112
|
-
var defaultEnv = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_ENV;
|
|
1113
|
-
_classCallCheck(this, Env);
|
|
1114
|
-
this.environmentConfigurations = configs;
|
|
1115
|
-
this.setEnv(defaultEnv);
|
|
1116
|
-
}
|
|
1117
|
-
return _createClass(Env, [{
|
|
1118
|
-
key: "setEnv",
|
|
1119
|
-
value: function setEnv(environmentId, alias) {
|
|
1120
|
-
this.validateAlias(alias);
|
|
1121
|
-
this.validateEnvironmentId(environmentId);
|
|
1122
|
-
this.environmentId = environmentId;
|
|
1123
|
-
if (alias) {
|
|
1124
|
-
this.alias = alias;
|
|
1125
|
-
} else if (ADDITIONAL_ENV.includes(this.environmentId)) {
|
|
1126
|
-
this.alias = DEFAULT_ALIAS.KOVENA;
|
|
1127
|
-
} else {
|
|
1128
|
-
this.alias = DEFAULT_ALIAS.PAYDOCK;
|
|
1129
|
-
}
|
|
1130
|
-
}
|
|
1131
|
-
}, {
|
|
1132
|
-
key: "getEnv",
|
|
1133
|
-
value: function getEnv() {
|
|
1134
|
-
return this.environmentId;
|
|
1135
|
-
}
|
|
1136
|
-
}, {
|
|
1137
|
-
key: "getConf",
|
|
1138
|
-
value: function getConf() {
|
|
1139
|
-
for (var index in this.environmentConfigurations) {
|
|
1140
|
-
if (!Object.hasOwn(this.environmentConfigurations, index)) {
|
|
1141
|
-
continue;
|
|
1142
|
-
}
|
|
1143
|
-
if (this.environmentConfigurations[index].env === this.getEnv()) {
|
|
1144
|
-
return {
|
|
1145
|
-
url: this.environmentConfigurations[index].url.indexOf('localhost') !== -1 ? this.environmentConfigurations[index].url : this.environmentConfigurations[index].url + this.alias,
|
|
1146
|
-
env: this.environmentConfigurations[index].env
|
|
1147
|
-
};
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
throw new Error('Env could not obtain configuration. Unknown environmentId.');
|
|
1151
|
-
}
|
|
1152
|
-
}, {
|
|
1153
|
-
key: "validateAlias",
|
|
1154
|
-
value: function validateAlias(alias) {
|
|
1155
|
-
if (typeof alias === 'undefined') {
|
|
1156
|
-
return;
|
|
1157
|
-
}
|
|
1158
|
-
if (typeof alias !== 'string') {
|
|
1159
|
-
throw new TypeError("Env expects parameter 'alias' to be of type 'string' or 'undefined'.");
|
|
1160
|
-
}
|
|
1161
|
-
if (!alias.match(REGEX_ALIAS)) {
|
|
1162
|
-
throw new Error("Env received malformed alias: ".concat(alias, ". Ensure it satisfies the regex: '").concat(REGEX_ALIAS, "'."));
|
|
1163
|
-
}
|
|
1164
|
-
}
|
|
1165
|
-
}, {
|
|
1166
|
-
key: "validateEnvironmentId",
|
|
1167
|
-
value: function validateEnvironmentId(environmentId) {
|
|
1168
|
-
for (var index in this.environmentConfigurations) {
|
|
1169
|
-
if (!Object.hasOwn(this.environmentConfigurations, index)) {
|
|
1170
|
-
continue;
|
|
1171
|
-
}
|
|
1172
|
-
if (this.environmentConfigurations[index].env === environmentId) {
|
|
1173
|
-
return;
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
throw new TypeError("Env received unknown environmentId: ".concat(environmentId));
|
|
1177
|
-
}
|
|
1178
|
-
}]);
|
|
1179
|
-
}();
|
|
1180
|
-
|
|
1181
|
-
var SDK = /*#__PURE__*/function () {
|
|
1182
|
-
function SDK() {
|
|
1183
|
-
_classCallCheck(this, SDK);
|
|
1184
|
-
}
|
|
1185
|
-
return _createClass(SDK, null, [{
|
|
1186
|
-
key: "version",
|
|
1187
|
-
get: function get() {
|
|
1188
|
-
return SDK._version.trim() || null;
|
|
1189
|
-
}
|
|
1190
|
-
}]);
|
|
1191
|
-
}();
|
|
1192
|
-
SDK.type = 'client';
|
|
1193
|
-
SDK.headerKeys = Object.freeze({
|
|
1194
|
-
version: 'x-sdk-version',
|
|
1195
|
-
type: 'x-sdk-type'
|
|
1196
|
-
});
|
|
1197
|
-
SDK._version = 'v1.144.0-beta';
|
|
1198
|
-
|
|
1199
973
|
function isFunction(value) {
|
|
1200
974
|
return typeof value === 'function';
|
|
1201
975
|
}
|
|
@@ -1853,17 +1627,257 @@ var BehaviorSubject = (function (_super) {
|
|
|
1853
1627
|
return BehaviorSubject;
|
|
1854
1628
|
}(Subject));
|
|
1855
1629
|
|
|
1856
|
-
var
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1630
|
+
var ENV = {
|
|
1631
|
+
SANDBOX: 'sandbox',
|
|
1632
|
+
SANDBOX_KOVENA: 'sandbox-kovena',
|
|
1633
|
+
SANDBOX_DEMO: 'sandbox-demo',
|
|
1634
|
+
SANDBOX_DEMO_KOVENA: 'sandbox-demo-kovena',
|
|
1635
|
+
PROD: 'production',
|
|
1636
|
+
STAGING: 'staging',
|
|
1637
|
+
STAGING_1: 'staging_1',
|
|
1638
|
+
STAGING_2: 'staging_2',
|
|
1639
|
+
STAGING_3: 'staging_3',
|
|
1640
|
+
STAGING_4: 'staging_4',
|
|
1641
|
+
STAGING_5: 'staging_5',
|
|
1642
|
+
STAGING_6: 'staging_6',
|
|
1643
|
+
STAGING_7: 'staging_7',
|
|
1644
|
+
STAGING_8: 'staging_8',
|
|
1645
|
+
STAGING_9: 'staging_9',
|
|
1646
|
+
STAGING_10: 'staging_10',
|
|
1647
|
+
STAGING_11: 'staging_11',
|
|
1648
|
+
STAGING_12: 'staging_12',
|
|
1649
|
+
STAGING_13: 'staging_13',
|
|
1650
|
+
STAGING_14: 'staging_14',
|
|
1651
|
+
STAGING_15: 'staging_15'
|
|
1652
|
+
};
|
|
1653
|
+
var WIDGET_URL = [{
|
|
1654
|
+
env: ENV.SANDBOX,
|
|
1655
|
+
url: 'https://widget-sandbox.'
|
|
1656
|
+
}, {
|
|
1657
|
+
env: ENV.SANDBOX_KOVENA,
|
|
1658
|
+
url: 'https://widget-sandbox.'
|
|
1659
|
+
}, {
|
|
1660
|
+
env: ENV.SANDBOX_DEMO,
|
|
1661
|
+
url: 'https://widget-sandbox-demo.'
|
|
1662
|
+
}, {
|
|
1663
|
+
env: ENV.SANDBOX_DEMO_KOVENA,
|
|
1664
|
+
url: 'https://widget-sandbox-demo.'
|
|
1665
|
+
}, {
|
|
1666
|
+
env: ENV.PROD,
|
|
1667
|
+
url: 'https://widget.'
|
|
1668
|
+
}, {
|
|
1669
|
+
env: ENV.STAGING,
|
|
1670
|
+
url: 'https://widsta.'
|
|
1671
|
+
}, {
|
|
1672
|
+
env: ENV.STAGING_1,
|
|
1673
|
+
url: 'https://widsta-1.'
|
|
1674
|
+
}, {
|
|
1675
|
+
env: ENV.STAGING_2,
|
|
1676
|
+
url: 'https://widsta-2.'
|
|
1677
|
+
}, {
|
|
1678
|
+
env: ENV.STAGING_3,
|
|
1679
|
+
url: 'https://widsta-3.'
|
|
1680
|
+
}, {
|
|
1681
|
+
env: ENV.STAGING_4,
|
|
1682
|
+
url: 'https://widsta-4.'
|
|
1683
|
+
}, {
|
|
1684
|
+
env: ENV.STAGING_5,
|
|
1685
|
+
url: 'https://widsta-5.'
|
|
1686
|
+
}, {
|
|
1687
|
+
env: ENV.STAGING_6,
|
|
1688
|
+
url: 'https://widsta-6.'
|
|
1689
|
+
}, {
|
|
1690
|
+
env: ENV.STAGING_7,
|
|
1691
|
+
url: 'https://widsta-7.'
|
|
1692
|
+
}, {
|
|
1693
|
+
env: ENV.STAGING_8,
|
|
1694
|
+
url: 'https://widsta-8.'
|
|
1695
|
+
}, {
|
|
1696
|
+
env: ENV.STAGING_9,
|
|
1697
|
+
url: 'https://widsta-9.'
|
|
1698
|
+
}, {
|
|
1699
|
+
env: ENV.STAGING_10,
|
|
1700
|
+
url: 'https://widsta-10.'
|
|
1701
|
+
}, {
|
|
1702
|
+
env: ENV.STAGING_11,
|
|
1703
|
+
url: 'https://widsta-11.'
|
|
1704
|
+
}, {
|
|
1705
|
+
env: ENV.STAGING_12,
|
|
1706
|
+
url: 'https://widsta-12.'
|
|
1707
|
+
}, {
|
|
1708
|
+
env: ENV.STAGING_13,
|
|
1709
|
+
url: 'https://widsta-13.'
|
|
1710
|
+
}, {
|
|
1711
|
+
env: ENV.STAGING_14,
|
|
1712
|
+
url: 'https://widsta-14.'
|
|
1713
|
+
}, {
|
|
1714
|
+
env: ENV.STAGING_15,
|
|
1715
|
+
url: 'https://widsta-15.'
|
|
1716
|
+
}];
|
|
1717
|
+
var API_URL = [{
|
|
1718
|
+
env: ENV.SANDBOX,
|
|
1719
|
+
url: 'https://api-sandbox.'
|
|
1720
|
+
}, {
|
|
1721
|
+
env: ENV.PROD,
|
|
1722
|
+
url: 'https://api.'
|
|
1723
|
+
}, {
|
|
1724
|
+
env: ENV.STAGING,
|
|
1725
|
+
url: 'https://apista.'
|
|
1726
|
+
}, {
|
|
1727
|
+
env: ENV.STAGING_1,
|
|
1728
|
+
url: 'https://apista-1.'
|
|
1729
|
+
}, {
|
|
1730
|
+
env: ENV.STAGING_2,
|
|
1731
|
+
url: 'https://apista-2.'
|
|
1732
|
+
}, {
|
|
1733
|
+
env: ENV.STAGING_3,
|
|
1734
|
+
url: 'https://apista-3.'
|
|
1735
|
+
}, {
|
|
1736
|
+
env: ENV.STAGING_4,
|
|
1737
|
+
url: 'https://apista-4.'
|
|
1738
|
+
}, {
|
|
1739
|
+
env: ENV.STAGING_5,
|
|
1740
|
+
url: 'https://apista-5.'
|
|
1741
|
+
}, {
|
|
1742
|
+
env: ENV.STAGING_6,
|
|
1743
|
+
url: 'https://apista-6.'
|
|
1744
|
+
}, {
|
|
1745
|
+
env: ENV.STAGING_7,
|
|
1746
|
+
url: 'https://apista-7.'
|
|
1747
|
+
}, {
|
|
1748
|
+
env: ENV.STAGING_8,
|
|
1749
|
+
url: 'https://apista-8.'
|
|
1750
|
+
}, {
|
|
1751
|
+
env: ENV.STAGING_9,
|
|
1752
|
+
url: 'https://apista-9.'
|
|
1753
|
+
}, {
|
|
1754
|
+
env: ENV.STAGING_10,
|
|
1755
|
+
url: 'https://apista-10.'
|
|
1756
|
+
}, {
|
|
1757
|
+
env: ENV.STAGING_11,
|
|
1758
|
+
url: 'https://apista-11.'
|
|
1759
|
+
}, {
|
|
1760
|
+
env: ENV.STAGING_12,
|
|
1761
|
+
url: 'https://apista-12.'
|
|
1762
|
+
}, {
|
|
1763
|
+
env: ENV.STAGING_13,
|
|
1764
|
+
url: 'https://apista-13.'
|
|
1765
|
+
}, {
|
|
1766
|
+
env: ENV.STAGING_14,
|
|
1767
|
+
url: 'https://apista-14.'
|
|
1768
|
+
}, {
|
|
1769
|
+
env: ENV.STAGING_15,
|
|
1770
|
+
url: 'https://apista-15.'
|
|
1771
|
+
}];
|
|
1772
|
+
var ADDITIONAL_ENV = [ENV.SANDBOX_KOVENA, ENV.SANDBOX_DEMO_KOVENA];
|
|
1773
|
+
var REGEX_ALIAS = '^([a-zA-Z0-9](?:(?:[a-zA-Z0-9-.]*(?!-)\\.(?![-.]))*[a-zA-Z0-9]+)?)$';
|
|
1774
|
+
var DEFAULT_ENV = ENV.SANDBOX;
|
|
1775
|
+
var DEFAULT_ALIAS = {
|
|
1776
|
+
PAYDOCK: 'paydock.com',
|
|
1777
|
+
KOVENA: 'kovena.com'
|
|
1778
|
+
};
|
|
1779
|
+
// TODO @ingeniousraccoons we should take advantage of TypeScript mechanism for static environmentId checking and simplified runtime validation
|
|
1780
|
+
// TODO @ingeniousraccoons unify `environment.paydock.ts` and `environment.cba.ts` making them configuration driven
|
|
1781
|
+
var Env = /*#__PURE__*/function () {
|
|
1782
|
+
function Env(configs) {
|
|
1783
|
+
var defaultEnv = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_ENV;
|
|
1784
|
+
_classCallCheck(this, Env);
|
|
1785
|
+
this.environmentConfigurations = configs;
|
|
1786
|
+
this.setEnv(defaultEnv);
|
|
1787
|
+
}
|
|
1788
|
+
return _createClass(Env, [{
|
|
1789
|
+
key: "setEnv",
|
|
1790
|
+
value: function setEnv(environmentId, alias) {
|
|
1791
|
+
this.validateAlias(alias);
|
|
1792
|
+
this.validateEnvironmentId(environmentId);
|
|
1793
|
+
this.environmentId = environmentId;
|
|
1794
|
+
if (alias) {
|
|
1795
|
+
this.alias = alias;
|
|
1796
|
+
} else if (ADDITIONAL_ENV.includes(this.environmentId)) {
|
|
1797
|
+
this.alias = DEFAULT_ALIAS.KOVENA;
|
|
1798
|
+
} else {
|
|
1799
|
+
this.alias = DEFAULT_ALIAS.PAYDOCK;
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
}, {
|
|
1803
|
+
key: "getEnv",
|
|
1804
|
+
value: function getEnv() {
|
|
1805
|
+
return this.environmentId;
|
|
1806
|
+
}
|
|
1807
|
+
}, {
|
|
1808
|
+
key: "getConf",
|
|
1809
|
+
value: function getConf() {
|
|
1810
|
+
for (var index in this.environmentConfigurations) {
|
|
1811
|
+
if (!Object.hasOwn(this.environmentConfigurations, index)) {
|
|
1812
|
+
continue;
|
|
1813
|
+
}
|
|
1814
|
+
if (this.environmentConfigurations[index].env === this.getEnv()) {
|
|
1815
|
+
return {
|
|
1816
|
+
url: this.environmentConfigurations[index].url.indexOf('localhost') !== -1 ? this.environmentConfigurations[index].url : this.environmentConfigurations[index].url + this.alias,
|
|
1817
|
+
env: this.environmentConfigurations[index].env
|
|
1818
|
+
};
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
throw new Error('Env could not obtain configuration. Unknown environmentId.');
|
|
1822
|
+
}
|
|
1823
|
+
}, {
|
|
1824
|
+
key: "validateAlias",
|
|
1825
|
+
value: function validateAlias(alias) {
|
|
1826
|
+
if (typeof alias === 'undefined') {
|
|
1827
|
+
return;
|
|
1828
|
+
}
|
|
1829
|
+
if (typeof alias !== 'string') {
|
|
1830
|
+
throw new TypeError("Env expects parameter 'alias' to be of type 'string' or 'undefined'.");
|
|
1831
|
+
}
|
|
1832
|
+
if (!alias.match(REGEX_ALIAS)) {
|
|
1833
|
+
throw new Error("Env received malformed alias: ".concat(alias, ". Ensure it satisfies the regex: '").concat(REGEX_ALIAS, "'."));
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
}, {
|
|
1837
|
+
key: "validateEnvironmentId",
|
|
1838
|
+
value: function validateEnvironmentId(environmentId) {
|
|
1839
|
+
for (var index in this.environmentConfigurations) {
|
|
1840
|
+
if (!Object.hasOwn(this.environmentConfigurations, index)) {
|
|
1841
|
+
continue;
|
|
1842
|
+
}
|
|
1843
|
+
if (this.environmentConfigurations[index].env === environmentId) {
|
|
1844
|
+
return;
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
throw new TypeError("Env received unknown environmentId: ".concat(environmentId));
|
|
1848
|
+
}
|
|
1849
|
+
}]);
|
|
1850
|
+
}();
|
|
1851
|
+
|
|
1852
|
+
var SDK = /*#__PURE__*/function () {
|
|
1853
|
+
function SDK() {
|
|
1854
|
+
_classCallCheck(this, SDK);
|
|
1855
|
+
}
|
|
1856
|
+
return _createClass(SDK, null, [{
|
|
1857
|
+
key: "version",
|
|
1858
|
+
get: function get() {
|
|
1859
|
+
return SDK._version.trim() || null;
|
|
1860
|
+
}
|
|
1861
|
+
}]);
|
|
1862
|
+
}();
|
|
1863
|
+
SDK.type = 'client';
|
|
1864
|
+
SDK.headerKeys = Object.freeze({
|
|
1865
|
+
version: 'x-sdk-version',
|
|
1866
|
+
type: 'x-sdk-type'
|
|
1867
|
+
});
|
|
1868
|
+
SDK._version = 'v1.145.0-beta';
|
|
1869
|
+
|
|
1870
|
+
var ACCESS_HEADER_NAME = {
|
|
1871
|
+
accessToken: 'x-access-token',
|
|
1872
|
+
publicKey: 'x-user-public-key'
|
|
1873
|
+
};
|
|
1874
|
+
var AccessToken = /*#__PURE__*/function () {
|
|
1875
|
+
function AccessToken() {
|
|
1876
|
+
_classCallCheck(this, AccessToken);
|
|
1877
|
+
}
|
|
1878
|
+
return _createClass(AccessToken, null, [{
|
|
1879
|
+
key: "validateJWT",
|
|
1880
|
+
value: function validateJWT(jwt) {
|
|
1867
1881
|
if (!jwt) return null;
|
|
1868
1882
|
var _jwt$split = jwt.split("."),
|
|
1869
1883
|
_jwt$split2 = _slicedToArray(_jwt$split, 3),
|
|
@@ -1941,7 +1955,140 @@ var AccessToken = /*#__PURE__*/function () {
|
|
|
1941
1955
|
return jwtPattern.test(value);
|
|
1942
1956
|
}
|
|
1943
1957
|
}]);
|
|
1944
|
-
}();
|
|
1958
|
+
}();
|
|
1959
|
+
|
|
1960
|
+
/**
|
|
1961
|
+
* Top-level classification of an error. Used by the SDK to route errors to the
|
|
1962
|
+
* right category in instrumentation and to give consumers a coarse-grained
|
|
1963
|
+
* tag for grouping/filtering. See {@link getErrorCategory} for the mapping
|
|
1964
|
+
* between {@link ERROR_CAUSE} and {@link ERROR_CATEGORY}.
|
|
1965
|
+
*/
|
|
1966
|
+
var ERROR_CATEGORY = {
|
|
1967
|
+
/** SDK was misconfigured (missing keys, invalid options, etc.). */
|
|
1968
|
+
CONFIGURATION: 'configuration',
|
|
1969
|
+
/** Authentication or authorization failure. */
|
|
1970
|
+
IDENTITY: 'identity_access_management',
|
|
1971
|
+
/** SDK internal failure or upstream service problem. */
|
|
1972
|
+
INTERNAL: 'internal',
|
|
1973
|
+
/** Flow lifecycle event (user cancelled, aborted, etc.) — not a real fault. */
|
|
1974
|
+
PROCESS: 'process',
|
|
1975
|
+
/** Resource lookup failed or was rate-limited. */
|
|
1976
|
+
RESOURCE: 'resource',
|
|
1977
|
+
/** Invalid input or business-rule validation failure. */
|
|
1978
|
+
VALIDATION: 'validation'
|
|
1979
|
+
};
|
|
1980
|
+
/**
|
|
1981
|
+
* Concrete cause of an error. More specific than {@link ERROR_CATEGORY} —
|
|
1982
|
+
* useful for deciding programmatic responses (e.g. show a retry button only
|
|
1983
|
+
* when `cause` is `'service_unreachable'` or `'server_busy'`).
|
|
1984
|
+
*/
|
|
1985
|
+
var ERROR_CAUSE = {
|
|
1986
|
+
/** Operation was aborted programmatically. */
|
|
1987
|
+
ABORTED: 'aborted',
|
|
1988
|
+
/** Caller has insufficient permissions for the operation. */
|
|
1989
|
+
ACCESS_FORBIDDEN: 'access_forbidden',
|
|
1990
|
+
/** Resource already exists when create was expected. */
|
|
1991
|
+
ALREADY_EXISTS: 'already_exists',
|
|
1992
|
+
/** User cancelled the flow (e.g. closed the wallet sheet). */
|
|
1993
|
+
CANCELED: 'canceled',
|
|
1994
|
+
/** SDK was instantiated or invoked with invalid configuration. */
|
|
1995
|
+
INVALID_CONFIGURATION: 'invalid_configuration',
|
|
1996
|
+
/** Input failed structural or business-rule validation. */
|
|
1997
|
+
INVALID_INPUT: 'invalid_input',
|
|
1998
|
+
/** Resource was not found by the backend. */
|
|
1999
|
+
NOT_FOUND: 'not_found',
|
|
2000
|
+
/** Operation is not supported in the current context or version. */
|
|
2001
|
+
NOT_IMPLEMENTED: 'not_implemented',
|
|
2002
|
+
/** Caller exceeded the allowed request rate. */
|
|
2003
|
+
RATE_LIMITED: 'rate_limited',
|
|
2004
|
+
/** Backend is healthy but currently overloaded — typically retryable. */
|
|
2005
|
+
SERVER_BUSY: 'server_busy',
|
|
2006
|
+
/** Backend or third-party service could not be reached — typically retryable. */
|
|
2007
|
+
SERVICE_UNREACHABLE: 'service_unreachable',
|
|
2008
|
+
/** Caller is not authenticated. */
|
|
2009
|
+
UNAUTHORIZED: 'unauthorized',
|
|
2010
|
+
/** Catch-all when no other cause applies. */
|
|
2011
|
+
UNKNOWN: 'unknown_error',
|
|
2012
|
+
/** Request was syntactically valid but semantically rejected. */
|
|
2013
|
+
UNPROCESSABLE_ENTITY: 'unprocessable_entity'
|
|
2014
|
+
};
|
|
2015
|
+
var EventError = /*#__PURE__*/function (_Error) {
|
|
2016
|
+
function EventError(cause, category, retryable, details) {
|
|
2017
|
+
var _this;
|
|
2018
|
+
_classCallCheck(this, EventError);
|
|
2019
|
+
_this = _callSuper(this, EventError, [details.message]);
|
|
2020
|
+
_this.cause = cause;
|
|
2021
|
+
_this.category = category;
|
|
2022
|
+
_this.retryable = retryable;
|
|
2023
|
+
_this.details = details;
|
|
2024
|
+
Object.setPrototypeOf(_this, EventError.prototype);
|
|
2025
|
+
_this.name = EventError.name;
|
|
2026
|
+
return _this;
|
|
2027
|
+
}
|
|
2028
|
+
_inherits(EventError, _Error);
|
|
2029
|
+
return _createClass(EventError, [{
|
|
2030
|
+
key: "toJSON",
|
|
2031
|
+
value: function toJSON() {
|
|
2032
|
+
return {
|
|
2033
|
+
error: {
|
|
2034
|
+
category: this.category,
|
|
2035
|
+
cause: this.cause,
|
|
2036
|
+
details: this.details,
|
|
2037
|
+
retryable: this.retryable
|
|
2038
|
+
}
|
|
2039
|
+
};
|
|
2040
|
+
}
|
|
2041
|
+
}, {
|
|
2042
|
+
key: "setContextId",
|
|
2043
|
+
value: function setContextId(contextId) {
|
|
2044
|
+
this.details.contextId = contextId;
|
|
2045
|
+
}
|
|
2046
|
+
}, {
|
|
2047
|
+
key: "setPurpose",
|
|
2048
|
+
value: function setPurpose(purpose) {
|
|
2049
|
+
this.purpose = purpose;
|
|
2050
|
+
}
|
|
2051
|
+
}], [{
|
|
2052
|
+
key: "create",
|
|
2053
|
+
value: function create(cause, message) {
|
|
2054
|
+
var contextId = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
|
|
2055
|
+
var retryable = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
2056
|
+
var details = {
|
|
2057
|
+
cause: cause,
|
|
2058
|
+
contextId: contextId,
|
|
2059
|
+
message: message,
|
|
2060
|
+
timestamp: new Date().toISOString()
|
|
2061
|
+
};
|
|
2062
|
+
var category = getErrorCategory(cause);
|
|
2063
|
+
return new EventError(cause, category, retryable, details);
|
|
2064
|
+
}
|
|
2065
|
+
}]);
|
|
2066
|
+
}(/*#__PURE__*/_wrapNativeSuper(Error));
|
|
2067
|
+
function getErrorCategory(cause) {
|
|
2068
|
+
switch (cause) {
|
|
2069
|
+
case ERROR_CAUSE.INVALID_CONFIGURATION:
|
|
2070
|
+
return ERROR_CATEGORY.CONFIGURATION;
|
|
2071
|
+
case ERROR_CAUSE.ACCESS_FORBIDDEN:
|
|
2072
|
+
case ERROR_CAUSE.UNAUTHORIZED:
|
|
2073
|
+
return ERROR_CATEGORY.IDENTITY;
|
|
2074
|
+
case ERROR_CAUSE.SERVICE_UNREACHABLE:
|
|
2075
|
+
case ERROR_CAUSE.NOT_IMPLEMENTED:
|
|
2076
|
+
case ERROR_CAUSE.SERVER_BUSY:
|
|
2077
|
+
return ERROR_CATEGORY.INTERNAL;
|
|
2078
|
+
case ERROR_CAUSE.ABORTED:
|
|
2079
|
+
case ERROR_CAUSE.CANCELED:
|
|
2080
|
+
return ERROR_CATEGORY.PROCESS;
|
|
2081
|
+
case ERROR_CAUSE.NOT_FOUND:
|
|
2082
|
+
case ERROR_CAUSE.RATE_LIMITED:
|
|
2083
|
+
return ERROR_CATEGORY.RESOURCE;
|
|
2084
|
+
case ERROR_CAUSE.ALREADY_EXISTS:
|
|
2085
|
+
case ERROR_CAUSE.INVALID_INPUT:
|
|
2086
|
+
case ERROR_CAUSE.UNPROCESSABLE_ENTITY:
|
|
2087
|
+
return ERROR_CATEGORY.VALIDATION;
|
|
2088
|
+
default:
|
|
2089
|
+
return ERROR_CATEGORY.INTERNAL;
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
1945
2092
|
|
|
1946
2093
|
var HttpRequest = /*#__PURE__*/function () {
|
|
1947
2094
|
function HttpRequest(request) {
|
|
@@ -4637,18 +4784,23 @@ var ApiBase = /*#__PURE__*/function () {
|
|
|
4637
4784
|
var errorCb = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function (data) {
|
|
4638
4785
|
return undefined;
|
|
4639
4786
|
};
|
|
4787
|
+
var onError = function onError(err) {
|
|
4788
|
+
_this4.reportError(errorRepository, err, _extends(_extends({}, _this4.ctx), {
|
|
4789
|
+
classMethod: 'getClient',
|
|
4790
|
+
description: 'Send unsuccessful.'
|
|
4791
|
+
}));
|
|
4792
|
+
errorCb(err);
|
|
4793
|
+
};
|
|
4640
4794
|
request.onload = function () {
|
|
4641
4795
|
return _this4.parser({
|
|
4642
4796
|
text: request.responseText,
|
|
4643
4797
|
status: request.status
|
|
4644
|
-
}, cb,
|
|
4645
|
-
_this4.reportError(errorRepository, err, _extends(_extends({}, _this4.ctx), {
|
|
4646
|
-
classMethod: 'getClient',
|
|
4647
|
-
description: 'Send unsuccessful.'
|
|
4648
|
-
}));
|
|
4649
|
-
errorCb(err);
|
|
4650
|
-
});
|
|
4798
|
+
}, cb, onError);
|
|
4651
4799
|
};
|
|
4800
|
+
// Transport-level failures (dropped connection, failed CORS
|
|
4801
|
+
// preflight, HTTP/2 protocol error, timeout) never fire `onload`,
|
|
4802
|
+
// so without these handlers the request would fail silently.
|
|
4803
|
+
_this4.attachFailureHandlers(request, onError);
|
|
4652
4804
|
request.send(JSON.stringify(body));
|
|
4653
4805
|
}
|
|
4654
4806
|
};
|
|
@@ -4661,13 +4813,18 @@ var ApiBase = /*#__PURE__*/function () {
|
|
|
4661
4813
|
return {
|
|
4662
4814
|
config: request,
|
|
4663
4815
|
send: function send(body) {
|
|
4664
|
-
return new Promise(function (resolve,
|
|
4816
|
+
return new Promise(function (resolve, reject) {
|
|
4665
4817
|
request.onload = function () {
|
|
4666
4818
|
return resolve({
|
|
4667
4819
|
text: request.responseText,
|
|
4668
4820
|
status: request.status
|
|
4669
4821
|
});
|
|
4670
4822
|
};
|
|
4823
|
+
// Transport-level failures (dropped connection, failed CORS
|
|
4824
|
+
// preflight, HTTP/2 protocol error, timeout) never fire
|
|
4825
|
+
// `onload`, so without these handlers the promise would never
|
|
4826
|
+
// settle and the caller would hang silently.
|
|
4827
|
+
_this5.attachFailureHandlers(request, reject);
|
|
4671
4828
|
request.send(JSON.stringify(body));
|
|
4672
4829
|
}).then(function (value) {
|
|
4673
4830
|
return _this5.parserPromise(value);
|
|
@@ -4719,6 +4876,36 @@ var ApiBase = /*#__PURE__*/function () {
|
|
|
4719
4876
|
return Promise.reject(err);
|
|
4720
4877
|
}
|
|
4721
4878
|
}
|
|
4879
|
+
/**
|
|
4880
|
+
* Wires the XHR failure events that `onload` does not cover. `onload` only
|
|
4881
|
+
* fires when an HTTP response is received (any status, including 4xx/5xx);
|
|
4882
|
+
* transport-level failures — a dropped connection, a failed CORS preflight,
|
|
4883
|
+
* an HTTP/2 protocol error, or a timeout — fire `onerror`/`ontimeout`/
|
|
4884
|
+
* `onabort` instead. Without these the request never settles and fails
|
|
4885
|
+
* silently (e.g. `onUnavailable` is never invoked for wallet callbacks).
|
|
4886
|
+
*/
|
|
4887
|
+
}, {
|
|
4888
|
+
key: "attachFailureHandlers",
|
|
4889
|
+
value: function attachFailureHandlers(request, onFailure) {
|
|
4890
|
+
request.onerror = function () {
|
|
4891
|
+
return onFailure({
|
|
4892
|
+
message: 'Network request failed: the service could not be reached.',
|
|
4893
|
+
code: ERROR_CAUSE.SERVICE_UNREACHABLE
|
|
4894
|
+
});
|
|
4895
|
+
};
|
|
4896
|
+
request.ontimeout = function () {
|
|
4897
|
+
return onFailure({
|
|
4898
|
+
message: 'Network request timed out: the service could not be reached.',
|
|
4899
|
+
code: ERROR_CAUSE.SERVICE_UNREACHABLE
|
|
4900
|
+
});
|
|
4901
|
+
};
|
|
4902
|
+
request.onabort = function () {
|
|
4903
|
+
return onFailure({
|
|
4904
|
+
message: 'Network request was aborted.',
|
|
4905
|
+
code: ERROR_CAUSE.ABORTED
|
|
4906
|
+
});
|
|
4907
|
+
};
|
|
4908
|
+
}
|
|
4722
4909
|
}, {
|
|
4723
4910
|
key: "newApiRequest",
|
|
4724
4911
|
value: function newApiRequest(method, link) {
|
|
@@ -5477,12 +5664,12 @@ var Uuid = /*#__PURE__*/function () {
|
|
|
5477
5664
|
return _createClass(Uuid, null, [{
|
|
5478
5665
|
key: "generate",
|
|
5479
5666
|
value: function generate() {
|
|
5480
|
-
if (typeof window !==
|
|
5667
|
+
if (typeof window !== 'undefined' && typeof window.crypto !== 'undefined' && typeof window.crypto.getRandomValues !== 'undefined') {
|
|
5481
5668
|
var buf = new Uint16Array(8);
|
|
5482
5669
|
window.crypto.getRandomValues(buf);
|
|
5483
|
-
return
|
|
5670
|
+
return Uuid.hash(buf[0]) + Uuid.hash(buf[1]) + '-' + Uuid.hash(buf[2]) + '-' + Uuid.hash(buf[3]) + '-' + Uuid.hash(buf[4]) + '-' + Uuid.hash(buf[5]) + Uuid.hash(buf[6]) + Uuid.hash(buf[7]);
|
|
5484
5671
|
} else {
|
|
5485
|
-
return
|
|
5672
|
+
return Uuid.random() + Uuid.random() + '-' + Uuid.random() + '-' + Uuid.random() + '-' + Uuid.random() + '-' + Uuid.random() + Uuid.random() + Uuid.random();
|
|
5486
5673
|
}
|
|
5487
5674
|
}
|
|
5488
5675
|
}, {
|
|
@@ -5490,14 +5677,22 @@ var Uuid = /*#__PURE__*/function () {
|
|
|
5490
5677
|
value: function hash(number) {
|
|
5491
5678
|
var hash = number.toString(16);
|
|
5492
5679
|
while (hash.length < 4) {
|
|
5493
|
-
hash =
|
|
5680
|
+
hash = '0' + hash;
|
|
5494
5681
|
}
|
|
5495
5682
|
return hash;
|
|
5496
5683
|
}
|
|
5497
5684
|
}, {
|
|
5498
5685
|
key: "random",
|
|
5499
5686
|
value: function random() {
|
|
5500
|
-
|
|
5687
|
+
var value;
|
|
5688
|
+
if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {
|
|
5689
|
+
var buf = new Uint16Array(1);
|
|
5690
|
+
crypto.getRandomValues(buf);
|
|
5691
|
+
value = buf[0] / 0x10000;
|
|
5692
|
+
} else {
|
|
5693
|
+
value = Math.random();
|
|
5694
|
+
}
|
|
5695
|
+
return Math.floor((1 + value) * 0x10000).toString(16).substring(1);
|
|
5501
5696
|
}
|
|
5502
5697
|
}]);
|
|
5503
5698
|
}();
|
|
@@ -8172,7 +8367,7 @@ var AfterPayWalletService = /*#__PURE__*/function (_WalletService) {
|
|
|
8172
8367
|
}]);
|
|
8173
8368
|
}(WalletService);
|
|
8174
8369
|
|
|
8175
|
-
/*! @license DOMPurify 3.4.
|
|
8370
|
+
/*! @license DOMPurify 3.4.11 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.11/LICENSE */
|
|
8176
8371
|
|
|
8177
8372
|
var purify_cjs;
|
|
8178
8373
|
var hasRequiredPurify_cjs;
|
|
@@ -8181,22 +8376,63 @@ function requirePurify_cjs () {
|
|
|
8181
8376
|
if (hasRequiredPurify_cjs) return purify_cjs;
|
|
8182
8377
|
hasRequiredPurify_cjs = 1;
|
|
8183
8378
|
|
|
8184
|
-
|
|
8185
|
-
|
|
8186
|
-
|
|
8187
|
-
|
|
8188
|
-
|
|
8189
|
-
|
|
8190
|
-
|
|
8191
|
-
|
|
8192
|
-
|
|
8193
|
-
|
|
8194
|
-
|
|
8195
|
-
|
|
8196
|
-
|
|
8197
|
-
|
|
8198
|
-
|
|
8199
|
-
|
|
8379
|
+
function _arrayLikeToArray(r, a) {
|
|
8380
|
+
(null == a || a > r.length) && (a = r.length);
|
|
8381
|
+
for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
|
|
8382
|
+
return n;
|
|
8383
|
+
}
|
|
8384
|
+
function _arrayWithHoles(r) {
|
|
8385
|
+
if (Array.isArray(r)) return r;
|
|
8386
|
+
}
|
|
8387
|
+
function _iterableToArrayLimit(r, l) {
|
|
8388
|
+
var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
|
|
8389
|
+
if (null != t) {
|
|
8390
|
+
var e,
|
|
8391
|
+
n,
|
|
8392
|
+
i,
|
|
8393
|
+
u,
|
|
8394
|
+
a = [],
|
|
8395
|
+
f = true,
|
|
8396
|
+
o = false;
|
|
8397
|
+
try {
|
|
8398
|
+
if (i = (t = t.call(r)).next, 0 === l) ; else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
|
|
8399
|
+
} catch (r) {
|
|
8400
|
+
o = true, n = r;
|
|
8401
|
+
} finally {
|
|
8402
|
+
try {
|
|
8403
|
+
if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
|
|
8404
|
+
} finally {
|
|
8405
|
+
if (o) throw n;
|
|
8406
|
+
}
|
|
8407
|
+
}
|
|
8408
|
+
return a;
|
|
8409
|
+
}
|
|
8410
|
+
}
|
|
8411
|
+
function _nonIterableRest() {
|
|
8412
|
+
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
8413
|
+
}
|
|
8414
|
+
function _slicedToArray(r, e) {
|
|
8415
|
+
return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
|
|
8416
|
+
}
|
|
8417
|
+
function _unsupportedIterableToArray(r, a) {
|
|
8418
|
+
if (r) {
|
|
8419
|
+
if ("string" == typeof r) return _arrayLikeToArray(r, a);
|
|
8420
|
+
var t = {}.toString.call(r).slice(8, -1);
|
|
8421
|
+
return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
|
|
8422
|
+
}
|
|
8423
|
+
}
|
|
8424
|
+
|
|
8425
|
+
const entries = Object.entries,
|
|
8426
|
+
setPrototypeOf = Object.setPrototypeOf,
|
|
8427
|
+
isFrozen = Object.isFrozen,
|
|
8428
|
+
getPrototypeOf = Object.getPrototypeOf,
|
|
8429
|
+
getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
|
|
8430
|
+
let freeze = Object.freeze,
|
|
8431
|
+
seal = Object.seal,
|
|
8432
|
+
create = Object.create; // eslint-disable-line import/no-mutable-exports
|
|
8433
|
+
let _ref = typeof Reflect !== 'undefined' && Reflect,
|
|
8434
|
+
apply = _ref.apply,
|
|
8435
|
+
construct = _ref.construct;
|
|
8200
8436
|
if (!freeze) {
|
|
8201
8437
|
freeze = function freeze(x) {
|
|
8202
8438
|
return x;
|
|
@@ -8228,13 +8464,19 @@ function requirePurify_cjs () {
|
|
|
8228
8464
|
const arrayPop = unapply(Array.prototype.pop);
|
|
8229
8465
|
const arrayPush = unapply(Array.prototype.push);
|
|
8230
8466
|
const arraySplice = unapply(Array.prototype.splice);
|
|
8467
|
+
const arrayIsArray = Array.isArray;
|
|
8231
8468
|
const stringToLowerCase = unapply(String.prototype.toLowerCase);
|
|
8232
8469
|
const stringToString = unapply(String.prototype.toString);
|
|
8233
8470
|
const stringMatch = unapply(String.prototype.match);
|
|
8234
8471
|
const stringReplace = unapply(String.prototype.replace);
|
|
8235
8472
|
const stringIndexOf = unapply(String.prototype.indexOf);
|
|
8236
8473
|
const stringTrim = unapply(String.prototype.trim);
|
|
8474
|
+
const numberToString = unapply(Number.prototype.toString);
|
|
8475
|
+
const booleanToString = unapply(Boolean.prototype.toString);
|
|
8476
|
+
const bigintToString = typeof BigInt === 'undefined' ? null : unapply(BigInt.prototype.toString);
|
|
8477
|
+
const symbolToString = typeof Symbol === 'undefined' ? null : unapply(Symbol.prototype.toString);
|
|
8237
8478
|
const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
|
|
8479
|
+
const objectToString = unapply(Object.prototype.toString);
|
|
8238
8480
|
const regExpTest = unapply(RegExp.prototype.test);
|
|
8239
8481
|
const typeErrorCreate = unconstruct(TypeError);
|
|
8240
8482
|
/**
|
|
@@ -8284,6 +8526,9 @@ function requirePurify_cjs () {
|
|
|
8284
8526
|
// Prevent prototype setters from intercepting set as a this value.
|
|
8285
8527
|
setPrototypeOf(set, null);
|
|
8286
8528
|
}
|
|
8529
|
+
if (!arrayIsArray(array)) {
|
|
8530
|
+
return set;
|
|
8531
|
+
}
|
|
8287
8532
|
let l = array.length;
|
|
8288
8533
|
while (l--) {
|
|
8289
8534
|
let element = array[l];
|
|
@@ -8324,10 +8569,13 @@ function requirePurify_cjs () {
|
|
|
8324
8569
|
*/
|
|
8325
8570
|
function clone(object) {
|
|
8326
8571
|
const newObject = create(null);
|
|
8327
|
-
for (const
|
|
8572
|
+
for (const _ref2 of entries(object)) {
|
|
8573
|
+
var _ref3 = _slicedToArray(_ref2, 2);
|
|
8574
|
+
const property = _ref3[0];
|
|
8575
|
+
const value = _ref3[1];
|
|
8328
8576
|
const isPropertyExist = objectHasOwnProperty(object, property);
|
|
8329
8577
|
if (isPropertyExist) {
|
|
8330
|
-
if (
|
|
8578
|
+
if (arrayIsArray(value)) {
|
|
8331
8579
|
newObject[property] = cleanArray(value);
|
|
8332
8580
|
} else if (value && typeof value === 'object' && value.constructor === Object) {
|
|
8333
8581
|
newObject[property] = clone(value);
|
|
@@ -8338,6 +8586,58 @@ function requirePurify_cjs () {
|
|
|
8338
8586
|
}
|
|
8339
8587
|
return newObject;
|
|
8340
8588
|
}
|
|
8589
|
+
/**
|
|
8590
|
+
* Convert non-node values into strings without depending on direct property access.
|
|
8591
|
+
*
|
|
8592
|
+
* @param value - The value to stringify.
|
|
8593
|
+
* @returns A string representation of the provided value.
|
|
8594
|
+
*/
|
|
8595
|
+
function stringifyValue(value) {
|
|
8596
|
+
switch (typeof value) {
|
|
8597
|
+
case 'string':
|
|
8598
|
+
{
|
|
8599
|
+
return value;
|
|
8600
|
+
}
|
|
8601
|
+
case 'number':
|
|
8602
|
+
{
|
|
8603
|
+
return numberToString(value);
|
|
8604
|
+
}
|
|
8605
|
+
case 'boolean':
|
|
8606
|
+
{
|
|
8607
|
+
return booleanToString(value);
|
|
8608
|
+
}
|
|
8609
|
+
case 'bigint':
|
|
8610
|
+
{
|
|
8611
|
+
return bigintToString ? bigintToString(value) : '0';
|
|
8612
|
+
}
|
|
8613
|
+
case 'symbol':
|
|
8614
|
+
{
|
|
8615
|
+
return symbolToString ? symbolToString(value) : 'Symbol()';
|
|
8616
|
+
}
|
|
8617
|
+
case 'undefined':
|
|
8618
|
+
{
|
|
8619
|
+
return objectToString(value);
|
|
8620
|
+
}
|
|
8621
|
+
case 'function':
|
|
8622
|
+
case 'object':
|
|
8623
|
+
{
|
|
8624
|
+
if (value === null) {
|
|
8625
|
+
return objectToString(value);
|
|
8626
|
+
}
|
|
8627
|
+
const valueAsRecord = value;
|
|
8628
|
+
const valueToString = lookupGetter(valueAsRecord, 'toString');
|
|
8629
|
+
if (typeof valueToString === 'function') {
|
|
8630
|
+
const stringified = valueToString(valueAsRecord);
|
|
8631
|
+
return typeof stringified === 'string' ? stringified : objectToString(stringified);
|
|
8632
|
+
}
|
|
8633
|
+
return objectToString(value);
|
|
8634
|
+
}
|
|
8635
|
+
default:
|
|
8636
|
+
{
|
|
8637
|
+
return objectToString(value);
|
|
8638
|
+
}
|
|
8639
|
+
}
|
|
8640
|
+
}
|
|
8341
8641
|
/**
|
|
8342
8642
|
* This method automatically checks if the prop is function or getter and behaves accordingly.
|
|
8343
8643
|
*
|
|
@@ -8363,6 +8663,14 @@ function requirePurify_cjs () {
|
|
|
8363
8663
|
}
|
|
8364
8664
|
return fallbackValue;
|
|
8365
8665
|
}
|
|
8666
|
+
function isRegex(value) {
|
|
8667
|
+
try {
|
|
8668
|
+
regExpTest(value, '');
|
|
8669
|
+
return true;
|
|
8670
|
+
} catch (_unused) {
|
|
8671
|
+
return false;
|
|
8672
|
+
}
|
|
8673
|
+
}
|
|
8366
8674
|
|
|
8367
8675
|
const html$1 = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'search', 'section', 'select', 'shadow', 'slot', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']);
|
|
8368
8676
|
const svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'enterkeyhint', 'exportparts', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'inputmode', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'part', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);
|
|
@@ -8378,15 +8686,14 @@ function requirePurify_cjs () {
|
|
|
8378
8686
|
const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
|
|
8379
8687
|
const text = freeze(['#text']);
|
|
8380
8688
|
|
|
8381
|
-
const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns'
|
|
8689
|
+
const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'command', 'commandfor', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns']);
|
|
8382
8690
|
const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'exponent', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'intercept', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'mask-type', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
|
|
8383
8691
|
const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnalign', 'columnlines', 'columnspacing', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lquote', 'lspace', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
|
|
8384
8692
|
const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
|
|
8385
8693
|
|
|
8386
|
-
|
|
8387
|
-
const
|
|
8388
|
-
const
|
|
8389
|
-
const TMPLIT_EXPR = seal(/\$\{[\w\W]*/gm); // eslint-disable-line unicorn/better-regex
|
|
8694
|
+
const MUSTACHE_EXPR = seal(/{{[\w\W]*|^[\w\W]*}}/g);
|
|
8695
|
+
const ERB_EXPR = seal(/<%[\w\W]*|^[\w\W]*%>/g);
|
|
8696
|
+
const TMPLIT_EXPR = seal(/\${[\w\W]*/g);
|
|
8390
8697
|
const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); // eslint-disable-line no-useless-escape
|
|
8391
8698
|
const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
|
|
8392
8699
|
const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
|
|
@@ -8396,30 +8703,31 @@ function requirePurify_cjs () {
|
|
|
8396
8703
|
);
|
|
8397
8704
|
const DOCTYPE_NAME = seal(/^html$/i);
|
|
8398
8705
|
const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
|
|
8706
|
+
// Markup-significant character probes used by _sanitizeElements.
|
|
8707
|
+
// Shared module-level instances are safe despite the sticky /g flags:
|
|
8708
|
+
// unapply() resets lastIndex for RegExp receivers before every call.
|
|
8709
|
+
const ELEMENT_MARKUP_PROBE = seal(/<[/\w!]/g);
|
|
8710
|
+
const COMMENT_MARKUP_PROBE = seal(/<[/\w]/g);
|
|
8711
|
+
const FALLBACK_TAG_CLOSE = seal(/<\/no(script|embed|frames)/i);
|
|
8712
|
+
const SELF_CLOSING_TAG = seal(/\/>/i);
|
|
8399
8713
|
|
|
8400
|
-
var EXPRESSIONS = /*#__PURE__*/Object.freeze({
|
|
8401
|
-
__proto__: null,
|
|
8402
|
-
ARIA_ATTR: ARIA_ATTR,
|
|
8403
|
-
ATTR_WHITESPACE: ATTR_WHITESPACE,
|
|
8404
|
-
CUSTOM_ELEMENT: CUSTOM_ELEMENT,
|
|
8405
|
-
DATA_ATTR: DATA_ATTR,
|
|
8406
|
-
DOCTYPE_NAME: DOCTYPE_NAME,
|
|
8407
|
-
ERB_EXPR: ERB_EXPR,
|
|
8408
|
-
IS_ALLOWED_URI: IS_ALLOWED_URI,
|
|
8409
|
-
IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
|
|
8410
|
-
MUSTACHE_EXPR: MUSTACHE_EXPR,
|
|
8411
|
-
TMPLIT_EXPR: TMPLIT_EXPR
|
|
8412
|
-
});
|
|
8413
|
-
|
|
8414
|
-
/* eslint-disable @typescript-eslint/indent */
|
|
8415
8714
|
// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
|
|
8416
8715
|
const NODE_TYPE = {
|
|
8417
8716
|
element: 1,
|
|
8717
|
+
attribute: 2,
|
|
8418
8718
|
text: 3,
|
|
8719
|
+
cdataSection: 4,
|
|
8720
|
+
entityReference: 5,
|
|
8419
8721
|
// Deprecated
|
|
8420
|
-
|
|
8722
|
+
entityNode: 6,
|
|
8723
|
+
// Deprecated
|
|
8724
|
+
processingInstruction: 7,
|
|
8421
8725
|
comment: 8,
|
|
8422
|
-
document: 9
|
|
8726
|
+
document: 9,
|
|
8727
|
+
documentType: 10,
|
|
8728
|
+
documentFragment: 11,
|
|
8729
|
+
notation: 12 // Deprecated
|
|
8730
|
+
};
|
|
8423
8731
|
const getGlobal = function getGlobal() {
|
|
8424
8732
|
return typeof window === 'undefined' ? null : window;
|
|
8425
8733
|
};
|
|
@@ -8474,10 +8782,25 @@ function requirePurify_cjs () {
|
|
|
8474
8782
|
uponSanitizeShadowNode: []
|
|
8475
8783
|
};
|
|
8476
8784
|
};
|
|
8785
|
+
/**
|
|
8786
|
+
* Resolve a set-valued configuration option: a fresh set built from
|
|
8787
|
+
* cfg[key] when it is an own array property (seeded with a clone of
|
|
8788
|
+
* options.base when given, case-normalized via options.transform),
|
|
8789
|
+
* the fallback set otherwise.
|
|
8790
|
+
*
|
|
8791
|
+
* @param cfg the cloned, prototype-free configuration object
|
|
8792
|
+
* @param key the configuration property to read
|
|
8793
|
+
* @param fallback the set to use when the option is absent or not an array
|
|
8794
|
+
* @param options transform and optional base set to merge into
|
|
8795
|
+
* @returns the resolved set
|
|
8796
|
+
*/
|
|
8797
|
+
const _resolveSetOption = function _resolveSetOption(cfg, key, fallback, options) {
|
|
8798
|
+
return objectHasOwnProperty(cfg, key) && arrayIsArray(cfg[key]) ? addToSet(options.base ? clone(options.base) : {}, cfg[key], options.transform) : fallback;
|
|
8799
|
+
};
|
|
8477
8800
|
function createDOMPurify() {
|
|
8478
8801
|
let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
|
|
8479
8802
|
const DOMPurify = root => createDOMPurify(root);
|
|
8480
|
-
DOMPurify.version = '3.4.
|
|
8803
|
+
DOMPurify.version = '3.4.11';
|
|
8481
8804
|
DOMPurify.removed = [];
|
|
8482
8805
|
if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
|
|
8483
8806
|
// Not running in a browser, provide a factory function
|
|
@@ -8485,28 +8808,29 @@ function requirePurify_cjs () {
|
|
|
8485
8808
|
DOMPurify.isSupported = false;
|
|
8486
8809
|
return DOMPurify;
|
|
8487
8810
|
}
|
|
8488
|
-
let
|
|
8489
|
-
document
|
|
8490
|
-
} = window;
|
|
8811
|
+
let document = window.document;
|
|
8491
8812
|
const originalDocument = document;
|
|
8492
8813
|
const currentScript = originalDocument.currentScript;
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
|
|
8498
|
-
|
|
8499
|
-
NamedNodeMap
|
|
8500
|
-
HTMLFormElement
|
|
8501
|
-
DOMParser,
|
|
8502
|
-
trustedTypes
|
|
8503
|
-
} = window;
|
|
8814
|
+
window.DocumentFragment;
|
|
8815
|
+
const HTMLTemplateElement = window.HTMLTemplateElement,
|
|
8816
|
+
Node = window.Node,
|
|
8817
|
+
Element = window.Element,
|
|
8818
|
+
NodeFilter = window.NodeFilter,
|
|
8819
|
+
_window$NamedNodeMap = window.NamedNodeMap;
|
|
8820
|
+
_window$NamedNodeMap === void 0 ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap;
|
|
8821
|
+
window.HTMLFormElement;
|
|
8822
|
+
const DOMParser = window.DOMParser,
|
|
8823
|
+
trustedTypes = window.trustedTypes;
|
|
8504
8824
|
const ElementPrototype = Element.prototype;
|
|
8505
8825
|
const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
|
|
8506
8826
|
const remove = lookupGetter(ElementPrototype, 'remove');
|
|
8507
8827
|
const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
|
|
8508
8828
|
const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
|
|
8509
8829
|
const getParentNode = lookupGetter(ElementPrototype, 'parentNode');
|
|
8830
|
+
const getShadowRoot = lookupGetter(ElementPrototype, 'shadowRoot');
|
|
8831
|
+
const getAttributes = lookupGetter(ElementPrototype, 'attributes');
|
|
8832
|
+
const getNodeType = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeType') : null;
|
|
8833
|
+
const getNodeName = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeName') : null;
|
|
8510
8834
|
// As per issue #47, the web-components registry is inherited by a
|
|
8511
8835
|
// new document created via createHTMLDocument. As per the spec
|
|
8512
8836
|
// (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
|
|
@@ -8521,33 +8845,74 @@ function requirePurify_cjs () {
|
|
|
8521
8845
|
}
|
|
8522
8846
|
let trustedTypesPolicy;
|
|
8523
8847
|
let emptyHTML = '';
|
|
8524
|
-
|
|
8525
|
-
|
|
8526
|
-
|
|
8527
|
-
|
|
8528
|
-
|
|
8529
|
-
|
|
8530
|
-
|
|
8531
|
-
|
|
8532
|
-
|
|
8848
|
+
// The instance's own internal Trusted Types policy. Unlike a caller-supplied
|
|
8849
|
+
// `TRUSTED_TYPES_POLICY`, this is created at most once — Trusted Types throws
|
|
8850
|
+
// on duplicate policy names — and is the only policy allowed to persist
|
|
8851
|
+
// across configurations and survive `clearConfig()`.
|
|
8852
|
+
let defaultTrustedTypesPolicy;
|
|
8853
|
+
let defaultTrustedTypesPolicyResolved = false;
|
|
8854
|
+
// Tracks whether we are already inside a call to the configured Trusted Types
|
|
8855
|
+
// policy (`createHTML` or `createScriptURL`). If a supplied policy callback
|
|
8856
|
+
// itself calls `DOMPurify.sanitize` (the cause of #1422), `sanitize` would
|
|
8857
|
+
// re-enter the policy and recurse until the stack overflows. We detect that
|
|
8858
|
+
// re-entry and throw a clear, actionable error instead. The guard is shared
|
|
8859
|
+
// across both callbacks, because either one re-entering `sanitize` triggers
|
|
8860
|
+
// the same unbounded recursion.
|
|
8861
|
+
let IN_TRUSTED_TYPES_POLICY = 0;
|
|
8862
|
+
const _assertNotInTrustedTypesPolicy = function _assertNotInTrustedTypesPolicy() {
|
|
8863
|
+
if (IN_TRUSTED_TYPES_POLICY > 0) {
|
|
8864
|
+
throw typeErrorCreate('A configured TRUSTED_TYPES_POLICY callback (createHTML or ' + 'createScriptURL) must not call DOMPurify.sanitize, as that causes ' + 'infinite recursion. Do not pass a policy whose callbacks wrap ' + 'DOMPurify as TRUSTED_TYPES_POLICY; see the "DOMPurify and Trusted ' + 'Types" section of the README.');
|
|
8865
|
+
}
|
|
8866
|
+
};
|
|
8867
|
+
const _createTrustedHTML = function _createTrustedHTML(html) {
|
|
8868
|
+
_assertNotInTrustedTypesPolicy();
|
|
8869
|
+
IN_TRUSTED_TYPES_POLICY++;
|
|
8870
|
+
try {
|
|
8871
|
+
return trustedTypesPolicy.createHTML(html);
|
|
8872
|
+
} finally {
|
|
8873
|
+
IN_TRUSTED_TYPES_POLICY--;
|
|
8874
|
+
}
|
|
8875
|
+
};
|
|
8876
|
+
const _createTrustedScriptURL = function _createTrustedScriptURL(scriptUrl) {
|
|
8877
|
+
_assertNotInTrustedTypesPolicy();
|
|
8878
|
+
IN_TRUSTED_TYPES_POLICY++;
|
|
8879
|
+
try {
|
|
8880
|
+
return trustedTypesPolicy.createScriptURL(scriptUrl);
|
|
8881
|
+
} finally {
|
|
8882
|
+
IN_TRUSTED_TYPES_POLICY--;
|
|
8883
|
+
}
|
|
8884
|
+
};
|
|
8885
|
+
// Lazily resolve (and cache) the instance's internal default policy.
|
|
8886
|
+
// Resolution is attempted at most once: a successful `createPolicy` cannot be
|
|
8887
|
+
// repeated (Trusted Types throws on duplicate names), and a failed or
|
|
8888
|
+
// unsupported attempt must not be retried on every parse.
|
|
8889
|
+
const _getDefaultTrustedTypesPolicy = function _getDefaultTrustedTypesPolicy() {
|
|
8890
|
+
if (!defaultTrustedTypesPolicyResolved) {
|
|
8891
|
+
defaultTrustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
|
|
8892
|
+
defaultTrustedTypesPolicyResolved = true;
|
|
8893
|
+
}
|
|
8894
|
+
return defaultTrustedTypesPolicy;
|
|
8895
|
+
};
|
|
8896
|
+
const _document = document,
|
|
8897
|
+
implementation = _document.implementation,
|
|
8898
|
+
createNodeIterator = _document.createNodeIterator,
|
|
8899
|
+
createDocumentFragment = _document.createDocumentFragment,
|
|
8900
|
+
getElementsByTagName = _document.getElementsByTagName;
|
|
8901
|
+
const importNode = originalDocument.importNode;
|
|
8533
8902
|
let hooks = _createHooksMap();
|
|
8534
8903
|
/**
|
|
8535
8904
|
* Expose whether this browser supports running the full DOMPurify.
|
|
8536
8905
|
*/
|
|
8537
8906
|
DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;
|
|
8538
|
-
const
|
|
8539
|
-
|
|
8540
|
-
|
|
8541
|
-
|
|
8542
|
-
|
|
8543
|
-
|
|
8544
|
-
|
|
8545
|
-
|
|
8546
|
-
|
|
8547
|
-
} = EXPRESSIONS;
|
|
8548
|
-
let {
|
|
8549
|
-
IS_ALLOWED_URI: IS_ALLOWED_URI$1
|
|
8550
|
-
} = EXPRESSIONS;
|
|
8907
|
+
const MUSTACHE_EXPR$1 = MUSTACHE_EXPR,
|
|
8908
|
+
ERB_EXPR$1 = ERB_EXPR,
|
|
8909
|
+
TMPLIT_EXPR$1 = TMPLIT_EXPR,
|
|
8910
|
+
DATA_ATTR$1 = DATA_ATTR,
|
|
8911
|
+
ARIA_ATTR$1 = ARIA_ATTR,
|
|
8912
|
+
IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA,
|
|
8913
|
+
ATTR_WHITESPACE$1 = ATTR_WHITESPACE,
|
|
8914
|
+
CUSTOM_ELEMENT$1 = CUSTOM_ELEMENT;
|
|
8915
|
+
let IS_ALLOWED_URI$1 = IS_ALLOWED_URI;
|
|
8551
8916
|
/**
|
|
8552
8917
|
* We consider the elements and attributes below to be safe. Ideally
|
|
8553
8918
|
* don't add any new ones but feel free to remove unwanted ones.
|
|
@@ -8624,6 +8989,13 @@ function requirePurify_cjs () {
|
|
|
8624
8989
|
let WHOLE_DOCUMENT = false;
|
|
8625
8990
|
/* Track whether config is already set on this instance of DOMPurify. */
|
|
8626
8991
|
let SET_CONFIG = false;
|
|
8992
|
+
/* Pristine allowlist bindings captured at setConfig() time. On the
|
|
8993
|
+
* persistent-config path sanitize() restores the sets from these before
|
|
8994
|
+
* the per-walk hook clone-guard, so a hook's in-call widening cannot
|
|
8995
|
+
* carry across calls. Null until setConfig() is called; reset by
|
|
8996
|
+
* clearConfig(). */
|
|
8997
|
+
let SET_CONFIG_ALLOWED_TAGS = null;
|
|
8998
|
+
let SET_CONFIG_ALLOWED_ATTR = null;
|
|
8627
8999
|
/* Decide if all elements (e.g. style, script) must be children of
|
|
8628
9000
|
* document.body. By default, browsers might move them to document.head */
|
|
8629
9001
|
let FORCE_BODY = false;
|
|
@@ -8666,7 +9038,17 @@ function requirePurify_cjs () {
|
|
|
8666
9038
|
let USE_PROFILES = {};
|
|
8667
9039
|
/* Tags to ignore content of when KEEP_CONTENT is true */
|
|
8668
9040
|
let FORBID_CONTENTS = null;
|
|
8669
|
-
const DEFAULT_FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script',
|
|
9041
|
+
const DEFAULT_FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script',
|
|
9042
|
+
// <selectedcontent> mirrors the selected <option>'s subtree, cloned by
|
|
9043
|
+
// the UA (customizable <select>) — including any on* handlers — and the
|
|
9044
|
+
// engine re-mirrors synchronously whenever a removal changes which
|
|
9045
|
+
// option/selectedcontent is current, even inside DOMPurify's inert
|
|
9046
|
+
// DOMParser document. Hoisting its children on removal re-inserts a fresh
|
|
9047
|
+
// mirror target ahead of the walk, which the engine refills, looping
|
|
9048
|
+
// forever (DoS) and amplifying output. Dropping its content on removal
|
|
9049
|
+
// (rather than hoisting) breaks that cascade; the content is a duplicate
|
|
9050
|
+
// of the option, which is sanitized on its own. See campaign-3 F1/F6.
|
|
9051
|
+
'selectedcontent', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']);
|
|
8670
9052
|
/* Tags that are safe for data: URIs */
|
|
8671
9053
|
let DATA_URI_TAGS = null;
|
|
8672
9054
|
const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);
|
|
@@ -8682,8 +9064,10 @@ function requirePurify_cjs () {
|
|
|
8682
9064
|
/* Allowed XHTML+XML namespaces */
|
|
8683
9065
|
let ALLOWED_NAMESPACES = null;
|
|
8684
9066
|
const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);
|
|
8685
|
-
|
|
8686
|
-
let
|
|
9067
|
+
const DEFAULT_MATHML_TEXT_INTEGRATION_POINTS = freeze(['mi', 'mo', 'mn', 'ms', 'mtext']);
|
|
9068
|
+
let MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, DEFAULT_MATHML_TEXT_INTEGRATION_POINTS);
|
|
9069
|
+
const DEFAULT_HTML_INTEGRATION_POINTS = freeze(['annotation-xml']);
|
|
9070
|
+
let HTML_INTEGRATION_POINTS = addToSet({}, DEFAULT_HTML_INTEGRATION_POINTS);
|
|
8687
9071
|
// Certain elements are allowed in both SVG and HTML
|
|
8688
9072
|
// namespace. We need to specify them explicitly
|
|
8689
9073
|
// so that they don't get erroneously deleted from
|
|
@@ -8725,15 +9109,33 @@ function requirePurify_cjs () {
|
|
|
8725
9109
|
// HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
|
|
8726
9110
|
transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
|
|
8727
9111
|
/* Set configuration parameters */
|
|
8728
|
-
ALLOWED_TAGS =
|
|
8729
|
-
|
|
8730
|
-
|
|
8731
|
-
|
|
8732
|
-
|
|
8733
|
-
|
|
8734
|
-
|
|
8735
|
-
|
|
8736
|
-
|
|
9112
|
+
ALLOWED_TAGS = _resolveSetOption(cfg, 'ALLOWED_TAGS', DEFAULT_ALLOWED_TAGS, {
|
|
9113
|
+
transform: transformCaseFunc
|
|
9114
|
+
});
|
|
9115
|
+
ALLOWED_ATTR = _resolveSetOption(cfg, 'ALLOWED_ATTR', DEFAULT_ALLOWED_ATTR, {
|
|
9116
|
+
transform: transformCaseFunc
|
|
9117
|
+
});
|
|
9118
|
+
ALLOWED_NAMESPACES = _resolveSetOption(cfg, 'ALLOWED_NAMESPACES', DEFAULT_ALLOWED_NAMESPACES, {
|
|
9119
|
+
transform: stringToString
|
|
9120
|
+
});
|
|
9121
|
+
URI_SAFE_ATTRIBUTES = _resolveSetOption(cfg, 'ADD_URI_SAFE_ATTR', DEFAULT_URI_SAFE_ATTRIBUTES, {
|
|
9122
|
+
transform: transformCaseFunc,
|
|
9123
|
+
base: DEFAULT_URI_SAFE_ATTRIBUTES
|
|
9124
|
+
});
|
|
9125
|
+
DATA_URI_TAGS = _resolveSetOption(cfg, 'ADD_DATA_URI_TAGS', DEFAULT_DATA_URI_TAGS, {
|
|
9126
|
+
transform: transformCaseFunc,
|
|
9127
|
+
base: DEFAULT_DATA_URI_TAGS
|
|
9128
|
+
});
|
|
9129
|
+
FORBID_CONTENTS = _resolveSetOption(cfg, 'FORBID_CONTENTS', DEFAULT_FORBID_CONTENTS, {
|
|
9130
|
+
transform: transformCaseFunc
|
|
9131
|
+
});
|
|
9132
|
+
FORBID_TAGS = _resolveSetOption(cfg, 'FORBID_TAGS', clone({}), {
|
|
9133
|
+
transform: transformCaseFunc
|
|
9134
|
+
});
|
|
9135
|
+
FORBID_ATTR = _resolveSetOption(cfg, 'FORBID_ATTR', clone({}), {
|
|
9136
|
+
transform: transformCaseFunc
|
|
9137
|
+
});
|
|
9138
|
+
USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES && typeof cfg.USE_PROFILES === 'object' ? clone(cfg.USE_PROFILES) : cfg.USE_PROFILES : false;
|
|
8737
9139
|
ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
|
|
8738
9140
|
ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
|
|
8739
9141
|
ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
|
|
@@ -8749,20 +9151,22 @@ function requirePurify_cjs () {
|
|
|
8749
9151
|
SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false
|
|
8750
9152
|
KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
|
|
8751
9153
|
IN_PLACE = cfg.IN_PLACE || false; // Default false
|
|
8752
|
-
IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP
|
|
8753
|
-
NAMESPACE = cfg.NAMESPACE
|
|
8754
|
-
MATHML_TEXT_INTEGRATION_POINTS = cfg.MATHML_TEXT_INTEGRATION_POINTS
|
|
8755
|
-
HTML_INTEGRATION_POINTS = cfg.HTML_INTEGRATION_POINTS
|
|
8756
|
-
|
|
8757
|
-
|
|
8758
|
-
|
|
9154
|
+
IS_ALLOWED_URI$1 = isRegex(cfg.ALLOWED_URI_REGEXP) ? cfg.ALLOWED_URI_REGEXP : IS_ALLOWED_URI; // Default regexp
|
|
9155
|
+
NAMESPACE = typeof cfg.NAMESPACE === 'string' ? cfg.NAMESPACE : HTML_NAMESPACE; // Default HTML namespace
|
|
9156
|
+
MATHML_TEXT_INTEGRATION_POINTS = objectHasOwnProperty(cfg, 'MATHML_TEXT_INTEGRATION_POINTS') && cfg.MATHML_TEXT_INTEGRATION_POINTS && typeof cfg.MATHML_TEXT_INTEGRATION_POINTS === 'object' ? clone(cfg.MATHML_TEXT_INTEGRATION_POINTS) : addToSet({}, DEFAULT_MATHML_TEXT_INTEGRATION_POINTS); // Default built-in map
|
|
9157
|
+
HTML_INTEGRATION_POINTS = objectHasOwnProperty(cfg, 'HTML_INTEGRATION_POINTS') && cfg.HTML_INTEGRATION_POINTS && typeof cfg.HTML_INTEGRATION_POINTS === 'object' ? clone(cfg.HTML_INTEGRATION_POINTS) : addToSet({}, DEFAULT_HTML_INTEGRATION_POINTS); // Default built-in map
|
|
9158
|
+
const customElementHandling = objectHasOwnProperty(cfg, 'CUSTOM_ELEMENT_HANDLING') && cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING === 'object' ? clone(cfg.CUSTOM_ELEMENT_HANDLING) : create(null);
|
|
9159
|
+
CUSTOM_ELEMENT_HANDLING = create(null);
|
|
9160
|
+
if (objectHasOwnProperty(customElementHandling, 'tagNameCheck') && isRegexOrFunction(customElementHandling.tagNameCheck)) {
|
|
9161
|
+
CUSTOM_ELEMENT_HANDLING.tagNameCheck = customElementHandling.tagNameCheck; // Default undefined
|
|
8759
9162
|
}
|
|
8760
|
-
if (
|
|
8761
|
-
CUSTOM_ELEMENT_HANDLING.attributeNameCheck =
|
|
9163
|
+
if (objectHasOwnProperty(customElementHandling, 'attributeNameCheck') && isRegexOrFunction(customElementHandling.attributeNameCheck)) {
|
|
9164
|
+
CUSTOM_ELEMENT_HANDLING.attributeNameCheck = customElementHandling.attributeNameCheck; // Default undefined
|
|
8762
9165
|
}
|
|
8763
|
-
if (
|
|
8764
|
-
CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements =
|
|
9166
|
+
if (objectHasOwnProperty(customElementHandling, 'allowCustomizedBuiltInElements') && typeof customElementHandling.allowCustomizedBuiltInElements === 'boolean') {
|
|
9167
|
+
CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = customElementHandling.allowCustomizedBuiltInElements; // Default undefined
|
|
8765
9168
|
}
|
|
9169
|
+
seal(CUSTOM_ELEMENT_HANDLING);
|
|
8766
9170
|
if (SAFE_FOR_TEMPLATES) {
|
|
8767
9171
|
ALLOW_DATA_ATTR = false;
|
|
8768
9172
|
}
|
|
@@ -8798,36 +9202,36 @@ function requirePurify_cjs () {
|
|
|
8798
9202
|
EXTRA_ELEMENT_HANDLING.tagCheck = null;
|
|
8799
9203
|
EXTRA_ELEMENT_HANDLING.attributeCheck = null;
|
|
8800
9204
|
/* Merge configuration parameters */
|
|
8801
|
-
if (cfg
|
|
9205
|
+
if (objectHasOwnProperty(cfg, 'ADD_TAGS')) {
|
|
8802
9206
|
if (typeof cfg.ADD_TAGS === 'function') {
|
|
8803
9207
|
EXTRA_ELEMENT_HANDLING.tagCheck = cfg.ADD_TAGS;
|
|
8804
|
-
} else {
|
|
9208
|
+
} else if (arrayIsArray(cfg.ADD_TAGS)) {
|
|
8805
9209
|
if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
|
|
8806
9210
|
ALLOWED_TAGS = clone(ALLOWED_TAGS);
|
|
8807
9211
|
}
|
|
8808
9212
|
addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
|
|
8809
9213
|
}
|
|
8810
9214
|
}
|
|
8811
|
-
if (cfg
|
|
9215
|
+
if (objectHasOwnProperty(cfg, 'ADD_ATTR')) {
|
|
8812
9216
|
if (typeof cfg.ADD_ATTR === 'function') {
|
|
8813
9217
|
EXTRA_ELEMENT_HANDLING.attributeCheck = cfg.ADD_ATTR;
|
|
8814
|
-
} else {
|
|
9218
|
+
} else if (arrayIsArray(cfg.ADD_ATTR)) {
|
|
8815
9219
|
if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
|
|
8816
9220
|
ALLOWED_ATTR = clone(ALLOWED_ATTR);
|
|
8817
9221
|
}
|
|
8818
9222
|
addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
|
|
8819
9223
|
}
|
|
8820
9224
|
}
|
|
8821
|
-
if (cfg.ADD_URI_SAFE_ATTR) {
|
|
9225
|
+
if (objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') && arrayIsArray(cfg.ADD_URI_SAFE_ATTR)) {
|
|
8822
9226
|
addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
|
|
8823
9227
|
}
|
|
8824
|
-
if (cfg.FORBID_CONTENTS) {
|
|
9228
|
+
if (objectHasOwnProperty(cfg, 'FORBID_CONTENTS') && arrayIsArray(cfg.FORBID_CONTENTS)) {
|
|
8825
9229
|
if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
|
|
8826
9230
|
FORBID_CONTENTS = clone(FORBID_CONTENTS);
|
|
8827
9231
|
}
|
|
8828
9232
|
addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
|
|
8829
9233
|
}
|
|
8830
|
-
if (cfg.ADD_FORBID_CONTENTS) {
|
|
9234
|
+
if (objectHasOwnProperty(cfg, 'ADD_FORBID_CONTENTS') && arrayIsArray(cfg.ADD_FORBID_CONTENTS)) {
|
|
8831
9235
|
if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
|
|
8832
9236
|
FORBID_CONTENTS = clone(FORBID_CONTENTS);
|
|
8833
9237
|
}
|
|
@@ -8846,6 +9250,13 @@ function requirePurify_cjs () {
|
|
|
8846
9250
|
addToSet(ALLOWED_TAGS, ['tbody']);
|
|
8847
9251
|
delete FORBID_TAGS.tbody;
|
|
8848
9252
|
}
|
|
9253
|
+
// Re-derive the active Trusted Types policy from this configuration on
|
|
9254
|
+
// every parse. The active policy must never be sticky closure state that
|
|
9255
|
+
// outlives the config that set it: a caller-supplied policy left in place
|
|
9256
|
+
// after `clearConfig()` — or after a later call that supplied none, or
|
|
9257
|
+
// `TRUSTED_TYPES_POLICY: null` — could sign a subsequent "default"
|
|
9258
|
+
// `RETURN_TRUSTED_TYPE` result with a foreign, possibly unsafe policy.
|
|
9259
|
+
// See GHSA-vxr8-fq34-vvx9.
|
|
8849
9260
|
if (cfg.TRUSTED_TYPES_POLICY) {
|
|
8850
9261
|
if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {
|
|
8851
9262
|
throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');
|
|
@@ -8853,18 +9264,45 @@ function requirePurify_cjs () {
|
|
|
8853
9264
|
if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {
|
|
8854
9265
|
throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');
|
|
8855
9266
|
}
|
|
8856
|
-
//
|
|
9267
|
+
// A caller-supplied policy applies to this configuration only.
|
|
9268
|
+
const previousTrustedTypesPolicy = trustedTypesPolicy;
|
|
8857
9269
|
trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;
|
|
8858
|
-
// Sign local variables required by `sanitize`.
|
|
8859
|
-
|
|
9270
|
+
// Sign local variables required by `sanitize`. If the supplied policy's
|
|
9271
|
+
// `createHTML` is circular (i.e. it calls `DOMPurify.sanitize`), this
|
|
9272
|
+
// throws via the re-entrancy guard. Restore the previous policy first so
|
|
9273
|
+
// the instance is not left in a poisoned state. See #1422.
|
|
9274
|
+
try {
|
|
9275
|
+
emptyHTML = _createTrustedHTML('');
|
|
9276
|
+
} catch (error) {
|
|
9277
|
+
trustedTypesPolicy = previousTrustedTypesPolicy;
|
|
9278
|
+
throw error;
|
|
9279
|
+
}
|
|
9280
|
+
} else if (cfg.TRUSTED_TYPES_POLICY === null) {
|
|
9281
|
+
// Explicit opt-out for this call: perform no Trusted Types signing and
|
|
9282
|
+
// create nothing (so a strict `trusted-types` CSP that disallows a
|
|
9283
|
+
// `dompurify` policy can still call `sanitize` from inside its own
|
|
9284
|
+
// policy — see #1422). Resetting to `undefined` rather than a sticky
|
|
9285
|
+
// `null` also drops any previously retained caller policy, so it cannot
|
|
9286
|
+
// resurface on a later call, while still allowing the next config-less
|
|
9287
|
+
// call to restore the internal default policy. See GHSA-vxr8-fq34-vvx9.
|
|
9288
|
+
trustedTypesPolicy = undefined;
|
|
9289
|
+
emptyHTML = '';
|
|
8860
9290
|
} else {
|
|
8861
|
-
//
|
|
9291
|
+
// No policy supplied: keep the currently active policy if one is set — a
|
|
9292
|
+
// previously supplied policy is intentionally sticky across config-less
|
|
9293
|
+
// calls — otherwise fall back to the instance's own internal policy,
|
|
9294
|
+
// created at most once. (A policy supplied for a *single* call still
|
|
9295
|
+
// lingers by design; what must not linger is a policy whose configuration
|
|
9296
|
+
// has been torn down via `clearConfig()`, which restores the default.)
|
|
8862
9297
|
if (trustedTypesPolicy === undefined) {
|
|
8863
|
-
trustedTypesPolicy =
|
|
9298
|
+
trustedTypesPolicy = _getDefaultTrustedTypesPolicy();
|
|
8864
9299
|
}
|
|
8865
|
-
//
|
|
8866
|
-
|
|
8867
|
-
|
|
9300
|
+
// Sign internal variables only when a policy is active. A falsy policy
|
|
9301
|
+
// (Trusted Types unsupported, creation failed, or an explicit opt-out)
|
|
9302
|
+
// leaves `emptyHTML` as a plain string, so we never call `.createHTML` on
|
|
9303
|
+
// a non-policy and throw. See #1422.
|
|
9304
|
+
if (trustedTypesPolicy && typeof emptyHTML === 'string') {
|
|
9305
|
+
emptyHTML = _createTrustedHTML('');
|
|
8868
9306
|
}
|
|
8869
9307
|
}
|
|
8870
9308
|
// Prevent further manipulation of configuration.
|
|
@@ -8879,6 +9317,77 @@ function requirePurify_cjs () {
|
|
|
8879
9317
|
* correctly. */
|
|
8880
9318
|
const ALL_SVG_TAGS = addToSet({}, [...svg$1, ...svgFilters, ...svgDisallowed]);
|
|
8881
9319
|
const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]);
|
|
9320
|
+
/**
|
|
9321
|
+
* Namespace rules for an element in the SVG namespace.
|
|
9322
|
+
*
|
|
9323
|
+
* @param tagName the element's lowercase tag name
|
|
9324
|
+
* @param parent the (possibly simulated) parent node
|
|
9325
|
+
* @param parentTagName the parent's lowercase tag name
|
|
9326
|
+
* @returns true if a spec-compliant parser could produce this element
|
|
9327
|
+
*/
|
|
9328
|
+
const _checkSvgNamespace = function _checkSvgNamespace(tagName, parent, parentTagName) {
|
|
9329
|
+
// The only way to switch from HTML namespace to SVG
|
|
9330
|
+
// is via <svg>. If it happens via any other tag, then
|
|
9331
|
+
// it should be killed.
|
|
9332
|
+
if (parent.namespaceURI === HTML_NAMESPACE) {
|
|
9333
|
+
return tagName === 'svg';
|
|
9334
|
+
}
|
|
9335
|
+
// The only way to switch from MathML to SVG is via <svg>
|
|
9336
|
+
// if the parent is either <annotation-xml> or a MathML
|
|
9337
|
+
// text integration point.
|
|
9338
|
+
if (parent.namespaceURI === MATHML_NAMESPACE) {
|
|
9339
|
+
return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
|
|
9340
|
+
}
|
|
9341
|
+
// We only allow elements that are defined in SVG
|
|
9342
|
+
// spec. All others are disallowed in SVG namespace.
|
|
9343
|
+
return Boolean(ALL_SVG_TAGS[tagName]);
|
|
9344
|
+
};
|
|
9345
|
+
/**
|
|
9346
|
+
* Namespace rules for an element in the MathML namespace.
|
|
9347
|
+
*
|
|
9348
|
+
* @param tagName the element's lowercase tag name
|
|
9349
|
+
* @param parent the (possibly simulated) parent node
|
|
9350
|
+
* @param parentTagName the parent's lowercase tag name
|
|
9351
|
+
* @returns true if a spec-compliant parser could produce this element
|
|
9352
|
+
*/
|
|
9353
|
+
const _checkMathMlNamespace = function _checkMathMlNamespace(tagName, parent, parentTagName) {
|
|
9354
|
+
// The only way to switch from HTML namespace to MathML
|
|
9355
|
+
// is via <math>. If it happens via any other tag, then
|
|
9356
|
+
// it should be killed.
|
|
9357
|
+
if (parent.namespaceURI === HTML_NAMESPACE) {
|
|
9358
|
+
return tagName === 'math';
|
|
9359
|
+
}
|
|
9360
|
+
// The only way to switch from SVG to MathML is via
|
|
9361
|
+
// <math> and HTML integration points
|
|
9362
|
+
if (parent.namespaceURI === SVG_NAMESPACE) {
|
|
9363
|
+
return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
|
|
9364
|
+
}
|
|
9365
|
+
// We only allow elements that are defined in MathML
|
|
9366
|
+
// spec. All others are disallowed in MathML namespace.
|
|
9367
|
+
return Boolean(ALL_MATHML_TAGS[tagName]);
|
|
9368
|
+
};
|
|
9369
|
+
/**
|
|
9370
|
+
* Namespace rules for an element in the HTML namespace.
|
|
9371
|
+
*
|
|
9372
|
+
* @param tagName the element's lowercase tag name
|
|
9373
|
+
* @param parent the (possibly simulated) parent node
|
|
9374
|
+
* @param parentTagName the parent's lowercase tag name
|
|
9375
|
+
* @returns true if a spec-compliant parser could produce this element
|
|
9376
|
+
*/
|
|
9377
|
+
const _checkHtmlNamespace = function _checkHtmlNamespace(tagName, parent, parentTagName) {
|
|
9378
|
+
// The only way to switch from SVG to HTML is via
|
|
9379
|
+
// HTML integration points, and from MathML to HTML
|
|
9380
|
+
// is via MathML text integration points
|
|
9381
|
+
if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
|
|
9382
|
+
return false;
|
|
9383
|
+
}
|
|
9384
|
+
if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
|
|
9385
|
+
return false;
|
|
9386
|
+
}
|
|
9387
|
+
// We disallow tags that are specific for MathML
|
|
9388
|
+
// or SVG and should never appear in HTML namespace
|
|
9389
|
+
return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
|
|
9390
|
+
};
|
|
8882
9391
|
/**
|
|
8883
9392
|
* @param element a DOM element whose namespace is being checked
|
|
8884
9393
|
* @returns Return false if the element has a
|
|
@@ -8901,51 +9410,13 @@ function requirePurify_cjs () {
|
|
|
8901
9410
|
return false;
|
|
8902
9411
|
}
|
|
8903
9412
|
if (element.namespaceURI === SVG_NAMESPACE) {
|
|
8904
|
-
|
|
8905
|
-
// is via <svg>. If it happens via any other tag, then
|
|
8906
|
-
// it should be killed.
|
|
8907
|
-
if (parent.namespaceURI === HTML_NAMESPACE) {
|
|
8908
|
-
return tagName === 'svg';
|
|
8909
|
-
}
|
|
8910
|
-
// The only way to switch from MathML to SVG is via`
|
|
8911
|
-
// svg if parent is either <annotation-xml> or MathML
|
|
8912
|
-
// text integration points.
|
|
8913
|
-
if (parent.namespaceURI === MATHML_NAMESPACE) {
|
|
8914
|
-
return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
|
|
8915
|
-
}
|
|
8916
|
-
// We only allow elements that are defined in SVG
|
|
8917
|
-
// spec. All others are disallowed in SVG namespace.
|
|
8918
|
-
return Boolean(ALL_SVG_TAGS[tagName]);
|
|
9413
|
+
return _checkSvgNamespace(tagName, parent, parentTagName);
|
|
8919
9414
|
}
|
|
8920
9415
|
if (element.namespaceURI === MATHML_NAMESPACE) {
|
|
8921
|
-
|
|
8922
|
-
// is via <math>. If it happens via any other tag, then
|
|
8923
|
-
// it should be killed.
|
|
8924
|
-
if (parent.namespaceURI === HTML_NAMESPACE) {
|
|
8925
|
-
return tagName === 'math';
|
|
8926
|
-
}
|
|
8927
|
-
// The only way to switch from SVG to MathML is via
|
|
8928
|
-
// <math> and HTML integration points
|
|
8929
|
-
if (parent.namespaceURI === SVG_NAMESPACE) {
|
|
8930
|
-
return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
|
|
8931
|
-
}
|
|
8932
|
-
// We only allow elements that are defined in MathML
|
|
8933
|
-
// spec. All others are disallowed in MathML namespace.
|
|
8934
|
-
return Boolean(ALL_MATHML_TAGS[tagName]);
|
|
9416
|
+
return _checkMathMlNamespace(tagName, parent, parentTagName);
|
|
8935
9417
|
}
|
|
8936
9418
|
if (element.namespaceURI === HTML_NAMESPACE) {
|
|
8937
|
-
|
|
8938
|
-
// HTML integration points, and from MathML to HTML
|
|
8939
|
-
// is via MathML text integration points
|
|
8940
|
-
if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
|
|
8941
|
-
return false;
|
|
8942
|
-
}
|
|
8943
|
-
if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
|
|
8944
|
-
return false;
|
|
8945
|
-
}
|
|
8946
|
-
// We disallow tags that are specific for MathML
|
|
8947
|
-
// or SVG and should never appear in HTML namespace
|
|
8948
|
-
return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
|
|
9419
|
+
return _checkHtmlNamespace(tagName, parent, parentTagName);
|
|
8949
9420
|
}
|
|
8950
9421
|
// For XHTML and XML documents that support custom namespaces
|
|
8951
9422
|
if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {
|
|
@@ -8970,7 +9441,74 @@ function requirePurify_cjs () {
|
|
|
8970
9441
|
// eslint-disable-next-line unicorn/prefer-dom-node-remove
|
|
8971
9442
|
getParentNode(node).removeChild(node);
|
|
8972
9443
|
} catch (_) {
|
|
9444
|
+
/* The normal detach failed — this is reached for a parentless node
|
|
9445
|
+
(getParentNode() is null, so .removeChild throws). Element.prototype
|
|
9446
|
+
.remove() is itself a spec no-op on a parentless node, so a recorded
|
|
9447
|
+
"removal" would otherwise hand the caller back an intact,
|
|
9448
|
+
payload-bearing node (e.g. a detached IN_PLACE root the mXSS canary or
|
|
9449
|
+
the style-with-element-child rule decided to kill). Fail closed by
|
|
9450
|
+
throwing — exactly as a clobbered root does at the IN_PLACE entry —
|
|
9451
|
+
rather than trying to "neutralize" the node via its own methods.
|
|
9452
|
+
Neutralizing would mean calling getAttributeNames()/removeAttribute()
|
|
9453
|
+
on the node, both of which a <form> root can clobber via a named child
|
|
9454
|
+
(and _isClobbered does not even probe getAttributeNames), so the
|
|
9455
|
+
neutralize step could itself be silently defeated, leaving the payload
|
|
9456
|
+
intact. A throw touches only the cached, clobber-safe remove() and
|
|
9457
|
+
getParentNode(). Generalizes GHSA-r47g-fvhr-h676 (clobbered-form root)
|
|
9458
|
+
to every root-kill reason. REPORT-3.
|
|
9459
|
+
This lives inside the catch, so it never fires for a normally-removed
|
|
9460
|
+
in-tree node: those have a parent, removeChild() succeeds, and the
|
|
9461
|
+
catch is not entered. Only a kept (parentless) root reaches here. */
|
|
8973
9462
|
remove(node);
|
|
9463
|
+
if (!getParentNode(node)) {
|
|
9464
|
+
throw typeErrorCreate('a node selected for removal could not be detached from its tree ' + 'and cannot be safely returned; refusing to sanitize in place');
|
|
9465
|
+
}
|
|
9466
|
+
}
|
|
9467
|
+
};
|
|
9468
|
+
/**
|
|
9469
|
+
* _neutralizeRoot
|
|
9470
|
+
*
|
|
9471
|
+
* Fail-closed teardown of an in-place root after the sanitize walk aborts
|
|
9472
|
+
* (campaign-3 F2). An internal throw mid-walk — e.g. a page-registered
|
|
9473
|
+
* custom element's reaction detaches a node so `_forceRemove`'s deliberate
|
|
9474
|
+
* parentless guard throws, or any other re-entrant engine mutation — would
|
|
9475
|
+
* otherwise leave the caller's *live* tree half-sanitized, with everything
|
|
9476
|
+
* after the abort point still carrying its handlers. There is no safe way
|
|
9477
|
+
* to resume the walk (the tree mutated under us), so we strip the root bare:
|
|
9478
|
+
* remove every child and every attribute, then let the caller's catch see
|
|
9479
|
+
* the original error. Clobber-safe (cached `remove`/`childNodes`/`attributes`
|
|
9480
|
+
* getters; the root was already clobber-pre-flighted at the IN_PLACE entry).
|
|
9481
|
+
*
|
|
9482
|
+
* @param root the in-place root to empty
|
|
9483
|
+
*/
|
|
9484
|
+
const _neutralizeRoot = function _neutralizeRoot(root) {
|
|
9485
|
+
const childNodes = getChildNodes(root);
|
|
9486
|
+
if (childNodes) {
|
|
9487
|
+
const snapshot = [];
|
|
9488
|
+
arrayForEach(childNodes, child => {
|
|
9489
|
+
arrayPush(snapshot, child);
|
|
9490
|
+
});
|
|
9491
|
+
arrayForEach(snapshot, child => {
|
|
9492
|
+
try {
|
|
9493
|
+
remove(child);
|
|
9494
|
+
} catch (_) {
|
|
9495
|
+
/* Best-effort teardown; a still-attached child is handled below */
|
|
9496
|
+
}
|
|
9497
|
+
});
|
|
9498
|
+
}
|
|
9499
|
+
const attributes = getAttributes(root);
|
|
9500
|
+
if (attributes) {
|
|
9501
|
+
for (let i = attributes.length - 1; i >= 0; --i) {
|
|
9502
|
+
const attribute = attributes[i];
|
|
9503
|
+
const name = attribute && attribute.name;
|
|
9504
|
+
if (typeof name === 'string') {
|
|
9505
|
+
try {
|
|
9506
|
+
root.removeAttribute(name);
|
|
9507
|
+
} catch (_) {
|
|
9508
|
+
/* Clobbered removeAttribute — ignore (fail-closed best effort) */
|
|
9509
|
+
}
|
|
9510
|
+
}
|
|
9511
|
+
}
|
|
8974
9512
|
}
|
|
8975
9513
|
};
|
|
8976
9514
|
/**
|
|
@@ -9005,6 +9543,72 @@ function requirePurify_cjs () {
|
|
|
9005
9543
|
}
|
|
9006
9544
|
}
|
|
9007
9545
|
};
|
|
9546
|
+
/**
|
|
9547
|
+
* _stripDisallowedAttributes
|
|
9548
|
+
*
|
|
9549
|
+
* Removes every attribute the active configuration does not allow from a
|
|
9550
|
+
* single element, using the same allowlist as the main attribute pass (so
|
|
9551
|
+
* `on*` handlers go, but no `/^on/` blocklist is introduced). Used only to
|
|
9552
|
+
* neutralise nodes that are being discarded from an in-place tree.
|
|
9553
|
+
*
|
|
9554
|
+
* @param element the element to strip
|
|
9555
|
+
*/
|
|
9556
|
+
const _stripDisallowedAttributes = function _stripDisallowedAttributes(element) {
|
|
9557
|
+
const attributes = getAttributes(element);
|
|
9558
|
+
if (!attributes) {
|
|
9559
|
+
return;
|
|
9560
|
+
}
|
|
9561
|
+
for (let i = attributes.length - 1; i >= 0; --i) {
|
|
9562
|
+
const attribute = attributes[i];
|
|
9563
|
+
const name = attribute && attribute.name;
|
|
9564
|
+
if (typeof name !== 'string' || ALLOWED_ATTR[transformCaseFunc(name)]) {
|
|
9565
|
+
continue;
|
|
9566
|
+
}
|
|
9567
|
+
try {
|
|
9568
|
+
element.removeAttribute(name);
|
|
9569
|
+
} catch (_) {
|
|
9570
|
+
/* Clobbered removeAttribute on a doomed node — ignore */
|
|
9571
|
+
}
|
|
9572
|
+
}
|
|
9573
|
+
};
|
|
9574
|
+
/**
|
|
9575
|
+
* _neutralizeSubtree
|
|
9576
|
+
*
|
|
9577
|
+
* Completes the audit-5 F1 fix across every removal path. The KEEP_CONTENT
|
|
9578
|
+
* move-hoist neutralises only disallowed-tag removals; clobber, mXSS-canary,
|
|
9579
|
+
* namespace, comment, processing-instruction and KEEP_CONTENT:false removals
|
|
9580
|
+
* all drop their subtree wholesale via `_forceRemove`. On the IN_PLACE path
|
|
9581
|
+
* those dropped nodes are detached from the caller's LIVE tree but a
|
|
9582
|
+
* handler-bearing original among them (an `<img onerror>`/`<video>` that was
|
|
9583
|
+
* loading) keeps its queued resource event, which fires in page scope after
|
|
9584
|
+
* sanitize returns. This walks a removed subtree and strips every attribute
|
|
9585
|
+
* the active configuration does not allow — so `on*` handlers are cancelled
|
|
9586
|
+
* through the SAME allowlist that governs kept nodes, not a separate `/^on/`
|
|
9587
|
+
* blocklist. Run synchronously before sanitize returns, i.e. before any
|
|
9588
|
+
* queued event can fire. Hook-free by design: these nodes leave the output,
|
|
9589
|
+
* so firing attribute hooks for them would be surprising. Clobber-safe reads;
|
|
9590
|
+
* a doomed clobbered node may shadow `removeAttribute` (its own attributes are
|
|
9591
|
+
* irrelevant — it is discarded — while its non-clobbered descendants, e.g.
|
|
9592
|
+
* the `<img>`, are reached and scrubbed).
|
|
9593
|
+
*
|
|
9594
|
+
* @param root the root of a removed subtree to neutralise
|
|
9595
|
+
*/
|
|
9596
|
+
const _neutralizeSubtree = function _neutralizeSubtree(root) {
|
|
9597
|
+
const stack = [root];
|
|
9598
|
+
while (stack.length > 0) {
|
|
9599
|
+
const node = stack.pop();
|
|
9600
|
+
const nodeType = getNodeType ? getNodeType(node) : node.nodeType;
|
|
9601
|
+
if (nodeType === NODE_TYPE.element) {
|
|
9602
|
+
_stripDisallowedAttributes(node);
|
|
9603
|
+
}
|
|
9604
|
+
const childNodes = getChildNodes(node);
|
|
9605
|
+
if (childNodes) {
|
|
9606
|
+
for (let i = childNodes.length - 1; i >= 0; --i) {
|
|
9607
|
+
stack.push(childNodes[i]);
|
|
9608
|
+
}
|
|
9609
|
+
}
|
|
9610
|
+
}
|
|
9611
|
+
};
|
|
9008
9612
|
/**
|
|
9009
9613
|
* _initDocument
|
|
9010
9614
|
*
|
|
@@ -9026,7 +9630,7 @@ function requirePurify_cjs () {
|
|
|
9026
9630
|
// Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)
|
|
9027
9631
|
dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
|
|
9028
9632
|
}
|
|
9029
|
-
const dirtyPayload = trustedTypesPolicy ?
|
|
9633
|
+
const dirtyPayload = trustedTypesPolicy ? _createTrustedHTML(dirty) : dirty;
|
|
9030
9634
|
/*
|
|
9031
9635
|
* Use the DOMParser API by default, fallback later if needs be
|
|
9032
9636
|
* DOMParser not work for svg when has multiple root element.
|
|
@@ -9066,29 +9670,254 @@ function requirePurify_cjs () {
|
|
|
9066
9670
|
// eslint-disable-next-line no-bitwise
|
|
9067
9671
|
NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);
|
|
9068
9672
|
};
|
|
9673
|
+
/**
|
|
9674
|
+
* Replace template expression syntax (mustache, ERB, template
|
|
9675
|
+
* literal) with a space; shared by all SAFE_FOR_TEMPLATES scrub
|
|
9676
|
+
* sites. Order matters: mustache, then ERB, then template literal.
|
|
9677
|
+
*
|
|
9678
|
+
* @param value the string to scrub
|
|
9679
|
+
* @returns the scrubbed string
|
|
9680
|
+
*/
|
|
9681
|
+
const _stripTemplateExpressions = function _stripTemplateExpressions(value) {
|
|
9682
|
+
value = stringReplace(value, MUSTACHE_EXPR$1, ' ');
|
|
9683
|
+
value = stringReplace(value, ERB_EXPR$1, ' ');
|
|
9684
|
+
value = stringReplace(value, TMPLIT_EXPR$1, ' ');
|
|
9685
|
+
return value;
|
|
9686
|
+
};
|
|
9687
|
+
/**
|
|
9688
|
+
* Strip template-engine expressions ({{...}}, ${...}, <%...%>) from the
|
|
9689
|
+
* character data of an element subtree. Used as the final safety net for
|
|
9690
|
+
* SAFE_FOR_TEMPLATES on every DOM-returning code path so that expressions
|
|
9691
|
+
* which only form after text-node normalization (e.g. fragments split across
|
|
9692
|
+
* stripped elements) cannot survive into a template-evaluating framework.
|
|
9693
|
+
*
|
|
9694
|
+
* Walks text/comment/CDATA/processing-instruction nodes and mutates `.data`
|
|
9695
|
+
* in place rather than round-tripping through innerHTML. This preserves
|
|
9696
|
+
* descendant node references (important for IN_PLACE callers), avoids a
|
|
9697
|
+
* serialize/reparse cycle, and reads literal character data — which means
|
|
9698
|
+
* `<%...%>` in text content matches the ERB regex against its real bytes
|
|
9699
|
+
* instead of the HTML-entity-escaped form innerHTML would produce.
|
|
9700
|
+
*
|
|
9701
|
+
* Attribute values are not visited here; SAFE_FOR_TEMPLATES handling for
|
|
9702
|
+
* attributes is performed during the per-node `_sanitizeAttributes` pass.
|
|
9703
|
+
*
|
|
9704
|
+
* @param node The root element whose character data should be scrubbed.
|
|
9705
|
+
*/
|
|
9706
|
+
const _scrubTemplateExpressions2 = function _scrubTemplateExpressions(node) {
|
|
9707
|
+
var _node$querySelectorAl;
|
|
9708
|
+
node.normalize();
|
|
9709
|
+
const walker = createNodeIterator.call(node.ownerDocument || node, node,
|
|
9710
|
+
// eslint-disable-next-line no-bitwise
|
|
9711
|
+
NodeFilter.SHOW_TEXT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_CDATA_SECTION | NodeFilter.SHOW_PROCESSING_INSTRUCTION, null);
|
|
9712
|
+
let currentNode = walker.nextNode();
|
|
9713
|
+
while (currentNode) {
|
|
9714
|
+
currentNode.data = _stripTemplateExpressions(currentNode.data);
|
|
9715
|
+
currentNode = walker.nextNode();
|
|
9716
|
+
}
|
|
9717
|
+
// NodeIterator does not descend into <template>.content per the DOM spec,
|
|
9718
|
+
// so we must explicitly recurse into each template's content fragment,
|
|
9719
|
+
// mirroring the approach used by _sanitizeShadowDOM.
|
|
9720
|
+
const templates = (_node$querySelectorAl = node.querySelectorAll) === null || _node$querySelectorAl === void 0 ? void 0 : _node$querySelectorAl.call(node, 'template');
|
|
9721
|
+
if (templates) {
|
|
9722
|
+
arrayForEach(templates, tmpl => {
|
|
9723
|
+
if (_isDocumentFragment(tmpl.content)) {
|
|
9724
|
+
_scrubTemplateExpressions2(tmpl.content);
|
|
9725
|
+
}
|
|
9726
|
+
});
|
|
9727
|
+
}
|
|
9728
|
+
};
|
|
9069
9729
|
/**
|
|
9070
9730
|
* _isClobbered
|
|
9071
9731
|
*
|
|
9732
|
+
* Detect DOM-clobbering on HTMLFormElement nodes. Form is the only HTML
|
|
9733
|
+
* interface with [LegacyOverrideBuiltIns]; a descendant element with a
|
|
9734
|
+
* `name` attribute matching a prototype property shadows that property
|
|
9735
|
+
* on direct reads. We use this check at the IN_PLACE entry-point and
|
|
9736
|
+
* during attribute sanitization to refuse clobbered forms.
|
|
9737
|
+
*
|
|
9072
9738
|
* @param element element to check for clobbering attacks
|
|
9073
9739
|
* @return true if clobbered, false if safe
|
|
9074
9740
|
*/
|
|
9075
9741
|
const _isClobbered = function _isClobbered(element) {
|
|
9076
|
-
|
|
9742
|
+
// Realm-independent tag-name probe. If we can't determine the tag
|
|
9743
|
+
// name at all, we can't reason about clobbering — return false
|
|
9744
|
+
// (the caller's other defences still apply).
|
|
9745
|
+
const realTagName = getNodeName ? getNodeName(element) : null;
|
|
9746
|
+
if (typeof realTagName !== 'string') {
|
|
9747
|
+
return false;
|
|
9748
|
+
}
|
|
9749
|
+
if (transformCaseFunc(realTagName) !== 'form') {
|
|
9750
|
+
return false;
|
|
9751
|
+
}
|
|
9752
|
+
return typeof element.nodeName !== 'string' || typeof element.textContent !== 'string' || typeof element.removeChild !== 'function' ||
|
|
9753
|
+
// Realm-safe NamedNodeMap detection: equality against the cached
|
|
9754
|
+
// prototype getter. Clobbered .attributes (e.g. <input name="attributes">)
|
|
9755
|
+
// makes the direct read diverge from the cached read; a clean form
|
|
9756
|
+
// (same-realm OR foreign-realm) has both reads pointing at the same
|
|
9757
|
+
// canonical NamedNodeMap.
|
|
9758
|
+
element.attributes !== getAttributes(element) || typeof element.removeAttribute !== 'function' || typeof element.setAttribute !== 'function' || typeof element.namespaceURI !== 'string' || typeof element.insertBefore !== 'function' || typeof element.hasChildNodes !== 'function' ||
|
|
9759
|
+
// NodeType clobbering probe. Cached Node.prototype.nodeType getter
|
|
9760
|
+
// returns the integer 1 for any Element regardless of realm; direct
|
|
9761
|
+
// read on a clobbered form (e.g. <input name="nodeType">) returns
|
|
9762
|
+
// the named child element. Cheap addition — nodeType is read from
|
|
9763
|
+
// an internal slot, no serialization cost — and removes a residual
|
|
9764
|
+
// clobbering surface used by several mXSS / PI / comment branches
|
|
9765
|
+
// in _sanitizeElements that compare currentNode.nodeType directly.
|
|
9766
|
+
element.nodeType !== getNodeType(element) ||
|
|
9767
|
+
// HTMLFormElement has [LegacyOverrideBuiltIns]: a descendant named
|
|
9768
|
+
// "childNodes" shadows the prototype getter. Direct reads of
|
|
9769
|
+
// form.childNodes from a clobbered form return the named child
|
|
9770
|
+
// instead of the real NodeList, so any walk that reads it directly
|
|
9771
|
+
// skips the form's real children. Compare the direct read to the
|
|
9772
|
+
// cached Node.prototype getter — when the form's named-property
|
|
9773
|
+
// getter intercepts the read, the two values differ and we flag
|
|
9774
|
+
// the form. This catches every clobbering child type (input,
|
|
9775
|
+
// select, etc.) regardless of whether the named child happens to
|
|
9776
|
+
// carry a numeric .length, which a typeof-based probe would miss
|
|
9777
|
+
// (e.g. HTMLSelectElement.length is a defined unsigned-long).
|
|
9778
|
+
element.childNodes !== getChildNodes(element);
|
|
9077
9779
|
};
|
|
9078
9780
|
/**
|
|
9079
|
-
* Checks whether the given
|
|
9781
|
+
* Checks whether the given value is a DocumentFragment from any realm.
|
|
9782
|
+
*
|
|
9783
|
+
* The realm-independent replacement reads `nodeType` through the cached
|
|
9784
|
+
* Node.prototype getter and compares to the DOCUMENT_FRAGMENT_NODE
|
|
9785
|
+
* constant (11). nodeType is a numeric value resolved from the node's
|
|
9786
|
+
* internal slot, identical across realms for the same kind of node.
|
|
9787
|
+
*
|
|
9788
|
+
* @param value object to check
|
|
9789
|
+
* @return true if value is a DocumentFragment-shaped node from any realm
|
|
9790
|
+
*/
|
|
9791
|
+
const _isDocumentFragment = function _isDocumentFragment(value) {
|
|
9792
|
+
if (!getNodeType || typeof value !== 'object' || value === null) {
|
|
9793
|
+
return false;
|
|
9794
|
+
}
|
|
9795
|
+
try {
|
|
9796
|
+
return getNodeType(value) === NODE_TYPE.documentFragment;
|
|
9797
|
+
} catch (_) {
|
|
9798
|
+
return false;
|
|
9799
|
+
}
|
|
9800
|
+
};
|
|
9801
|
+
/**
|
|
9802
|
+
* Checks whether the given object is a DOM node, including nodes that
|
|
9803
|
+
* originate from a different window/realm (e.g. an iframe's
|
|
9804
|
+
* contentDocument). The previous `value instanceof Node` check was
|
|
9805
|
+
* realm-bound: nodes from a different window failed it, causing
|
|
9806
|
+
* sanitize() to silently stringify them and reset IN_PLACE to false,
|
|
9807
|
+
* returning the original node unsanitized. See GHSA-4w3q-35jp-p934.
|
|
9080
9808
|
*
|
|
9081
9809
|
* @param value object to check whether it's a DOM node
|
|
9082
|
-
* @return true
|
|
9810
|
+
* @return true if value is a DOM node from any realm
|
|
9083
9811
|
*/
|
|
9084
9812
|
const _isNode = function _isNode(value) {
|
|
9085
|
-
|
|
9813
|
+
if (!getNodeType || typeof value !== 'object' || value === null) {
|
|
9814
|
+
return false;
|
|
9815
|
+
}
|
|
9816
|
+
try {
|
|
9817
|
+
return typeof getNodeType(value) === 'number';
|
|
9818
|
+
} catch (_) {
|
|
9819
|
+
return false;
|
|
9820
|
+
}
|
|
9086
9821
|
};
|
|
9087
9822
|
function _executeHooks(hooks, currentNode, data) {
|
|
9823
|
+
if (hooks.length === 0) {
|
|
9824
|
+
return;
|
|
9825
|
+
}
|
|
9088
9826
|
arrayForEach(hooks, hook => {
|
|
9089
9827
|
hook.call(DOMPurify, currentNode, data, CONFIG);
|
|
9090
9828
|
});
|
|
9091
9829
|
}
|
|
9830
|
+
/**
|
|
9831
|
+
* Structural-threat checks that condemn a node regardless of the
|
|
9832
|
+
* allowlists: mXSS via namespace confusion, risky CSS construction,
|
|
9833
|
+
* processing instructions, markup-bearing comments. Pure predicate;
|
|
9834
|
+
* the caller removes. Check order is load-bearing.
|
|
9835
|
+
*
|
|
9836
|
+
* @param currentNode the node to inspect
|
|
9837
|
+
* @param tagName the node's transformCaseFunc'd tag name
|
|
9838
|
+
* @return true if the node must be removed
|
|
9839
|
+
*/
|
|
9840
|
+
const _isUnsafeNode = function _isUnsafeNode(currentNode, tagName) {
|
|
9841
|
+
/* Detect mXSS attempts abusing namespace confusion */
|
|
9842
|
+
if (SAFE_FOR_XML && currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.textContent) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.innerHTML)) {
|
|
9843
|
+
return true;
|
|
9844
|
+
}
|
|
9845
|
+
/* Remove risky CSS construction leading to mXSS */
|
|
9846
|
+
if (SAFE_FOR_XML && currentNode.namespaceURI === HTML_NAMESPACE && tagName === 'style' && _isNode(currentNode.firstElementChild)) {
|
|
9847
|
+
return true;
|
|
9848
|
+
}
|
|
9849
|
+
/* Remove any occurrence of processing instructions */
|
|
9850
|
+
if (currentNode.nodeType === NODE_TYPE.processingInstruction) {
|
|
9851
|
+
return true;
|
|
9852
|
+
}
|
|
9853
|
+
/* Remove any kind of possibly harmful comments */
|
|
9854
|
+
if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, currentNode.data)) {
|
|
9855
|
+
return true;
|
|
9856
|
+
}
|
|
9857
|
+
return false;
|
|
9858
|
+
};
|
|
9859
|
+
/**
|
|
9860
|
+
* Handle a node whose tag is forbidden or not allowlisted: keep
|
|
9861
|
+
* allowed custom elements (false return exits _sanitizeElements
|
|
9862
|
+
* early - namespace/fallback checks and the afterSanitizeElements
|
|
9863
|
+
* hook are intentionally skipped for kept custom elements), else
|
|
9864
|
+
* hoist content per KEEP_CONTENT and remove.
|
|
9865
|
+
*
|
|
9866
|
+
* @param currentNode the disallowed node
|
|
9867
|
+
* @param tagName the node's transformCaseFunc'd tag name
|
|
9868
|
+
* @return true if the node was removed, false if kept
|
|
9869
|
+
*/
|
|
9870
|
+
const _sanitizeDisallowedNode = function _sanitizeDisallowedNode(currentNode, tagName) {
|
|
9871
|
+
/* Check if we have a custom element to handle */
|
|
9872
|
+
if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
|
|
9873
|
+
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
|
|
9874
|
+
return false;
|
|
9875
|
+
}
|
|
9876
|
+
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) {
|
|
9877
|
+
return false;
|
|
9878
|
+
}
|
|
9879
|
+
}
|
|
9880
|
+
/* Keep content except for bad-listed elements.
|
|
9881
|
+
Use the cached prototype getters exclusively — the previous code
|
|
9882
|
+
had `|| currentNode.parentNode` / `|| currentNode.childNodes`
|
|
9883
|
+
fallbacks, but the cached getters always return the canonical
|
|
9884
|
+
value (or null for a real parent-less node), so the fallback
|
|
9885
|
+
path was dead in safe cases and a clobbering surface in unsafe
|
|
9886
|
+
ones. Falsy cached results stay falsy; the `if (childNodes &&
|
|
9887
|
+
parentNode)` check already gates correctly. */
|
|
9888
|
+
if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
|
|
9889
|
+
const parentNode = getParentNode(currentNode);
|
|
9890
|
+
const childNodes = getChildNodes(currentNode);
|
|
9891
|
+
if (childNodes && parentNode) {
|
|
9892
|
+
const childCount = childNodes.length;
|
|
9893
|
+
/* In-place: hoist the *original* children so the iterator visits
|
|
9894
|
+
and sanitises them through the same allowlist pass as every other
|
|
9895
|
+
node. The caller built the tree in the live document, so the
|
|
9896
|
+
originals carry already-queued resource events (`<img onerror>`,
|
|
9897
|
+
`<video>`/`<audio>` error, lazy/`onload`, …); cloning would leave
|
|
9898
|
+
those originals detached but still armed, firing in page scope
|
|
9899
|
+
while the returned tree looked clean. Moving is safe in-place: the
|
|
9900
|
+
root is pre-validated as an allowed tag and so is never the node
|
|
9901
|
+
being removed, which keeps `parentNode` inside the iterator root
|
|
9902
|
+
and the relocated child inside the serialised tree.
|
|
9903
|
+
Otherwise (string / DOM-copy paths): clone. The iterator is rooted
|
|
9904
|
+
at — and the result serialised from — `body`, so a restrictive
|
|
9905
|
+
ALLOWED_TAGS that removes `body` itself must leave its content in
|
|
9906
|
+
place, which only cloning does; and those paths parse into an
|
|
9907
|
+
inert document, so their discarded originals never had a queued
|
|
9908
|
+
event to neutralise.
|
|
9909
|
+
`childNodes` is live; a tail-to-head walk keeps `childNodes[i]`
|
|
9910
|
+
valid whether we move (drops the trailing entry) or clone (leaves
|
|
9911
|
+
the list intact). */
|
|
9912
|
+
for (let i = childCount - 1; i >= 0; --i) {
|
|
9913
|
+
const hoisted = IN_PLACE ? childNodes[i] : cloneNode(childNodes[i], true);
|
|
9914
|
+
parentNode.insertBefore(hoisted, getNextSibling(currentNode));
|
|
9915
|
+
}
|
|
9916
|
+
}
|
|
9917
|
+
}
|
|
9918
|
+
_forceRemove(currentNode);
|
|
9919
|
+
return true;
|
|
9920
|
+
};
|
|
9092
9921
|
/**
|
|
9093
9922
|
* _sanitizeElements
|
|
9094
9923
|
*
|
|
@@ -9099,7 +9928,6 @@ function requirePurify_cjs () {
|
|
|
9099
9928
|
* @return true if node was killed, false if left alive
|
|
9100
9929
|
*/
|
|
9101
9930
|
const _sanitizeElements = function _sanitizeElements(currentNode) {
|
|
9102
|
-
let content = null;
|
|
9103
9931
|
/* Execute a hook if present */
|
|
9104
9932
|
_executeHooks(hooks.beforeSanitizeElements, currentNode, null);
|
|
9105
9933
|
/* Check if element is clobbered or can clobber */
|
|
@@ -9108,76 +9936,41 @@ function requirePurify_cjs () {
|
|
|
9108
9936
|
return true;
|
|
9109
9937
|
}
|
|
9110
9938
|
/* Now let's check the element's type and name */
|
|
9111
|
-
const tagName = transformCaseFunc(currentNode.nodeName);
|
|
9939
|
+
const tagName = transformCaseFunc(getNodeName ? getNodeName(currentNode) : currentNode.nodeName);
|
|
9112
9940
|
/* Execute a hook if present */
|
|
9113
9941
|
_executeHooks(hooks.uponSanitizeElement, currentNode, {
|
|
9114
9942
|
tagName,
|
|
9115
9943
|
allowedTags: ALLOWED_TAGS
|
|
9116
9944
|
});
|
|
9117
|
-
/*
|
|
9118
|
-
if (
|
|
9119
|
-
_forceRemove(currentNode);
|
|
9120
|
-
return true;
|
|
9121
|
-
}
|
|
9122
|
-
/* Remove risky CSS construction leading to mXSS */
|
|
9123
|
-
if (SAFE_FOR_XML && currentNode.namespaceURI === HTML_NAMESPACE && tagName === 'style' && _isNode(currentNode.firstElementChild)) {
|
|
9124
|
-
_forceRemove(currentNode);
|
|
9125
|
-
return true;
|
|
9126
|
-
}
|
|
9127
|
-
/* Remove any occurrence of processing instructions */
|
|
9128
|
-
if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {
|
|
9129
|
-
_forceRemove(currentNode);
|
|
9130
|
-
return true;
|
|
9131
|
-
}
|
|
9132
|
-
/* Remove any kind of possibly harmful comments */
|
|
9133
|
-
if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(/<[/\w]/g, currentNode.data)) {
|
|
9945
|
+
/* Remove mXSS vectors, processing instructions and risky comments */
|
|
9946
|
+
if (_isUnsafeNode(currentNode, tagName)) {
|
|
9134
9947
|
_forceRemove(currentNode);
|
|
9135
9948
|
return true;
|
|
9136
9949
|
}
|
|
9137
9950
|
/* Remove element if anything forbids its presence */
|
|
9138
9951
|
if (FORBID_TAGS[tagName] || !(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) && !ALLOWED_TAGS[tagName]) {
|
|
9139
|
-
|
|
9140
|
-
if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
|
|
9141
|
-
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
|
|
9142
|
-
return false;
|
|
9143
|
-
}
|
|
9144
|
-
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) {
|
|
9145
|
-
return false;
|
|
9146
|
-
}
|
|
9147
|
-
}
|
|
9148
|
-
/* Keep content except for bad-listed elements */
|
|
9149
|
-
if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
|
|
9150
|
-
const parentNode = getParentNode(currentNode) || currentNode.parentNode;
|
|
9151
|
-
const childNodes = getChildNodes(currentNode) || currentNode.childNodes;
|
|
9152
|
-
if (childNodes && parentNode) {
|
|
9153
|
-
const childCount = childNodes.length;
|
|
9154
|
-
for (let i = childCount - 1; i >= 0; --i) {
|
|
9155
|
-
const childClone = cloneNode(childNodes[i], true);
|
|
9156
|
-
childClone.__removalCount = (currentNode.__removalCount || 0) + 1;
|
|
9157
|
-
parentNode.insertBefore(childClone, getNextSibling(currentNode));
|
|
9158
|
-
}
|
|
9159
|
-
}
|
|
9160
|
-
}
|
|
9161
|
-
_forceRemove(currentNode);
|
|
9162
|
-
return true;
|
|
9952
|
+
return _sanitizeDisallowedNode(currentNode, tagName);
|
|
9163
9953
|
}
|
|
9164
|
-
/* Check whether element has a valid namespace
|
|
9165
|
-
|
|
9954
|
+
/* Check whether element has a valid namespace.
|
|
9955
|
+
Realm-safe check (GHSA-hpcv-96wg-7vj8): use the cached Node.prototype
|
|
9956
|
+
nodeType getter rather than `instanceof Element`, which is realm-
|
|
9957
|
+
bound and short-circuits to false for any node minted in a different
|
|
9958
|
+
realm — letting a foreign-realm element with a forbidden namespace
|
|
9959
|
+
slip past the namespace check entirely. */
|
|
9960
|
+
const nt = getNodeType ? getNodeType(currentNode) : currentNode.nodeType;
|
|
9961
|
+
if (nt === NODE_TYPE.element && !_checkValidNamespace(currentNode)) {
|
|
9166
9962
|
_forceRemove(currentNode);
|
|
9167
9963
|
return true;
|
|
9168
9964
|
}
|
|
9169
9965
|
/* Make sure that older browsers don't get fallback-tag mXSS */
|
|
9170
|
-
if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(
|
|
9966
|
+
if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(FALLBACK_TAG_CLOSE, currentNode.innerHTML)) {
|
|
9171
9967
|
_forceRemove(currentNode);
|
|
9172
9968
|
return true;
|
|
9173
9969
|
}
|
|
9174
9970
|
/* Sanitize element content to be template-safe */
|
|
9175
9971
|
if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
|
|
9176
9972
|
/* Get the element's text content */
|
|
9177
|
-
content = currentNode.textContent;
|
|
9178
|
-
arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
|
|
9179
|
-
content = stringReplace(content, expr, ' ');
|
|
9180
|
-
});
|
|
9973
|
+
const content = _stripTemplateExpressions(currentNode.textContent);
|
|
9181
9974
|
if (currentNode.textContent !== content) {
|
|
9182
9975
|
arrayPush(DOMPurify.removed, {
|
|
9183
9976
|
element: currentNode.cloneNode()
|
|
@@ -9207,11 +10000,12 @@ function requirePurify_cjs () {
|
|
|
9207
10000
|
if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
|
|
9208
10001
|
return false;
|
|
9209
10002
|
}
|
|
10003
|
+
const nameIsPermitted = ALLOWED_ATTR[lcName] || EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag);
|
|
9210
10004
|
/* Allow valid data-* attributes: At least one character after "-"
|
|
9211
10005
|
(https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
|
|
9212
10006
|
XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
|
|
9213
10007
|
We don't need to check the value; it's always URI safe. */
|
|
9214
|
-
if (ALLOW_DATA_ATTR &&
|
|
10008
|
+
if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$1, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$1, lcName)) ; else if (!nameIsPermitted) {
|
|
9215
10009
|
if (
|
|
9216
10010
|
// First condition does a very basic check if a) it's basically a valid custom element tagname AND
|
|
9217
10011
|
// b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
|
|
@@ -9223,11 +10017,15 @@ function requirePurify_cjs () {
|
|
|
9223
10017
|
return false;
|
|
9224
10018
|
}
|
|
9225
10019
|
/* Check value is safe. First, is attr inert? If so, is safe */
|
|
9226
|
-
} else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ; else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if (value) {
|
|
10020
|
+
} else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE$1, ''))) ; else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ; else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$1, stringReplace(value, ATTR_WHITESPACE$1, ''))) ; else if (value) {
|
|
9227
10021
|
return false;
|
|
9228
10022
|
} else ;
|
|
9229
10023
|
return true;
|
|
9230
10024
|
};
|
|
10025
|
+
/* Names the HTML spec reserves from valid-custom-element-name; these must
|
|
10026
|
+
* never be treated as basic custom elements even when a permissive
|
|
10027
|
+
* CUSTOM_ELEMENT_HANDLING.tagNameCheck is configured. */
|
|
10028
|
+
const RESERVED_CUSTOM_ELEMENT_NAMES = addToSet({}, ['annotation-xml', 'color-profile', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'missing-glyph']);
|
|
9231
10029
|
/**
|
|
9232
10030
|
* _isBasicCustomElement
|
|
9233
10031
|
* checks if at least one dash is included in tagName, and it's not the first char
|
|
@@ -9237,7 +10035,64 @@ function requirePurify_cjs () {
|
|
|
9237
10035
|
* @returns Returns true if the tag name meets the basic criteria for a custom element, otherwise false.
|
|
9238
10036
|
*/
|
|
9239
10037
|
const _isBasicCustomElement = function _isBasicCustomElement(tagName) {
|
|
9240
|
-
return tagName
|
|
10038
|
+
return !RESERVED_CUSTOM_ELEMENT_NAMES[stringToLowerCase(tagName)] && regExpTest(CUSTOM_ELEMENT$1, tagName);
|
|
10039
|
+
};
|
|
10040
|
+
/**
|
|
10041
|
+
* Wrap an attribute value in the matching Trusted Types object when
|
|
10042
|
+
* the active policy requires it. Namespaced attributes pass through
|
|
10043
|
+
* unchanged (no TT support yet, see
|
|
10044
|
+
* https://bugs.chromium.org/p/chromium/issues/detail?id=1305293).
|
|
10045
|
+
*
|
|
10046
|
+
* @param lcTag lowercase tag name of the containing element
|
|
10047
|
+
* @param lcName lowercase attribute name
|
|
10048
|
+
* @param namespaceURI the attribute's namespace, if any
|
|
10049
|
+
* @param value the attribute value to wrap
|
|
10050
|
+
* @return the value, wrapped when Trusted Types demand it
|
|
10051
|
+
*/
|
|
10052
|
+
const _applyTrustedTypesToAttribute = function _applyTrustedTypesToAttribute(lcTag, lcName, namespaceURI, value) {
|
|
10053
|
+
if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function' && !namespaceURI) {
|
|
10054
|
+
switch (trustedTypes.getAttributeType(lcTag, lcName)) {
|
|
10055
|
+
case 'TrustedHTML':
|
|
10056
|
+
{
|
|
10057
|
+
return _createTrustedHTML(value);
|
|
10058
|
+
}
|
|
10059
|
+
case 'TrustedScriptURL':
|
|
10060
|
+
{
|
|
10061
|
+
return _createTrustedScriptURL(value);
|
|
10062
|
+
}
|
|
10063
|
+
}
|
|
10064
|
+
}
|
|
10065
|
+
return value;
|
|
10066
|
+
};
|
|
10067
|
+
/**
|
|
10068
|
+
* Write a modified attribute value back onto the element. On
|
|
10069
|
+
* success, re-probe for clobbering introduced by the new value and
|
|
10070
|
+
* remove the element when found; otherwise pop the removal entry
|
|
10071
|
+
* recorded by the earlier _removeAttribute (long-standing pairing
|
|
10072
|
+
* with the SANITIZE_NAMED_PROPS path - do not "fix" casually). On
|
|
10073
|
+
* failure, remove the attribute instead.
|
|
10074
|
+
*
|
|
10075
|
+
* @param currentNode the element carrying the attribute
|
|
10076
|
+
* @param name the attribute name as present on the element
|
|
10077
|
+
* @param namespaceURI the attribute's namespace, if any
|
|
10078
|
+
* @param value the new attribute value
|
|
10079
|
+
*/
|
|
10080
|
+
const _setAttributeValue = function _setAttributeValue(currentNode, name, namespaceURI, value) {
|
|
10081
|
+
try {
|
|
10082
|
+
if (namespaceURI) {
|
|
10083
|
+
currentNode.setAttributeNS(namespaceURI, name, value);
|
|
10084
|
+
} else {
|
|
10085
|
+
/* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
|
|
10086
|
+
currentNode.setAttribute(name, value);
|
|
10087
|
+
}
|
|
10088
|
+
if (_isClobbered(currentNode)) {
|
|
10089
|
+
_forceRemove(currentNode);
|
|
10090
|
+
} else {
|
|
10091
|
+
arrayPop(DOMPurify.removed);
|
|
10092
|
+
}
|
|
10093
|
+
} catch (_) {
|
|
10094
|
+
_removeAttribute(name, currentNode);
|
|
10095
|
+
}
|
|
9241
10096
|
};
|
|
9242
10097
|
/**
|
|
9243
10098
|
* _sanitizeAttributes
|
|
@@ -9252,9 +10107,7 @@ function requirePurify_cjs () {
|
|
|
9252
10107
|
const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
|
|
9253
10108
|
/* Execute a hook if present */
|
|
9254
10109
|
_executeHooks(hooks.beforeSanitizeAttributes, currentNode, null);
|
|
9255
|
-
const
|
|
9256
|
-
attributes
|
|
9257
|
-
} = currentNode;
|
|
10110
|
+
const attributes = currentNode.attributes;
|
|
9258
10111
|
/* Check if we have attributes; if not we might have a text node */
|
|
9259
10112
|
if (!attributes || _isClobbered(currentNode)) {
|
|
9260
10113
|
return;
|
|
@@ -9267,14 +10120,13 @@ function requirePurify_cjs () {
|
|
|
9267
10120
|
forceKeepAttr: undefined
|
|
9268
10121
|
};
|
|
9269
10122
|
let l = attributes.length;
|
|
10123
|
+
const lcTag = transformCaseFunc(currentNode.nodeName);
|
|
9270
10124
|
/* Go backwards over all attributes; safely remove bad ones */
|
|
9271
10125
|
while (l--) {
|
|
9272
10126
|
const attr = attributes[l];
|
|
9273
|
-
const
|
|
9274
|
-
|
|
9275
|
-
|
|
9276
|
-
value: attrValue
|
|
9277
|
-
} = attr;
|
|
10127
|
+
const name = attr.name,
|
|
10128
|
+
namespaceURI = attr.namespaceURI,
|
|
10129
|
+
attrValue = attr.value;
|
|
9278
10130
|
const lcName = transformCaseFunc(name);
|
|
9279
10131
|
const initValue = attrValue;
|
|
9280
10132
|
let value = name === 'value' ? initValue : stringTrim(initValue);
|
|
@@ -9288,12 +10140,14 @@ function requirePurify_cjs () {
|
|
|
9288
10140
|
/* Full DOM Clobbering protection via namespace isolation,
|
|
9289
10141
|
* Prefix id and name attributes with `user-content-`
|
|
9290
10142
|
*/
|
|
9291
|
-
if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
|
|
10143
|
+
if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name') && stringIndexOf(value, SANITIZE_NAMED_PROPS_PREFIX) !== 0) {
|
|
9292
10144
|
// Remove the attribute with this value
|
|
9293
10145
|
_removeAttribute(name, currentNode);
|
|
9294
10146
|
// Prefix the value and later re-create the attribute with the sanitized value
|
|
9295
10147
|
value = SANITIZE_NAMED_PROPS_PREFIX + value;
|
|
9296
10148
|
}
|
|
10149
|
+
// Else: already prefixed, leave the attribute alone — the prefix is
|
|
10150
|
+
// itself the clobbering protection, and re-applying it is incorrect.
|
|
9297
10151
|
/* Work around a security issue with comments inside attributes */
|
|
9298
10152
|
if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i, value)) {
|
|
9299
10153
|
_removeAttribute(name, currentNode);
|
|
@@ -9304,7 +10158,7 @@ function requirePurify_cjs () {
|
|
|
9304
10158
|
_removeAttribute(name, currentNode);
|
|
9305
10159
|
continue;
|
|
9306
10160
|
}
|
|
9307
|
-
/* Did the hooks
|
|
10161
|
+
/* Did the hooks force-keep the attribute? */
|
|
9308
10162
|
if (hookEvent.forceKeepAttr) {
|
|
9309
10163
|
continue;
|
|
9310
10164
|
}
|
|
@@ -9314,56 +10168,24 @@ function requirePurify_cjs () {
|
|
|
9314
10168
|
continue;
|
|
9315
10169
|
}
|
|
9316
10170
|
/* Work around a security issue in jQuery 3.0 */
|
|
9317
|
-
if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(
|
|
10171
|
+
if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(SELF_CLOSING_TAG, value)) {
|
|
9318
10172
|
_removeAttribute(name, currentNode);
|
|
9319
10173
|
continue;
|
|
9320
10174
|
}
|
|
9321
10175
|
/* Sanitize attribute content to be template-safe */
|
|
9322
10176
|
if (SAFE_FOR_TEMPLATES) {
|
|
9323
|
-
|
|
9324
|
-
value = stringReplace(value, expr, ' ');
|
|
9325
|
-
});
|
|
10177
|
+
value = _stripTemplateExpressions(value);
|
|
9326
10178
|
}
|
|
9327
10179
|
/* Is `value` valid for this attribute? */
|
|
9328
|
-
const lcTag = transformCaseFunc(currentNode.nodeName);
|
|
9329
10180
|
if (!_isValidAttribute(lcTag, lcName, value)) {
|
|
9330
10181
|
_removeAttribute(name, currentNode);
|
|
9331
10182
|
continue;
|
|
9332
10183
|
}
|
|
9333
10184
|
/* Handle attributes that require Trusted Types */
|
|
9334
|
-
|
|
9335
|
-
if (namespaceURI) ; else {
|
|
9336
|
-
switch (trustedTypes.getAttributeType(lcTag, lcName)) {
|
|
9337
|
-
case 'TrustedHTML':
|
|
9338
|
-
{
|
|
9339
|
-
value = trustedTypesPolicy.createHTML(value);
|
|
9340
|
-
break;
|
|
9341
|
-
}
|
|
9342
|
-
case 'TrustedScriptURL':
|
|
9343
|
-
{
|
|
9344
|
-
value = trustedTypesPolicy.createScriptURL(value);
|
|
9345
|
-
break;
|
|
9346
|
-
}
|
|
9347
|
-
}
|
|
9348
|
-
}
|
|
9349
|
-
}
|
|
10185
|
+
value = _applyTrustedTypesToAttribute(lcTag, lcName, namespaceURI, value);
|
|
9350
10186
|
/* Handle invalid data-* attribute set by try-catching it */
|
|
9351
10187
|
if (value !== initValue) {
|
|
9352
|
-
|
|
9353
|
-
if (namespaceURI) {
|
|
9354
|
-
currentNode.setAttributeNS(namespaceURI, name, value);
|
|
9355
|
-
} else {
|
|
9356
|
-
/* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
|
|
9357
|
-
currentNode.setAttribute(name, value);
|
|
9358
|
-
}
|
|
9359
|
-
if (_isClobbered(currentNode)) {
|
|
9360
|
-
_forceRemove(currentNode);
|
|
9361
|
-
} else {
|
|
9362
|
-
arrayPop(DOMPurify.removed);
|
|
9363
|
-
}
|
|
9364
|
-
} catch (_) {
|
|
9365
|
-
_removeAttribute(name, currentNode);
|
|
9366
|
-
}
|
|
10188
|
+
_setAttributeValue(currentNode, name, namespaceURI, value);
|
|
9367
10189
|
}
|
|
9368
10190
|
}
|
|
9369
10191
|
/* Execute a hook if present */
|
|
@@ -9386,14 +10208,133 @@ function requirePurify_cjs () {
|
|
|
9386
10208
|
_sanitizeElements(shadowNode);
|
|
9387
10209
|
/* Check attributes next */
|
|
9388
10210
|
_sanitizeAttributes(shadowNode);
|
|
9389
|
-
/* Deep shadow DOM detected
|
|
9390
|
-
|
|
10211
|
+
/* Deep shadow DOM detected.
|
|
10212
|
+
Realm-safe check (GHSA-hpcv-96wg-7vj8): use nodeType against the
|
|
10213
|
+
DOCUMENT_FRAGMENT_NODE constant rather than instanceof, so we
|
|
10214
|
+
recurse into <template>.content from foreign realms too. */
|
|
10215
|
+
if (_isDocumentFragment(shadowNode.content)) {
|
|
9391
10216
|
_sanitizeShadowDOM2(shadowNode.content);
|
|
9392
10217
|
}
|
|
10218
|
+
/* An element iterated here may itself host an attached
|
|
10219
|
+
shadow root. The default NodeIterator does not enter shadow
|
|
10220
|
+
trees, so a shadow root nested inside template.content was
|
|
10221
|
+
previously reached by no walk at all (the pre-pass at
|
|
10222
|
+
_sanitizeAttachedShadowRoots descends via childNodes, which
|
|
10223
|
+
doesn't enter template.content; the template-content recursion
|
|
10224
|
+
above iterates the content but never inspected shadowRoot).
|
|
10225
|
+
Walk it explicitly. The nodeType guard avoids reading
|
|
10226
|
+
shadowRoot off text / comment / CDATA / PI nodes that the
|
|
10227
|
+
iterator also surfaces. */
|
|
10228
|
+
const shadowNodeType = getNodeType ? getNodeType(shadowNode) : shadowNode.nodeType;
|
|
10229
|
+
if (shadowNodeType === NODE_TYPE.element) {
|
|
10230
|
+
const innerSr = getShadowRoot(shadowNode);
|
|
10231
|
+
if (_isDocumentFragment(innerSr)) {
|
|
10232
|
+
_sanitizeAttachedShadowRoots(innerSr);
|
|
10233
|
+
_sanitizeShadowDOM2(innerSr);
|
|
10234
|
+
}
|
|
10235
|
+
}
|
|
9393
10236
|
}
|
|
9394
10237
|
/* Execute a hook if present */
|
|
9395
10238
|
_executeHooks(hooks.afterSanitizeShadowDOM, fragment, null);
|
|
9396
10239
|
};
|
|
10240
|
+
/**
|
|
10241
|
+
* _sanitizeAttachedShadowRoots
|
|
10242
|
+
*
|
|
10243
|
+
* Walks `root` and feeds every attached shadow root we encounter into
|
|
10244
|
+
* the existing _sanitizeShadowDOM pipeline. The default node iterator
|
|
10245
|
+
* does not descend into shadow trees, so nodes inside an attached
|
|
10246
|
+
* shadow root would otherwise be skipped entirely.
|
|
10247
|
+
*
|
|
10248
|
+
* Two real input paths put attached shadow roots in front of us:
|
|
10249
|
+
* 1. IN_PLACE on a DOM node that already has shadow roots attached.
|
|
10250
|
+
* 2. DOM-node input where importNode(dirty, true) deep-clones the
|
|
10251
|
+
* shadow root because it was created with `clonable: true`.
|
|
10252
|
+
*
|
|
10253
|
+
* This pass runs once, up front, so the main iteration loop (and the
|
|
10254
|
+
* existing _sanitizeShadowDOM template-content recursion) stay
|
|
10255
|
+
* untouched — string-input paths are not affected.
|
|
10256
|
+
*
|
|
10257
|
+
* @param root the subtree root to walk for attached shadow roots
|
|
10258
|
+
*/
|
|
10259
|
+
const _sanitizeAttachedShadowRoots = function _sanitizeAttachedShadowRoots(root) {
|
|
10260
|
+
/* Iterative (explicit stack) rather than per-child recursion. DOM APIs
|
|
10261
|
+
impose no depth cap, so an attacker-shaped tree (JSON/CRDT/editor data
|
|
10262
|
+
built straight into the DOM — the IN_PLACE surface) deeper than the JS
|
|
10263
|
+
call-stack budget would otherwise overflow native recursion here and
|
|
10264
|
+
throw at the IN_PLACE entry pre-pass, before a single node is
|
|
10265
|
+
sanitized, leaving the caller's live tree untouched (fail-open). See
|
|
10266
|
+
campaign-3 F4. A heap stack keeps depth off the call stack.
|
|
10267
|
+
Each work item is either a node to descend into, or a deferred
|
|
10268
|
+
`_sanitizeShadowDOM` for an already-walked shadow root. The deferred
|
|
10269
|
+
form preserves the original post-order discipline: a shadow root's
|
|
10270
|
+
nested shadow roots are discovered before the outer shadow is
|
|
10271
|
+
sanitized (which may remove hosts). Pushes are in reverse of the
|
|
10272
|
+
desired processing order (LIFO): template content, then children, then
|
|
10273
|
+
the shadow-sanitize, then the shadow walk — so the order matches the
|
|
10274
|
+
previous recursion exactly. */
|
|
10275
|
+
const stack = [{
|
|
10276
|
+
node: root,
|
|
10277
|
+
shadow: null
|
|
10278
|
+
}];
|
|
10279
|
+
while (stack.length > 0) {
|
|
10280
|
+
const item = stack.pop();
|
|
10281
|
+
/* Deferred shadow-DOM sanitisation: runs after its subtree was walked. */
|
|
10282
|
+
if (item.shadow) {
|
|
10283
|
+
_sanitizeShadowDOM2(item.shadow);
|
|
10284
|
+
continue;
|
|
10285
|
+
}
|
|
10286
|
+
const node = item.node;
|
|
10287
|
+
const nodeType = getNodeType ? getNodeType(node) : node.nodeType;
|
|
10288
|
+
const isElement = nodeType === NODE_TYPE.element;
|
|
10289
|
+
/* (pushed last → processed first) Children, snapshotted in reverse so
|
|
10290
|
+
the first child is processed first. Snapshotting matters because a
|
|
10291
|
+
hook may detach siblings mid-walk. */
|
|
10292
|
+
const childNodes = getChildNodes(node);
|
|
10293
|
+
if (childNodes) {
|
|
10294
|
+
for (let i = childNodes.length - 1; i >= 0; --i) {
|
|
10295
|
+
stack.push({
|
|
10296
|
+
node: childNodes[i],
|
|
10297
|
+
shadow: null
|
|
10298
|
+
});
|
|
10299
|
+
}
|
|
10300
|
+
}
|
|
10301
|
+
/* (pushed before children → processed after them, matching the old
|
|
10302
|
+
"template content last" order) When the node is a <template>,
|
|
10303
|
+
descend into its content. */
|
|
10304
|
+
if (isElement) {
|
|
10305
|
+
const rootName = getNodeName ? getNodeName(node) : null;
|
|
10306
|
+
if (typeof rootName === 'string' && transformCaseFunc(rootName) === 'template') {
|
|
10307
|
+
const content = node.content;
|
|
10308
|
+
if (_isDocumentFragment(content)) {
|
|
10309
|
+
stack.push({
|
|
10310
|
+
node: content,
|
|
10311
|
+
shadow: null
|
|
10312
|
+
});
|
|
10313
|
+
}
|
|
10314
|
+
}
|
|
10315
|
+
}
|
|
10316
|
+
/* Shadow root (processed first): walk its subtree, then sanitise it.
|
|
10317
|
+
Realm-safe check (GHSA-hpcv-96wg-7vj8): nodeType-based detection
|
|
10318
|
+
rather than `instanceof DocumentFragment`, which is realm-bound and
|
|
10319
|
+
silently skipped foreign-realm shadow roots (e.g.
|
|
10320
|
+
iframe.contentDocument attachShadow). */
|
|
10321
|
+
if (isElement) {
|
|
10322
|
+
const sr = getShadowRoot(node);
|
|
10323
|
+
if (_isDocumentFragment(sr)) {
|
|
10324
|
+
/* Push the deferred sanitise first so it pops after the shadow
|
|
10325
|
+
walk we push next, i.e. nested shadow roots are discovered
|
|
10326
|
+
before this one is sanitised. */
|
|
10327
|
+
stack.push({
|
|
10328
|
+
node: null,
|
|
10329
|
+
shadow: sr
|
|
10330
|
+
}, {
|
|
10331
|
+
node: sr,
|
|
10332
|
+
shadow: null
|
|
10333
|
+
});
|
|
10334
|
+
}
|
|
10335
|
+
}
|
|
10336
|
+
}
|
|
10337
|
+
};
|
|
9397
10338
|
// eslint-disable-next-line complexity
|
|
9398
10339
|
DOMPurify.sanitize = function (dirty) {
|
|
9399
10340
|
let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
@@ -9410,13 +10351,9 @@ function requirePurify_cjs () {
|
|
|
9410
10351
|
}
|
|
9411
10352
|
/* Stringify, in case dirty is an object */
|
|
9412
10353
|
if (typeof dirty !== 'string' && !_isNode(dirty)) {
|
|
9413
|
-
|
|
9414
|
-
|
|
9415
|
-
|
|
9416
|
-
throw typeErrorCreate('dirty is not a string, aborting');
|
|
9417
|
-
}
|
|
9418
|
-
} else {
|
|
9419
|
-
throw typeErrorCreate('toString is not a function');
|
|
10354
|
+
dirty = stringifyValue(dirty);
|
|
10355
|
+
if (typeof dirty !== 'string') {
|
|
10356
|
+
throw typeErrorCreate('dirty is not a string, aborting');
|
|
9420
10357
|
}
|
|
9421
10358
|
}
|
|
9422
10359
|
/* Return dirty HTML if DOMPurify cannot run */
|
|
@@ -9424,24 +10361,78 @@ function requirePurify_cjs () {
|
|
|
9424
10361
|
return dirty;
|
|
9425
10362
|
}
|
|
9426
10363
|
/* Assign config vars */
|
|
9427
|
-
if (
|
|
10364
|
+
if (SET_CONFIG) {
|
|
10365
|
+
/* Persistent setConfig() path: _parseConfig is skipped, so the sets are
|
|
10366
|
+
* not re-derived per call. Restore them from the pristine bindings
|
|
10367
|
+
* captured at setConfig() time so a previous call's hook clone (mutated
|
|
10368
|
+
* below) does not carry over. */
|
|
10369
|
+
ALLOWED_TAGS = SET_CONFIG_ALLOWED_TAGS;
|
|
10370
|
+
ALLOWED_ATTR = SET_CONFIG_ALLOWED_ATTR;
|
|
10371
|
+
} else {
|
|
9428
10372
|
_parseConfig(cfg);
|
|
9429
10373
|
}
|
|
10374
|
+
/* Clone the hook-mutable allowlists before the walk whenever an
|
|
10375
|
+
* uponSanitize* hook is registered. The hook event exposes ALLOWED_TAGS
|
|
10376
|
+
* and ALLOWED_ATTR by reference (as allowedTags / allowedAttributes), so
|
|
10377
|
+
* a hook that widens them would otherwise mutate the shared set
|
|
10378
|
+
* permanently: across later calls and across every element. Cloning per
|
|
10379
|
+
* walk keeps documented in-call widening working while scoping it to the
|
|
10380
|
+
* call. A single guard for both config paths - the per-call path rebinds
|
|
10381
|
+
* the sets in _parseConfig each call, the persistent path restores them
|
|
10382
|
+
* from the captured bindings just above - so the two cannot diverge. */
|
|
10383
|
+
if (hooks.uponSanitizeElement.length > 0 || hooks.uponSanitizeAttribute.length > 0) {
|
|
10384
|
+
ALLOWED_TAGS = clone(ALLOWED_TAGS);
|
|
10385
|
+
}
|
|
10386
|
+
if (hooks.uponSanitizeAttribute.length > 0) {
|
|
10387
|
+
ALLOWED_ATTR = clone(ALLOWED_ATTR);
|
|
10388
|
+
}
|
|
9430
10389
|
/* Clean up removed elements */
|
|
9431
10390
|
DOMPurify.removed = [];
|
|
9432
|
-
/*
|
|
9433
|
-
|
|
9434
|
-
|
|
9435
|
-
|
|
9436
|
-
|
|
9437
|
-
|
|
9438
|
-
|
|
9439
|
-
|
|
10391
|
+
/* Resolve IN_PLACE for this call without mutating persistent config.
|
|
10392
|
+
Writing the IN_PLACE closure variable here leaks under setConfig(),
|
|
10393
|
+
where _parseConfig is skipped on later calls: a single string call would
|
|
10394
|
+
disable in-place mode for every subsequent node call, returning a
|
|
10395
|
+
sanitized copy while leaving the caller's node — which in-place callers
|
|
10396
|
+
keep using and whose return value they ignore — unsanitized. REPORT-2. */
|
|
10397
|
+
const inPlace = IN_PLACE && typeof dirty !== 'string' && _isNode(dirty);
|
|
10398
|
+
if (inPlace) {
|
|
10399
|
+
/* Do some early pre-sanitization to avoid unsafe root nodes.
|
|
10400
|
+
Read nodeName through the cached prototype getter — a clobbering
|
|
10401
|
+
child named "nodeName" on the form root would otherwise shadow
|
|
10402
|
+
the property and let this check skip the root-allowlist
|
|
10403
|
+
validation entirely. */
|
|
10404
|
+
const nn = getNodeName ? getNodeName(dirty) : dirty.nodeName;
|
|
10405
|
+
if (typeof nn === 'string') {
|
|
10406
|
+
const tagName = transformCaseFunc(nn);
|
|
9440
10407
|
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
|
9441
10408
|
throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
|
|
9442
10409
|
}
|
|
9443
10410
|
}
|
|
9444
|
-
|
|
10411
|
+
/* Pre-flight the root through _isClobbered. The iterator-driven
|
|
10412
|
+
removal path can not detach a parent-less root: _forceRemove
|
|
10413
|
+
falls through to Element.prototype.remove(), which per spec
|
|
10414
|
+
is a no-op on a node with no parent. A clobbered root would
|
|
10415
|
+
then survive the main loop with its attributes uninspected,
|
|
10416
|
+
because _sanitizeAttributes early-returns on _isClobbered. The
|
|
10417
|
+
result would be an attacker-controlled form, complete with any
|
|
10418
|
+
event-handler attributes the caller passed in, handed back to
|
|
10419
|
+
the application unsanitized. Refuse to sanitize such a root
|
|
10420
|
+
the same way we refuse a forbidden tag. GHSA-r47g-fvhr-h676. */
|
|
10421
|
+
if (_isClobbered(dirty)) {
|
|
10422
|
+
throw typeErrorCreate('root node is clobbered and cannot be sanitized in-place');
|
|
10423
|
+
}
|
|
10424
|
+
/* Sanitize attached shadow roots before the main iterator runs.
|
|
10425
|
+
The iterator does not descend into shadow trees. Same fail-closed
|
|
10426
|
+
barrier as the main walk (campaign-3 F2): a custom-element reaction
|
|
10427
|
+
inside a shadow root could abort this pre-pass before the walk runs,
|
|
10428
|
+
which would otherwise leave the entire live tree unsanitized. */
|
|
10429
|
+
try {
|
|
10430
|
+
_sanitizeAttachedShadowRoots(dirty);
|
|
10431
|
+
} catch (error) {
|
|
10432
|
+
_neutralizeRoot(dirty);
|
|
10433
|
+
throw error;
|
|
10434
|
+
}
|
|
10435
|
+
} else if (_isNode(dirty)) {
|
|
9445
10436
|
/* If dirty is a DOM element, append to an empty document to avoid
|
|
9446
10437
|
elements being stripped by the parser */
|
|
9447
10438
|
body = _initDocument('<!---->');
|
|
@@ -9455,12 +10446,18 @@ function requirePurify_cjs () {
|
|
|
9455
10446
|
// eslint-disable-next-line unicorn/prefer-dom-node-append
|
|
9456
10447
|
body.appendChild(importedNode);
|
|
9457
10448
|
}
|
|
10449
|
+
/* Clonable shadow roots are deep-cloned by importNode(); sanitize
|
|
10450
|
+
them before the main iterator runs, since the iterator does not
|
|
10451
|
+
descend into shadow trees. The walk routes every read through a
|
|
10452
|
+
cached prototype getter so clobbering descendants on a form root
|
|
10453
|
+
cannot hide a shadow host from this pass. */
|
|
10454
|
+
_sanitizeAttachedShadowRoots(importedNode);
|
|
9458
10455
|
} else {
|
|
9459
10456
|
/* Exit directly if we have nothing to do */
|
|
9460
10457
|
if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&
|
|
9461
10458
|
// eslint-disable-next-line unicorn/prefer-includes
|
|
9462
10459
|
dirty.indexOf('<') === -1) {
|
|
9463
|
-
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ?
|
|
10460
|
+
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(dirty) : dirty;
|
|
9464
10461
|
}
|
|
9465
10462
|
/* Initialize the document to work on */
|
|
9466
10463
|
body = _initDocument(dirty);
|
|
@@ -9474,31 +10471,59 @@ function requirePurify_cjs () {
|
|
|
9474
10471
|
_forceRemove(body.firstChild);
|
|
9475
10472
|
}
|
|
9476
10473
|
/* Get node iterator */
|
|
9477
|
-
const nodeIterator = _createNodeIterator(
|
|
9478
|
-
/* Now start iterating over the created document
|
|
9479
|
-
|
|
9480
|
-
|
|
9481
|
-
|
|
9482
|
-
|
|
9483
|
-
|
|
9484
|
-
|
|
9485
|
-
|
|
9486
|
-
|
|
10474
|
+
const nodeIterator = _createNodeIterator(inPlace ? dirty : body);
|
|
10475
|
+
/* Now start iterating over the created document.
|
|
10476
|
+
The walk runs inside an exception barrier (campaign-3 F2): a re-entrant
|
|
10477
|
+
engine/custom-element mutation can detach a node mid-walk so
|
|
10478
|
+
`_forceRemove`'s parentless guard throws, aborting the loop. Without the
|
|
10479
|
+
barrier the caller's in-place tree would be left half-sanitized with the
|
|
10480
|
+
unvisited tail still armed. On any throw we fail closed — strip the
|
|
10481
|
+
in-place root bare — then rethrow so the existing throw contract is
|
|
10482
|
+
preserved. (String/DOM-copy paths never return the partial body, so the
|
|
10483
|
+
propagating throw is already fail-closed there.) */
|
|
10484
|
+
try {
|
|
10485
|
+
while (currentNode = nodeIterator.nextNode()) {
|
|
10486
|
+
/* Sanitize tags and elements */
|
|
10487
|
+
_sanitizeElements(currentNode);
|
|
10488
|
+
/* Check attributes next */
|
|
10489
|
+
_sanitizeAttributes(currentNode);
|
|
10490
|
+
/* Shadow DOM detected, sanitize it.
|
|
10491
|
+
Realm-safe check (GHSA-hpcv-96wg-7vj8): nodeType-based detection
|
|
10492
|
+
instead of instanceof, so foreign-realm <template>.content is
|
|
10493
|
+
walked correctly. */
|
|
10494
|
+
if (_isDocumentFragment(currentNode.content)) {
|
|
10495
|
+
_sanitizeShadowDOM2(currentNode.content);
|
|
10496
|
+
}
|
|
9487
10497
|
}
|
|
10498
|
+
} catch (error) {
|
|
10499
|
+
if (inPlace) {
|
|
10500
|
+
_neutralizeRoot(dirty);
|
|
10501
|
+
}
|
|
10502
|
+
throw error;
|
|
9488
10503
|
}
|
|
9489
10504
|
/* If we sanitized `dirty` in-place, return it. */
|
|
9490
|
-
if (
|
|
10505
|
+
if (inPlace) {
|
|
10506
|
+
/* Fail-closed completion of the audit-5 F1 fix: every node removed from
|
|
10507
|
+
the caller's live tree is detached but may still hold a queued
|
|
10508
|
+
resource-event handler that fires in page scope after we return. The
|
|
10509
|
+
move-hoist covers only disallowed-tag KEEP_CONTENT removals; strip the
|
|
10510
|
+
non-allow-listed attributes off every other removed subtree (clobber,
|
|
10511
|
+
mXSS, namespace, comments, KEEP_CONTENT:false, …) so those handlers are
|
|
10512
|
+
cancelled before any event can fire. Runs synchronously, pre-return. */
|
|
10513
|
+
arrayForEach(DOMPurify.removed, entry => {
|
|
10514
|
+
if (entry.element) {
|
|
10515
|
+
_neutralizeSubtree(entry.element);
|
|
10516
|
+
}
|
|
10517
|
+
});
|
|
10518
|
+
if (SAFE_FOR_TEMPLATES) {
|
|
10519
|
+
_scrubTemplateExpressions2(dirty);
|
|
10520
|
+
}
|
|
9491
10521
|
return dirty;
|
|
9492
10522
|
}
|
|
9493
10523
|
/* Return sanitized string or DOM */
|
|
9494
10524
|
if (RETURN_DOM) {
|
|
9495
10525
|
if (SAFE_FOR_TEMPLATES) {
|
|
9496
|
-
body
|
|
9497
|
-
let html = body.innerHTML;
|
|
9498
|
-
arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
|
|
9499
|
-
html = stringReplace(html, expr, ' ');
|
|
9500
|
-
});
|
|
9501
|
-
body.innerHTML = html;
|
|
10526
|
+
_scrubTemplateExpressions2(body);
|
|
9502
10527
|
}
|
|
9503
10528
|
if (RETURN_DOM_FRAGMENT) {
|
|
9504
10529
|
returnNode = createDocumentFragment.call(body.ownerDocument);
|
|
@@ -9528,20 +10553,28 @@ function requirePurify_cjs () {
|
|
|
9528
10553
|
}
|
|
9529
10554
|
/* Sanitize final string template-safe */
|
|
9530
10555
|
if (SAFE_FOR_TEMPLATES) {
|
|
9531
|
-
|
|
9532
|
-
serializedHTML = stringReplace(serializedHTML, expr, ' ');
|
|
9533
|
-
});
|
|
10556
|
+
serializedHTML = _stripTemplateExpressions(serializedHTML);
|
|
9534
10557
|
}
|
|
9535
|
-
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ?
|
|
10558
|
+
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(serializedHTML) : serializedHTML;
|
|
9536
10559
|
};
|
|
9537
10560
|
DOMPurify.setConfig = function () {
|
|
9538
10561
|
let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
9539
10562
|
_parseConfig(cfg);
|
|
9540
10563
|
SET_CONFIG = true;
|
|
10564
|
+
SET_CONFIG_ALLOWED_TAGS = ALLOWED_TAGS;
|
|
10565
|
+
SET_CONFIG_ALLOWED_ATTR = ALLOWED_ATTR;
|
|
9541
10566
|
};
|
|
9542
10567
|
DOMPurify.clearConfig = function () {
|
|
9543
10568
|
CONFIG = null;
|
|
9544
10569
|
SET_CONFIG = false;
|
|
10570
|
+
SET_CONFIG_ALLOWED_TAGS = null;
|
|
10571
|
+
SET_CONFIG_ALLOWED_ATTR = null;
|
|
10572
|
+
// Drop any caller-supplied Trusted Types policy so it cannot poison later
|
|
10573
|
+
// `RETURN_TRUSTED_TYPE` output. The internal default policy (cached, and
|
|
10574
|
+
// never recreated — Trusted Types throws on duplicate names) is restored by
|
|
10575
|
+
// the next `_parseConfig`. See GHSA-vxr8-fq34-vvx9.
|
|
10576
|
+
trustedTypesPolicy = defaultTrustedTypesPolicy;
|
|
10577
|
+
emptyHTML = '';
|
|
9545
10578
|
};
|
|
9546
10579
|
DOMPurify.isValidAttribute = function (tag, attr, value) {
|
|
9547
10580
|
/* Initialize shared config vars if necessary. */
|
|
@@ -9556,9 +10589,19 @@ function requirePurify_cjs () {
|
|
|
9556
10589
|
if (typeof hookFunction !== 'function') {
|
|
9557
10590
|
return;
|
|
9558
10591
|
}
|
|
10592
|
+
/* Reject unknown entry points. Without this, a non-hook key (e.g.
|
|
10593
|
+
* '__proto__') indexes off the prototype chain rather than a real
|
|
10594
|
+
* hook array, and arrayPush then writes to Object.prototype. Guard
|
|
10595
|
+
* with an own-property check against the known hook names. */
|
|
10596
|
+
if (!objectHasOwnProperty(hooks, entryPoint)) {
|
|
10597
|
+
return;
|
|
10598
|
+
}
|
|
9559
10599
|
arrayPush(hooks[entryPoint], hookFunction);
|
|
9560
10600
|
};
|
|
9561
10601
|
DOMPurify.removeHook = function (entryPoint, hookFunction) {
|
|
10602
|
+
if (!objectHasOwnProperty(hooks, entryPoint)) {
|
|
10603
|
+
return undefined;
|
|
10604
|
+
}
|
|
9562
10605
|
if (hookFunction !== undefined) {
|
|
9563
10606
|
const index = arrayLastIndexOf(hooks[entryPoint], hookFunction);
|
|
9564
10607
|
return index === -1 ? undefined : arraySplice(hooks[entryPoint], index, 1)[0];
|
|
@@ -9566,6 +10609,9 @@ function requirePurify_cjs () {
|
|
|
9566
10609
|
return arrayPop(hooks[entryPoint]);
|
|
9567
10610
|
};
|
|
9568
10611
|
DOMPurify.removeHooks = function (entryPoint) {
|
|
10612
|
+
if (!objectHasOwnProperty(hooks, entryPoint)) {
|
|
10613
|
+
return;
|
|
10614
|
+
}
|
|
9569
10615
|
hooks[entryPoint] = [];
|
|
9570
10616
|
};
|
|
9571
10617
|
DOMPurify.removeAllHooks = function () {
|
|
@@ -9826,10 +10872,26 @@ var WalletBackground = /*#__PURE__*/function (_Background) {
|
|
|
9826
10872
|
}(Background);
|
|
9827
10873
|
|
|
9828
10874
|
/**
|
|
9829
|
-
* Generate a unique id compatible with HTML element id
|
|
10875
|
+
* Generate a unique id compatible with HTML element id.
|
|
10876
|
+
* Uses the Web Crypto API for cryptographically strong randomness, with a
|
|
10877
|
+
* deterministic fallback only when crypto is unavailable.
|
|
9830
10878
|
*/
|
|
9831
10879
|
function getUniqueId() {
|
|
9832
|
-
|
|
10880
|
+
var letters = 'abcdefghijklmnopqrstuvwxyz';
|
|
10881
|
+
var length = 10;
|
|
10882
|
+
var bytes = new Uint8Array(length);
|
|
10883
|
+
if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {
|
|
10884
|
+
crypto.getRandomValues(bytes);
|
|
10885
|
+
} else {
|
|
10886
|
+
for (var i = 0; i < length; i++) {
|
|
10887
|
+
bytes[i] = (i * 31 + 7) % 256;
|
|
10888
|
+
}
|
|
10889
|
+
}
|
|
10890
|
+
var id = '';
|
|
10891
|
+
for (var _i = 0; _i < length; _i++) {
|
|
10892
|
+
id += letters[bytes[_i] % letters.length];
|
|
10893
|
+
}
|
|
10894
|
+
return id;
|
|
9833
10895
|
}
|
|
9834
10896
|
|
|
9835
10897
|
function getFlypayV2Button(widgetId) {
|
|
@@ -12795,208 +13857,75 @@ function getBaseFormFields(configuration) {
|
|
|
12795
13857
|
function getDefinedFormFields(configuration) {
|
|
12796
13858
|
return getBaseFormFields(configuration).map(function (field) {
|
|
12797
13859
|
var _a, _b;
|
|
12798
|
-
if ((_a = configuration.defined_form_fields) === null || _a === void 0 ? void 0 : _a.includes(field)) {
|
|
12799
|
-
return field;
|
|
12800
|
-
}
|
|
12801
|
-
if ((_b = configuration.defined_form_fields) === null || _b === void 0 ? void 0 : _b.includes("".concat(field, "*"))) {
|
|
12802
|
-
return "".concat(field, "*");
|
|
12803
|
-
}
|
|
12804
|
-
}).filter(Boolean);
|
|
12805
|
-
}
|
|
12806
|
-
function getDynamicFormFields(configuration) {
|
|
12807
|
-
var _a;
|
|
12808
|
-
var baseFormFields = getBaseFormFields(configuration);
|
|
12809
|
-
return (_a = configuration.defined_form_fields) === null || _a === void 0 ? void 0 : _a.map(function (field) {
|
|
12810
|
-
var sanitizedField = field.replace('*', '');
|
|
12811
|
-
if (baseFormFields.includes(sanitizedField)) {
|
|
12812
|
-
return field;
|
|
12813
|
-
}
|
|
12814
|
-
}).filter(Boolean);
|
|
12815
|
-
}
|
|
12816
|
-
function getMetaFields(configuration) {
|
|
12817
|
-
return Object.values(META_FIELDS).reduce(function (accumulator, metaField) {
|
|
12818
|
-
var _a;
|
|
12819
|
-
var configurationMetaFieldValue = (_a = configuration.meta) === null || _a === void 0 ? void 0 : _a[metaField];
|
|
12820
|
-
if (!configurationMetaFieldValue) {
|
|
12821
|
-
return accumulator;
|
|
12822
|
-
}
|
|
12823
|
-
return _extends({}, accumulator, _defineProperty({}, metaField, configuration.meta[metaField]));
|
|
12824
|
-
}, {});
|
|
12825
|
-
}
|
|
12826
|
-
function getPredefinedFields(configuration) {
|
|
12827
|
-
var gatewayId = configuration.predefined_fields.gateway_id === 'not_configured' ? '' : configuration.predefined_fields.gateway_id;
|
|
12828
|
-
return _extends({}, configuration.predefined_fields, {
|
|
12829
|
-
gateway_id: gatewayId
|
|
12830
|
-
});
|
|
12831
|
-
}
|
|
12832
|
-
function getWrongPredefinedFields(configuration) {
|
|
12833
|
-
var erroringFields = getBasePredefinedFields(configuration).map(function (field) {
|
|
12834
|
-
return !configuration.predefined_fields[field] ? field : '';
|
|
12835
|
-
}).filter(Boolean);
|
|
12836
|
-
if (erroringFields.length) {
|
|
12837
|
-
return erroringFields.join(', ').concat(" ".concat(erroringFields.length > 1 ? 'are' : 'is', " cannot be empty"));
|
|
12838
|
-
}
|
|
12839
|
-
}
|
|
12840
|
-
function getBasePredefinedFields(configuration) {
|
|
12841
|
-
var basePredefinedFields = [PREDEFINED_FIELDS.GATEWAY_ID, PREDEFINED_FIELDS.TYPE];
|
|
12842
|
-
switch (configuration.predefined_fields.type) {
|
|
12843
|
-
case PAYMENT_SOURCE_TYPE.GIFT_CARD:
|
|
12844
|
-
{
|
|
12845
|
-
return basePredefinedFields.concat([PREDEFINED_FIELDS.CARD_SCHEME, PREDEFINED_FIELDS.CARD_PROCESSING_NETWORK]);
|
|
12846
|
-
}
|
|
12847
|
-
default:
|
|
12848
|
-
{
|
|
12849
|
-
return basePredefinedFields;
|
|
12850
|
-
}
|
|
12851
|
-
}
|
|
12852
|
-
}
|
|
12853
|
-
function getHandleCvv(configuration) {
|
|
12854
|
-
switch (configuration.purpose) {
|
|
12855
|
-
case PURPOSE.CARD_PAYMENT_SOURCE_WITH_CVV:
|
|
12856
|
-
{
|
|
12857
|
-
return true;
|
|
12858
|
-
}
|
|
12859
|
-
case PURPOSE.CARD_PAYMENT_SOURCE_WITHOUT_CVV:
|
|
12860
|
-
{
|
|
12861
|
-
return false;
|
|
12862
|
-
}
|
|
12863
|
-
default:
|
|
12864
|
-
{
|
|
12865
|
-
return undefined;
|
|
12866
|
-
}
|
|
12867
|
-
}
|
|
12868
|
-
}
|
|
12869
|
-
|
|
12870
|
-
/**
|
|
12871
|
-
* Top-level classification of an error. Used by the SDK to route errors to the
|
|
12872
|
-
* right category in instrumentation and to give consumers a coarse-grained
|
|
12873
|
-
* tag for grouping/filtering. See {@link getErrorCategory} for the mapping
|
|
12874
|
-
* between {@link ERROR_CAUSE} and {@link ERROR_CATEGORY}.
|
|
12875
|
-
*/
|
|
12876
|
-
var ERROR_CATEGORY = {
|
|
12877
|
-
/** SDK was misconfigured (missing keys, invalid options, etc.). */
|
|
12878
|
-
CONFIGURATION: 'configuration',
|
|
12879
|
-
/** Authentication or authorization failure. */
|
|
12880
|
-
IDENTITY: 'identity_access_management',
|
|
12881
|
-
/** SDK internal failure or upstream service problem. */
|
|
12882
|
-
INTERNAL: 'internal',
|
|
12883
|
-
/** Flow lifecycle event (user cancelled, aborted, etc.) — not a real fault. */
|
|
12884
|
-
PROCESS: 'process',
|
|
12885
|
-
/** Resource lookup failed or was rate-limited. */
|
|
12886
|
-
RESOURCE: 'resource',
|
|
12887
|
-
/** Invalid input or business-rule validation failure. */
|
|
12888
|
-
VALIDATION: 'validation'
|
|
12889
|
-
};
|
|
12890
|
-
/**
|
|
12891
|
-
* Concrete cause of an error. More specific than {@link ERROR_CATEGORY} —
|
|
12892
|
-
* useful for deciding programmatic responses (e.g. show a retry button only
|
|
12893
|
-
* when `cause` is `'service_unreachable'` or `'server_busy'`).
|
|
12894
|
-
*/
|
|
12895
|
-
var ERROR_CAUSE = {
|
|
12896
|
-
/** Operation was aborted programmatically. */
|
|
12897
|
-
ABORTED: 'aborted',
|
|
12898
|
-
/** Caller has insufficient permissions for the operation. */
|
|
12899
|
-
ACCESS_FORBIDDEN: 'access_forbidden',
|
|
12900
|
-
/** Resource already exists when create was expected. */
|
|
12901
|
-
ALREADY_EXISTS: 'already_exists',
|
|
12902
|
-
/** User cancelled the flow (e.g. closed the wallet sheet). */
|
|
12903
|
-
CANCELED: 'canceled',
|
|
12904
|
-
/** SDK was instantiated or invoked with invalid configuration. */
|
|
12905
|
-
INVALID_CONFIGURATION: 'invalid_configuration',
|
|
12906
|
-
/** Input failed structural or business-rule validation. */
|
|
12907
|
-
INVALID_INPUT: 'invalid_input',
|
|
12908
|
-
/** Resource was not found by the backend. */
|
|
12909
|
-
NOT_FOUND: 'not_found',
|
|
12910
|
-
/** Operation is not supported in the current context or version. */
|
|
12911
|
-
NOT_IMPLEMENTED: 'not_implemented',
|
|
12912
|
-
/** Caller exceeded the allowed request rate. */
|
|
12913
|
-
RATE_LIMITED: 'rate_limited',
|
|
12914
|
-
/** Backend is healthy but currently overloaded — typically retryable. */
|
|
12915
|
-
SERVER_BUSY: 'server_busy',
|
|
12916
|
-
/** Backend or third-party service could not be reached — typically retryable. */
|
|
12917
|
-
SERVICE_UNREACHABLE: 'service_unreachable',
|
|
12918
|
-
/** Caller is not authenticated. */
|
|
12919
|
-
UNAUTHORIZED: 'unauthorized',
|
|
12920
|
-
/** Catch-all when no other cause applies. */
|
|
12921
|
-
UNKNOWN: 'unknown_error',
|
|
12922
|
-
/** Request was syntactically valid but semantically rejected. */
|
|
12923
|
-
UNPROCESSABLE_ENTITY: 'unprocessable_entity'
|
|
12924
|
-
};
|
|
12925
|
-
var EventError = /*#__PURE__*/function (_Error) {
|
|
12926
|
-
function EventError(cause, category, retryable, details) {
|
|
12927
|
-
var _this;
|
|
12928
|
-
_classCallCheck(this, EventError);
|
|
12929
|
-
_this = _callSuper(this, EventError, [details.message]);
|
|
12930
|
-
_this.cause = cause;
|
|
12931
|
-
_this.category = category;
|
|
12932
|
-
_this.retryable = retryable;
|
|
12933
|
-
_this.details = details;
|
|
12934
|
-
Object.setPrototypeOf(_this, EventError.prototype);
|
|
12935
|
-
_this.name = EventError.name;
|
|
12936
|
-
return _this;
|
|
12937
|
-
}
|
|
12938
|
-
_inherits(EventError, _Error);
|
|
12939
|
-
return _createClass(EventError, [{
|
|
12940
|
-
key: "toJSON",
|
|
12941
|
-
value: function toJSON() {
|
|
12942
|
-
return {
|
|
12943
|
-
error: {
|
|
12944
|
-
category: this.category,
|
|
12945
|
-
cause: this.cause,
|
|
12946
|
-
details: this.details,
|
|
12947
|
-
retryable: this.retryable
|
|
12948
|
-
}
|
|
12949
|
-
};
|
|
13860
|
+
if ((_a = configuration.defined_form_fields) === null || _a === void 0 ? void 0 : _a.includes(field)) {
|
|
13861
|
+
return field;
|
|
12950
13862
|
}
|
|
12951
|
-
|
|
12952
|
-
|
|
12953
|
-
value: function setContextId(contextId) {
|
|
12954
|
-
this.details.contextId = contextId;
|
|
13863
|
+
if ((_b = configuration.defined_form_fields) === null || _b === void 0 ? void 0 : _b.includes("".concat(field, "*"))) {
|
|
13864
|
+
return "".concat(field, "*");
|
|
12955
13865
|
}
|
|
12956
|
-
}
|
|
12957
|
-
|
|
12958
|
-
|
|
12959
|
-
|
|
13866
|
+
}).filter(Boolean);
|
|
13867
|
+
}
|
|
13868
|
+
function getDynamicFormFields(configuration) {
|
|
13869
|
+
var _a;
|
|
13870
|
+
var baseFormFields = getBaseFormFields(configuration);
|
|
13871
|
+
return (_a = configuration.defined_form_fields) === null || _a === void 0 ? void 0 : _a.map(function (field) {
|
|
13872
|
+
var sanitizedField = field.replace('*', '');
|
|
13873
|
+
if (baseFormFields.includes(sanitizedField)) {
|
|
13874
|
+
return field;
|
|
12960
13875
|
}
|
|
12961
|
-
}
|
|
12962
|
-
|
|
12963
|
-
|
|
12964
|
-
|
|
12965
|
-
|
|
12966
|
-
|
|
12967
|
-
|
|
12968
|
-
|
|
12969
|
-
message: message,
|
|
12970
|
-
timestamp: new Date().toISOString()
|
|
12971
|
-
};
|
|
12972
|
-
var category = getErrorCategory(cause);
|
|
12973
|
-
return new EventError(cause, category, retryable, details);
|
|
13876
|
+
}).filter(Boolean);
|
|
13877
|
+
}
|
|
13878
|
+
function getMetaFields(configuration) {
|
|
13879
|
+
return Object.values(META_FIELDS).reduce(function (accumulator, metaField) {
|
|
13880
|
+
var _a;
|
|
13881
|
+
var configurationMetaFieldValue = (_a = configuration.meta) === null || _a === void 0 ? void 0 : _a[metaField];
|
|
13882
|
+
if (!configurationMetaFieldValue) {
|
|
13883
|
+
return accumulator;
|
|
12974
13884
|
}
|
|
12975
|
-
|
|
12976
|
-
}
|
|
12977
|
-
|
|
12978
|
-
|
|
12979
|
-
|
|
12980
|
-
|
|
12981
|
-
|
|
12982
|
-
|
|
12983
|
-
|
|
12984
|
-
|
|
12985
|
-
|
|
12986
|
-
|
|
12987
|
-
|
|
12988
|
-
|
|
12989
|
-
|
|
12990
|
-
|
|
12991
|
-
|
|
12992
|
-
|
|
12993
|
-
|
|
12994
|
-
|
|
12995
|
-
case
|
|
12996
|
-
|
|
12997
|
-
|
|
13885
|
+
return _extends({}, accumulator, _defineProperty({}, metaField, configuration.meta[metaField]));
|
|
13886
|
+
}, {});
|
|
13887
|
+
}
|
|
13888
|
+
function getPredefinedFields(configuration) {
|
|
13889
|
+
var gatewayId = configuration.predefined_fields.gateway_id === 'not_configured' ? '' : configuration.predefined_fields.gateway_id;
|
|
13890
|
+
return _extends({}, configuration.predefined_fields, {
|
|
13891
|
+
gateway_id: gatewayId
|
|
13892
|
+
});
|
|
13893
|
+
}
|
|
13894
|
+
function getWrongPredefinedFields(configuration) {
|
|
13895
|
+
var erroringFields = getBasePredefinedFields(configuration).map(function (field) {
|
|
13896
|
+
return !configuration.predefined_fields[field] ? field : '';
|
|
13897
|
+
}).filter(Boolean);
|
|
13898
|
+
if (erroringFields.length) {
|
|
13899
|
+
return erroringFields.join(', ').concat(" ".concat(erroringFields.length > 1 ? 'are' : 'is', " cannot be empty"));
|
|
13900
|
+
}
|
|
13901
|
+
}
|
|
13902
|
+
function getBasePredefinedFields(configuration) {
|
|
13903
|
+
var basePredefinedFields = [PREDEFINED_FIELDS.GATEWAY_ID, PREDEFINED_FIELDS.TYPE];
|
|
13904
|
+
switch (configuration.predefined_fields.type) {
|
|
13905
|
+
case PAYMENT_SOURCE_TYPE.GIFT_CARD:
|
|
13906
|
+
{
|
|
13907
|
+
return basePredefinedFields.concat([PREDEFINED_FIELDS.CARD_SCHEME, PREDEFINED_FIELDS.CARD_PROCESSING_NETWORK]);
|
|
13908
|
+
}
|
|
12998
13909
|
default:
|
|
12999
|
-
|
|
13910
|
+
{
|
|
13911
|
+
return basePredefinedFields;
|
|
13912
|
+
}
|
|
13913
|
+
}
|
|
13914
|
+
}
|
|
13915
|
+
function getHandleCvv(configuration) {
|
|
13916
|
+
switch (configuration.purpose) {
|
|
13917
|
+
case PURPOSE.CARD_PAYMENT_SOURCE_WITH_CVV:
|
|
13918
|
+
{
|
|
13919
|
+
return true;
|
|
13920
|
+
}
|
|
13921
|
+
case PURPOSE.CARD_PAYMENT_SOURCE_WITHOUT_CVV:
|
|
13922
|
+
{
|
|
13923
|
+
return false;
|
|
13924
|
+
}
|
|
13925
|
+
default:
|
|
13926
|
+
{
|
|
13927
|
+
return undefined;
|
|
13928
|
+
}
|
|
13000
13929
|
}
|
|
13001
13930
|
}
|
|
13002
13931
|
|
|
@@ -19094,6 +20023,90 @@ var EVENT$1;
|
|
|
19094
20023
|
EVENT["ON_SHIPPING_OPTIONS_CHANGE"] = "onShippingOptionsChange";
|
|
19095
20024
|
})(EVENT$1 || (EVENT$1 = {}));
|
|
19096
20025
|
|
|
20026
|
+
/** TTL for a cached service configuration: 1 day, in milliseconds. */
|
|
20027
|
+
var CACHE_TTL_MS = 86400000;
|
|
20028
|
+
/** Builds the `localStorage` key used to cache a service's configuration. */
|
|
20029
|
+
function serviceConfigStorageKey(serviceId) {
|
|
20030
|
+
return "paydock-serviceConfig-".concat(serviceId);
|
|
20031
|
+
}
|
|
20032
|
+
/**
|
|
20033
|
+
* Removes the cached service configuration for the given service ID, forcing the next
|
|
20034
|
+
* fetch to go to the network. Called on error / unavailable flows so a potentially
|
|
20035
|
+
* stale cached config is not reused after something changed server-side. No-throw when
|
|
20036
|
+
* `localStorage` is unavailable.
|
|
20037
|
+
*
|
|
20038
|
+
* @param serviceId - The service ID whose cached configuration should be cleared.
|
|
20039
|
+
*/
|
|
20040
|
+
function clearServiceConfigCache(serviceId) {
|
|
20041
|
+
try {
|
|
20042
|
+
localStorage.removeItem(serviceConfigStorageKey(serviceId));
|
|
20043
|
+
} catch (_error) {
|
|
20044
|
+
// localStorage may be unavailable; nothing to clear
|
|
20045
|
+
}
|
|
20046
|
+
}
|
|
20047
|
+
/**
|
|
20048
|
+
* Fetches the wallet service configuration, backed by a 1-day `localStorage` cache
|
|
20049
|
+
* keyed on the service ID. Falls back gracefully (no caching) when `localStorage`
|
|
20050
|
+
* is unavailable (e.g. private browsing). Shared by the instance `load()` flow and
|
|
20051
|
+
* the static availability checks so both reuse the same cached fetch.
|
|
20052
|
+
*
|
|
20053
|
+
* @param api - The configured API client (env must already be set).
|
|
20054
|
+
* @param serviceId - The service ID to fetch the configuration for.
|
|
20055
|
+
* @returns The service configuration response.
|
|
20056
|
+
*/
|
|
20057
|
+
function getServiceConfigCached(api, serviceId) {
|
|
20058
|
+
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator().m(function _callee() {
|
|
20059
|
+
var storageKey, cachedData, _JSON$parse, data, timestamp, serviceConfigResponse, encodedData;
|
|
20060
|
+
return _regenerator().w(function (_context) {
|
|
20061
|
+
while (1) switch (_context.p = _context.n) {
|
|
20062
|
+
case 0:
|
|
20063
|
+
storageKey = serviceConfigStorageKey(serviceId);
|
|
20064
|
+
_context.p = 1;
|
|
20065
|
+
cachedData = localStorage.getItem(storageKey);
|
|
20066
|
+
if (!cachedData) {
|
|
20067
|
+
_context.n = 5;
|
|
20068
|
+
break;
|
|
20069
|
+
}
|
|
20070
|
+
_context.p = 2;
|
|
20071
|
+
_JSON$parse = JSON.parse(atob(cachedData)), data = _JSON$parse.data, timestamp = _JSON$parse.timestamp;
|
|
20072
|
+
if (!(Date.now() - timestamp < CACHE_TTL_MS)) {
|
|
20073
|
+
_context.n = 3;
|
|
20074
|
+
break;
|
|
20075
|
+
}
|
|
20076
|
+
return _context.a(2, JSON.parse(data));
|
|
20077
|
+
case 3:
|
|
20078
|
+
_context.n = 5;
|
|
20079
|
+
break;
|
|
20080
|
+
case 4:
|
|
20081
|
+
_context.p = 4;
|
|
20082
|
+
_context.v;
|
|
20083
|
+
localStorage.removeItem(storageKey);
|
|
20084
|
+
case 5:
|
|
20085
|
+
_context.n = 7;
|
|
20086
|
+
break;
|
|
20087
|
+
case 6:
|
|
20088
|
+
_context.p = 6;
|
|
20089
|
+
_context.v;
|
|
20090
|
+
case 7:
|
|
20091
|
+
_context.n = 8;
|
|
20092
|
+
return api.service().getConfig(serviceId);
|
|
20093
|
+
case 8:
|
|
20094
|
+
serviceConfigResponse = _context.v;
|
|
20095
|
+
try {
|
|
20096
|
+
encodedData = btoa(JSON.stringify({
|
|
20097
|
+
data: JSON.stringify(serviceConfigResponse),
|
|
20098
|
+
timestamp: Date.now()
|
|
20099
|
+
}));
|
|
20100
|
+
localStorage.setItem(storageKey, encodedData);
|
|
20101
|
+
} catch (_error) {
|
|
20102
|
+
// localStorage may be unavailable; proceed without caching
|
|
20103
|
+
}
|
|
20104
|
+
return _context.a(2, serviceConfigResponse);
|
|
20105
|
+
}
|
|
20106
|
+
}, _callee, null, [[2, 4], [1, 6]]);
|
|
20107
|
+
}));
|
|
20108
|
+
}
|
|
20109
|
+
|
|
19097
20110
|
/**
|
|
19098
20111
|
* @classdesc Abstract base class for Open Wallet buttons. **Do not instantiate directly.**
|
|
19099
20112
|
* Use {@link ApplePayOpenWalletButton} or {@link GooglePayOpenWalletButton} instead.
|
|
@@ -19127,10 +20140,30 @@ var OpenWalletButtons = /*#__PURE__*/function () {
|
|
|
19127
20140
|
this.api = new ApiInternal(publicKeyOrAccessToken, this.getApiAuthType(publicKeyOrAccessToken));
|
|
19128
20141
|
this.serviceId = serviceId;
|
|
19129
20142
|
this.meta = meta;
|
|
20143
|
+
this.registerCacheInvalidationOnError();
|
|
19130
20144
|
this.validateBaseMeta();
|
|
19131
20145
|
this.validateWalletMeta();
|
|
19132
20146
|
}
|
|
20147
|
+
/**
|
|
20148
|
+
* Invalidates the cached service configuration whenever an error or unavailable
|
|
20149
|
+
* event fires, so the next `load()` re-fetches a fresh config. The cache is keyed
|
|
20150
|
+
* on the service ID with a 1-day TTL; clearing it on failure means a config that
|
|
20151
|
+
* changed server-side (and caused the failure) is not reused until the TTL expires.
|
|
20152
|
+
* Registered once per button, independently of any merchant-registered handlers.
|
|
20153
|
+
*
|
|
20154
|
+
* @private
|
|
20155
|
+
*/
|
|
19133
20156
|
return _createClass(OpenWalletButtons, [{
|
|
20157
|
+
key: "registerCacheInvalidationOnError",
|
|
20158
|
+
value: function registerCacheInvalidationOnError() {
|
|
20159
|
+
var _this = this;
|
|
20160
|
+
var invalidate = function invalidate() {
|
|
20161
|
+
return clearServiceConfigCache(_this.serviceId);
|
|
20162
|
+
};
|
|
20163
|
+
this.eventEmitter.subscribe(EVENT$1.ERROR, invalidate);
|
|
20164
|
+
this.eventEmitter.subscribe(EVENT$1.UNAVAILABLE, invalidate);
|
|
20165
|
+
}
|
|
20166
|
+
}, {
|
|
19134
20167
|
key: "getApiAuthType",
|
|
19135
20168
|
value: function getApiAuthType(publicKeyOrAccessToken) {
|
|
19136
20169
|
if (AccessToken.validateJWT(publicKeyOrAccessToken)) {
|
|
@@ -19164,57 +20197,7 @@ var OpenWalletButtons = /*#__PURE__*/function () {
|
|
|
19164
20197
|
}, {
|
|
19165
20198
|
key: "getOpenWalletServiceConfig",
|
|
19166
20199
|
value: function getOpenWalletServiceConfig() {
|
|
19167
|
-
return
|
|
19168
|
-
var storageKey, cachedData, _JSON$parse, data, timestamp, oneDay, serviceConfigResponse, encodedData;
|
|
19169
|
-
return _regenerator().w(function (_context) {
|
|
19170
|
-
while (1) switch (_context.p = _context.n) {
|
|
19171
|
-
case 0:
|
|
19172
|
-
storageKey = "serviceConfig-".concat(this.serviceId);
|
|
19173
|
-
_context.p = 1;
|
|
19174
|
-
cachedData = localStorage.getItem(storageKey);
|
|
19175
|
-
if (!cachedData) {
|
|
19176
|
-
_context.n = 5;
|
|
19177
|
-
break;
|
|
19178
|
-
}
|
|
19179
|
-
_context.p = 2;
|
|
19180
|
-
_JSON$parse = JSON.parse(atob(cachedData)), data = _JSON$parse.data, timestamp = _JSON$parse.timestamp;
|
|
19181
|
-
oneDay = 86400000;
|
|
19182
|
-
if (!(Date.now() - timestamp < oneDay)) {
|
|
19183
|
-
_context.n = 3;
|
|
19184
|
-
break;
|
|
19185
|
-
}
|
|
19186
|
-
return _context.a(2, JSON.parse(data));
|
|
19187
|
-
case 3:
|
|
19188
|
-
_context.n = 5;
|
|
19189
|
-
break;
|
|
19190
|
-
case 4:
|
|
19191
|
-
_context.p = 4;
|
|
19192
|
-
_context.v;
|
|
19193
|
-
localStorage.removeItem(storageKey);
|
|
19194
|
-
case 5:
|
|
19195
|
-
_context.n = 7;
|
|
19196
|
-
break;
|
|
19197
|
-
case 6:
|
|
19198
|
-
_context.p = 6;
|
|
19199
|
-
_context.v;
|
|
19200
|
-
case 7:
|
|
19201
|
-
_context.n = 8;
|
|
19202
|
-
return this.api.service().getConfig(this.serviceId);
|
|
19203
|
-
case 8:
|
|
19204
|
-
serviceConfigResponse = _context.v;
|
|
19205
|
-
try {
|
|
19206
|
-
encodedData = btoa(JSON.stringify({
|
|
19207
|
-
data: JSON.stringify(serviceConfigResponse),
|
|
19208
|
-
timestamp: Date.now()
|
|
19209
|
-
}));
|
|
19210
|
-
localStorage.setItem(storageKey, encodedData);
|
|
19211
|
-
} catch (_error) {
|
|
19212
|
-
// localStorage may be unavailable; proceed without caching
|
|
19213
|
-
}
|
|
19214
|
-
return _context.a(2, serviceConfigResponse);
|
|
19215
|
-
}
|
|
19216
|
-
}, _callee, this, [[2, 4], [1, 6]]);
|
|
19217
|
-
}));
|
|
20200
|
+
return getServiceConfigCached(this.api, this.serviceId);
|
|
19218
20201
|
}
|
|
19219
20202
|
}, {
|
|
19220
20203
|
key: "handleOnError",
|
|
@@ -19249,13 +20232,13 @@ var OpenWalletButtons = /*#__PURE__*/function () {
|
|
|
19249
20232
|
}, {
|
|
19250
20233
|
key: "load",
|
|
19251
20234
|
value: function load() {
|
|
19252
|
-
var
|
|
20235
|
+
var _this2 = this;
|
|
19253
20236
|
this.getOpenWalletServiceConfig().then(function (serviceConfig) {
|
|
19254
|
-
|
|
19255
|
-
|
|
19256
|
-
|
|
20237
|
+
_this2.validateServiceType(serviceConfig);
|
|
20238
|
+
_this2.walletService = _this2.createWalletService(serviceConfig);
|
|
20239
|
+
_this2.walletService.load();
|
|
19257
20240
|
})["catch"](function (error) {
|
|
19258
|
-
|
|
20241
|
+
_this2.handleOnError(error instanceof Error ? error : new Error(String(error)), exports.ERROR_OPERATION.CONFIGURATION);
|
|
19259
20242
|
});
|
|
19260
20243
|
}
|
|
19261
20244
|
/**
|
|
@@ -19453,28 +20436,28 @@ var OpenWalletButtons = /*#__PURE__*/function () {
|
|
|
19453
20436
|
}, {
|
|
19454
20437
|
key: "onSuccess",
|
|
19455
20438
|
value: function onSuccess(handler) {
|
|
19456
|
-
var
|
|
20439
|
+
var _this3 = this;
|
|
19457
20440
|
if (typeof handler === 'function') {
|
|
19458
20441
|
this.eventEmitter.subscribe(EVENT$1.SUCCESS, function (data) {
|
|
19459
|
-
return __awaiter(
|
|
19460
|
-
var
|
|
19461
|
-
return _regenerator().w(function (
|
|
19462
|
-
while (1) switch (
|
|
20442
|
+
return __awaiter(_this3, void 0, void 0, /*#__PURE__*/_regenerator().m(function _callee() {
|
|
20443
|
+
var _t;
|
|
20444
|
+
return _regenerator().w(function (_context) {
|
|
20445
|
+
while (1) switch (_context.p = _context.n) {
|
|
19463
20446
|
case 0:
|
|
19464
|
-
|
|
19465
|
-
|
|
20447
|
+
_context.p = 0;
|
|
20448
|
+
_context.n = 1;
|
|
19466
20449
|
return handler(data);
|
|
19467
20450
|
case 1:
|
|
19468
|
-
|
|
20451
|
+
_context.n = 3;
|
|
19469
20452
|
break;
|
|
19470
20453
|
case 2:
|
|
19471
|
-
|
|
19472
|
-
|
|
19473
|
-
console.warn('Merchant onSuccess handler threw (swallowed):',
|
|
20454
|
+
_context.p = 2;
|
|
20455
|
+
_t = _context.v;
|
|
20456
|
+
console.warn('Merchant onSuccess handler threw (swallowed):', _t);
|
|
19474
20457
|
case 3:
|
|
19475
|
-
return
|
|
20458
|
+
return _context.a(2);
|
|
19476
20459
|
}
|
|
19477
|
-
},
|
|
20460
|
+
}, _callee, null, [[0, 2]]);
|
|
19478
20461
|
}));
|
|
19479
20462
|
});
|
|
19480
20463
|
return;
|
|
@@ -19505,28 +20488,28 @@ var OpenWalletButtons = /*#__PURE__*/function () {
|
|
|
19505
20488
|
}, {
|
|
19506
20489
|
key: "onUnavailable",
|
|
19507
20490
|
value: function onUnavailable(handler) {
|
|
19508
|
-
var
|
|
20491
|
+
var _this4 = this;
|
|
19509
20492
|
if (typeof handler === 'function') {
|
|
19510
20493
|
this.eventEmitter.subscribe(EVENT$1.UNAVAILABLE, function (data) {
|
|
19511
|
-
return __awaiter(
|
|
19512
|
-
var
|
|
19513
|
-
return _regenerator().w(function (
|
|
19514
|
-
while (1) switch (
|
|
20494
|
+
return __awaiter(_this4, void 0, void 0, /*#__PURE__*/_regenerator().m(function _callee2() {
|
|
20495
|
+
var _t2;
|
|
20496
|
+
return _regenerator().w(function (_context2) {
|
|
20497
|
+
while (1) switch (_context2.p = _context2.n) {
|
|
19515
20498
|
case 0:
|
|
19516
|
-
|
|
19517
|
-
|
|
20499
|
+
_context2.p = 0;
|
|
20500
|
+
_context2.n = 1;
|
|
19518
20501
|
return handler(data);
|
|
19519
20502
|
case 1:
|
|
19520
|
-
|
|
20503
|
+
_context2.n = 3;
|
|
19521
20504
|
break;
|
|
19522
20505
|
case 2:
|
|
19523
|
-
|
|
19524
|
-
|
|
19525
|
-
console.warn('Merchant onUnavailable handler threw (swallowed):',
|
|
20506
|
+
_context2.p = 2;
|
|
20507
|
+
_t2 = _context2.v;
|
|
20508
|
+
console.warn('Merchant onUnavailable handler threw (swallowed):', _t2);
|
|
19526
20509
|
case 3:
|
|
19527
|
-
return
|
|
20510
|
+
return _context2.a(2);
|
|
19528
20511
|
}
|
|
19529
|
-
},
|
|
20512
|
+
}, _callee2, null, [[0, 2]]);
|
|
19530
20513
|
}));
|
|
19531
20514
|
});
|
|
19532
20515
|
return;
|
|
@@ -19558,28 +20541,28 @@ var OpenWalletButtons = /*#__PURE__*/function () {
|
|
|
19558
20541
|
}, {
|
|
19559
20542
|
key: "onError",
|
|
19560
20543
|
value: function onError(handler) {
|
|
19561
|
-
var
|
|
20544
|
+
var _this5 = this;
|
|
19562
20545
|
if (typeof handler === 'function') {
|
|
19563
20546
|
this.eventEmitter.subscribe(EVENT$1.ERROR, function (data) {
|
|
19564
|
-
return __awaiter(
|
|
19565
|
-
var
|
|
19566
|
-
return _regenerator().w(function (
|
|
19567
|
-
while (1) switch (
|
|
20547
|
+
return __awaiter(_this5, void 0, void 0, /*#__PURE__*/_regenerator().m(function _callee3() {
|
|
20548
|
+
var _t3;
|
|
20549
|
+
return _regenerator().w(function (_context3) {
|
|
20550
|
+
while (1) switch (_context3.p = _context3.n) {
|
|
19568
20551
|
case 0:
|
|
19569
|
-
|
|
19570
|
-
|
|
20552
|
+
_context3.p = 0;
|
|
20553
|
+
_context3.n = 1;
|
|
19571
20554
|
return handler(data);
|
|
19572
20555
|
case 1:
|
|
19573
|
-
|
|
20556
|
+
_context3.n = 3;
|
|
19574
20557
|
break;
|
|
19575
20558
|
case 2:
|
|
19576
|
-
|
|
19577
|
-
|
|
19578
|
-
console.warn('Merchant onError handler threw (swallowed):',
|
|
20559
|
+
_context3.p = 2;
|
|
20560
|
+
_t3 = _context3.v;
|
|
20561
|
+
console.warn('Merchant onError handler threw (swallowed):', _t3);
|
|
19579
20562
|
case 3:
|
|
19580
|
-
return
|
|
20563
|
+
return _context3.a(2);
|
|
19581
20564
|
}
|
|
19582
|
-
},
|
|
20565
|
+
}, _callee3, null, [[0, 2]]);
|
|
19583
20566
|
}));
|
|
19584
20567
|
});
|
|
19585
20568
|
return;
|
|
@@ -19610,28 +20593,28 @@ var OpenWalletButtons = /*#__PURE__*/function () {
|
|
|
19610
20593
|
}, {
|
|
19611
20594
|
key: "onCancel",
|
|
19612
20595
|
value: function onCancel(handler) {
|
|
19613
|
-
var
|
|
20596
|
+
var _this6 = this;
|
|
19614
20597
|
if (typeof handler === 'function') {
|
|
19615
20598
|
this.eventEmitter.subscribe(EVENT$1.CHECKOUT_CLOSE, function (data) {
|
|
19616
|
-
return __awaiter(
|
|
19617
|
-
var
|
|
19618
|
-
return _regenerator().w(function (
|
|
19619
|
-
while (1) switch (
|
|
20599
|
+
return __awaiter(_this6, void 0, void 0, /*#__PURE__*/_regenerator().m(function _callee4() {
|
|
20600
|
+
var _t4;
|
|
20601
|
+
return _regenerator().w(function (_context4) {
|
|
20602
|
+
while (1) switch (_context4.p = _context4.n) {
|
|
19620
20603
|
case 0:
|
|
19621
|
-
|
|
19622
|
-
|
|
20604
|
+
_context4.p = 0;
|
|
20605
|
+
_context4.n = 1;
|
|
19623
20606
|
return handler(data);
|
|
19624
20607
|
case 1:
|
|
19625
|
-
|
|
20608
|
+
_context4.n = 3;
|
|
19626
20609
|
break;
|
|
19627
20610
|
case 2:
|
|
19628
|
-
|
|
19629
|
-
|
|
19630
|
-
console.warn('Merchant onCancel handler threw (swallowed):',
|
|
20611
|
+
_context4.p = 2;
|
|
20612
|
+
_t4 = _context4.v;
|
|
20613
|
+
console.warn('Merchant onCancel handler threw (swallowed):', _t4);
|
|
19631
20614
|
case 3:
|
|
19632
|
-
return
|
|
20615
|
+
return _context4.a(2);
|
|
19633
20616
|
}
|
|
19634
|
-
},
|
|
20617
|
+
}, _callee4, null, [[0, 2]]);
|
|
19635
20618
|
}));
|
|
19636
20619
|
});
|
|
19637
20620
|
return;
|
|
@@ -19655,28 +20638,28 @@ var OpenWalletButtons = /*#__PURE__*/function () {
|
|
|
19655
20638
|
}, {
|
|
19656
20639
|
key: "onLoaded",
|
|
19657
20640
|
value: function onLoaded(handler) {
|
|
19658
|
-
var
|
|
20641
|
+
var _this7 = this;
|
|
19659
20642
|
if (typeof handler === 'function') {
|
|
19660
20643
|
this.eventEmitter.subscribe(EVENT$1.LOADED, function (data) {
|
|
19661
|
-
return __awaiter(
|
|
19662
|
-
var
|
|
19663
|
-
return _regenerator().w(function (
|
|
19664
|
-
while (1) switch (
|
|
20644
|
+
return __awaiter(_this7, void 0, void 0, /*#__PURE__*/_regenerator().m(function _callee5() {
|
|
20645
|
+
var _t5;
|
|
20646
|
+
return _regenerator().w(function (_context5) {
|
|
20647
|
+
while (1) switch (_context5.p = _context5.n) {
|
|
19665
20648
|
case 0:
|
|
19666
|
-
|
|
19667
|
-
|
|
20649
|
+
_context5.p = 0;
|
|
20650
|
+
_context5.n = 1;
|
|
19668
20651
|
return handler(data);
|
|
19669
20652
|
case 1:
|
|
19670
|
-
|
|
20653
|
+
_context5.n = 3;
|
|
19671
20654
|
break;
|
|
19672
20655
|
case 2:
|
|
19673
|
-
|
|
19674
|
-
|
|
19675
|
-
console.warn('Merchant onLoaded handler threw (swallowed):',
|
|
20656
|
+
_context5.p = 2;
|
|
20657
|
+
_t5 = _context5.v;
|
|
20658
|
+
console.warn('Merchant onLoaded handler threw (swallowed):', _t5);
|
|
19676
20659
|
case 3:
|
|
19677
|
-
return
|
|
20660
|
+
return _context5.a(2);
|
|
19678
20661
|
}
|
|
19679
|
-
},
|
|
20662
|
+
}, _callee5, null, [[0, 2]]);
|
|
19680
20663
|
}));
|
|
19681
20664
|
});
|
|
19682
20665
|
return;
|
|
@@ -20024,7 +21007,143 @@ exports.WALLET_TYPES = void 0;
|
|
|
20024
21007
|
WALLET_TYPES["GOOGLE_PAY"] = "google";
|
|
20025
21008
|
})(exports.WALLET_TYPES || (exports.WALLET_TYPES = {}));
|
|
20026
21009
|
|
|
20027
|
-
|
|
21010
|
+
/** CDN location of Apple's web SDK (provides the `<apple-pay-button>` web component). */
|
|
21011
|
+
var APPLE_PAY_SDK_URL = 'https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js';
|
|
21012
|
+
/**
|
|
21013
|
+
* Statuses that count as available when the merchant does not override them.
|
|
21014
|
+
* Includes `paymentCredentialStatusUnknown` so the button is shown in third-party /
|
|
21015
|
+
* cross-device (QR) browsers, per Apple's guidance.
|
|
21016
|
+
*/
|
|
21017
|
+
var DEFAULT_APPLE_PAY_CAPABILITIES$1 = ['paymentCredentialsAvailable', 'paymentCredentialStatusUnknown'];
|
|
21018
|
+
/**
|
|
21019
|
+
* Maps the SDK's friendly capability tokens to Apple's `PaymentCredentialStatus` values.
|
|
21020
|
+
* Unknown tokens are passed through unchanged.
|
|
21021
|
+
*/
|
|
21022
|
+
function formatCapabilities(capabilities) {
|
|
21023
|
+
var fieldMap = {
|
|
21024
|
+
credentials_available: 'paymentCredentialsAvailable',
|
|
21025
|
+
credentials_status_unknown: 'paymentCredentialStatusUnknown',
|
|
21026
|
+
credentials_unavailable: 'paymentCredentialsUnavailable'
|
|
21027
|
+
};
|
|
21028
|
+
return capabilities.map(function (capability) {
|
|
21029
|
+
return fieldMap[capability] || capability;
|
|
21030
|
+
});
|
|
21031
|
+
}
|
|
21032
|
+
/**
|
|
21033
|
+
* Synchronous, network-free check for a **native, same-device** Apple Pay session
|
|
21034
|
+
* (`window.ApplePaySession` exists and `canMakePayments()` is `true`). Safe to call in
|
|
21035
|
+
* any environment (never throws).
|
|
21036
|
+
*
|
|
21037
|
+
* Note: this is a legacy/Safari-oriented signal. It is **not** authoritative for
|
|
21038
|
+
* cross-browser / cross-device (QR) availability — in Chrome/Edge/Firefox
|
|
21039
|
+
* `window.ApplePaySession` is supplied by the CDN SDK and may be absent until it loads,
|
|
21040
|
+
* and the cross-device flow is reflected by `applePayCapabilities()`, not this call.
|
|
21041
|
+
* Use {@link evaluateApplePayAvailability} for the authoritative, cross-browser answer.
|
|
21042
|
+
*/
|
|
21043
|
+
function hasNativeApplePaySession() {
|
|
21044
|
+
try {
|
|
21045
|
+
return typeof window !== 'undefined' && !!window.ApplePaySession && typeof ApplePaySession !== 'undefined' && ApplePaySession.canMakePayments();
|
|
21046
|
+
} catch (_a) {
|
|
21047
|
+
return false;
|
|
21048
|
+
}
|
|
21049
|
+
}
|
|
21050
|
+
var sdkLoadPromise = null;
|
|
21051
|
+
/**
|
|
21052
|
+
* Idempotently loads Apple's web SDK from the CDN.
|
|
21053
|
+
* Resolves immediately if the `<apple-pay-button>` custom element is already
|
|
21054
|
+
* registered, and de-duplicates concurrent loads. Rejects if the script fails to load.
|
|
21055
|
+
*/
|
|
21056
|
+
function loadApplePaySdk() {
|
|
21057
|
+
if (typeof customElements !== 'undefined' && customElements.get('apple-pay-button')) {
|
|
21058
|
+
return Promise.resolve();
|
|
21059
|
+
}
|
|
21060
|
+
if (sdkLoadPromise) {
|
|
21061
|
+
return sdkLoadPromise;
|
|
21062
|
+
}
|
|
21063
|
+
sdkLoadPromise = new Promise(function (resolve, reject) {
|
|
21064
|
+
var script = document.createElement('script');
|
|
21065
|
+
script.src = APPLE_PAY_SDK_URL;
|
|
21066
|
+
script.type = 'text/javascript';
|
|
21067
|
+
script.crossOrigin = 'anonymous';
|
|
21068
|
+
script.onload = function () {
|
|
21069
|
+
return resolve();
|
|
21070
|
+
};
|
|
21071
|
+
script.onerror = function () {
|
|
21072
|
+
// Allow a future retry after a transient failure.
|
|
21073
|
+
sdkLoadPromise = null;
|
|
21074
|
+
reject(new Error('Failed to load Apple Pay script'));
|
|
21075
|
+
};
|
|
21076
|
+
document.head.appendChild(script);
|
|
21077
|
+
});
|
|
21078
|
+
return sdkLoadPromise;
|
|
21079
|
+
}
|
|
21080
|
+
/**
|
|
21081
|
+
* Core Apple Pay availability evaluation, shared by the instance flow
|
|
21082
|
+
* (`ApplePayOpenWalletService`) and the static `ApplePayOpenWalletButton.checkAvailability`.
|
|
21083
|
+
*
|
|
21084
|
+
* Assumes the Apple Pay SDK is already loaded (call {@link loadApplePaySdk} first).
|
|
21085
|
+
*/
|
|
21086
|
+
function evaluateApplePayAvailability(params) {
|
|
21087
|
+
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator().m(function _callee() {
|
|
21088
|
+
var _a, hasNativeSession, allowed, capabilities, paymentCredentialStatus, available;
|
|
21089
|
+
return _regenerator().w(function (_context) {
|
|
21090
|
+
while (1) switch (_context.p = _context.n) {
|
|
21091
|
+
case 0:
|
|
21092
|
+
if (!(typeof window === 'undefined' || !window.ApplePaySession)) {
|
|
21093
|
+
_context.n = 1;
|
|
21094
|
+
break;
|
|
21095
|
+
}
|
|
21096
|
+
return _context.a(2, {
|
|
21097
|
+
available: false,
|
|
21098
|
+
supported: false,
|
|
21099
|
+
has_native_session: false,
|
|
21100
|
+
reason: 'unsupported_browser'
|
|
21101
|
+
});
|
|
21102
|
+
case 1:
|
|
21103
|
+
hasNativeSession = hasNativeApplePaySession();
|
|
21104
|
+
allowed = ((_a = params.apple_pay_capabilities) === null || _a === void 0 ? void 0 : _a.length) ? formatCapabilities(params.apple_pay_capabilities) : DEFAULT_APPLE_PAY_CAPABILITIES$1;
|
|
21105
|
+
_context.p = 2;
|
|
21106
|
+
_context.n = 3;
|
|
21107
|
+
return ApplePaySession.applePayCapabilities(params.merchantId);
|
|
21108
|
+
case 3:
|
|
21109
|
+
capabilities = _context.v;
|
|
21110
|
+
paymentCredentialStatus = capabilities === null || capabilities === void 0 ? void 0 : capabilities.paymentCredentialStatus; // `applePayCapabilities` is authoritative: trust an explicit `applePayUnsupported`
|
|
21111
|
+
// (e.g. an unregistered/misconfigured merchant) rather than overriding it with the
|
|
21112
|
+
// coarse `canMakePayments()` signal.
|
|
21113
|
+
if (!(paymentCredentialStatus === 'applePayUnsupported')) {
|
|
21114
|
+
_context.n = 4;
|
|
21115
|
+
break;
|
|
21116
|
+
}
|
|
21117
|
+
return _context.a(2, {
|
|
21118
|
+
available: false,
|
|
21119
|
+
supported: false,
|
|
21120
|
+
has_native_session: hasNativeSession,
|
|
21121
|
+
payment_credential_status: paymentCredentialStatus,
|
|
21122
|
+
reason: 'unsupported_browser'
|
|
21123
|
+
});
|
|
21124
|
+
case 4:
|
|
21125
|
+
available = allowed.includes(paymentCredentialStatus);
|
|
21126
|
+
return _context.a(2, {
|
|
21127
|
+
available: available,
|
|
21128
|
+
supported: true,
|
|
21129
|
+
has_native_session: hasNativeSession,
|
|
21130
|
+
payment_credential_status: paymentCredentialStatus,
|
|
21131
|
+
reason: available ? undefined : 'no_credentials'
|
|
21132
|
+
});
|
|
21133
|
+
case 5:
|
|
21134
|
+
_context.p = 5;
|
|
21135
|
+
_context.v;
|
|
21136
|
+
return _context.a(2, {
|
|
21137
|
+
available: false,
|
|
21138
|
+
supported: hasNativeSession,
|
|
21139
|
+
has_native_session: hasNativeSession,
|
|
21140
|
+
reason: 'query_failed'
|
|
21141
|
+
});
|
|
21142
|
+
}
|
|
21143
|
+
}, _callee, null, [[2, 5]]);
|
|
21144
|
+
}));
|
|
21145
|
+
}
|
|
21146
|
+
|
|
20028
21147
|
/**
|
|
20029
21148
|
* Apple Pay implementation of the OpenWallet service.
|
|
20030
21149
|
*
|
|
@@ -20300,7 +21419,6 @@ var ApplePayOpenWalletService = /*#__PURE__*/function (_OpenWalletService) {
|
|
|
20300
21419
|
value: function load() {
|
|
20301
21420
|
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator().m(function _callee3() {
|
|
20302
21421
|
var _this4 = this;
|
|
20303
|
-
var applePayScript;
|
|
20304
21422
|
return _regenerator().w(function (_context3) {
|
|
20305
21423
|
while (1) switch (_context3.n) {
|
|
20306
21424
|
case 0:
|
|
@@ -20311,26 +21429,12 @@ var ApplePayOpenWalletService = /*#__PURE__*/function (_OpenWalletService) {
|
|
|
20311
21429
|
this.handleOnUnavailable('Promises not supported');
|
|
20312
21430
|
return _context3.a(2);
|
|
20313
21431
|
case 1:
|
|
20314
|
-
|
|
20315
|
-
_context3.n = 2;
|
|
20316
|
-
break;
|
|
20317
|
-
}
|
|
20318
|
-
this.onScriptLoaded();
|
|
20319
|
-
return _context3.a(2);
|
|
20320
|
-
case 2:
|
|
20321
|
-
applePayScript = document.createElement('script');
|
|
20322
|
-
applePayScript.src = 'https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js';
|
|
20323
|
-
applePayScript.type = 'text/javascript';
|
|
20324
|
-
applePayScript.crossOrigin = 'anonymous';
|
|
20325
|
-
applePayScript.onload = function () {
|
|
21432
|
+
loadApplePaySdk().then(function () {
|
|
20326
21433
|
_this4.onScriptLoaded();
|
|
20327
|
-
}
|
|
20328
|
-
applePayScript.onerror = function () {
|
|
21434
|
+
})["catch"](function () {
|
|
20329
21435
|
_this4.handleOnUnavailable('Failed to load Apple Pay script');
|
|
20330
|
-
|
|
20331
|
-
|
|
20332
|
-
document.head.appendChild(applePayScript);
|
|
20333
|
-
case 3:
|
|
21436
|
+
});
|
|
21437
|
+
case 2:
|
|
20334
21438
|
return _context3.a(2);
|
|
20335
21439
|
}
|
|
20336
21440
|
}, _callee3, this);
|
|
@@ -20358,26 +21462,22 @@ var ApplePayOpenWalletService = /*#__PURE__*/function (_OpenWalletService) {
|
|
|
20358
21462
|
}, {
|
|
20359
21463
|
key: "checkAvailability",
|
|
20360
21464
|
value: function checkAvailability() {
|
|
20361
|
-
|
|
20362
|
-
|
|
20363
|
-
|
|
20364
|
-
|
|
20365
|
-
|
|
20366
|
-
|
|
20367
|
-
|
|
20368
|
-
|
|
20369
|
-
|
|
20370
|
-
|
|
20371
|
-
|
|
20372
|
-
|
|
20373
|
-
|
|
21465
|
+
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator().m(function _callee4() {
|
|
21466
|
+
var result;
|
|
21467
|
+
return _regenerator().w(function (_context4) {
|
|
21468
|
+
while (1) switch (_context4.n) {
|
|
21469
|
+
case 0:
|
|
21470
|
+
_context4.n = 1;
|
|
21471
|
+
return evaluateApplePayAvailability({
|
|
21472
|
+
merchantId: this.getMerchantId(),
|
|
21473
|
+
apple_pay_capabilities: this.meta.apple_pay_capabilities
|
|
21474
|
+
});
|
|
21475
|
+
case 1:
|
|
21476
|
+
result = _context4.v;
|
|
21477
|
+
return _context4.a(2, result.available);
|
|
20374
21478
|
}
|
|
20375
|
-
|
|
20376
|
-
|
|
20377
|
-
})["catch"](function () {
|
|
20378
|
-
resolve(false);
|
|
20379
|
-
});
|
|
20380
|
-
});
|
|
21479
|
+
}, _callee4, this);
|
|
21480
|
+
}));
|
|
20381
21481
|
}
|
|
20382
21482
|
}, {
|
|
20383
21483
|
key: "mount",
|
|
@@ -20403,7 +21503,7 @@ var ApplePayOpenWalletService = /*#__PURE__*/function (_OpenWalletService) {
|
|
|
20403
21503
|
}, {
|
|
20404
21504
|
key: "onApplePayButtonClicked",
|
|
20405
21505
|
value: function onApplePayButtonClicked() {
|
|
20406
|
-
var
|
|
21506
|
+
var _this6 = this;
|
|
20407
21507
|
if (this.isButtonDisabled()) {
|
|
20408
21508
|
return;
|
|
20409
21509
|
}
|
|
@@ -20422,26 +21522,27 @@ var ApplePayOpenWalletService = /*#__PURE__*/function (_OpenWalletService) {
|
|
|
20422
21522
|
// As part of PAYCA-2065 we detect that the paymentSession.onvalidatemerchant is not
|
|
20423
21523
|
// executed if the browser is not safari. In that case, we handle it outside the
|
|
20424
21524
|
// actual merchant validation function.
|
|
20425
|
-
var
|
|
20426
|
-
var
|
|
21525
|
+
var userAgent = navigator.userAgent || '';
|
|
21526
|
+
var isIOS = userAgent.includes('iPhone') || userAgent.includes('iPad') || userAgent.includes('iPod');
|
|
21527
|
+
var isDesktopRequestIOS = navigator.maxTouchPoints > 1 && userAgent.includes('Macintosh');
|
|
20427
21528
|
if (!window.safari && !isIOS && !isDesktopRequestIOS) {
|
|
20428
21529
|
this.handleMerchantOnButtonClickEvent()["catch"](function (err) {
|
|
20429
21530
|
console.error('Error while processing merchant callback', err);
|
|
20430
|
-
|
|
21531
|
+
_this6.paymentSession.abort();
|
|
20431
21532
|
});
|
|
20432
21533
|
}
|
|
20433
21534
|
}
|
|
20434
21535
|
}, {
|
|
20435
21536
|
key: "getMerchantSession",
|
|
20436
21537
|
value: function getMerchantSession() {
|
|
20437
|
-
var
|
|
21538
|
+
var _this7 = this;
|
|
20438
21539
|
return new Promise(function (resolve, reject) {
|
|
20439
|
-
return
|
|
20440
|
-
service_id:
|
|
21540
|
+
return _this7.api.paymentSource().createSession(_extends({
|
|
21541
|
+
service_id: _this7.serviceId,
|
|
20441
21542
|
session_id: window.location.hostname,
|
|
20442
|
-
store_name:
|
|
20443
|
-
},
|
|
20444
|
-
request_shipping:
|
|
21543
|
+
store_name: _this7.meta.store_name
|
|
21544
|
+
}, _this7.isShippingRequired() && {
|
|
21545
|
+
request_shipping: _this7.meta.request_shipping
|
|
20445
21546
|
})).then(function (res) {
|
|
20446
21547
|
resolve(res);
|
|
20447
21548
|
})["catch"](function (err) {
|
|
@@ -20452,42 +21553,30 @@ var ApplePayOpenWalletService = /*#__PURE__*/function (_OpenWalletService) {
|
|
|
20452
21553
|
}, {
|
|
20453
21554
|
key: "handleMerchantOnButtonClickEvent",
|
|
20454
21555
|
value: function handleMerchantOnButtonClickEvent() {
|
|
20455
|
-
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator().m(function
|
|
21556
|
+
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator().m(function _callee5() {
|
|
20456
21557
|
var results;
|
|
20457
|
-
return _regenerator().w(function (
|
|
20458
|
-
while (1) switch (
|
|
21558
|
+
return _regenerator().w(function (_context5) {
|
|
21559
|
+
while (1) switch (_context5.n) {
|
|
20459
21560
|
case 0:
|
|
20460
|
-
|
|
21561
|
+
_context5.n = 1;
|
|
20461
21562
|
return this.eventEmitter.emitWithResult(EVENT$1.ON_CLICK, {
|
|
20462
21563
|
event: EVENT$1.ON_CLICK
|
|
20463
21564
|
});
|
|
20464
21565
|
case 1:
|
|
20465
|
-
results =
|
|
21566
|
+
results = _context5.v;
|
|
20466
21567
|
if (!results.some(function (r) {
|
|
20467
21568
|
return r === false;
|
|
20468
21569
|
})) {
|
|
20469
|
-
|
|
21570
|
+
_context5.n = 2;
|
|
20470
21571
|
break;
|
|
20471
21572
|
}
|
|
20472
21573
|
throw new Error('onClick handler aborted the payment flow');
|
|
20473
21574
|
case 2:
|
|
20474
|
-
return
|
|
21575
|
+
return _context5.a(2);
|
|
20475
21576
|
}
|
|
20476
|
-
},
|
|
21577
|
+
}, _callee5, this);
|
|
20477
21578
|
}));
|
|
20478
21579
|
}
|
|
20479
|
-
}, {
|
|
20480
|
-
key: "formatCapabilities",
|
|
20481
|
-
value: function formatCapabilities(capabilities) {
|
|
20482
|
-
var fieldMap = {
|
|
20483
|
-
credentials_available: 'paymentCredentialsAvailable',
|
|
20484
|
-
credentials_status_unknown: 'paymentCredentialStatusUnknown',
|
|
20485
|
-
credentials_unavailable: 'paymentCredentialsUnavailable'
|
|
20486
|
-
};
|
|
20487
|
-
return capabilities.map(function (capability) {
|
|
20488
|
-
return fieldMap[capability] || capability;
|
|
20489
|
-
});
|
|
20490
|
-
}
|
|
20491
21580
|
}, {
|
|
20492
21581
|
key: "formatErrorFields",
|
|
20493
21582
|
value: function formatErrorFields(error) {
|
|
@@ -20654,11 +21743,6 @@ var ApplePayOpenWalletService = /*#__PURE__*/function (_OpenWalletService) {
|
|
|
20654
21743
|
applePayLaterAvailability: this.meta.apple_pay_later_availability
|
|
20655
21744
|
});
|
|
20656
21745
|
}
|
|
20657
|
-
}, {
|
|
20658
|
-
key: "isUnsuportedBrowser",
|
|
20659
|
-
value: function isUnsuportedBrowser(capabilities) {
|
|
20660
|
-
return (capabilities === null || capabilities === void 0 ? void 0 : capabilities.paymentCredentialStatus) === 'applePayUnsupported';
|
|
20661
|
-
}
|
|
20662
21746
|
}]);
|
|
20663
21747
|
}(OpenWalletService);
|
|
20664
21748
|
|
|
@@ -20707,17 +21791,57 @@ var ApplePayOpenWalletButton = /*#__PURE__*/function (_OpenWalletButtons) {
|
|
|
20707
21791
|
return _this;
|
|
20708
21792
|
}
|
|
20709
21793
|
/**
|
|
20710
|
-
*
|
|
20711
|
-
*
|
|
21794
|
+
* Checks Apple Pay availability **without instantiating the button** — the single,
|
|
21795
|
+
* authoritative, cross-browser-aware availability entry point.
|
|
20712
21796
|
*
|
|
20713
|
-
*
|
|
20714
|
-
*
|
|
20715
|
-
*
|
|
21797
|
+
* Resolves the merchant identifier (either supplied directly or fetched from the
|
|
21798
|
+
* service configuration), loads Apple's web SDK if needed, then queries
|
|
21799
|
+
* `ApplePaySession.applePayCapabilities()`. Returns a convenience `available` verdict
|
|
21800
|
+
* (computed against `apple_pay_capabilities`), the raw device-reported
|
|
21801
|
+
* `payment_credential_status`, and `has_native_session` so callers can infer the transport:
|
|
21802
|
+
* `available && has_native_session` ⇒ native sheet likely; `available && !has_native_session`
|
|
21803
|
+
* ⇒ cross-device / QR handoff likely.
|
|
21804
|
+
*
|
|
21805
|
+
* Pass `{ sync: true }` for a cheap, network-free native same-device pre-check that
|
|
21806
|
+
* resolves immediately (see {@link ApplePayAvailabilityOptions.sync}).
|
|
21807
|
+
*
|
|
21808
|
+
* @param {ApplePayAvailabilityOptions} [options] - Merchant context, allowed capabilities, and mode.
|
|
21809
|
+
* @returns {Promise<ApplePayAvailabilityResult>} The availability result.
|
|
21810
|
+
*
|
|
21811
|
+
* @example
|
|
21812
|
+
* // Lightest path — no network, when you already know the merchant identifier:
|
|
21813
|
+
* const result = await ApplePayOpenWalletButton.checkAvailability({ merchant_id });
|
|
21814
|
+
*
|
|
21815
|
+
* @example
|
|
21816
|
+
* // Resolve the merchant identifier from the service configuration:
|
|
21817
|
+
* const result = await ApplePayOpenWalletButton.checkAvailability({
|
|
21818
|
+
* public_key_or_access_token,
|
|
21819
|
+
* service_id,
|
|
21820
|
+
* env: 'sandbox',
|
|
21821
|
+
* });
|
|
21822
|
+
* if (result.available) {
|
|
21823
|
+
* // Render the Apple Pay button (native sheet or cross-device QR, per has_native_session).
|
|
21824
|
+
* } else {
|
|
21825
|
+
* console.log('Unavailable:', result.reason, result.payment_credential_status);
|
|
21826
|
+
* }
|
|
21827
|
+
*
|
|
21828
|
+
* @example
|
|
21829
|
+
* // Synchronous native-only fast check (no network / SDK load):
|
|
21830
|
+
* const { has_native_session } = await ApplePayOpenWalletButton.checkAvailability({ sync: true });
|
|
20716
21831
|
*/
|
|
20717
21832
|
_inherits(ApplePayOpenWalletButton, _OpenWalletButtons);
|
|
20718
21833
|
return _createClass(ApplePayOpenWalletButton, [{
|
|
20719
21834
|
key: "validateWalletMeta",
|
|
20720
|
-
value:
|
|
21835
|
+
value:
|
|
21836
|
+
/**
|
|
21837
|
+
* Validates Apple Pay-specific required metadata fields.
|
|
21838
|
+
* Apple Pay requires `amount_label` and `store_name` to be present and strings.
|
|
21839
|
+
*
|
|
21840
|
+
* @private
|
|
21841
|
+
* @throws {Error} If `amount_label` is missing or not a string.
|
|
21842
|
+
* @throws {Error} If `store_name` is missing or not a string.
|
|
21843
|
+
*/
|
|
21844
|
+
function validateWalletMeta() {
|
|
20721
21845
|
if (typeof this.meta.amount_label !== 'string' || this.meta.amount_label.trim() === '') {
|
|
20722
21846
|
throw new Error("meta.amount_label is required for Apple Pay and must be a non-empty string (e.g. 'TOTAL').");
|
|
20723
21847
|
}
|
|
@@ -20751,6 +21875,114 @@ var ApplePayOpenWalletButton = /*#__PURE__*/function (_OpenWalletButtons) {
|
|
|
20751
21875
|
value: function createWalletService(serviceConfig) {
|
|
20752
21876
|
return new ApplePayOpenWalletService(this.api, this.eventEmitter, this.serviceId, this.container, this.meta, serviceConfig);
|
|
20753
21877
|
}
|
|
21878
|
+
}], [{
|
|
21879
|
+
key: "checkAvailability",
|
|
21880
|
+
value: function checkAvailability() {
|
|
21881
|
+
return __awaiter(this, arguments, void 0, function () {
|
|
21882
|
+
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
21883
|
+
return /*#__PURE__*/_regenerator().m(function _callee() {
|
|
21884
|
+
var hasNativeSession, merchantId, authType, api, serviceConfig;
|
|
21885
|
+
return _regenerator().w(function (_context) {
|
|
21886
|
+
while (1) switch (_context.p = _context.n) {
|
|
21887
|
+
case 0:
|
|
21888
|
+
hasNativeSession = hasNativeApplePaySession();
|
|
21889
|
+
if (!options.sync) {
|
|
21890
|
+
_context.n = 1;
|
|
21891
|
+
break;
|
|
21892
|
+
}
|
|
21893
|
+
return _context.a(2, {
|
|
21894
|
+
available: hasNativeSession,
|
|
21895
|
+
supported: hasNativeSession,
|
|
21896
|
+
has_native_session: hasNativeSession,
|
|
21897
|
+
reason: hasNativeSession ? undefined : 'no_native_session'
|
|
21898
|
+
});
|
|
21899
|
+
case 1:
|
|
21900
|
+
merchantId = options.merchant_id;
|
|
21901
|
+
if (merchantId) {
|
|
21902
|
+
_context.n = 6;
|
|
21903
|
+
break;
|
|
21904
|
+
}
|
|
21905
|
+
if (!(!options.public_key_or_access_token || !options.service_id)) {
|
|
21906
|
+
_context.n = 2;
|
|
21907
|
+
break;
|
|
21908
|
+
}
|
|
21909
|
+
return _context.a(2, {
|
|
21910
|
+
available: false,
|
|
21911
|
+
supported: hasNativeSession,
|
|
21912
|
+
has_native_session: hasNativeSession,
|
|
21913
|
+
reason: 'missing_merchant_id'
|
|
21914
|
+
});
|
|
21915
|
+
case 2:
|
|
21916
|
+
_context.p = 2;
|
|
21917
|
+
authType = AccessToken.validateJWT(options.public_key_or_access_token) ? API_AUTH_TYPE.TOKEN : API_AUTH_TYPE.PUBLIC_KEY;
|
|
21918
|
+
api = new ApiInternal(options.public_key_or_access_token, authType);
|
|
21919
|
+
if (options.env) {
|
|
21920
|
+
api.setEnv(options.env);
|
|
21921
|
+
}
|
|
21922
|
+
_context.n = 3;
|
|
21923
|
+
return getServiceConfigCached(api, options.service_id);
|
|
21924
|
+
case 3:
|
|
21925
|
+
serviceConfig = _context.v;
|
|
21926
|
+
if (!(serviceConfig.type !== SERVICE_TYPES.APPLE_PAY)) {
|
|
21927
|
+
_context.n = 4;
|
|
21928
|
+
break;
|
|
21929
|
+
}
|
|
21930
|
+
return _context.a(2, {
|
|
21931
|
+
available: false,
|
|
21932
|
+
supported: hasNativeSession,
|
|
21933
|
+
has_native_session: hasNativeSession,
|
|
21934
|
+
reason: 'service_type_mismatch'
|
|
21935
|
+
});
|
|
21936
|
+
case 4:
|
|
21937
|
+
merchantId = serviceConfig.merchant;
|
|
21938
|
+
_context.n = 6;
|
|
21939
|
+
break;
|
|
21940
|
+
case 5:
|
|
21941
|
+
_context.p = 5;
|
|
21942
|
+
_context.v;
|
|
21943
|
+
return _context.a(2, {
|
|
21944
|
+
available: false,
|
|
21945
|
+
supported: hasNativeSession,
|
|
21946
|
+
has_native_session: hasNativeSession,
|
|
21947
|
+
reason: 'config_fetch_failed'
|
|
21948
|
+
});
|
|
21949
|
+
case 6:
|
|
21950
|
+
if (merchantId) {
|
|
21951
|
+
_context.n = 7;
|
|
21952
|
+
break;
|
|
21953
|
+
}
|
|
21954
|
+
return _context.a(2, {
|
|
21955
|
+
available: false,
|
|
21956
|
+
supported: hasNativeSession,
|
|
21957
|
+
has_native_session: hasNativeSession,
|
|
21958
|
+
reason: 'missing_merchant_id'
|
|
21959
|
+
});
|
|
21960
|
+
case 7:
|
|
21961
|
+
_context.p = 7;
|
|
21962
|
+
_context.n = 8;
|
|
21963
|
+
return loadApplePaySdk();
|
|
21964
|
+
case 8:
|
|
21965
|
+
_context.n = 10;
|
|
21966
|
+
break;
|
|
21967
|
+
case 9:
|
|
21968
|
+
_context.p = 9;
|
|
21969
|
+
_context.v;
|
|
21970
|
+
return _context.a(2, {
|
|
21971
|
+
available: false,
|
|
21972
|
+
supported: hasNativeSession,
|
|
21973
|
+
has_native_session: hasNativeSession,
|
|
21974
|
+
reason: 'sdk_load_failed'
|
|
21975
|
+
});
|
|
21976
|
+
case 10:
|
|
21977
|
+
return _context.a(2, evaluateApplePayAvailability({
|
|
21978
|
+
merchantId: merchantId,
|
|
21979
|
+
apple_pay_capabilities: options.apple_pay_capabilities
|
|
21980
|
+
}));
|
|
21981
|
+
}
|
|
21982
|
+
}, _callee, null, [[7, 9], [2, 5]]);
|
|
21983
|
+
})();
|
|
21984
|
+
});
|
|
21985
|
+
}
|
|
20754
21986
|
}]);
|
|
20755
21987
|
}(OpenWalletButtons);
|
|
20756
21988
|
|
|
@@ -20787,6 +22019,137 @@ var GOOGLE_PAY_CARD_NETWORKS = ['AMEX', 'DISCOVER', 'INTERAC', 'JCB', 'MASTERCAR
|
|
|
20787
22019
|
SHIPPING_OPTION: EVENT$1.ON_SHIPPING_OPTIONS_CHANGE
|
|
20788
22020
|
});
|
|
20789
22021
|
|
|
22022
|
+
/**
|
|
22023
|
+
* Synchronous, network-free check for whether the Google Pay JS API is already present
|
|
22024
|
+
* in the page (`window.google.payments.api.PaymentsClient`). Safe to call in any
|
|
22025
|
+
* environment (never throws).
|
|
22026
|
+
*
|
|
22027
|
+
* Note: Google Pay has no synchronous device/card capability API — this only reports
|
|
22028
|
+
* whether the SDK script has loaded. The authoritative readiness signal comes from
|
|
22029
|
+
* {@link evaluateGooglePayAvailability} (which runs `isReadyToPay`).
|
|
22030
|
+
*/
|
|
22031
|
+
function isGooglePayApiPresent() {
|
|
22032
|
+
var _a, _b, _c;
|
|
22033
|
+
try {
|
|
22034
|
+
return typeof window !== 'undefined' && !!((_c = (_b = (_a = window.google) === null || _a === void 0 ? void 0 : _a.payments) === null || _b === void 0 ? void 0 : _b.api) === null || _c === void 0 ? void 0 : _c.PaymentsClient);
|
|
22035
|
+
} catch (_d) {
|
|
22036
|
+
return false;
|
|
22037
|
+
}
|
|
22038
|
+
}
|
|
22039
|
+
var scriptLoadPromise = null;
|
|
22040
|
+
/**
|
|
22041
|
+
* Idempotently loads the Google Pay JS SDK from the CDN.
|
|
22042
|
+
* Resolves immediately if the API is already present, de-duplicates concurrent loads,
|
|
22043
|
+
* and rejects if the script fails to load.
|
|
22044
|
+
*/
|
|
22045
|
+
function loadGooglePayScript() {
|
|
22046
|
+
if (isGooglePayApiPresent()) {
|
|
22047
|
+
return Promise.resolve();
|
|
22048
|
+
}
|
|
22049
|
+
if (scriptLoadPromise) {
|
|
22050
|
+
return scriptLoadPromise;
|
|
22051
|
+
}
|
|
22052
|
+
scriptLoadPromise = new Promise(function (resolve, reject) {
|
|
22053
|
+
var script = document.createElement('script');
|
|
22054
|
+
script.type = 'text/javascript';
|
|
22055
|
+
script.src = GOOGLE_PAY_SCRIPT_URL;
|
|
22056
|
+
script.async = true;
|
|
22057
|
+
script.onload = function () {
|
|
22058
|
+
if (!isGooglePayApiPresent()) {
|
|
22059
|
+
scriptLoadPromise = null;
|
|
22060
|
+
reject(new Error('Google Pay not available'));
|
|
22061
|
+
return;
|
|
22062
|
+
}
|
|
22063
|
+
resolve();
|
|
22064
|
+
};
|
|
22065
|
+
script.onerror = function () {
|
|
22066
|
+
// Allow a future retry after a transient failure.
|
|
22067
|
+
scriptLoadPromise = null;
|
|
22068
|
+
reject(new Error('Failed to load Google Pay script'));
|
|
22069
|
+
};
|
|
22070
|
+
document.head.appendChild(script);
|
|
22071
|
+
});
|
|
22072
|
+
return scriptLoadPromise;
|
|
22073
|
+
}
|
|
22074
|
+
/**
|
|
22075
|
+
* Builds the base `isReadyToPay` request using the default card configuration
|
|
22076
|
+
* (standard auth methods + card networks). Mirrors the instance service's request:
|
|
22077
|
+
* `existingPaymentMethodRequired` is `false` on Safari (where Google Pay surfaces a
|
|
22078
|
+
* different flow) and `true` elsewhere.
|
|
22079
|
+
*/
|
|
22080
|
+
function buildIsReadyToPayRequest() {
|
|
22081
|
+
var isSafariBrowser = Browser.getBrowserName() === 'Apple Safari';
|
|
22082
|
+
return _extends(_extends({}, GOOGLE_PAY_API_CONFIG), {
|
|
22083
|
+
allowedPaymentMethods: [{
|
|
22084
|
+
type: 'CARD',
|
|
22085
|
+
parameters: {
|
|
22086
|
+
allowedAuthMethods: GOOGLE_PAY_AUTH_METHODS,
|
|
22087
|
+
allowedCardNetworks: GOOGLE_PAY_CARD_NETWORKS
|
|
22088
|
+
}
|
|
22089
|
+
}],
|
|
22090
|
+
existingPaymentMethodRequired: !isSafariBrowser
|
|
22091
|
+
});
|
|
22092
|
+
}
|
|
22093
|
+
/**
|
|
22094
|
+
* Core Google Pay availability evaluation, shared by the instance flow
|
|
22095
|
+
* (`GooglePayOpenWalletService`) and the static `GooglePayOpenWalletButton.checkAvailability`.
|
|
22096
|
+
*
|
|
22097
|
+
* The static check passes no `request`, so it uses the **default** card configuration
|
|
22098
|
+
* (a button instance with a custom `card_config` may produce a different result). The
|
|
22099
|
+
* instance flow passes its own `paymentsClient` and `request` so the readiness check
|
|
22100
|
+
* honours the merchant's `card_config` and runs against the same client it pays with.
|
|
22101
|
+
*
|
|
22102
|
+
* Assumes the Google Pay SDK is already loaded (call {@link loadGooglePayScript} first).
|
|
22103
|
+
*/
|
|
22104
|
+
function evaluateGooglePayAvailability() {
|
|
22105
|
+
return __awaiter(this, arguments, void 0, function () {
|
|
22106
|
+
var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
22107
|
+
return /*#__PURE__*/_regenerator().m(function _callee() {
|
|
22108
|
+
var _a, _b, paymentsClient, response, available;
|
|
22109
|
+
return _regenerator().w(function (_context) {
|
|
22110
|
+
while (1) switch (_context.p = _context.n) {
|
|
22111
|
+
case 0:
|
|
22112
|
+
if (isGooglePayApiPresent()) {
|
|
22113
|
+
_context.n = 1;
|
|
22114
|
+
break;
|
|
22115
|
+
}
|
|
22116
|
+
return _context.a(2, {
|
|
22117
|
+
available: false,
|
|
22118
|
+
supported: false,
|
|
22119
|
+
reason: 'unsupported_browser'
|
|
22120
|
+
});
|
|
22121
|
+
case 1:
|
|
22122
|
+
_context.p = 1;
|
|
22123
|
+
paymentsClient = (_a = params.paymentsClient) !== null && _a !== void 0 ? _a : new google.payments.api.PaymentsClient({
|
|
22124
|
+
merchantInfo: {
|
|
22125
|
+
merchantId: params.merchantId || ''
|
|
22126
|
+
}
|
|
22127
|
+
});
|
|
22128
|
+
_context.n = 2;
|
|
22129
|
+
return paymentsClient.isReadyToPay((_b = params.request) !== null && _b !== void 0 ? _b : buildIsReadyToPayRequest());
|
|
22130
|
+
case 2:
|
|
22131
|
+
response = _context.v;
|
|
22132
|
+
available = !!response.result;
|
|
22133
|
+
return _context.a(2, {
|
|
22134
|
+
available: available,
|
|
22135
|
+
supported: true,
|
|
22136
|
+
payment_method_present: response.paymentMethodPresent,
|
|
22137
|
+
reason: available ? undefined : 'no_payment_method'
|
|
22138
|
+
});
|
|
22139
|
+
case 3:
|
|
22140
|
+
_context.p = 3;
|
|
22141
|
+
_context.v;
|
|
22142
|
+
return _context.a(2, {
|
|
22143
|
+
available: false,
|
|
22144
|
+
supported: isGooglePayApiPresent(),
|
|
22145
|
+
reason: 'query_failed'
|
|
22146
|
+
});
|
|
22147
|
+
}
|
|
22148
|
+
}, _callee, null, [[1, 3]]);
|
|
22149
|
+
})();
|
|
22150
|
+
});
|
|
22151
|
+
}
|
|
22152
|
+
|
|
20790
22153
|
/**
|
|
20791
22154
|
* Parses intermediate payment data from Google Pay into a normalized format
|
|
20792
22155
|
* for use in shipping address/option change events.
|
|
@@ -21122,14 +22485,18 @@ var GooglePayOpenWalletService = /*#__PURE__*/function (_OpenWalletService) {
|
|
|
21122
22485
|
key: "checkAvailability",
|
|
21123
22486
|
value: function checkAvailability() {
|
|
21124
22487
|
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator().m(function _callee2() {
|
|
22488
|
+
var result;
|
|
21125
22489
|
return _regenerator().w(function (_context2) {
|
|
21126
22490
|
while (1) switch (_context2.n) {
|
|
21127
22491
|
case 0:
|
|
21128
|
-
|
|
21129
|
-
|
|
21130
|
-
|
|
21131
|
-
|
|
21132
|
-
})
|
|
22492
|
+
_context2.n = 1;
|
|
22493
|
+
return evaluateGooglePayAvailability({
|
|
22494
|
+
paymentsClient: this.paymentsClient,
|
|
22495
|
+
request: this.createRequest()
|
|
22496
|
+
});
|
|
22497
|
+
case 1:
|
|
22498
|
+
result = _context2.v;
|
|
22499
|
+
return _context2.a(2, result.available);
|
|
21133
22500
|
}
|
|
21134
22501
|
}, _callee2, this);
|
|
21135
22502
|
}));
|
|
@@ -21587,14 +22954,46 @@ var GooglePayOpenWalletButton = /*#__PURE__*/function (_OpenWalletButtons) {
|
|
|
21587
22954
|
return _this;
|
|
21588
22955
|
}
|
|
21589
22956
|
/**
|
|
21590
|
-
*
|
|
21591
|
-
*
|
|
21592
|
-
*
|
|
22957
|
+
* Checks Google Pay availability **without instantiating the button** — the static
|
|
22958
|
+
* availability entry point.
|
|
22959
|
+
*
|
|
22960
|
+
* Loads the Google Pay JS SDK if needed, then runs `PaymentsClient.isReadyToPay()` using
|
|
22961
|
+
* the **default** card configuration (a button instance with a custom `card_config` may
|
|
22962
|
+
* produce a different result). All options are optional — unlike Apple Pay, Google Pay's
|
|
22963
|
+
* readiness check does not require a merchant identifier; supplying `service_id` +
|
|
22964
|
+
* `public_key_or_access_token` additionally validates that the service is a Google Pay service.
|
|
22965
|
+
*
|
|
22966
|
+
* Pass `{ sync: true }` for a cheap, network-free check that only reports whether the
|
|
22967
|
+
* Google Pay JS API is already present (see {@link GooglePayAvailabilityOptions.sync}).
|
|
22968
|
+
*
|
|
22969
|
+
* @param {GooglePayAvailabilityOptions} [options] - Optional merchant context and mode.
|
|
22970
|
+
* @returns {Promise<GooglePayAvailabilityResult>} The availability result.
|
|
22971
|
+
*
|
|
22972
|
+
* @example
|
|
22973
|
+
* // Simplest form — no merchant context needed:
|
|
22974
|
+
* const result = await GooglePayOpenWalletButton.checkAvailability();
|
|
22975
|
+
* if (result.available) {
|
|
22976
|
+
* // Render the Google Pay button.
|
|
22977
|
+
* }
|
|
22978
|
+
*
|
|
22979
|
+
* @example
|
|
22980
|
+
* // Validate the service is a Google Pay service while checking:
|
|
22981
|
+
* const result = await GooglePayOpenWalletButton.checkAvailability({
|
|
22982
|
+
* public_key_or_access_token,
|
|
22983
|
+
* service_id,
|
|
22984
|
+
* env: 'sandbox',
|
|
22985
|
+
* });
|
|
21593
22986
|
*/
|
|
21594
22987
|
_inherits(GooglePayOpenWalletButton, _OpenWalletButtons);
|
|
21595
22988
|
return _createClass(GooglePayOpenWalletButton, [{
|
|
21596
22989
|
key: "validateWalletMeta",
|
|
21597
|
-
value:
|
|
22990
|
+
value:
|
|
22991
|
+
/**
|
|
22992
|
+
* Validates Google Pay-specific required metadata fields.
|
|
22993
|
+
* Google Pay has no additional required fields beyond the base (amount, currency, country).
|
|
22994
|
+
* @private
|
|
22995
|
+
*/
|
|
22996
|
+
function validateWalletMeta() {
|
|
21598
22997
|
// Google Pay has no additional required meta fields beyond the base.
|
|
21599
22998
|
// Optional fields (merchant_name, card_config, etc.) are validated
|
|
21600
22999
|
// at runtime by the Google Pay SDK.
|
|
@@ -21625,6 +23024,87 @@ var GooglePayOpenWalletButton = /*#__PURE__*/function (_OpenWalletButtons) {
|
|
|
21625
23024
|
value: function createWalletService(serviceConfig) {
|
|
21626
23025
|
return new GooglePayOpenWalletService(this.api, this.eventEmitter, this.serviceId, this.container, this.meta, serviceConfig);
|
|
21627
23026
|
}
|
|
23027
|
+
}], [{
|
|
23028
|
+
key: "checkAvailability",
|
|
23029
|
+
value: function checkAvailability() {
|
|
23030
|
+
return __awaiter(this, arguments, void 0, function () {
|
|
23031
|
+
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
23032
|
+
return /*#__PURE__*/_regenerator().m(function _callee() {
|
|
23033
|
+
var present, merchantId, authType, api, serviceConfig;
|
|
23034
|
+
return _regenerator().w(function (_context) {
|
|
23035
|
+
while (1) switch (_context.p = _context.n) {
|
|
23036
|
+
case 0:
|
|
23037
|
+
if (!options.sync) {
|
|
23038
|
+
_context.n = 1;
|
|
23039
|
+
break;
|
|
23040
|
+
}
|
|
23041
|
+
present = isGooglePayApiPresent();
|
|
23042
|
+
return _context.a(2, {
|
|
23043
|
+
available: present,
|
|
23044
|
+
supported: present,
|
|
23045
|
+
reason: present ? undefined : 'api_not_loaded'
|
|
23046
|
+
});
|
|
23047
|
+
case 1:
|
|
23048
|
+
merchantId = options.merchant_id;
|
|
23049
|
+
if (!(!merchantId && options.public_key_or_access_token && options.service_id)) {
|
|
23050
|
+
_context.n = 6;
|
|
23051
|
+
break;
|
|
23052
|
+
}
|
|
23053
|
+
_context.p = 2;
|
|
23054
|
+
authType = AccessToken.validateJWT(options.public_key_or_access_token) ? API_AUTH_TYPE.TOKEN : API_AUTH_TYPE.PUBLIC_KEY;
|
|
23055
|
+
api = new ApiInternal(options.public_key_or_access_token, authType);
|
|
23056
|
+
if (options.env) {
|
|
23057
|
+
api.setEnv(options.env);
|
|
23058
|
+
}
|
|
23059
|
+
_context.n = 3;
|
|
23060
|
+
return getServiceConfigCached(api, options.service_id);
|
|
23061
|
+
case 3:
|
|
23062
|
+
serviceConfig = _context.v;
|
|
23063
|
+
if (!(serviceConfig.type !== SERVICE_TYPES.GOOGLE_PAY)) {
|
|
23064
|
+
_context.n = 4;
|
|
23065
|
+
break;
|
|
23066
|
+
}
|
|
23067
|
+
return _context.a(2, {
|
|
23068
|
+
available: false,
|
|
23069
|
+
supported: isGooglePayApiPresent(),
|
|
23070
|
+
reason: 'service_type_mismatch'
|
|
23071
|
+
});
|
|
23072
|
+
case 4:
|
|
23073
|
+
merchantId = serviceConfig.merchant;
|
|
23074
|
+
_context.n = 6;
|
|
23075
|
+
break;
|
|
23076
|
+
case 5:
|
|
23077
|
+
_context.p = 5;
|
|
23078
|
+
_context.v;
|
|
23079
|
+
return _context.a(2, {
|
|
23080
|
+
available: false,
|
|
23081
|
+
supported: isGooglePayApiPresent(),
|
|
23082
|
+
reason: 'config_fetch_failed'
|
|
23083
|
+
});
|
|
23084
|
+
case 6:
|
|
23085
|
+
_context.p = 6;
|
|
23086
|
+
_context.n = 7;
|
|
23087
|
+
return loadGooglePayScript();
|
|
23088
|
+
case 7:
|
|
23089
|
+
_context.n = 9;
|
|
23090
|
+
break;
|
|
23091
|
+
case 8:
|
|
23092
|
+
_context.p = 8;
|
|
23093
|
+
_context.v;
|
|
23094
|
+
return _context.a(2, {
|
|
23095
|
+
available: false,
|
|
23096
|
+
supported: isGooglePayApiPresent(),
|
|
23097
|
+
reason: 'sdk_load_failed'
|
|
23098
|
+
});
|
|
23099
|
+
case 9:
|
|
23100
|
+
return _context.a(2, evaluateGooglePayAvailability({
|
|
23101
|
+
merchantId: merchantId
|
|
23102
|
+
}));
|
|
23103
|
+
}
|
|
23104
|
+
}, _callee, null, [[6, 8], [2, 5]]);
|
|
23105
|
+
})();
|
|
23106
|
+
});
|
|
23107
|
+
}
|
|
21628
23108
|
}]);
|
|
21629
23109
|
}(OpenWalletButtons);
|
|
21630
23110
|
|
|
@@ -22897,6 +24377,14 @@ var SRC = /*#__PURE__*/function () {
|
|
|
22897
24377
|
if (_this.provider) {
|
|
22898
24378
|
_this.provider.load();
|
|
22899
24379
|
}
|
|
24380
|
+
})["catch"](function (error) {
|
|
24381
|
+
var _a;
|
|
24382
|
+
// Surface config-load failures (including transport-level ones now
|
|
24383
|
+
// rejected by ApiBase) instead of leaving the widget hung silently.
|
|
24384
|
+
_this.eventEmitter.emit(EVENT.CHECKOUT_ERROR, {
|
|
24385
|
+
type: EVENT_DATA_TYPE.CRITICAL_ERROR,
|
|
24386
|
+
data: (_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : 'Failed to load Click to Pay configuration.'
|
|
24387
|
+
});
|
|
22900
24388
|
});
|
|
22901
24389
|
}
|
|
22902
24390
|
/**
|