samlify 2.10.2 → 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/.circleci/config.yml +8 -38
  2. package/.snyk +2 -6
  3. package/build/index.js +17 -7
  4. package/build/index.js.map +1 -1
  5. package/build/src/api.js +15 -5
  6. package/build/src/api.js.map +1 -1
  7. package/build/src/binding-post.js +25 -15
  8. package/build/src/binding-post.js.map +1 -1
  9. package/build/src/binding-redirect.js +21 -7
  10. package/build/src/binding-redirect.js.map +1 -1
  11. package/build/src/binding-simplesign.js +24 -14
  12. package/build/src/binding-simplesign.js.map +1 -1
  13. package/build/src/entity-idp.js +4 -4
  14. package/build/src/entity-idp.js.map +1 -1
  15. package/build/src/entity-sp.js +2 -2
  16. package/build/src/entity-sp.js.map +1 -1
  17. package/build/src/entity.js +2 -25
  18. package/build/src/entity.js.map +1 -1
  19. package/build/src/extractor.js +33 -28
  20. package/build/src/extractor.js.map +1 -1
  21. package/build/src/flow.js +4 -5
  22. package/build/src/flow.js.map +1 -1
  23. package/build/src/libsaml.js +44 -24
  24. package/build/src/libsaml.js.map +1 -1
  25. package/build/src/metadata-idp.js +9 -9
  26. package/build/src/metadata-idp.js.map +1 -1
  27. package/build/src/metadata-sp.js +9 -9
  28. package/build/src/metadata-sp.js.map +1 -1
  29. package/build/src/metadata.js +17 -7
  30. package/build/src/metadata.js.map +1 -1
  31. package/build/src/urn.js +4 -4
  32. package/build/src/urn.js.map +1 -1
  33. package/build/src/utility.js +53 -26
  34. package/build/src/utility.js.map +1 -1
  35. package/build/src/validator.js +1 -2
  36. package/build/src/validator.js.map +1 -1
  37. package/package.json +17 -19
  38. package/samlify-2.11.0.tgz +0 -0
  39. package/src/api.ts +13 -1
  40. package/src/binding-redirect.ts +4 -0
  41. package/src/entity.ts +2 -2
  42. package/src/extractor.ts +33 -26
  43. package/src/libsaml.ts +26 -17
  44. package/src/utility.ts +42 -13
  45. package/types/src/binding-post.d.ts +1 -1
  46. package/types/src/binding-simplesign.d.ts +1 -1
  47. package/types/src/entity.d.ts +1 -2
  48. package/types/src/extractor.d.ts +1 -1
  49. package/types/src/libsaml.d.ts +5 -6
  50. package/types/src/metadata.d.ts +0 -1
  51. package/types/src/types.d.ts +7 -8
  52. package/types/src/utility.d.ts +7 -2
  53. package/types/src/validator.d.ts +1 -1
  54. package/.travis.yml +0 -29
  55. package/CHANGELOG.md +0 -7
  56. package/types/vitest.config.d.ts +0 -2
package/src/entity.ts CHANGED
@@ -3,9 +3,9 @@
3
3
  * @author tngan
4
4
  * @desc An abstraction for identity provider and service provider.
5
5
  */
6
+ import { randomUUID } from 'crypto';
6
7
  import { isString, isNonEmptyArray } from './utility';
7
8
  import { namespace, wording, algorithms, messageConfigurations } from './urn';
8
- import * as uuid from 'uuid';
9
9
  import IdpMetadata, { IdpMetadata as IdpMetadataConstructor } from './metadata-idp';
10
10
  import SpMetadata, { SpMetadata as SpMetadataConstructor } from './metadata-sp';
11
11
  import redirectBinding from './binding-redirect';
@@ -27,7 +27,7 @@ const defaultEntitySetting = {
27
27
  requestSignatureAlgorithm: signatureAlgorithms.RSA_SHA256,
28
28
  dataEncryptionAlgorithm: dataEncryptionAlgorithm.AES_256,
29
29
  keyEncryptionAlgorithm: keyEncryptionAlgorithm.RSA_OAEP_MGF1P,
30
- generateID: (): string => ('_' + uuid.v4()),
30
+ generateID: (): string => ('_' + randomUUID()),
31
31
  relayState: '',
32
32
  };
33
33
 
package/src/extractor.ts CHANGED
@@ -1,7 +1,13 @@
1
- import { select, SelectedValue } from 'xpath';
2
- import { uniq, last, zipObject, notEmpty } from './utility';
1
+ import { select, SelectedValue, SelectReturnType } from 'xpath';
2
+ import { uniq, last, zipObject, notEmpty, escapeXPathValue } from './utility';
3
+
4
+ function toNodeArray(result: SelectReturnType): Node[] {
5
+ if (Array.isArray(result)) return result;
6
+ if (result != null && typeof result === 'object' && 'nodeType' in (result as object)) return [result as Node];
7
+ return [];
8
+ }
3
9
  import { getContext } from './api';
4
- import camelCase from 'camelcase';
10
+ import { camelCase } from './utility';
5
11
 
6
12
  interface ExtractorField {
7
13
  key: string;
@@ -20,10 +26,10 @@ function buildAbsoluteXPath(paths) {
20
26
  const isWildcard = name.startsWith('~');
21
27
  if (isWildcard) {
22
28
  const pathName = name.replace('~', '');
23
- appendedPath = currentPath + `/*[contains(local-name(), '${pathName}')]`;
29
+ appendedPath = currentPath + `/*[contains(local-name(), ${escapeXPathValue(pathName)})]`;
24
30
  }
25
31
  if (!isWildcard) {
26
- appendedPath = currentPath + `/*[local-name(.)='${name}']`;
32
+ appendedPath = currentPath + `/*[local-name(.)=${escapeXPathValue(name)}]`;
27
33
  }
28
34
  return appendedPath;
29
35
  }, '');
@@ -36,7 +42,7 @@ function buildAttributeXPath(attributes) {
36
42
  if (attributes.length === 1) {
37
43
  return `/@${attributes[0]}`;
38
44
  }
39
- const filters = attributes.map(attribute => `name()='${attribute}'`).join(' or ');
45
+ const filters = attributes.map(attribute => `name()=${escapeXPathValue(attribute)}`).join(' or ');
40
46
  return `/@*[${filters}]`;
41
47
  }
42
48
 
@@ -241,7 +247,7 @@ export function extract(context: string, fields) {
241
247
 
242
248
  return {
243
249
  ...result,
244
- [key]: uniq(select(multiXPaths, targetDoc).map((n: Node) => n.nodeValue).filter(notEmpty))
250
+ [key]: uniq(toNodeArray(select(multiXPaths, targetDoc)).map((n: Node) => n.nodeValue).filter(notEmpty))
245
251
  };
246
252
  }
247
253
  // eo special case: multiple path
@@ -263,9 +269,9 @@ export function extract(context: string, fields) {
263
269
  // find the index in localpath
264
270
  const indexPath = buildAttributeXPath(index);
265
271
  const fullLocalXPath = `${baseXPath}${indexPath}`;
266
- const parentNodes = select(baseXPath, targetDoc);
272
+ const parentNodes = toNodeArray(select(baseXPath, targetDoc));
267
273
  // [uid, mail, edupersonaffiliation], ready for aggregate
268
- const parentAttributes = select(fullLocalXPath, targetDoc).map((n: Attr) => n.value);
274
+ const parentAttributes = toNodeArray(select(fullLocalXPath, targetDoc)).map((n: Attr) => n.value);
269
275
  // [attribute, attributevalue]
270
276
  const childXPath = buildAbsoluteXPath([last(localPath)].concat(attributePath));
271
277
  const childAttributeXPath = buildAttributeXPath(attributes);
@@ -274,14 +280,14 @@ export function extract(context: string, fields) {
274
280
  const childAttributes = parentNodes.map(node => {
275
281
  const nodeDoc = dom.parseFromString(node.toString());
276
282
  if (attributes.length === 0) {
277
- const childValues = select(fullChildXPath, nodeDoc).map((n: Node) => n.nodeValue);
283
+ const childValues = toNodeArray(select(fullChildXPath, nodeDoc)).map((n: Node) => n.nodeValue);
278
284
  if (childValues.length === 1) {
279
285
  return childValues[0];
280
286
  }
281
287
  return childValues;
282
288
  }
283
289
  if (attributes.length > 0) {
284
- const childValues = select(fullChildXPath, nodeDoc).map((n: Attr) => n.value);
290
+ const childValues = toNodeArray(select(fullChildXPath, nodeDoc)).map((n: Attr) => n.value);
285
291
  if (childValues.length === 1) {
286
292
  return childValues[0];
287
293
  }
@@ -307,13 +313,13 @@ export function extract(context: string, fields) {
307
313
  }
308
314
  */
309
315
  if (isEntire) {
310
- const node = select(baseXPath, targetDoc);
316
+ const nodes = toNodeArray(select(baseXPath, targetDoc));
311
317
  let value: string | string[] | null = null;
312
- if (node.length === 1) {
313
- value = node[0].toString();
318
+ if (nodes.length === 1) {
319
+ value = nodes[0].toString();
314
320
  }
315
- if (node.length > 1) {
316
- value = node.map(n => n.toString());
321
+ if (nodes.length > 1) {
322
+ value = nodes.map(n => n.toString());
317
323
  }
318
324
  return {
319
325
  ...result,
@@ -330,12 +336,12 @@ export function extract(context: string, fields) {
330
336
  }
331
337
  */
332
338
  if (attributes.length > 1) {
333
- const baseNode = select(baseXPath, targetDoc).map(n => n.toString());
339
+ const baseNode = toNodeArray(select(baseXPath, targetDoc)).map(n => n.toString());
334
340
  const childXPath = `${buildAbsoluteXPath([last(localPath)])}${attributeXPath}`;
335
341
  const attributeValues = baseNode.map((node: string) => {
336
342
  const nodeDoc = dom.parseFromString(node);
337
- const values = select(childXPath, nodeDoc).reduce((r: any, n: Attr) => {
338
- r[camelCase(n.name, {locale: 'en-us'})] = n.value;
343
+ const values = toNodeArray(select(childXPath, nodeDoc)).reduce((r: any, n: Attr) => {
344
+ r[camelCase(n.name)] = n.value;
339
345
  return r;
340
346
  }, {});
341
347
  return values;
@@ -355,7 +361,7 @@ export function extract(context: string, fields) {
355
361
  */
356
362
  if (attributes.length === 1) {
357
363
  const fullPath = `${baseXPath}${attributeXPath}`;
358
- const attributeValues = select(fullPath, targetDoc).map((n: Attr) => n.value);
364
+ const attributeValues = toNodeArray(select(fullPath, targetDoc)).map((n: Attr) => n.value);
359
365
  return {
360
366
  ...result,
361
367
  [key]: attributeValues[0]
@@ -370,14 +376,15 @@ export function extract(context: string, fields) {
370
376
  }
371
377
  */
372
378
  if (attributes.length === 0) {
373
- let attributeValue: SelectedValue[] | (string | null)[] | null = null;
374
- const node = select(baseXPath, targetDoc);
375
- if (node.length === 1) {
379
+ let attributeValue: SelectedValue[] | (string | null)[] | string | null = null;
380
+ const nodes = toNodeArray(select(baseXPath, targetDoc));
381
+ if (nodes.length === 1) {
376
382
  const fullPath = `string(${baseXPath}${attributeXPath})`;
377
- attributeValue = select(fullPath, targetDoc);
383
+ const strResult = select(fullPath, targetDoc);
384
+ attributeValue = typeof strResult === 'string' ? strResult : strResult === null ? null : Array.isArray(strResult) ? strResult : null;
378
385
  }
379
- if (node.length > 1) {
380
- attributeValue = node.filter((n: Node) => n.firstChild)
386
+ if (nodes.length > 1) {
387
+ attributeValue = nodes.filter((n: Node) => n.firstChild)
381
388
  .map((n: Node) => n.firstChild!.nodeValue);
382
389
  }
383
390
  return {
package/src/libsaml.ts CHANGED
@@ -4,15 +4,21 @@
4
4
  * @desc A simple library including some common functions
5
5
  */
6
6
 
7
- import utility, { flattenDeep, isString } from './utility';
7
+ import utility, { flattenDeep, isString, escapeXPathValue } from './utility';
8
8
  import { algorithms, wording, namespace } from './urn';
9
- import { select } from 'xpath';
9
+ import { select, SelectReturnType } from 'xpath';
10
+
11
+ function toNodeArray(result: SelectReturnType): Node[] {
12
+ if (Array.isArray(result)) return result;
13
+ if (result != null && typeof result === 'object' && 'nodeType' in (result as object)) return [result as Node];
14
+ return [];
15
+ }
10
16
  import { MetadataInterface } from './metadata';
11
17
  import nrsa, { SigningSchemeHash } from 'node-rsa';
12
18
  import { SignedXml } from 'xml-crypto';
13
19
  import * as xmlenc from '@authenio/xml-encryption';
14
20
  import { extract } from './extractor';
15
- import camelCase from 'camelcase';
21
+ import { camelCase } from './utility';
16
22
  import { getContext } from './api';
17
23
  import xmlEscape from 'xml-escape';
18
24
  import * as fs from 'fs';
@@ -221,9 +227,10 @@ const libSaml = () => {
221
227
  */
222
228
  function createXPath(local, isExtractAll?: boolean): string {
223
229
  if (isString(local)) {
224
- return isExtractAll === true ? "//*[local-name(.)='" + local + "']/text()" : "//*[local-name(.)='" + local + "']";
230
+ const escaped = escapeXPathValue(local);
231
+ return isExtractAll === true ? "//*[local-name(.)=" + escaped + "]/text()" : "//*[local-name(.)=" + escaped + "]";
225
232
  }
226
- return "//*[local-name(.)='" + local.name + "']/@" + local.attr;
233
+ return "//*[local-name(.)=" + escapeXPathValue(local.name) + "]/@" + local.attr;
227
234
  }
228
235
 
229
236
  /**
@@ -234,7 +241,7 @@ const libSaml = () => {
234
241
  * @return {string}
235
242
  */
236
243
  function tagging(prefix: string, content: string): string {
237
- const camelContent = camelCase(content, {locale: 'en-us'});
244
+ const camelContent = camelCase(content);
238
245
  return prefix + camelContent.charAt(0).toUpperCase() + camelContent.slice(1);
239
246
  }
240
247
 
@@ -370,7 +377,8 @@ const libSaml = () => {
370
377
  const { dom } = getContext();
371
378
  const doc = dom.parseFromString(xml);
372
379
 
373
- const docParser = new DOMParser();
380
+ const { dom: contextDom } = getContext();
381
+ const docParser = contextDom;
374
382
  // In order to avoid the wrapping attack, we have changed to use absolute xpath instead of naively fetching the signature element
375
383
  // message signature (logout response / saml response)
376
384
  const messageSignatureXpath = "/*[contains(local-name(), 'Response') or contains(local-name(), 'Request')]/*[local-name(.)='Signature']";
@@ -380,10 +388,10 @@ const libSaml = () => {
380
388
  const wrappingElementsXPath = "/*[contains(local-name(), 'Response')]/*[local-name(.)='Assertion']/*[local-name(.)='Subject']/*[local-name(.)='SubjectConfirmation']/*[local-name(.)='SubjectConfirmationData']//*[local-name(.)='Assertion' or local-name(.)='Signature']";
381
389
 
382
390
  // select the signature node
383
- let selection: any = [];
384
- const messageSignatureNode = select(messageSignatureXpath, doc);
385
- const assertionSignatureNode = select(assertionSignatureXpath, doc);
386
- const wrappingElementNode = select(wrappingElementsXPath, doc);
391
+ let selection: Node[] = [];
392
+ const messageSignatureNode = toNodeArray(select(messageSignatureXpath, doc));
393
+ const assertionSignatureNode = toNodeArray(select(assertionSignatureXpath, doc));
394
+ const wrappingElementNode = toNodeArray(select(wrappingElementsXPath, doc));
387
395
 
388
396
  selection = selection.concat(messageSignatureNode);
389
397
  selection = selection.concat(assertionSignatureNode);
@@ -415,7 +423,7 @@ const libSaml = () => {
415
423
 
416
424
  if (opts.metadata) {
417
425
 
418
- const certificateNode = select(".//*[local-name(.)='X509Certificate']", signatureNode) as any;
426
+ const certificateNode = toNodeArray(select(".//*[local-name(.)='X509Certificate']", signatureNode));
419
427
  // certificate in metadata
420
428
  let metadataCert: any = opts.metadata.getX509Certificate(certUse.signing);
421
429
  // flattens the nested array of Certificates from each KeyDescriptor
@@ -434,7 +442,8 @@ const libSaml = () => {
434
442
 
435
443
  // certificate node in response
436
444
  if (certificateNode.length !== 0) {
437
- const x509CertificateData = certificateNode[0].firstChild.data;
445
+ const certEl = certificateNode[0] as Element;
446
+ const x509CertificateData = certEl.textContent ?? '';
438
447
  const x509Certificate = utility.normalizeCerString(x509CertificateData);
439
448
 
440
449
  if (
@@ -473,15 +482,15 @@ const libSaml = () => {
473
482
  // case 1, rootSignedDoc is a response:
474
483
  if (rootNode.localName === 'Response') {
475
484
  // try getting the Xml from the first assertion
476
- const assertions = select(
485
+ const assertions = toNodeArray(select(
477
486
  "./*[local-name()='Assertion']",
478
487
  rootNode
479
- );
488
+ ));
480
489
 
481
- const encryptedAssertions = select(
490
+ const encryptedAssertions = toNodeArray(select(
482
491
  "./*[local-name()='EncryptedAssertion']",
483
492
  rootNode
484
- );
493
+ ));
485
494
  // now we can process the assertion as an assertion
486
495
  if (assertions.length === 1) {
487
496
  return [true, assertions[0].toString()];
package/src/utility.ts CHANGED
@@ -3,8 +3,8 @@
3
3
  * @author tngan
4
4
  * @desc Library for some common functions (e.g. de/inflation, en/decoding)
5
5
  */
6
- import { pki, util, asn1 } from 'node-forge';
7
- import { inflate, deflate } from 'pako';
6
+ import { X509Certificate, createPrivateKey } from 'crypto';
7
+ import { deflateRawSync, inflateRawSync } from 'zlib';
8
8
 
9
9
  const BASE64_STR = 'base64';
10
10
 
@@ -102,8 +102,8 @@ export function base64Decode(base64Message: string, isBytes?: boolean): string |
102
102
  * @return {string} compressed string
103
103
  */
104
104
  function deflateString(message: string): number[] {
105
- const input = Array.prototype.map.call(message, char => char.charCodeAt(0));
106
- return Array.from(deflate(input, { raw: true }));
105
+ const input = Buffer.from(message, 'utf8');
106
+ return Array.from(deflateRawSync(input));
107
107
  }
108
108
  /**
109
109
  * @desc Decompress the compressed string
@@ -112,10 +112,7 @@ function deflateString(message: string): number[] {
112
112
  */
113
113
  export function inflateString(compressedString: string): string {
114
114
  const inputBuffer = Buffer.from(compressedString, BASE64_STR);
115
- const input = Array.prototype.map.call(inputBuffer.toString('binary'), char => char.charCodeAt(0));
116
- return Array.from(inflate(input, { raw: true }))
117
- .map((byte: number) => String.fromCharCode(byte))
118
- .join('');
115
+ return inflateRawSync(inputBuffer).toString('utf8');
119
116
  }
120
117
  /**
121
118
  * @desc Abstract the normalizeCerString and normalizePemString
@@ -173,10 +170,9 @@ function applyDefault(obj1, obj2) {
173
170
  * @return {string} public key fetched from the certificate
174
171
  */
175
172
  function getPublicKeyPemFromCertificate(x509Certificate: string) {
176
- const certDerBytes = util.decode64(x509Certificate);
177
- const obj = asn1.fromDer(certDerBytes);
178
- const cert = pki.certificateFromAsn1(obj);
179
- return pki.publicKeyToPem(cert.publicKey);
173
+ const der = Buffer.from(x509Certificate, 'base64');
174
+ const cert = new X509Certificate(der);
175
+ return cert.publicKey.export({ type: 'spki', format: 'pem' });
180
176
  }
181
177
  /**
182
178
  * @desc Read private key from pem-formatted string
@@ -186,7 +182,12 @@ function getPublicKeyPemFromCertificate(x509Certificate: string) {
186
182
  * If passphrase is used to protect the .pem content (recommend)
187
183
  */
188
184
  export function readPrivateKey(keyString: string | Buffer, passphrase: string | undefined, isOutputString?: boolean) {
189
- return isString(passphrase) ? this.convertToString(pki.privateKeyToPem(pki.decryptRsaPrivateKey(String(keyString), passphrase)), isOutputString) : keyString;
185
+ if (isString(passphrase)) {
186
+ const key = createPrivateKey({ key: keyString, format: 'pem', passphrase });
187
+ const pem = key.export({ type: 'pkcs1', format: 'pem' });
188
+ return convertToString(pem, isOutputString);
189
+ }
190
+ return keyString;
190
191
  }
191
192
  /**
192
193
  * @desc Inline syntax sugar
@@ -210,6 +211,34 @@ export function notEmpty<TValue>(value: TValue | null | undefined): value is TVa
210
211
  return value !== null && value !== undefined;
211
212
  }
212
213
 
214
+ /**
215
+ * @desc Escape a string for safe use inside an XPath single-quoted string literal.
216
+ * Prevents XPath injection by splitting on single quotes and using concat().
217
+ */
218
+ export function escapeXPathValue(value: string): string {
219
+ if (!value.includes("'")) {
220
+ return "'" + value + "'";
221
+ }
222
+ // Use XPath concat() to safely handle strings containing single quotes
223
+ const parts = value.split("'").map(part => "'" + part + "'");
224
+ return 'concat(' + parts.join(`,"'",`) + ')';
225
+ }
226
+
227
+ export function camelCase(input: string): string {
228
+ const words = input
229
+ .replace(/([a-z\d])([A-Z])/g, '$1\0$2')
230
+ .replace(/([A-Z]+)([A-Z][a-z])/g, '$1\0$2')
231
+ .split(/[\0\s\-_\.]+/)
232
+ .filter(w => w.length > 0);
233
+
234
+ return words
235
+ .map((word, i) => {
236
+ const lower = word.toLocaleLowerCase('en-US');
237
+ return i === 0 ? lower : lower.charAt(0).toLocaleUpperCase('en-US') + lower.slice(1);
238
+ })
239
+ .join('');
240
+ }
241
+
213
242
  const utility = {
214
243
  isString,
215
244
  base64Encode,
@@ -19,7 +19,7 @@ declare function base64LoginRequest(referenceTagXPath: string, entity: any, cust
19
19
  * @param {function} customTagReplacement used when developers have their own login response template
20
20
  * @param {boolean} encryptThenSign whether or not to encrypt then sign first (if signing). Defaults to sign-then-encrypt
21
21
  */
22
- declare function base64LoginResponse(requestInfo: any, entity: any, user?: any, customTagReplacement?: (template: string) => BindingContext, encryptThenSign?: boolean): Promise<BindingContext>;
22
+ declare function base64LoginResponse(requestInfo: any | undefined, entity: any, user?: any, customTagReplacement?: (template: string) => BindingContext, encryptThenSign?: boolean): Promise<BindingContext>;
23
23
  /**
24
24
  * @desc Generate a base64 encoded logout request
25
25
  * @param {object} user current logged user (e.g. req.user)
@@ -31,7 +31,7 @@ declare function base64LoginRequest(entity: any, customTagReplacement?: (templat
31
31
  * @param {string} relayState the relay state
32
32
  * @param {function} customTagReplacement used when developers have their own login response template
33
33
  */
34
- declare function base64LoginResponse(requestInfo: any, entity: any, user?: any, relayState?: string, customTagReplacement?: (template: string) => BindingContext): Promise<BindingSimpleSignContext>;
34
+ declare function base64LoginResponse(requestInfo: any | undefined, entity: any, user?: any, relayState?: string, customTagReplacement?: (template: string) => BindingContext): Promise<BindingSimpleSignContext>;
35
35
  declare const simpleSignBinding: {
36
36
  base64LoginRequest: typeof base64LoginRequest;
37
37
  base64LoginResponse: typeof base64LoginResponse;
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import { IdpMetadata as IdpMetadataConstructor } from './metadata-idp';
3
2
  import { SpMetadata as SpMetadataConstructor } from './metadata-sp';
4
3
  import { MetadataIdpConstructor, MetadataSpConstructor, EntitySetting } from './types';
@@ -31,7 +30,7 @@ export interface ParseResult {
31
30
  extract: any;
32
31
  sigAlg: string;
33
32
  }
34
- export declare type EntityConstructor = (MetadataIdpConstructor | MetadataSpConstructor) & {
33
+ export type EntityConstructor = (MetadataIdpConstructor | MetadataSpConstructor) & {
35
34
  metadata?: string | Buffer;
36
35
  };
37
36
  export default class Entity {
@@ -6,7 +6,7 @@ interface ExtractorField {
6
6
  attributePath?: string[];
7
7
  context?: boolean;
8
8
  }
9
- export declare type ExtractorFields = ExtractorField[];
9
+ export type ExtractorFields = ExtractorField[];
10
10
  export declare const loginRequestFields: ExtractorFields;
11
11
  export declare const loginResponseStatusFields: {
12
12
  key: string;
@@ -3,7 +3,6 @@
3
3
  * @author tngan
4
4
  * @desc A simple library including some common functions
5
5
  */
6
- /// <reference types="node" />
7
6
  import { MetadataInterface } from './metadata';
8
7
  export interface SignatureConstructor {
9
8
  rawSamlMessage: string;
@@ -58,7 +57,7 @@ export interface LogoutRequestTemplate extends BaseSamlTemplate {
58
57
  }
59
58
  export interface LogoutResponseTemplate extends BaseSamlTemplate {
60
59
  }
61
- export declare type KeyUse = 'signing' | 'encryption';
60
+ export type KeyUse = 'signing' | 'encryption';
62
61
  export interface KeyComponent {
63
62
  [key: string]: any;
64
63
  }
@@ -86,7 +85,7 @@ export interface LibSamlInterface {
86
85
  defaultLogoutResponseTemplate: LogoutResponseTemplate;
87
86
  }
88
87
  declare const _default: {
89
- createXPath: (local: any, isExtractAll?: boolean | undefined) => string;
88
+ createXPath: (local: any, isExtractAll?: boolean) => string;
90
89
  getQueryParamByType: (type: string) => "SAMLRequest" | "SAMLResponse";
91
90
  defaultLoginRequestTemplate: {
92
91
  context: string;
@@ -166,7 +165,7 @@ declare const _default: {
166
165
  * @param {string} signingAlgorithm signing algorithm
167
166
  * @return {string} message signature
168
167
  */
169
- constructMessageSignature(octetString: string, key: string, passphrase?: string | undefined, isBase64?: boolean | undefined, signingAlgorithm?: string | undefined): string | Buffer;
168
+ constructMessageSignature(octetString: string, key: string, passphrase?: string, isBase64?: boolean, signingAlgorithm?: string): string | Buffer<ArrayBufferLike>;
170
169
  /**
171
170
  * @desc Verifies message signature
172
171
  * @param {Metadata} metadata metadata object of identity provider or service provider
@@ -175,7 +174,7 @@ declare const _default: {
175
174
  * @param {string} verifyAlgorithm algorithm used to verify
176
175
  * @return {boolean} verification result
177
176
  */
178
- verifyMessageSignature(metadata: any, octetString: string, signature: string | Buffer, verifyAlgorithm?: string | undefined): boolean;
177
+ verifyMessageSignature(metadata: any, octetString: string, signature: string | Buffer, verifyAlgorithm?: string): boolean;
179
178
  /**
180
179
  * @desc Get the public key in string format
181
180
  * @param {string} x509Certificate certificate
@@ -192,7 +191,7 @@ declare const _default: {
192
191
  * @param {string} xml response in xml string format
193
192
  * @return {Promise} a promise to resolve the finalized xml
194
193
  */
195
- encryptAssertion(sourceEntity: any, targetEntity: any, xml?: string | undefined): Promise<string>;
194
+ encryptAssertion(sourceEntity: any, targetEntity: any, xml?: string): Promise<string>;
196
195
  /**
197
196
  * @desc Decrypt the assertion section in Response
198
197
  * @param {string} type only accept SAMLResponse to proceed decryption
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  export interface MetadataInterface {
3
2
  xmlString: string;
4
3
  getMetadata: () => string;
@@ -1,11 +1,10 @@
1
- /// <reference types="node" />
2
1
  import { LoginResponseTemplate } from './libsaml';
3
2
  export { IdentityProvider as IdentityProviderConstructor } from './entity-idp';
4
3
  export { IdpMetadata as IdentityProviderMetadata } from './metadata-idp';
5
4
  export { ServiceProvider as ServiceProviderConstructor } from './entity-sp';
6
5
  export { SpMetadata as ServiceProviderMetadata } from './metadata-sp';
7
- export declare type MetadataFile = string | Buffer;
8
- declare type SSOService = {
6
+ export type MetadataFile = string | Buffer;
7
+ type SSOService = {
9
8
  isDefault?: boolean;
10
9
  Binding: string;
11
10
  Location: string;
@@ -20,7 +19,7 @@ export interface MetadataIdpOptions {
20
19
  singleLogoutService?: SSOService[];
21
20
  requestSignatureAlgorithm?: string;
22
21
  }
23
- export declare type MetadataIdpConstructor = MetadataIdpOptions | MetadataFile;
22
+ export type MetadataIdpConstructor = MetadataIdpOptions | MetadataFile;
24
23
  export interface MetadataSpOptions {
25
24
  entityID?: string;
26
25
  signingCert?: string | Buffer | (string | Buffer)[];
@@ -37,8 +36,8 @@ export interface MetadataSpOptions {
37
36
  assertionConsumerService?: SSOService[];
38
37
  elementsOrder?: string[];
39
38
  }
40
- export declare type MetadataSpConstructor = MetadataSpOptions | MetadataFile;
41
- export declare type EntitySetting = ServiceProviderSettings & IdentityProviderSettings;
39
+ export type MetadataSpConstructor = MetadataSpOptions | MetadataFile;
40
+ export type EntitySetting = ServiceProviderSettings & IdentityProviderSettings;
42
41
  export interface SignatureConfig {
43
42
  prefix?: string;
44
43
  location?: {
@@ -49,7 +48,7 @@ export interface SignatureConfig {
49
48
  export interface SAMLDocumentTemplate {
50
49
  context?: string;
51
50
  }
52
- export declare type ServiceProviderSettings = {
51
+ export type ServiceProviderSettings = {
53
52
  metadata?: string | Buffer;
54
53
  entityID?: string;
55
54
  authnRequestsSigned?: boolean;
@@ -76,7 +75,7 @@ export declare type ServiceProviderSettings = {
76
75
  relayState?: string;
77
76
  clockDrifts?: [number, number];
78
77
  };
79
- export declare type IdentityProviderSettings = {
78
+ export type IdentityProviderSettings = {
80
79
  metadata?: string | Buffer;
81
80
  /** signature algorithm */
82
81
  requestSignatureAlgorithm?: string;
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  /**
3
2
  * @desc Mimic lodash.zipObject
4
3
  * @param arr1 {string[]}
@@ -35,7 +34,7 @@ export declare function get(obj: any, path: any, defaultValue: any): any;
35
34
  * @desc Check if the input is string
36
35
  * @param {any} input
37
36
  */
38
- export declare function isString(input: any): boolean;
37
+ export declare function isString(input: any): input is string;
39
38
  /**
40
39
  * @desc Encode string with base64 format
41
40
  * @param {string} message plain-text message
@@ -116,6 +115,12 @@ declare function convertToString(input: any, isOutputString: any): any;
116
115
  export declare function isNonEmptyArray(a: any): boolean;
117
116
  export declare function castArrayOpt<T>(a?: T | T[]): T[];
118
117
  export declare function notEmpty<TValue>(value: TValue | null | undefined): value is TValue;
118
+ /**
119
+ * @desc Escape a string for safe use inside an XPath single-quoted string literal.
120
+ * Prevents XPath injection by splitting on single quotes and using concat().
121
+ */
122
+ export declare function escapeXPathValue(value: string): string;
123
+ export declare function camelCase(input: string): string;
119
124
  declare const utility: {
120
125
  isString: typeof isString;
121
126
  base64Encode: typeof base64Encode;
@@ -1,3 +1,3 @@
1
- declare type DriftTolerance = [number, number];
1
+ type DriftTolerance = [number, number];
2
2
  declare function verifyTime(utcNotBefore: string | undefined, utcNotOnOrAfter: string | undefined, drift?: DriftTolerance): boolean;
3
3
  export { verifyTime };
package/.travis.yml DELETED
@@ -1,29 +0,0 @@
1
- language: node_js
2
-
3
- node_js:
4
- - "16"
5
- - "18"
6
- - "20"
7
-
8
- env:
9
- - INSTALL_JDK=1
10
- - INSTALL_JDK=0
11
-
12
- before_install:
13
- - if [[ "$INSTALL_JDK" == "1" ]] ; then make install_jdk ; fi
14
-
15
- install:
16
- - yarn install --production=true
17
-
18
- script:
19
- - yarn add @authenio/samlify-xsd-schema-validator
20
- - yarn test --timeout=30s
21
-
22
- branches:
23
- only:
24
- - master
25
- - /^.*-alpha$/
26
- - /^.*-rc.*$/
27
- - /^feature\/.*$/
28
-
29
- after_success: npm run coverage
package/CHANGELOG.md DELETED
@@ -1,7 +0,0 @@
1
- # 2.10.1
2
-
3
- * Changes to libsaml.ts verifySignature. This is an internal function, but we still document changes
4
- - Does not raise error when signature is missing/invalid. Instead it now returns false. This is to simplify logic
5
- - When there are encrypted assertions, returns the entire response, as the "verifiedAssertionNode"
6
-
7
- * Fix logic around handling encrypted assertions
@@ -1,2 +0,0 @@
1
- declare const _default: import("vite").UserConfig;
2
- export default _default;