samlesa 2.16.6 → 2.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of samlesa might be problematic. Click here for more details.

Files changed (82) hide show
  1. package/README.md +30 -50
  2. package/build/index.js +2 -1
  3. package/build/src/binding-artifact.js +330 -146
  4. package/build/src/binding-post.js +45 -31
  5. package/build/src/binding-redirect.js +0 -10
  6. package/build/src/binding-simplesign.js +0 -1
  7. package/build/src/entity-idp.js +1 -5
  8. package/build/src/entity-sp.js +21 -96
  9. package/build/src/extractor.js +48 -4
  10. package/build/src/flow.js +24 -166
  11. package/build/src/libsaml.js +468 -264
  12. package/build/src/libsamlSoap.js +115 -0
  13. package/build/src/schema/xml.xsd +88 -88
  14. package/build/src/schemaValidator.js +5 -13
  15. package/build/src/soap.js +123 -3
  16. package/build/src/utility.js +12 -7
  17. package/package.json +77 -81
  18. package/types/api.d.ts +15 -0
  19. package/types/api.d.ts.map +1 -0
  20. package/types/binding-post.d.ts +48 -0
  21. package/types/binding-post.d.ts.map +1 -0
  22. package/types/binding-redirect.d.ts +54 -0
  23. package/types/binding-redirect.d.ts.map +1 -0
  24. package/types/binding-simplesign.d.ts +41 -0
  25. package/types/binding-simplesign.d.ts.map +1 -0
  26. package/types/entity-idp.d.ts +38 -0
  27. package/types/entity-idp.d.ts.map +1 -0
  28. package/types/entity-sp.d.ts +38 -0
  29. package/types/entity-sp.d.ts.map +1 -0
  30. package/types/entity.d.ts +100 -0
  31. package/types/entity.d.ts.map +1 -0
  32. package/types/extractor.d.ts +26 -0
  33. package/types/extractor.d.ts.map +1 -0
  34. package/types/flow.d.ts +7 -0
  35. package/types/flow.d.ts.map +1 -0
  36. package/types/index.d.ts +2 -1
  37. package/types/index.d.ts.map +1 -1
  38. package/types/libsaml.d.ts +208 -0
  39. package/types/libsaml.d.ts.map +1 -0
  40. package/types/metadata-idp.d.ts +25 -0
  41. package/types/metadata-idp.d.ts.map +1 -0
  42. package/types/metadata-sp.d.ts +37 -0
  43. package/types/metadata-sp.d.ts.map +1 -0
  44. package/types/metadata.d.ts +58 -0
  45. package/types/metadata.d.ts.map +1 -0
  46. package/types/src/api.d.ts +3 -3
  47. package/types/src/api.d.ts.map +1 -1
  48. package/types/src/binding-artifact.d.ts +24 -29
  49. package/types/src/binding-artifact.d.ts.map +1 -1
  50. package/types/src/binding-post.d.ts +22 -22
  51. package/types/src/binding-post.d.ts.map +1 -1
  52. package/types/src/binding-redirect.d.ts.map +1 -1
  53. package/types/src/binding-simplesign.d.ts.map +1 -1
  54. package/types/src/entity-idp.d.ts +3 -4
  55. package/types/src/entity-idp.d.ts.map +1 -1
  56. package/types/src/entity-sp.d.ts +13 -24
  57. package/types/src/entity-sp.d.ts.map +1 -1
  58. package/types/src/entity.d.ts.map +1 -1
  59. package/types/src/extractor.d.ts +22 -0
  60. package/types/src/extractor.d.ts.map +1 -1
  61. package/types/src/flow.d.ts +1 -0
  62. package/types/src/flow.d.ts.map +1 -1
  63. package/types/src/libsaml.d.ts +16 -7
  64. package/types/src/libsaml.d.ts.map +1 -1
  65. package/types/src/libsamlSoap.d.ts +7 -0
  66. package/types/src/libsamlSoap.d.ts.map +1 -0
  67. package/types/src/schemaValidator.d.ts +1 -1
  68. package/types/src/schemaValidator.d.ts.map +1 -1
  69. package/types/src/soap.d.ts +33 -0
  70. package/types/src/soap.d.ts.map +1 -1
  71. package/types/src/utility.d.ts.map +1 -1
  72. package/types/src/validator.d.ts.map +1 -1
  73. package/types/types.d.ts +128 -0
  74. package/types/types.d.ts.map +1 -0
  75. package/types/urn.d.ts +195 -0
  76. package/types/urn.d.ts.map +1 -0
  77. package/types/utility.d.ts +133 -0
  78. package/types/utility.d.ts.map +1 -0
  79. package/types/validator.d.ts +4 -0
  80. package/types/validator.d.ts.map +1 -0
  81. package/build/src/schema/XMLSchema.dtd +0 -402
  82. package/build/src/schema/datatypes.dtd +0 -203
@@ -1,18 +1,18 @@
1
1
  /**
2
- * @file binding-post.ts
3
- * @author tngan
4
- * @desc Binding-level API, declare the functions using POST binding
5
- */
2
+ * @file binding-post.ts
3
+ * @author tngan
4
+ * @desc Binding-level API, declare the functions using POST binding
5
+ */
6
6
  import { wording, StatusCode } from './urn.js';
7
7
  import libsaml from './libsaml.js';
8
8
  import utility, { get } from './utility.js';
9
9
  const binding = wording.binding;
10
10
  /**
11
- * @desc Generate a base64 encoded login request
12
- * @param {string} referenceTagXPath reference uri
13
- * @param {object} entity object includes both idp and sp
14
- * @param {function} customTagReplacement used when developers have their own login response template
15
- */
11
+ * @desc Generate a base64 encoded login request
12
+ * @param {string} referenceTagXPath reference uri
13
+ * @param {object} entity object includes both idp and sp
14
+ * @param {function} customTagReplacement used when developers have their own login response template
15
+ */
16
16
  function base64LoginRequest(referenceTagXPath, entity, customTagReplacement) {
17
17
  const metadata = { idp: entity.idp.entityMeta, sp: entity.sp.entityMeta };
18
18
  const spSetting = entity.sp.entitySetting;
@@ -141,7 +141,6 @@ async function base64LoginResponse(requestInfo = {}, entity, user = {}, customTa
141
141
  };
142
142
  // step: sign assertion ? -> encrypted ? -> sign message ?
143
143
  if (metadata.sp.isWantAssertionsSigned()) {
144
- // console.debug('sp wants assertion signed');
145
144
  rawSamlResponse = libsaml.constructSAMLSignature({
146
145
  ...config,
147
146
  rawSamlMessage: rawSamlResponse,
@@ -149,7 +148,10 @@ async function base64LoginResponse(requestInfo = {}, entity, user = {}, customTa
149
148
  referenceTagXPath: "/*[local-name(.)='Response']/*[local-name(.)='Assertion']",
150
149
  signatureConfig: {
151
150
  prefix: 'ds',
152
- location: { reference: "/*[local-name(.)='Response']/*[local-name(.)='Assertion']/*[local-name(.)='Issuer']", action: 'after' },
151
+ location: {
152
+ reference: "/*[local-name(.)='Response']/*[local-name(.)='Assertion']/*[local-name(.)='Issuer']",
153
+ action: 'after'
154
+ },
153
155
  },
154
156
  });
155
157
  }
@@ -168,7 +170,19 @@ async function base64LoginResponse(requestInfo = {}, entity, user = {}, customTa
168
170
  },
169
171
  });
170
172
  }
171
- // console.debug('after message signed', rawSamlResponse);
173
+ /* if (spSetting.wantMessageSigned) {
174
+ // console.debug('sign then encrypt and sign entire message');
175
+ rawSamlResponse = libsaml.constructSAMLSignature({
176
+ ...config,
177
+ rawSamlMessage: rawSamlResponse,
178
+ isMessageSigned: true,
179
+ transformationAlgorithms: spSetting.transformationAlgorithms,
180
+ signatureConfig: spSetting.signatureConfig || {
181
+ prefix: 'ds',
182
+ location: {reference: "/!*[local-name(.)='Response']/!*[local-name(.)='Issuer']", action: 'after'},
183
+ },
184
+ });
185
+ }*/
172
186
  if (idpSetting.isAssertionEncrypted) {
173
187
  // console.debug('idp is configured to do encryption');
174
188
  const context = await libsaml.encryptAssertion(entity.idp, entity.sp, rawSamlResponse);
@@ -181,18 +195,18 @@ async function base64LoginResponse(requestInfo = {}, entity, user = {}, customTa
181
195
  }
182
196
  }
183
197
  //sign after encrypting
184
- if (encryptThenSign && (spSetting.wantMessageSigned || !metadata.sp.isWantAssertionsSigned())) {
185
- rawSamlResponse = libsaml.constructSAMLSignature({
198
+ /* if (encryptThenSign && (spSetting.wantMessageSigned || !metadata.sp.isWantAssertionsSigned())) {
199
+ rawSamlResponse = libsaml.constructSAMLSignature({
186
200
  ...config,
187
201
  rawSamlMessage: rawSamlResponse,
188
202
  isMessageSigned: true,
189
203
  transformationAlgorithms: spSetting.transformationAlgorithms,
190
204
  signatureConfig: spSetting.signatureConfig || {
191
- prefix: 'ds',
192
- location: { reference: "/*[local-name(.)='Response']/*[local-name(.)='Issuer']", action: 'after' },
205
+ prefix: 'ds',
206
+ location: {reference: "/!*[local-name(.)='Response']/!*[local-name(.)='Issuer']", action: 'after'},
193
207
  },
194
- });
195
- }
208
+ });
209
+ }*/
196
210
  return Promise.resolve({
197
211
  id,
198
212
  context: utility.base64Encode(rawSamlResponse),
@@ -201,13 +215,13 @@ async function base64LoginResponse(requestInfo = {}, entity, user = {}, customTa
201
215
  throw new Error('ERR_GENERATE_POST_LOGIN_RESPONSE_MISSING_METADATA');
202
216
  }
203
217
  /**
204
- * @desc Generate a base64 encoded logout request
205
- * @param {object} user current logged user (e.g. req.user)
206
- * @param {string} referenceTagXPath reference uri
207
- * @param {object} entity object includes both idp and sp
208
- * @param {function} customTagReplacement used when developers have their own login response template
209
- * @return {string} base64 encoded request
210
- */
218
+ * @desc Generate a base64 encoded logout request
219
+ * @param {object} user current logged user (e.g. req.user)
220
+ * @param {string} referenceTagXPath reference uri
221
+ * @param {object} entity object includes both idp and sp
222
+ * @param {function} customTagReplacement used when developers have their own login response template
223
+ * @return {string} base64 encoded request
224
+ */
211
225
  function base64LogoutRequest(user, referenceTagXPath, entity, customTagReplacement) {
212
226
  const metadata = { init: entity.init.entityMeta, target: entity.target.entityMeta };
213
227
  const initSetting = entity.init.entitySetting;
@@ -262,12 +276,12 @@ function base64LogoutRequest(user, referenceTagXPath, entity, customTagReplaceme
262
276
  throw new Error('ERR_GENERATE_POST_LOGOUT_REQUEST_MISSING_METADATA');
263
277
  }
264
278
  /**
265
- * @desc Generate a base64 encoded logout response
266
- * @param {object} requestInfo corresponding request, used to obtain the id
267
- * @param {string} referenceTagXPath reference uri
268
- * @param {object} entity object includes both idp and sp
269
- * @param {function} customTagReplacement used when developers have their own login response template
270
- */
279
+ * @desc Generate a base64 encoded logout response
280
+ * @param {object} requestInfo corresponding request, used to obtain the id
281
+ * @param {string} referenceTagXPath reference uri
282
+ * @param {object} entity object includes both idp and sp
283
+ * @param {function} customTagReplacement used when developers have their own login response template
284
+ */
271
285
  function base64LogoutResponse(requestInfo, entity, customTagReplacement) {
272
286
  const metadata = {
273
287
  init: entity.init.entityMeta,
@@ -135,8 +135,6 @@ function loginRequestRedirectURLArt(entity, customTagReplacement) {
135
135
  AllowCreate: spSetting.allowCreate,
136
136
  });
137
137
  }
138
- console.log(rawSamlRequest);
139
- console.log("-----------------这是原始请求模板-------------------");
140
138
  const { privateKey, privateKeyPass, requestSignatureAlgorithm: signatureAlgorithm, transformationAlgorithms } = spSetting;
141
139
  if (metadata.idp.isWantAuthnRequestsSigned()) {
142
140
  let signAuthnRequest = libsaml.constructSAMLSignature({
@@ -156,8 +154,6 @@ function loginRequestRedirectURLArt(entity, customTagReplacement) {
156
154
  },
157
155
  }
158
156
  });
159
- console.log(signAuthnRequest);
160
- console.log("签名后的模板");
161
157
  rawSamlRequest = signAuthnRequest;
162
158
  }
163
159
  /* console.log(metadata.idp)
@@ -169,9 +165,6 @@ function loginRequestRedirectURLArt(entity, customTagReplacement) {
169
165
  Issuer: metadata.sp.getEntityID(),
170
166
  AuthnRequest: rawSamlRequest
171
167
  });
172
- console.log(soapTemplate);
173
- console.log("======================最后结果========================");
174
- console.log("======================开始签名根节点========================");
175
168
  let rootSignSoap = libsaml.constructSAMLSignature({
176
169
  isMessageSigned: true,
177
170
  isBase64Output: false,
@@ -186,8 +179,6 @@ function loginRequestRedirectURLArt(entity, customTagReplacement) {
186
179
  location: { reference: "//*[local-name()='Header']", action: 'after' },
187
180
  }
188
181
  });
189
- console.log(rootSignSoap);
190
- console.log("======================已经签名========================");
191
182
  return {
192
183
  authnRequest: rootSignSoap
193
184
  };
@@ -224,7 +215,6 @@ function loginResponseRedirectURL(requestInfo, entity, user = {}, relayState, cu
224
215
  // Five minutes later : nowtime + 5 * 60 * 1000 (in milliseconds)
225
216
  const fiveMinutesLaterTime = new Date(nowTime.getTime() + 300_000);
226
217
  const now = nowTime.toISOString();
227
- console.log(`现在是北京时间:${nowTime.toLocaleString()}`);
228
218
  const sessionIndex = 'session' + idpSetting.generateID(); // 这个是当前系统的会话索引,用于单点注销
229
219
  const tenHoursLaterTime = new Date(nowTime.getTime());
230
220
  tenHoursLaterTime.setHours(tenHoursLaterTime.getHours() + 10);
@@ -119,7 +119,6 @@ async function base64LoginResponse(requestInfo = {}, entity, user = {}, relaySta
119
119
  // Five minutes later : nowtime + 5 * 60 * 1000 (in milliseconds)
120
120
  const fiveMinutesLaterTime = new Date(nowTime.getTime() + 300_000);
121
121
  const now = nowTime.toISOString();
122
- console.log(`现在是北京时间:${nowTime.toLocaleString()}`);
123
122
  const sessionIndex = 'session' + idpSetting.generateID(); // 这个是当前系统的会话索引,用于单点注销
124
123
  const tenHoursLaterTime = new Date(nowTime.getTime());
125
124
  tenHoursLaterTime.setHours(tenHoursLaterTime.getHours() + 10);
@@ -59,11 +59,7 @@ export class IdentityProvider extends Entity {
59
59
  sp,
60
60
  }, user, relayState, customTagReplacement, AttributeStatement);
61
61
  default:
62
- context = await postBinding.base64LoginResponse(requestInfo, {
63
- idp: this,
64
- sp,
65
- }, user, customTagReplacement, encryptThenSign, AttributeStatement);
66
- /* throw new Error('ERR_CREATE_RESPONSE_UNDEFINED_BINDING');*/
62
+ throw new Error('ERR_CREATE_RESPONSE_UNDEFINED_BINDING');
67
63
  }
68
64
  return {
69
65
  ...context,
@@ -4,7 +4,7 @@
4
4
  * @desc Declares the actions taken by service provider
5
5
  */
6
6
  import Entity from './entity.js';
7
- import * as crypto from "node:crypto";
7
+ import Artifact from './binding-artifact.js';
8
8
  import { namespace } from './urn.js';
9
9
  import redirectBinding from './binding-redirect.js';
10
10
  import postBinding from './binding-post.js';
@@ -61,12 +61,6 @@ export class ServiceProvider extends Entity {
61
61
  // Object context = {id, context, signature, sigAlg}
62
62
  context = simpleSignBinding.base64LoginRequest({ idp, sp: this }, customTagReplacement);
63
63
  break;
64
- case nsBinding.artifact:
65
- context = artifactSignBinding.base64LoginRequest("/*[local-name(.)='AuthnRequest']", {
66
- idp,
67
- sp: this
68
- }, customTagReplacement);
69
- break;
70
64
  default:
71
65
  // Will support artifact in the next release
72
66
  throw new Error('ERR_SP_LOGIN_REQUEST_UNDEFINED_BINDING');
@@ -78,39 +72,20 @@ export class ServiceProvider extends Entity {
78
72
  type: 'SAMLRequest',
79
73
  };
80
74
  }
81
- /**
82
- * @desc Generates the Art login request for developers to design their own method
83
- * @param {IdentityProvider} idp object of identity provider
84
- * @param {string} binding protocol binding
85
- * @param {function} customTagReplacement used when developers have their own login response template
86
- */
87
- createLoginRequestArt(idp, binding = 'redirect', customTagReplacement) {
75
+ async createLoginSoapRequest(idp, binding = 'artifact', config) {
88
76
  const nsBinding = namespace.binding;
89
77
  const protocol = nsBinding[binding];
90
78
  if (this.entityMeta.isAuthnRequestSigned() !== idp.entityMeta.isWantAuthnRequestsSigned()) {
91
79
  throw new Error('ERR_METADATA_CONFLICT_REQUEST_SIGNED_FLAG');
92
80
  }
93
81
  let context = null;
94
- switch (protocol) {
95
- case nsBinding.redirect:
96
- return redirectBinding.loginRequestRedirectURLArt({ idp, sp: this }, customTagReplacement);
97
- case nsBinding.post:
98
- context = postBinding.base64LoginRequest("/*[local-name(.)='AuthnRequest']", {
99
- idp,
100
- sp: this,
101
- soap: true
102
- }, customTagReplacement);
103
- break;
104
- default:
105
- // Will support artifact in the next release
106
- throw new Error('ERR_SP_LOGIN_REQUEST_UNDEFINED_BINDING');
107
- }
108
- return {
109
- ...context,
110
- relayState: this.entitySetting.relayState,
111
- entityEndpoint: idp.entityMeta.getSingleSignOnService(binding),
112
- type: 'SAMLRequest',
113
- };
82
+ context = await artifactSignBinding.soapLoginRequest("/*[local-name(.)='AuthnRequest']", {
83
+ idp,
84
+ sp: this,
85
+ inResponse: config?.inResponseTo,
86
+ relayState: config?.relayState,
87
+ }, config?.customTagReplacement);
88
+ return context;
114
89
  }
115
90
  /**
116
91
  * @desc Validation of the parsed the URL parameters
@@ -136,70 +111,20 @@ export class ServiceProvider extends Entity {
136
111
  * @param {string} binding protocol binding
137
112
  * @param {request} req request
138
113
  */
139
- parseLoginResponseArt(idp, binding, request) {
114
+ parseLoginRequestResolve(idp, xml) {
140
115
  const self = this;
141
- return flow({
142
- soap: true,
143
- from: idp,
144
- self: self,
145
- checkSignature: true, // saml response must have signature
146
- parserType: 'SAMLResponse',
147
- type: 'login',
148
- binding: binding,
149
- request: request
116
+ return Artifact.parseLoginRequestResolve({
117
+ idp: idp,
118
+ sp: self,
119
+ xml: xml
150
120
  });
151
121
  }
152
- /**
153
- * @desc generate Art id
154
- *
155
- * @param entityIDString
156
- */
157
- createArt(entityIDString, endpointIndex = 0) {
158
- let sourceEntityId = entityIDString ? entityIDString : this.entityMeta.getEntityID();
159
- console.log(sourceEntityId);
160
- console.log("0000000000000000000000000000000000000000");
161
- // 1. 固定类型代码 (0x0004 - 2字节)
162
- const typeCode = Buffer.from([0x00, 0x04]);
163
- // 2. 端点索引 (2字节,大端序)
164
- if (endpointIndex < 0 || endpointIndex > 65535) {
165
- throw new Error('Endpoint index must be between 0 and 65535');
166
- }
167
- const endpointBuf = Buffer.alloc(2);
168
- endpointBuf.writeUInt16BE(endpointIndex);
169
- // 3. Source ID - 实体ID的SHA-1哈希 (20字节)
170
- const sourceId = crypto.createHash('sha1')
171
- .update(sourceEntityId)
172
- .digest();
173
- // 4. Message Handler - 20字节随机值
174
- const messageHandler = crypto.randomBytes(20);
175
- // 组合所有组件 (2+2+20+20 = 44字节)
176
- const artifact = Buffer.concat([typeCode, endpointBuf, sourceId, messageHandler]);
177
- // 返回Base64编码的Artifact
178
- return artifact.toString('base64');
179
- }
180
- /**
181
- * @desc generate Art id
182
- * @param artifact
183
- */
184
- parseArt(artifact) {
185
- // 解码 Base64
186
- const decoded = Buffer.from(artifact, 'base64');
187
- // 确保长度正确(SAML 工件固定为 44 字节)
188
- if (decoded.length !== 44) {
189
- throw new Error(`Invalid artifact length: ${decoded.length}, expected 44 bytes`);
190
- }
191
- // 读取前 4 字节(TypeCode + EndpointIndex)
192
- const typeCode = decoded.readUInt16BE(0);
193
- const endpointIndex = decoded.readUInt16BE(2);
194
- // 使用 Buffer.from() 替代 slice()
195
- const sourceId = Buffer.from(decoded.buffer, // 底层 ArrayBuffer
196
- decoded.byteOffset + 4, // 起始偏移量
197
- 20 // 长度
198
- ).toString('hex');
199
- const messageHandle = Buffer.from(decoded.buffer, // 底层 ArrayBuffer
200
- decoded.byteOffset + 24, // 起始偏移量
201
- 20 // 长度
202
- ).toString('hex');
203
- return { typeCode, endpointIndex, sourceId, messageHandle };
122
+ parseLoginResponseResolve(idp, art, request) {
123
+ const self = this;
124
+ return Artifact.parseLoginResponseResolve({
125
+ idp: idp,
126
+ sp: self,
127
+ art: art
128
+ });
204
129
  }
205
130
  }
@@ -54,6 +54,38 @@ export const loginRequestFields = [
54
54
  context: true
55
55
  }
56
56
  ];
57
+ export const artifactResolveFields = [
58
+ {
59
+ key: 'request',
60
+ localPath: ['ArtifactResolve'],
61
+ attributes: ['ID', 'IssueInstant', 'Version']
62
+ },
63
+ {
64
+ key: 'issuer', localPath: ['ArtifactResolve', 'Issuer'], attributes: []
65
+ },
66
+ {
67
+ key: 'Artifact', localPath: ['ArtifactResolve', 'Artifact'], attributes: []
68
+ },
69
+ {
70
+ key: 'signature', localPath: ['ArtifactResolve', 'Signature'], attributes: [], context: true
71
+ },
72
+ ];
73
+ export const artifactResponseFields = [
74
+ {
75
+ key: 'request',
76
+ localPath: ['Envelope', 'Body', 'ArtifactResolve'],
77
+ attributes: ['ID', 'IssueInstant', 'Version']
78
+ },
79
+ {
80
+ key: 'issuer', localPath: ['Envelope', 'Body', 'ArtifactResolve', 'Issuer'], attributes: []
81
+ },
82
+ {
83
+ key: 'Artifact', localPath: ['Envelope', 'Body', 'ArtifactResolve', 'Artifact'], attributes: []
84
+ },
85
+ {
86
+ key: 'signature', localPath: ['Envelope', 'Body', 'ArtifactResolve', 'Signature'], attributes: [], context: true
87
+ },
88
+ ];
57
89
  // support two-tiers status code
58
90
  export const loginResponseStatusFields = [
59
91
  {
@@ -191,7 +223,7 @@ export const logoutResponseFields = [
191
223
  ];
192
224
  export function extract(context, fields) {
193
225
  const { dom } = getContext();
194
- const rootDoc = dom.parseFromString(context);
226
+ const rootDoc = dom.parseFromString(context, 'application/xml');
195
227
  return fields.reduce((result, field) => {
196
228
  // get essential fields
197
229
  const key = field.key;
@@ -207,7 +239,7 @@ export function extract(context, fields) {
207
239
  // if shortcut is used, then replace the doc
208
240
  // it's a design for overriding the doc used during runtime
209
241
  if (shortcut) {
210
- targetDoc = dom.parseFromString(shortcut);
242
+ targetDoc = dom.parseFromString(shortcut, 'application/xml');
211
243
  }
212
244
  // special case: multiple path
213
245
  /*
@@ -229,6 +261,7 @@ export function extract(context, fields) {
229
261
  .join(' | ');
230
262
  return {
231
263
  ...result,
264
+ // @ts-expect-error misssing Node properties are not needed
232
265
  [key]: uniq(select(multiXPaths, targetDoc).map((n) => n.nodeValue).filter(notEmpty))
233
266
  };
234
267
  }
@@ -249,8 +282,10 @@ export function extract(context, fields) {
249
282
  // find the index in localpath
250
283
  const indexPath = buildAttributeXPath(index);
251
284
  const fullLocalXPath = `${baseXPath}${indexPath}`;
285
+ // @ts-expect-error misssing Node properties are not needed
252
286
  const parentNodes = select(baseXPath, targetDoc);
253
287
  // [uid, mail, edupersonaffiliation], ready for aggregate
288
+ // @ts-expect-error misssing Node properties are not needed
254
289
  const parentAttributes = select(fullLocalXPath, targetDoc).map((n) => n.value);
255
290
  // [attribute, attributevalue]
256
291
  const childXPath = buildAbsoluteXPath([last(localPath)].concat(attributePath));
@@ -258,8 +293,9 @@ export function extract(context, fields) {
258
293
  const fullChildXPath = `${childXPath}${childAttributeXPath}`;
259
294
  // [ 'test', 'test@example.com', [ 'users', 'examplerole1' ] ]
260
295
  const childAttributes = parentNodes.map(node => {
261
- const nodeDoc = dom.parseFromString(node.toString());
296
+ const nodeDoc = dom.parseFromString(node.toString(), 'application/xml');
262
297
  if (attributes.length === 0) {
298
+ // @ts-ignore
263
299
  const childValues = select(fullChildXPath, nodeDoc).map((n) => n.nodeValue);
264
300
  if (childValues.length === 1) {
265
301
  return childValues[0];
@@ -267,6 +303,7 @@ export function extract(context, fields) {
267
303
  return childValues;
268
304
  }
269
305
  if (attributes.length > 0) {
306
+ // @ts-ignore
270
307
  const childValues = select(fullChildXPath, nodeDoc).map((n) => n.value);
271
308
  if (childValues.length === 1) {
272
309
  return childValues[0];
@@ -292,6 +329,7 @@ export function extract(context, fields) {
292
329
  }
293
330
  */
294
331
  if (isEntire) {
332
+ // @ts-expect-error misssing Node properties are not needed
295
333
  const node = select(baseXPath, targetDoc);
296
334
  let value = null;
297
335
  if (node.length === 1) {
@@ -314,10 +352,13 @@ export function extract(context, fields) {
314
352
  }
315
353
  */
316
354
  if (attributes.length > 1) {
355
+ // @ts-ignore
317
356
  const baseNode = select(baseXPath, targetDoc).map(n => n.toString());
318
357
  const childXPath = `${buildAbsoluteXPath([last(localPath)])}${attributeXPath}`;
319
358
  const attributeValues = baseNode.map((node) => {
320
- const nodeDoc = dom.parseFromString(node);
359
+ // @ts-ignore
360
+ const nodeDoc = dom.parseFromString(node, 'application/xml');
361
+ // @ts-ignore
321
362
  const values = select(childXPath, nodeDoc).reduce((r, n) => {
322
363
  r[camelCase(n.name, { locale: 'en-us' })] = n.value;
323
364
  return r;
@@ -339,6 +380,7 @@ export function extract(context, fields) {
339
380
  */
340
381
  if (attributes.length === 1) {
341
382
  const fullPath = `${baseXPath}${attributeXPath}`;
383
+ // @ts-ignore
342
384
  const attributeValues = select(fullPath, targetDoc).map((n) => n.value);
343
385
  return {
344
386
  ...result,
@@ -355,9 +397,11 @@ export function extract(context, fields) {
355
397
  */
356
398
  if (attributes.length === 0) {
357
399
  let attributeValue = null;
400
+ // @ts-expect-error misssing Node properties are not needed
358
401
  const node = select(baseXPath, targetDoc);
359
402
  if (node.length === 1) {
360
403
  const fullPath = `string(${baseXPath}${attributeXPath})`;
404
+ // @ts-expect-error misssing Node properties are not needed
361
405
  attributeValue = select(fullPath, targetDoc);
362
406
  }
363
407
  if (node.length > 1) {