samlesa 4.3.5 → 4.5.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.
@@ -1,122 +1,114 @@
1
- import { getContext } from "./api.js";
2
- import { select } from "xpath";
3
- import { SignedXml } from "xml-crypto-next";
4
- import fs from "fs";
5
- import utility, { flattenDeep } from "./utility.js";
6
- import libsaml from "./libsaml.js";
7
- import { wording } from "./urn.js";
1
+ import fs from 'fs';
8
2
  import { DOMParser } from '@xmldom/xmldom';
3
+ import { select } from 'xpath';
4
+ import { SignedXml } from 'xml-crypto-next';
5
+ import utility, { normalizeCertificates } from './utility.js';
6
+ import libsaml from './libsaml.js';
7
+ import { wording } from './urn.js';
8
+ import { getContext } from './api.js';
9
9
  function toNodeArray(result) {
10
- if (Array.isArray(result))
10
+ if (Array.isArray(result)) {
11
11
  return result;
12
- if (result != null && typeof result === 'object' && 'nodeType' in result)
12
+ }
13
+ if (result != null && typeof result === 'object' && 'nodeType' in result) {
13
14
  return [result];
15
+ }
14
16
  return [];
15
17
  }
16
18
  const certUse = wording.certUse;
17
19
  const docParser = new DOMParser();
18
- async function verifyAndDecryptSoapMessage(xml, opts) {
19
- const { dom } = getContext();
20
- const doc = dom.parseFromString(xml, 'application/xml');
21
- const docParser = new DOMParser();
22
- let type = '';
23
- // 为 SOAP 消息定义 XPath
24
- const artifactResolveXpath = "/*[local-name()='Envelope']/*[local-name()='Body']/*[local-name()='ArtifactResolve']";
25
- const artifactResponseXpath = "/*[local-name()='Envelope']/*[local-name()='Body']/*[local-name()='ArtifactResponse']";
26
- // 检测 ArtifactResolve 或 ArtifactResponse 的存在
27
- // @ts-expect-error
28
- const artifactResolveNodes = toNodeArray(select(artifactResolveXpath, doc));
29
- // @ts-expect-error
30
- const artifactResponseNodes = toNodeArray(select(artifactResponseXpath, doc));
31
- // 根据消息类型选择合适的 XPath
32
- let basePath = "";
33
- if (artifactResolveNodes?.length > 0) {
34
- type = 'artifactResolve';
35
- basePath = "/*[local-name()='Envelope']/*[local-name()='Body']/*[local-name()='ArtifactResolve']";
20
+ function resolvePublicCertificate(signatureNode, opts) {
21
+ if (!opts.keyFile && !opts.metadata) {
22
+ throw new Error('ERR_UNDEFINED_SIGNATURE_VERIFIER_OPTIONS');
36
23
  }
37
- else if (artifactResponseNodes?.length > 0) {
38
- type = 'artifactResponse';
39
- basePath = "/*[local-name()='Envelope']/*[local-name()='Body']/*[local-name()='ArtifactResponse']";
24
+ if (opts.keyFile) {
25
+ return fs.readFileSync(opts.keyFile);
40
26
  }
41
- else {
42
- throw new Error('ERR_UNSUPPORTED_SOAP_MESSAGE_TYPE');
27
+ const certificateNode = toNodeArray(select(".//*[local-name(.)='X509Certificate']", signatureNode));
28
+ const metadataCerts = normalizeCertificates(opts.metadata.getX509Certificate(certUse.signing));
29
+ if (certificateNode.length === 0 && metadataCerts.length === 0) {
30
+ throw new Error('NO_SELECTED_CERTIFICATE');
43
31
  }
44
- // 基于 SOAP 结构重新定义 XPath
45
- const messageSignatureXpath = `${basePath}/*[local-name(.)='Signature']`;
46
- // @ts-expect-error
47
- const messageSignatureNode = toNodeArray(select(messageSignatureXpath, doc));
48
- let selection = [];
49
- if (messageSignatureNode?.length > 0) {
50
- selection = selection.concat(messageSignatureNode);
32
+ if (certificateNode.length > 0) {
33
+ const x509CertificateData = certificateNode[0].firstChild?.nodeValue || '';
34
+ const x509Certificate = utility.normalizeCerString(x509CertificateData);
35
+ if (metadataCerts.length > 0 && !metadataCerts.includes(x509Certificate)) {
36
+ throw new Error('ERROR_UNMATCH_CERTIFICATE_DECLARATION_IN_METADATA');
37
+ }
38
+ return libsaml.getKeyInfo(x509Certificate).getKey();
51
39
  }
52
- if (selection.length === 0) {
53
- throw new Error('ERR_ZERO_SIGNATURE');
40
+ return libsaml.getKeyInfo(metadataCerts[0]).getKey();
41
+ }
42
+ function extractResolvedMessage(rootNode) {
43
+ const resolvedNodes = toNodeArray(select("./*[local-name()='Response' or local-name()='AuthnRequest' or local-name()='LogoutRequest' or local-name()='LogoutResponse']", rootNode));
44
+ if (resolvedNodes.length === 0) {
45
+ return null;
54
46
  }
55
- return verifySignature(xml, selection, opts);
47
+ return resolvedNodes[0].toString();
56
48
  }
57
- function verifySignature(xml, selection, opts) {
58
- // 尝试所有签名节点
59
- for (const signatureNode of selection) {
49
+ function verifySignature(xml, signatureNodes, opts) {
50
+ for (const signatureNode of signatureNodes) {
60
51
  const sig = new SignedXml();
61
- let verified = false;
62
- sig.signatureAlgorithm = opts.signatureAlgorithm;
63
- if (!opts.keyFile && !opts.metadata) {
64
- throw new Error('ERR_UNDEFINED_SIGNATURE_VERIFIER_OPTIONS');
65
- }
66
- if (opts.keyFile) {
67
- sig.publicCert = fs.readFileSync(opts.keyFile);
68
- }
69
- if (opts.metadata) {
70
- const certificateNode = select(".//*[local-name(.)='X509Certificate']", signatureNode);
71
- // 证书处理逻辑
72
- let metadataCert = opts.metadata.getX509Certificate(certUse.signing);
73
- if (Array.isArray(metadataCert)) {
74
- metadataCert = flattenDeep(metadataCert);
75
- }
76
- else if (typeof metadataCert === 'string') {
77
- metadataCert = [metadataCert];
78
- }
79
- metadataCert = metadataCert.map(utility.normalizeCerString);
80
- // 没有证书的情况
81
- if (certificateNode.length === 0 && metadataCert.length === 0) {
82
- throw new Error('NO_SELECTED_CERTIFICATE');
83
- }
84
- if (certificateNode.length !== 0) {
85
- const x509CertificateData = certificateNode[0].firstChild.data;
86
- const x509Certificate = utility.normalizeCerString(x509CertificateData);
87
- if (metadataCert.length >= 1 && !metadataCert.includes(x509Certificate)) {
88
- throw new Error('ERROR_UNMATCH_CERTIFICATE_DECLARATION_IN_METADATA');
89
- }
90
- sig.publicCert = libsaml.getKeyInfo(x509Certificate).getKey();
91
- }
92
- else {
93
- sig.publicCert = libsaml.getKeyInfo(metadataCert[0]).getKey();
94
- }
95
- }
52
+ sig.publicCert = resolvePublicCertificate(signatureNode, opts);
96
53
  sig.loadSignature(signatureNode);
97
- verified = sig.checkSignature(xml); // 使用原始XML验证
54
+ const verified = sig.checkSignature(xml);
98
55
  if (!verified) {
99
56
  throw new Error('ERR_FAILED_TO_VERIFY_SIGNATURE');
100
57
  }
101
- if (sig.getSignedReferences().length < 1) {
58
+ const signedReferences = sig.getSignedReferences();
59
+ if (signedReferences.length < 1) {
102
60
  throw new Error('NO_SIGNATURE_REFERENCES');
103
61
  }
104
- const signedVerifiedXML = sig.getSignedReferences()[0];
105
- const rootNode = docParser.parseFromString(signedVerifiedXML, 'application/xml').documentElement;
106
- // 处理签名的内容
107
- switch (rootNode?.localName) {
108
- case 'ArtifactResolve':
109
- return [true, rootNode.toString(), false, false];
110
- case 'ArtifactResponse':
111
- // @ts-expect-error
112
- const Response = select("/*[local-name()='ArtifactResponse']/*[local-name()='Response']", rootNode);
113
- return [true, Response?.[0].toString(), false, false]; // 签名验证成功但未找到断言
114
- default:
115
- return [true, null, false, true]; // 签名验证成功但未找到可识别的内容
62
+ const signedXml = signedReferences[0];
63
+ const rootNode = docParser.parseFromString(signedXml, 'application/xml').documentElement;
64
+ if (!rootNode) {
65
+ throw new Error('ERR_INVALID_SOAP_PAYLOAD');
116
66
  }
67
+ if (rootNode.localName === 'ArtifactResolve') {
68
+ return {
69
+ verified: true,
70
+ soapContent: xml,
71
+ message: rootNode.toString(),
72
+ type: 'ArtifactResolve',
73
+ resolvedMessage: null,
74
+ };
75
+ }
76
+ if (rootNode.localName === 'ArtifactResponse') {
77
+ return {
78
+ verified: true,
79
+ soapContent: xml,
80
+ message: rootNode.toString(),
81
+ type: 'ArtifactResponse',
82
+ resolvedMessage: extractResolvedMessage(rootNode),
83
+ };
84
+ }
85
+ }
86
+ throw new Error('ERR_UNSUPPORTED_SOAP_MESSAGE_TYPE');
87
+ }
88
+ async function verifyAndDecryptSoapMessage(xml, opts) {
89
+ const { dom } = getContext();
90
+ const doc = dom.parseFromString(xml, 'application/xml');
91
+ const artifactResolveXpath = "/*[local-name()='Envelope']/*[local-name()='Body']/*[local-name()='ArtifactResolve']";
92
+ const artifactResponseXpath = "/*[local-name()='Envelope']/*[local-name()='Body']/*[local-name()='ArtifactResponse']";
93
+ const artifactResolveNodes = toNodeArray(select(artifactResolveXpath, doc));
94
+ const artifactResponseNodes = toNodeArray(select(artifactResponseXpath, doc));
95
+ let basePath = '';
96
+ if (artifactResolveNodes.length > 0) {
97
+ basePath = artifactResolveXpath;
98
+ }
99
+ else if (artifactResponseNodes.length > 0) {
100
+ basePath = artifactResponseXpath;
101
+ }
102
+ else {
103
+ throw new Error('ERR_UNSUPPORTED_SOAP_MESSAGE_TYPE');
104
+ }
105
+ const messageSignatureXpath = `${basePath}/*[local-name(.)='Signature']`;
106
+ const messageSignatureNodes = toNodeArray(select(messageSignatureXpath, doc));
107
+ if (messageSignatureNodes.length === 0) {
108
+ throw new Error('ERR_ZERO_SIGNATURE');
117
109
  }
118
- return [false, null, false, true];
110
+ return verifySignature(xml, messageSignatureNodes, opts);
119
111
  }
120
112
  export default {
121
- verifyAndDecryptSoapMessage
113
+ verifyAndDecryptSoapMessage,
122
114
  };
@@ -29,16 +29,15 @@ export function applyAuthnRequestEnhancements(rawSamlRequest, enhancements) {
29
29
  if (enhancements.providerName) {
30
30
  authnRequestElement.setAttribute('ProviderName', enhancements.providerName);
31
31
  }
32
- // 2. 添加 Scoping 元素
33
- if (enhancements.scoping) {
34
- const scopingElement = buildScopingElement(enhancements.scoping, doc);
35
- authnRequestElement.appendChild(scopingElement);
36
- }
37
- // 3. 添加 RequestedAuthnContext 元素
32
+ // AuthnRequestType 要求 RequestedAuthnContext 先于 Scoping
38
33
  if (enhancements.requestedAuthnContext) {
39
34
  const contextElement = buildRequestedAuthnContextElement(enhancements.requestedAuthnContext, doc);
40
35
  authnRequestElement.appendChild(contextElement);
41
36
  }
37
+ if (enhancements.scoping) {
38
+ const scopingElement = buildScopingElement(enhancements.scoping, doc);
39
+ authnRequestElement.appendChild(scopingElement);
40
+ }
42
41
  return new XMLSerializer().serializeToString(doc);
43
42
  }
44
43
  /**
@@ -30,15 +30,7 @@ export function buildScoping(config) {
30
30
  if (config.proxyCount !== undefined) {
31
31
  scoping['samlp:Scoping'][0]._attr.ProxyCount = config.proxyCount.toString();
32
32
  }
33
- // 添加 RequesterID 元素
34
- if (config.requesterID && config.requesterID.length > 0) {
35
- config.requesterID.forEach(id => {
36
- scoping['samlp:Scoping'].push({
37
- 'samlp:RequesterID': [{ _attr: { URI: id } }]
38
- });
39
- });
40
- }
41
- // 添加 IDPList 元素
33
+ // SAML Core 要求 IDPList 先于 RequesterID 出现
42
34
  if (config.idpList && config.idpList.length > 0) {
43
35
  const idpList = { 'samlp:IDPList': [] };
44
36
  config.idpList.forEach(entry => {
@@ -55,6 +47,14 @@ export function buildScoping(config) {
55
47
  });
56
48
  scoping['samlp:Scoping'].push(idpList);
57
49
  }
50
+ // RequesterID 的类型是 anyURI,值必须写在元素文本中而不是属性里
51
+ if (config.requesterID && config.requesterID.length > 0) {
52
+ config.requesterID.forEach(id => {
53
+ scoping['samlp:Scoping'].push({
54
+ 'samlp:RequesterID': [id]
55
+ });
56
+ });
57
+ }
58
58
  return scoping;
59
59
  }
60
60
  /**
@@ -86,7 +86,7 @@ export function buildRequestedAuthnContext(config) {
86
86
  if (config.declRefs && config.declRefs.length > 0) {
87
87
  config.declRefs.forEach(ref => {
88
88
  requestedAuthnContext['samlp:RequestedAuthnContext'].push({
89
- 'saml:AuthnContextDeclRef': [{ _attr: { URI: ref } }]
89
+ 'saml:AuthnContextDeclRef': [ref]
90
90
  });
91
91
  });
92
92
  }
@@ -292,14 +292,13 @@ export function enhanceAuthnRequest(baseAuthnRequest, enhancedConfig) {
292
292
  }
293
293
  authnRequestContent[0]._attr.ProviderName = enhancedConfig.providerName;
294
294
  }
295
- // 添加 Scoping 元素
296
- if (enhancedConfig.scoping) {
297
- authnRequestContent.push(buildScoping(enhancedConfig.scoping));
298
- }
299
- // 添加 RequestedAuthnContext 元素
295
+ // AuthnRequestType 的序列顺序为 RequestedAuthnContext 在前、Scoping 在后
300
296
  if (enhancedConfig.requestedAuthnContext) {
301
297
  authnRequestContent.push(buildRequestedAuthnContext(enhancedConfig.requestedAuthnContext));
302
298
  }
299
+ if (enhancedConfig.scoping) {
300
+ authnRequestContent.push(buildScoping(enhancedConfig.scoping));
301
+ }
303
302
  return authnRequest;
304
303
  }
305
304
  /**
package/build/src/soap.js CHANGED
@@ -1,144 +1,73 @@
1
1
  import axios from 'axios';
2
- import https from 'node:https';
3
- import crypto from "node:crypto";
4
2
  import { Builder } from 'xml2js';
5
3
  import iconv from 'iconv-lite';
6
- // 2. 配置 Axios 实例(处理自签名证书)
4
+ import { generateArtifactId, parseArtifact } from './artifact.js';
7
5
  const axiosInstance = axios.create({
8
- httpsAgent: new https.Agent({
9
- rejectUnauthorized: false // 允许自签名证书
10
- })
6
+ timeout: 5000,
11
7
  });
12
- export async function sendArtifactResolve(url, soapRequest) {
13
- try {
14
- const response = await axiosInstance.post(url, soapRequest, {
15
- headers: {
16
- 'Content-Type': 'text/xml',
17
- 'SOAPAction': '"ArtifactResolve"'
18
- },
19
- timeout: 5000 // 5秒超时
20
- });
21
- return response.data;
8
+ function getAxiosErrorPayload(error) {
9
+ if (error?.response?.data) {
10
+ return error.response.data;
22
11
  }
23
- catch (error) {
24
- throw error.response.data;
12
+ if (error instanceof Error) {
13
+ return error;
25
14
  }
15
+ return new Error('ERR_SOAP_REQUEST_FAILED');
26
16
  }
27
- export async function sendArtifactResponse(url, soapRequest) {
17
+ async function sendSoapRequest(url, soapRequest, soapAction) {
28
18
  try {
29
19
  const response = await axiosInstance.post(url, soapRequest, {
30
20
  headers: {
31
- 'Content-Type': 'text/xml',
32
- 'SOAPAction': '"ArtifactResponse"'
21
+ 'Content-Type': 'text/xml; charset=utf-8',
22
+ SOAPAction: `"${soapAction}"`,
33
23
  },
34
- timeout: 5000 // 5秒超时
35
24
  });
36
25
  return response.data;
37
26
  }
38
27
  catch (error) {
39
- throw error.response.data;
28
+ throw getAxiosErrorPayload(error);
40
29
  }
41
30
  }
42
- /**
43
- * @desc generate Art id
44
- *
45
- * @param entityIDString
46
- * @param endpointIndex
47
- */
31
+ export async function sendArtifactResolve(url, soapRequest) {
32
+ return sendSoapRequest(url, soapRequest, 'ArtifactResolve');
33
+ }
34
+ export async function sendArtifactResponse(url, soapRequest) {
35
+ return sendSoapRequest(url, soapRequest, 'ArtifactResponse');
36
+ }
48
37
  export function createArt(entityIDString, endpointIndex = 0) {
49
- // 安全获取 sourceEntityId
50
- let sourceEntityId;
51
- if (typeof entityIDString === "string") {
52
- sourceEntityId = entityIDString;
53
- }
54
- else {
55
- // 确保只在非字符串类型上访问 entityMeta
56
- sourceEntityId = entityIDString.entityMeta.getEntityID();
57
- }
58
- // 1. 固定类型代码 (0x0004 - 2字节)
59
- const typeCode = Buffer.from([0x00, 0x04]);
60
- // 2. 端点索引 (2字节,大端序)
61
- if (endpointIndex < 0 || endpointIndex > 65535) {
62
- throw new Error("Endpoint index must be between 0 and 65535");
63
- }
64
- const endpointBuf = Buffer.alloc(2);
65
- endpointBuf.writeUInt16BE(endpointIndex);
66
- // 3. Source ID - 实体ID的SHA-1哈希 (20字节)
67
- const sourceId = crypto
68
- .createHash("sha1")
69
- .update(sourceEntityId)
70
- .digest();
71
- // 4. Message Handler - 20字节随机值
72
- const messageHandler = crypto.randomBytes(20);
73
- // 组合所有组件 (2+2+20+20 = 44字节)
74
- const artifact = Buffer.concat([
75
- typeCode,
76
- endpointBuf,
77
- sourceId,
78
- messageHandler,
79
- ]);
80
- // 返回Base64编码的Artifact
38
+ const sourceEntityId = typeof entityIDString === 'string'
39
+ ? entityIDString
40
+ : entityIDString.entityMeta.getEntityID();
41
+ const artifact = generateArtifactId(sourceEntityId, endpointIndex);
42
+ const origin = parseArtifact(artifact);
81
43
  return {
82
- artifact: artifact.toString("base64"),
44
+ artifact,
83
45
  origin: {
84
- typeCode: typeCode.readUInt16BE(0), // 改为整数值
85
- endpointIndex: endpointIndex, // 修复字段名并赋正确的值
86
- sourceId: sourceId.toString("hex"), // 转为十六进制
87
- messageHandle: messageHandler.toString("hex"), // 转为十六进制
46
+ typeCode: origin.typeCode,
47
+ endpointIndex: origin.endpointIndex,
48
+ sourceId: origin.sourceId,
49
+ messageHandle: origin.messageHandle,
88
50
  },
89
51
  };
90
52
  }
91
- /**
92
- * @desc generate Art id
93
- * @param artifact
94
- */
95
53
  export function parseArt(artifact) {
96
- // 解码 Base64
97
- if (Object.prototype.toString.call(artifact) !== '[object String]') {
98
- return;
99
- }
100
- const decoded = Buffer.from(artifact, 'base64');
101
- // 确保长度正确(SAML 工件固定为 44 字节)
102
- if (decoded.length !== 44) {
103
- throw new Error(`Invalid artifact length: ${decoded.length}, expected 44 bytes`);
104
- }
105
- // 读取前 4 字节(TypeCode + EndpointIndex)
106
- const typeCode = decoded.readUInt16BE(0);
107
- const endpointIndex = decoded.readUInt16BE(2);
108
- // 使用 Buffer.from() 替代 slice()
109
- const sourceId = Buffer.from(decoded.buffer, // 底层 ArrayBuffer
110
- decoded.byteOffset + 4, // 起始偏移量
111
- 20 // 长度
112
- ).toString('hex');
113
- const messageHandle = Buffer.from(decoded.buffer, // 底层 ArrayBuffer
114
- decoded.byteOffset + 24, // 起始偏移量
115
- 20 // 长度
116
- ).toString('hex');
117
- return { typeCode, endpointIndex, sourceId, messageHandle };
54
+ return parseArtifact(artifact);
118
55
  }
119
- /**
120
- * 将对象转换为 ISO-8859-1 编码的 XML 字符串
121
- * @param {Object} data - 要转换的数据对象
122
- * @returns {Buffer} - ISO-8859-1 编码的 XML 数据 (Buffer)
123
- */
124
56
  export function encodeXmlToIso88591(data) {
125
57
  try {
126
- // 1. 创建 XML 构建器
127
58
  const builder = new Builder({
128
- headless: false, // 包含 XML 声明
129
- renderOpts: { 'pretty': false }, // 紧凑格式
59
+ headless: false,
60
+ renderOpts: { pretty: false },
130
61
  xmldec: {
131
62
  version: '1.0',
132
63
  encoding: 'ISO-8859-1',
133
- standalone: true
134
- }
64
+ standalone: true,
65
+ },
135
66
  });
136
- // 2. 构建 XML 字符串 (UTF-8 格式)
137
67
  const utf8Xml = builder.buildObject(data);
138
- // 3. 转换为 ISO-8859-1 编码的 Buffer
139
68
  return iconv.encode(utf8Xml, 'iso-8859-1');
140
69
  }
141
70
  catch (error) {
142
- throw new Error(`XML 编码失败: ${error.message}`);
71
+ throw new Error(`XML 缂栫爜澶辫触: ${error.message}`);
143
72
  }
144
73
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "samlesa",
3
- "version": "4.3.5",
3
+ "version": "4.5.0",
4
4
  "description": "High-level API for Single Sign On (SAML 2.0) baseed on samlify ",
5
5
  "main": "build/index.js",
6
6
  "keywords": [
@@ -55,8 +55,8 @@
55
55
  "docs": "https://saml.veclea.com",
56
56
  "license": "MIT",
57
57
  "dependencies": {
58
- "@xmldom/xmldom": "^0.9.8",
59
- "axios": "^1.13.6",
58
+ "@xmldom/xmldom": "^0.9.10",
59
+ "axios": "^1.15.2",
60
60
  "camelcase": "^9.0.0",
61
61
  "cross-env": "^10.1.0",
62
62
  "iconv-lite": "^0.7.2",
@@ -71,17 +71,17 @@
71
71
  "xpath": "^0.0.34"
72
72
  },
73
73
  "devDependencies": {
74
- "@types/node": "^25.5.0",
74
+ "@types/node": "^25.6.0",
75
75
  "@types/pako": "2.0.4",
76
76
  "@types/uuid": "11.0.0",
77
- "@vitest/coverage-istanbul": "^4.1.2",
78
- "@vitest/coverage-v8": "4.1.2",
77
+ "@vitest/coverage-istanbul": "^4.1.5",
78
+ "@vitest/coverage-v8": "4.1.5",
79
79
  "copyfiles": "^2.4.1",
80
80
  "coveralls": "^3.1.1",
81
- "esbuild": "^0.27.4",
82
- "jsdom": "^29.0.1",
81
+ "esbuild": "^0.28.0",
82
+ "jsdom": "^29.0.2",
83
83
  "timekeeper": "^2.3.1",
84
- "typescript": "6.0.2",
85
- "vitest": "^4.1.2"
84
+ "typescript": "6.0.3",
85
+ "vitest": "^4.1.5"
86
86
  }
87
87
  }
@@ -0,0 +1,14 @@
1
+ export declare const SAML2_ARTIFACT_TYPE_CODE = 4;
2
+ export declare const SAML2_ARTIFACT_LENGTH = 44;
3
+ export interface ParsedArtifact {
4
+ artifact: string;
5
+ typeCode: number;
6
+ endpointIndex: number;
7
+ sourceId: string;
8
+ messageHandle: string;
9
+ }
10
+ export declare function computeArtifactSourceId(entityId: string): Buffer;
11
+ export declare function generateArtifactId(entityId: string, endpointIndex?: number): string;
12
+ export declare function parseArtifact(artifact: string): ParsedArtifact;
13
+ export declare function validateArtifact(artifact: string, expectedEntityId?: string): ParsedArtifact;
14
+ //# sourceMappingURL=artifact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact.d.ts","sourceRoot":"","sources":["../../src/artifact.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,wBAAwB,IAAS,CAAC;AAC/C,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,SAAI,GAAG,MAAM,CAsB9E;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,CAsB9D;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,cAAc,CAS5F"}