@adobe/acc-js-sdk 1.0.3 → 1.0.7
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/.github/workflows/codeql-analysis.yml +70 -0
- package/.vscode/launch.json +0 -1
- package/CHANGELOG.md +37 -1
- package/README.md +63 -3
- package/compile.js +2 -0
- package/package-lock.json +2438 -3367
- package/package.json +10 -7
- package/samples/002 - basics - schemas.js +3 -3
- package/samples/020 - encryption.js +5 -5
- package/src/application.js +66 -5
- package/src/cache.js +275 -0
- package/src/campaign.js +35 -22
- package/src/client.js +246 -125
- package/src/crypto.js +5 -2
- package/src/domUtil.js +53 -20
- package/src/entityAccessor.js +4 -2
- package/src/index.js +107 -105
- package/src/methodCache.js +55 -46
- package/src/optionCache.js +40 -28
- package/src/soap.js +53 -23
- package/src/transport.js +11 -7
- package/src/util.js +103 -64
- package/src/xtkCaster.js +66 -11
- package/src/xtkEntityCache.js +42 -24
- package/test/application.test.js +40 -1
- package/test/caches.test.js +214 -14
- package/test/client.test.js +485 -30
- package/test/crypto.test.js +16 -12
- package/test/domUtil.test.js +23 -0
- package/test/mock.js +52 -10
- package/test/soap.test.js +13 -6
- package/test/util.test.js +151 -1
- package/test/xtkCaster.test.js +97 -0
package/test/crypto.test.js
CHANGED
|
@@ -19,61 +19,65 @@ governing permissions and limitations under the License.
|
|
|
19
19
|
|
|
20
20
|
const assert = require('assert');
|
|
21
21
|
const crypto = require('../src/crypto.js');
|
|
22
|
+
const { Mock } = require('./mock.js');
|
|
22
23
|
const Cipher = crypto.Cipher;
|
|
23
24
|
|
|
24
25
|
describe('crypto', function() {
|
|
25
26
|
|
|
26
27
|
it("Should decrypt password", function() {
|
|
27
|
-
const cipher = new Cipher(
|
|
28
|
-
|
|
28
|
+
const cipher = new Cipher(Mock.makeKey());
|
|
29
|
+
const encrypted = cipher.encryptPassword("mid");
|
|
30
|
+
var decrypted = cipher.decryptPassword(encrypted);
|
|
29
31
|
assert.equal(decrypted, "mid");
|
|
30
32
|
});
|
|
31
33
|
|
|
32
34
|
it("Should fail on invalid encrypted string", function() {
|
|
33
|
-
const cipher = new Cipher(
|
|
35
|
+
const cipher = new Cipher(Mock.makeKey());
|
|
34
36
|
assert.throws(function() {
|
|
35
37
|
cipher.decryptPassword("Hello");
|
|
36
38
|
});
|
|
37
39
|
});
|
|
38
40
|
|
|
39
41
|
it("Should decrypt password twice", function() {
|
|
40
|
-
const cipher = new Cipher(
|
|
41
|
-
|
|
42
|
+
const cipher = new Cipher(Mock.makeKey());
|
|
43
|
+
const encrypted = cipher.encryptPassword("mid");
|
|
44
|
+
var decrypted = cipher.decryptPassword(encrypted);
|
|
42
45
|
assert.equal(decrypted, "mid");
|
|
43
|
-
decrypted = cipher.decryptPassword(
|
|
46
|
+
decrypted = cipher.decryptPassword(encrypted);
|
|
44
47
|
assert.equal(decrypted, "mid");
|
|
45
48
|
});
|
|
46
49
|
|
|
47
50
|
it("Should decrypt password after failure", function() {
|
|
48
|
-
const cipher = new Cipher(
|
|
51
|
+
const cipher = new Cipher(Mock.makeKey());
|
|
49
52
|
assert.throws(function() {
|
|
50
53
|
cipher.decryptPassword("@Hello");
|
|
51
54
|
});
|
|
52
55
|
// make sure state is valid after failure
|
|
53
|
-
|
|
56
|
+
const encrypted = cipher.encryptPassword("mid");
|
|
57
|
+
var decrypted = cipher.decryptPassword(encrypted);
|
|
54
58
|
assert.equal(decrypted, "mid");
|
|
55
59
|
});
|
|
56
60
|
|
|
57
61
|
it("Should handle plain text passwords", function() {
|
|
58
|
-
const cipher = new Cipher(
|
|
62
|
+
const cipher = new Cipher(Mock.makeKey());
|
|
59
63
|
var decrypted = cipher.decryptPassword("__PLAINTEXT__pass");
|
|
60
64
|
assert.equal(decrypted, "pass");
|
|
61
65
|
});
|
|
62
66
|
|
|
63
67
|
it("Should fail if no marker", function() {
|
|
64
|
-
const cipher = new Cipher(
|
|
68
|
+
const cipher = new Cipher(Mock.makeKey());
|
|
65
69
|
expect(() => { cipher.decryptPassword("57QS5VHMb9BCsojLVrKI/Q=="); }).toThrow("SDK-000011");
|
|
66
70
|
});
|
|
67
71
|
|
|
68
72
|
it("Should support empty passwords", function() {
|
|
69
|
-
const cipher = new Cipher(
|
|
73
|
+
const cipher = new Cipher(Mock.makeKey());
|
|
70
74
|
assert.equal(cipher.decryptPassword(""), "");
|
|
71
75
|
assert.equal(cipher.decryptPassword(null), "");
|
|
72
76
|
assert.equal(cipher.decryptPassword(undefined), "");
|
|
73
77
|
});
|
|
74
78
|
|
|
75
79
|
it("Encrypt - decrypt", function() {
|
|
76
|
-
const cipher = new Cipher(
|
|
80
|
+
const cipher = new Cipher(Mock.makeKey());
|
|
77
81
|
expect(cipher.decryptPassword(cipher.encryptPassword(""))).toBe("");
|
|
78
82
|
expect(cipher.decryptPassword(cipher.encryptPassword("1"))).toBe("1");
|
|
79
83
|
expect(cipher.decryptPassword(cipher.encryptPassword("Hello"))).toBe("Hello");
|
package/test/domUtil.test.js
CHANGED
|
@@ -523,4 +523,27 @@ describe('DomUtil', function() {
|
|
|
523
523
|
});
|
|
524
524
|
});
|
|
525
525
|
|
|
526
|
+
describe("Text and CDATA nodes", () => {
|
|
527
|
+
it("Should handle cdata node", () => {
|
|
528
|
+
const xml = DomUtil.parse(`<workflow-collection><workflow id="1840" internalName="cleanup" label="Database cleanup"><desc><![CDATA[Ensure that obsolete data are deleted from the database.]]></desc></workflow></workflow-collection>`);
|
|
529
|
+
const json = DomUtil.toJSON(xml);
|
|
530
|
+
expect(json.workflow[0]["$desc"]).toBe("Ensure that obsolete data are deleted from the database.");
|
|
531
|
+
expect(json.workflow[0]["desc"]).toBeUndefined();
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
it("Should handle text node", () => {
|
|
535
|
+
const xml = DomUtil.parse(`<workflow-collection><workflow id="1840" internalName="cleanup" label="Database cleanup"><desc>Ensure that obsolete data are deleted from the database.</desc></workflow></workflow-collection>`);
|
|
536
|
+
const json = DomUtil.toJSON(xml);
|
|
537
|
+
expect(json.workflow[0]["$desc"]).toBe("Ensure that obsolete data are deleted from the database.");
|
|
538
|
+
expect(json.workflow[0]["desc"]).toBeUndefined();
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
it("Should handle empty node", () => {
|
|
542
|
+
const xml = DomUtil.parse(`<workflow-collection><workflow id="1840" internalName="cleanup" label="Database cleanup"><desc/></workflow></workflow-collection>`);
|
|
543
|
+
const json = DomUtil.toJSON(xml);
|
|
544
|
+
expect(json.workflow[0]["$desc"]).toBeUndefined();
|
|
545
|
+
expect(json.workflow[0]["desc"]).toStrictEqual({});
|
|
546
|
+
});
|
|
547
|
+
});
|
|
548
|
+
|
|
526
549
|
});
|
package/test/mock.js
CHANGED
|
@@ -17,18 +17,31 @@ governing permissions and limitations under the License.
|
|
|
17
17
|
*
|
|
18
18
|
*********************************************************************************/
|
|
19
19
|
const sdk = require('../src/index.js');
|
|
20
|
+
const crypto = require("crypto");
|
|
21
|
+
|
|
22
|
+
const makeKey = () => {
|
|
23
|
+
const a = [];
|
|
24
|
+
for (let i=0; i<32; i++) {
|
|
25
|
+
a.push(Math.floor(crypto.randomInt(0, 256)));
|
|
26
|
+
}
|
|
27
|
+
const buffer = Buffer.from(a);
|
|
28
|
+
const s = buffer.toString('base64');
|
|
29
|
+
return s;
|
|
30
|
+
}
|
|
20
31
|
|
|
21
32
|
async function makeAnonymousClient(options) {
|
|
22
33
|
const connectionParameters = sdk.ConnectionParameters.ofAnonymousUser("http://acc-sdk:8080", options);
|
|
23
34
|
const client = await sdk.init(connectionParameters);
|
|
24
|
-
|
|
35
|
+
if (!options || !options.transport) // allow tests to explicitely set the transport
|
|
36
|
+
client._transport = jest.fn();
|
|
25
37
|
return client;
|
|
26
38
|
}
|
|
27
39
|
|
|
28
40
|
async function makeClient(options) {
|
|
29
41
|
const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword("http://acc-sdk:8080", "admin", "admin", options);
|
|
30
42
|
const client = await sdk.init(connectionParameters);
|
|
31
|
-
|
|
43
|
+
if (!options || !options.transport) // allow tests to explicitely set the transport
|
|
44
|
+
client._transport = jest.fn();
|
|
32
45
|
return client;
|
|
33
46
|
}
|
|
34
47
|
|
|
@@ -61,7 +74,7 @@ const LOGON_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
|
|
|
61
74
|
<SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='urn:xtk:session' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
|
|
62
75
|
<SOAP-ENV:Body>
|
|
63
76
|
<LogonResponse xmlns='urn:xtk:session' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
|
|
64
|
-
<pstrSessionToken xsi:type='xsd:string'>
|
|
77
|
+
<pstrSessionToken xsi:type='xsd:string'>___$session_token$</pstrSessionToken>
|
|
65
78
|
<pSessionInfo xsi:type='ns:Element' SOAP-ENV:encodingStyle='http://xml.apache.org/xml-soap/literalxml'>
|
|
66
79
|
<sessionInfo>
|
|
67
80
|
<serverInfo advisedClientBuildNumber="0" allowSQL="false" buildNumber="9219" commitId="f5f3ec3" databaseId="uFE80000000000000F1FA913DD7CC7C480041161C" defaultNameSpace="cus" fohVersion="2" instanceName="ffdamkt" majNumber="6" minClientBuildNumber="8969" minNumber="7" minNumberTechnical="0" releaseName="20.3" securityTimeOut="86400" serverDate="2020-07-05 14:11:31.986Z" servicePack="0" sessionTimeOut="86400" useVault="false"/>
|
|
@@ -73,11 +86,32 @@ const LOGON_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
|
|
|
73
86
|
</userInfo>
|
|
74
87
|
</sessionInfo>
|
|
75
88
|
</pSessionInfo>
|
|
76
|
-
<pstrSecurityToken xsi:type='xsd:string'
|
|
89
|
+
<pstrSecurityToken xsi:type='xsd:string'>@$security_token$==</pstrSecurityToken>
|
|
77
90
|
</LogonResponse>
|
|
78
91
|
</SOAP-ENV:Body>
|
|
79
92
|
</SOAP-ENV:Envelope>`);
|
|
80
93
|
|
|
94
|
+
const BEARER_LOGON_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
|
|
95
|
+
<SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='urn:xtk:session' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
|
|
96
|
+
<SOAP-ENV:Body>
|
|
97
|
+
<BearerTokenLogonResponse xmlns='urn:xtk:session' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
|
|
98
|
+
<pstrSessionToken xsi:type='xsd:string'>___$session_token$</pstrSessionToken>
|
|
99
|
+
<pSessionInfo xsi:type='ns:Element' SOAP-ENV:encodingStyle='http://xml.apache.org/xml-soap/literalxml'>
|
|
100
|
+
<sessionInfo>
|
|
101
|
+
<serverInfo advisedClientBuildNumber="0" allowSQL="false" buildNumber="9219" commitId="f5f3ec3" databaseId="uFE80000000000000F1FA913DD7CC7C480041161C" defaultNameSpace="cus" fohVersion="2" instanceName="ffdamkt" majNumber="6" minClientBuildNumber="8969" minNumber="7" minNumberTechnical="0" releaseName="20.3" securityTimeOut="86400" serverDate="2020-07-05 14:11:31.986Z" servicePack="0" sessionTimeOut="86400" useVault="false"/>
|
|
102
|
+
<userInfo datakitInDatabase="true" homeDir="" instanceLocale="en" locale="en" login="admin" loginCS="Administrator (admin)" loginId="1059" noConsoleCnx="false" orgUnitId="0" theme="" timezone="Europe/Paris">
|
|
103
|
+
<login-group id="1060"/>
|
|
104
|
+
<login-right right="admin"/>
|
|
105
|
+
<installed-package name="campaign" namespace="nms"/>
|
|
106
|
+
<installed-package name="core" namespace="nms"/>
|
|
107
|
+
</userInfo>
|
|
108
|
+
</sessionInfo>
|
|
109
|
+
</pSessionInfo>
|
|
110
|
+
<pstrSecurityToken xsi:type='xsd:string'>@$security_token$==</pstrSecurityToken>
|
|
111
|
+
</BearerTokenLogonResponse>
|
|
112
|
+
</SOAP-ENV:Body>
|
|
113
|
+
</SOAP-ENV:Envelope>`);
|
|
114
|
+
|
|
81
115
|
const LOGON_RESPONSE_NO_USERINFO = Promise.resolve(`<?xml version='1.0'?>
|
|
82
116
|
<SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='urn:xtk:session' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
|
|
83
117
|
<SOAP-ENV:Body>
|
|
@@ -257,37 +291,43 @@ const GET_XTK_QUERY_SCHEMA_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
|
|
|
257
291
|
</SOAP-ENV:Body>
|
|
258
292
|
</SOAP-ENV:Envelope>`);
|
|
259
293
|
|
|
260
|
-
const GET_MID_EXT_ACCOUNT_RESPONSE =
|
|
294
|
+
const GET_MID_EXT_ACCOUNT_RESPONSE = (encryptedPassword) => {
|
|
295
|
+
return Promise.resolve(`<?xml version='1.0'?>
|
|
261
296
|
<SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='urn:xtk:queryDef' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
|
|
262
297
|
<SOAP-ENV:Body>
|
|
263
298
|
<ExecuteQueryResponse xmlns='urn:xtk:queryDef' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
|
|
264
299
|
<pdomOutput xsi:type='ns:Element' SOAP-ENV:encodingStyle='http://xml.apache.org/xml-soap/literalxml'>
|
|
265
|
-
<extAccount account="mid" id="2088" name="defaultEmailMid" password="
|
|
300
|
+
<extAccount account="mid" id="2088" name="defaultEmailMid" password="${encryptedPassword}" server="http://ffdamid:8080" type="3"/>
|
|
266
301
|
</pdomOutput>
|
|
267
302
|
</ExecuteQueryResponse>
|
|
268
303
|
</SOAP-ENV:Body>
|
|
269
304
|
</SOAP-ENV:Envelope>`);
|
|
305
|
+
}
|
|
270
306
|
|
|
271
|
-
const GET_BAD_EXT_ACCOUNT_RESPONSE =
|
|
307
|
+
const GET_BAD_EXT_ACCOUNT_RESPONSE = (encryptedPassword) => {
|
|
308
|
+
return Promise.resolve(`<?xml version='1.0'?>
|
|
272
309
|
<SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='urn:xtk:queryDef' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
|
|
273
310
|
<SOAP-ENV:Body>
|
|
274
311
|
<ExecuteQueryResponse xmlns='urn:xtk:queryDef' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
|
|
275
312
|
<pdomOutput xsi:type='ns:Element' SOAP-ENV:encodingStyle='http://xml.apache.org/xml-soap/literalxml'>
|
|
276
|
-
<extAccount account="bad" id="2088" name="bad" password="
|
|
313
|
+
<extAccount account="bad" id="2088" name="bad" password="${encryptedPassword}" server="http://zz:8080" type="999"/>
|
|
277
314
|
</pdomOutput>
|
|
278
315
|
</ExecuteQueryResponse>
|
|
279
316
|
</SOAP-ENV:Body>
|
|
280
317
|
</SOAP-ENV:Envelope>`);
|
|
318
|
+
}
|
|
281
319
|
|
|
282
|
-
const GET_SECRET_KEY_OPTION_RESPONSE =
|
|
320
|
+
const GET_SECRET_KEY_OPTION_RESPONSE = (key) => {
|
|
321
|
+
return Promise.resolve(`<?xml version='1.0'?>
|
|
283
322
|
<SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='urn:xtk:session' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
|
|
284
323
|
<SOAP-ENV:Body>
|
|
285
324
|
<GetOptionResponse xmlns='urn:xtk:session' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
|
|
286
|
-
<pstrValue xsi:type='xsd:string'
|
|
325
|
+
<pstrValue xsi:type='xsd:string'>${key}</pstrValue>
|
|
287
326
|
<pbtType xsi:type='xsd:byte'>6</pbtType>
|
|
288
327
|
</GetOptionResponse>
|
|
289
328
|
</SOAP-ENV:Body>
|
|
290
329
|
</SOAP-ENV:Envelope>`);
|
|
330
|
+
}
|
|
291
331
|
|
|
292
332
|
const GET_LOGON_MID_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
|
|
293
333
|
<SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='urn:xtk:session' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
|
|
@@ -571,11 +611,13 @@ exports.Mock = {
|
|
|
571
611
|
makeClient: makeClient,
|
|
572
612
|
makeAnonymousClient: makeAnonymousClient,
|
|
573
613
|
withMockConsole: withMockConsole,
|
|
614
|
+
makeKey: makeKey,
|
|
574
615
|
R_TEST: R_TEST,
|
|
575
616
|
PING: PING,
|
|
576
617
|
MC_PING: MC_PING,
|
|
577
618
|
MC_PING_ERROR: MC_PING_ERROR,
|
|
578
619
|
LOGON_RESPONSE: LOGON_RESPONSE,
|
|
620
|
+
BEARER_LOGON_RESPONSE: BEARER_LOGON_RESPONSE,
|
|
579
621
|
LOGON_RESPONSE_NO_SESSIONTOKEN: LOGON_RESPONSE_NO_SESSIONTOKEN,
|
|
580
622
|
LOGON_RESPONSE_NO_SECURITYTOKEN: LOGON_RESPONSE_NO_SECURITYTOKEN,
|
|
581
623
|
LOGOFF_RESPONSE: LOGOFF_RESPONSE,
|
package/test/soap.test.js
CHANGED
|
@@ -154,11 +154,8 @@ describe('SOAP', function() {
|
|
|
154
154
|
const env = DomUtil.parse(request.data).documentElement;
|
|
155
155
|
const header = hasChildElement(env, "SOAP-ENV:Header");
|
|
156
156
|
expect(DomUtil.findElement(header, "Cookie")).toBeFalsy();
|
|
157
|
-
hasChildElement(header, "X-Security-Token");
|
|
158
157
|
const body = hasChildElement(env, "SOAP-ENV:Body");
|
|
159
158
|
const method = hasChildElement(body, "m:Empty", undefined, "xmlns:m", "urn:xtk:session", "SOAP-ENV:encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/");
|
|
160
|
-
// sessiontoken is always required as first parameter, even if not set
|
|
161
|
-
expect(DomUtil.findElement(method, "sessiontoken")).toBeTruthy();
|
|
162
159
|
});
|
|
163
160
|
|
|
164
161
|
it('Should have set authentication tokens', function() {
|
|
@@ -168,11 +165,8 @@ describe('SOAP', function() {
|
|
|
168
165
|
assert.equal(request.headers["Cookie"], "__sessiontoken=$session$", "Session token matches");
|
|
169
166
|
const env = DomUtil.parse(request.data).documentElement;
|
|
170
167
|
const header = hasChildElement(env, "SOAP-ENV:Header");
|
|
171
|
-
hasChildElement(header, "Cookie", "__sessiontoken=$session$");
|
|
172
|
-
hasChildElement(header, "X-Security-Token", "$security$");
|
|
173
168
|
const body = hasChildElement(env, "SOAP-ENV:Body");
|
|
174
169
|
const method = hasChildElement(body, "m:Empty");
|
|
175
|
-
hasChildElement(method, "sessiontoken", "$session$", "xsi:type", "xsd:string");
|
|
176
170
|
});
|
|
177
171
|
|
|
178
172
|
it('Should set boolean parameters', function() {
|
|
@@ -792,5 +786,18 @@ describe("Campaign exception", () => {
|
|
|
792
786
|
})
|
|
793
787
|
})
|
|
794
788
|
|
|
789
|
+
it("CampaignException should hide sensitive information", () => {
|
|
790
|
+
const call = makeSoapMethodCall(undefined, "xtk:session", "Date", "$session$", "$security$", "My User Agent");
|
|
791
|
+
call.finalize("http://ffdamkt:8080/nl/jsp/soaprouter.jsp")
|
|
792
|
+
const ex = makeCampaignException(call, new Error("Failed"));
|
|
793
|
+
const req = ex.methodCall.request;
|
|
794
|
+
expect(req.data.indexOf("$session$")).toBe(-1);
|
|
795
|
+
expect(req.data.indexOf("$security$")).toBe(-1);
|
|
796
|
+
expect(req.headers.Cookie.indexOf("$session$")).toBe(-1);
|
|
797
|
+
expect(req.headers.Cookie.indexOf("$security$")).toBe(-1);
|
|
798
|
+
expect(req.headers["X-Security-Token"].indexOf("$session$")).toBe(-1);
|
|
799
|
+
expect(req.headers["X-Security-Token"].indexOf("$security$")).toBe(-1);
|
|
800
|
+
})
|
|
801
|
+
|
|
795
802
|
});
|
|
796
803
|
|
package/test/util.test.js
CHANGED
|
@@ -17,7 +17,8 @@ governing permissions and limitations under the License.
|
|
|
17
17
|
*
|
|
18
18
|
*********************************************************************************/
|
|
19
19
|
|
|
20
|
-
const { Util } = require('../src/util.js');
|
|
20
|
+
const { Util } = require('../src/util.js');
|
|
21
|
+
const { SafeStorage, Cache } = require('../src/cache.js');
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
describe('Util', function() {
|
|
@@ -80,6 +81,155 @@ describe('Util', function() {
|
|
|
80
81
|
expect(Util.trim({hello:'Lead<sessiontoken xsi:type="xsd:string">Stuff</sessiontoken>Trail'})).toStrictEqual({hello:'Lead<sessiontoken xsi:type="xsd:string">***</sessiontoken>Trail'});
|
|
81
82
|
})
|
|
82
83
|
|
|
84
|
+
it("Should remove password", () => {
|
|
85
|
+
expect(Util.trim({hello:`<sessiontoken xsi:type="xsd:string"/><login xsi:type="xsd:string">admin</login><password xsi:type="xsd:string">password</password><parameters xsi:type="ns:Element" SOAP-ENV:encodingStyle="http://xml.apache.org/xml-soap/literalxml"/>`})).toStrictEqual({hello:`<sessiontoken xsi:type="xsd:string"/><login xsi:type="xsd:string">admin</login><password xsi:type="xsd:string">***</password><parameters xsi:type="ns:Element" SOAP-ENV:encodingStyle="http://xml.apache.org/xml-soap/literalxml"/>`});
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
it("Should hide X-Security-Token properties", () => {
|
|
89
|
+
expect(Util.trim({"x-security-token": "Hello"})).toMatchObject({"x-security-token": "***"});
|
|
90
|
+
expect(Util.trim({"X-Security-Token": "Hello"})).toMatchObject({"X-Security-Token": "***"});
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
it("Should remove session tokens from cookies", () => {
|
|
94
|
+
expect(Util.trim({"Cookie": "__sessiontoken=ABC"})).toMatchObject({"Cookie": "__sessiontoken=***"});
|
|
95
|
+
expect(Util.trim({"Cookie": "__sessionToken=ABC"})).toMatchObject({"Cookie": "__sessionToken=***"});
|
|
96
|
+
expect(Util.trim({"Cookie": "__sessiontoken=ABC;"})).toMatchObject({"Cookie": "__sessiontoken=***;"});
|
|
97
|
+
expect(Util.trim({"Cookie": "__sessiontoken =ABC"})).toMatchObject({"Cookie": "__sessiontoken =***"});
|
|
98
|
+
expect(Util.trim({"Cookie": "__sessiontoken ABC"})).toMatchObject({"Cookie": "__sessiontoken ABC"}); // no = sign => no token value
|
|
99
|
+
expect(Util.trim({"Cookie": "a=b; __sessiontoken =ABC"})).toMatchObject({"Cookie": "a=b; __sessiontoken =***"});
|
|
100
|
+
expect(Util.trim({"Cookie": "a=b; __sessiontoken =ABC; c=d"})).toMatchObject({"Cookie": "a=b; __sessiontoken =***; c=d"});
|
|
101
|
+
expect(Util.trim({"Cookie": "a=b; __token =ABC; c=d"})).toMatchObject({"Cookie": "a=b; __token =ABC; c=d"});
|
|
102
|
+
})
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
describe("Safe storage", () => {
|
|
107
|
+
it("Should support undefined delegate", () => {
|
|
108
|
+
const storage = new SafeStorage();
|
|
109
|
+
expect(storage.getItem("Hello")).toBeUndefined();
|
|
110
|
+
storage.setItem("Hello", { text: "World" });
|
|
111
|
+
expect(storage.getItem("Hello")).toBeUndefined();
|
|
112
|
+
storage.setItem("Hello", "World"); // value should be JSON but errors are ignored
|
|
113
|
+
expect(storage.getItem("Hello")).toBeUndefined();
|
|
114
|
+
storage.removeItem("Hello");
|
|
115
|
+
expect(storage.getItem("Hello")).toBeUndefined();
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
it("Should handle map", () => {
|
|
119
|
+
const map = {};
|
|
120
|
+
const delegate = {
|
|
121
|
+
getItem: (key) => map[key],
|
|
122
|
+
setItem: (key, value) => { map[key] = value },
|
|
123
|
+
removeItem: (key) => { delete map[key] }
|
|
124
|
+
};
|
|
125
|
+
const storage = new SafeStorage(delegate);
|
|
126
|
+
expect(storage.getItem("Hello")).toBeUndefined();
|
|
127
|
+
storage.setItem("Hello", { text: "World" });
|
|
128
|
+
expect(map["Hello"]).toStrictEqual(JSON.stringify({text: "World"}));
|
|
129
|
+
expect(storage.getItem("Hello")).toStrictEqual({"text": "World"});
|
|
130
|
+
storage.setItem("Hello", "World"); // value should be JSON but errors are ignored
|
|
131
|
+
expect(storage.getItem("Hello")).toBeUndefined();
|
|
132
|
+
storage.setItem("Hello", { text: "World" });
|
|
133
|
+
storage.removeItem("Hello");
|
|
134
|
+
expect(storage.getItem("Hello")).toBeUndefined();
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
it("Should handle root key", () => {
|
|
138
|
+
const map = {};
|
|
139
|
+
const delegate = {
|
|
140
|
+
getItem: (key) => map[key],
|
|
141
|
+
setItem: (key, value) => { map[key] = value },
|
|
142
|
+
removeItem: (key) => { delete map[key] }
|
|
143
|
+
};
|
|
144
|
+
const storage = new SafeStorage(delegate, "root");
|
|
145
|
+
expect(storage.getItem("Hello")).toBeUndefined();
|
|
146
|
+
storage.setItem("Hello", { text: "World" });
|
|
147
|
+
expect(map["root$Hello"]).toStrictEqual(JSON.stringify({text: "World"}));
|
|
148
|
+
expect(storage.getItem("Hello")).toStrictEqual({"text": "World"});
|
|
149
|
+
storage.setItem("Hello", "World"); // value should be JSON but errors are ignored
|
|
150
|
+
expect(map["root$Hello"]).toBeUndefined();
|
|
151
|
+
expect(storage.getItem("Hello")).toBeUndefined();
|
|
152
|
+
storage.setItem("Hello", { text: "World" });
|
|
153
|
+
storage.removeItem("Hello");
|
|
154
|
+
expect(map["root$Hello"]).toBeUndefined();
|
|
155
|
+
expect(storage.getItem("Hello")).toBeUndefined();
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
it("Edge cases", () => {
|
|
159
|
+
expect(new SafeStorage()._storage).toBeUndefined();
|
|
160
|
+
expect(new SafeStorage()._rootKey).toBe("");
|
|
161
|
+
expect(new SafeStorage(null)._storage).toBeUndefined();
|
|
162
|
+
expect(new SafeStorage(null)._rootKey).toBe("");
|
|
163
|
+
expect(new SafeStorage(null, "")._storage).toBeUndefined();
|
|
164
|
+
expect(new SafeStorage(null, "")._rootKey).toBe("");
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
it("Should remove invalid items on get", () => {
|
|
168
|
+
const map = {};
|
|
169
|
+
const delegate = {
|
|
170
|
+
getItem: (key) => map[key],
|
|
171
|
+
setItem: (key, value) => { map[key] = value },
|
|
172
|
+
removeItem: (key) => { delete map[key] }
|
|
173
|
+
};
|
|
174
|
+
const storage = new SafeStorage(delegate, "root");
|
|
175
|
+
// value is not valid because not a JSON serialized string
|
|
176
|
+
map["root$Hello"] = "Invalid";
|
|
177
|
+
expect(storage.getItem("Hello")).toBeUndefined();
|
|
178
|
+
// Get should have removed invalid value
|
|
179
|
+
expect(map["root$Hello"]).toBeUndefined()
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
it("Should handle cache last cleared", () => {
|
|
183
|
+
const map = {};
|
|
184
|
+
const delegate = {
|
|
185
|
+
getItem: (key) => map[key],
|
|
186
|
+
setItem: (key, value) => { map[key] = value },
|
|
187
|
+
removeItem: (key) => { delete map[key] }
|
|
188
|
+
};
|
|
189
|
+
const cache = new Cache(delegate, "root");
|
|
190
|
+
cache.put("Hello", "World");
|
|
191
|
+
expect(JSON.parse(map["root$Hello"])).toMatchObject({ value:"World" });
|
|
192
|
+
expect(cache.get("Hello")).toBe("World");
|
|
193
|
+
cache.clear();
|
|
194
|
+
// Clear could not remove the item from the map
|
|
195
|
+
expect(JSON.parse(map["root$Hello"])).toMatchObject({ value:"World" });
|
|
196
|
+
// But get from cache will
|
|
197
|
+
expect(cache.get("Hello")).toBeUndefined();
|
|
198
|
+
})
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
it("Should preserve last cleared", () => {
|
|
202
|
+
const map = {};
|
|
203
|
+
const delegate = {
|
|
204
|
+
getItem: (key) => map[key],
|
|
205
|
+
setItem: (key, value) => { map[key] = value },
|
|
206
|
+
removeItem: (key) => { delete map[key] }
|
|
207
|
+
};
|
|
208
|
+
const cache = new Cache(delegate, "root");
|
|
209
|
+
expect(cache._lastCleared).toBeUndefined();
|
|
210
|
+
cache.put("Hello", "World");
|
|
211
|
+
cache.clear();
|
|
212
|
+
const lastCleared = cache._lastCleared;
|
|
213
|
+
expect(lastCleared).not.toBeUndefined();
|
|
214
|
+
expect(cache.get("Hello")).toBeUndefined();
|
|
215
|
+
expect(map["root$lastCleared"]).toBe(JSON.stringify({timestamp:lastCleared}));
|
|
216
|
+
// New cache with same delegate storage should preserve lastCleared date
|
|
217
|
+
const cache2 = new Cache(delegate, "root");
|
|
218
|
+
expect(cache2._lastCleared).toBe(lastCleared);
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
it("Should cache in memory value which is in local storage", () => {
|
|
222
|
+
const map = {};
|
|
223
|
+
const delegate = {
|
|
224
|
+
getItem: (key) => map[key],
|
|
225
|
+
setItem: (key, value) => { map[key] = value },
|
|
226
|
+
removeItem: (key) => { delete map[key] }
|
|
227
|
+
};
|
|
228
|
+
const cache = new Cache(delegate, "root");
|
|
229
|
+
map["root$Hello"] = JSON.stringify({ value: "World", cachedAt:Date.now() + 99999999 });
|
|
230
|
+
const value = cache.get("Hello");
|
|
231
|
+
expect(value).toBe("World");
|
|
232
|
+
expect(cache._cache["Hello"].value).toBe("World");
|
|
83
233
|
})
|
|
84
234
|
|
|
85
235
|
});
|
package/test/xtkCaster.test.js
CHANGED
|
@@ -696,14 +696,22 @@ describe('XtkCaster', function() {
|
|
|
696
696
|
expect(XtkCaster._variantStorageAttribute(6)).toBe("stringValue");
|
|
697
697
|
expect(XtkCaster._variantStorageAttribute("string")).toBe("stringValue");
|
|
698
698
|
expect(XtkCaster._variantStorageAttribute("int64")).toBe("stringValue");
|
|
699
|
+
expect(XtkCaster._variantStorageAttribute("uuid")).toBe("stringValue");
|
|
699
700
|
expect(XtkCaster._variantStorageAttribute(12)).toBe("memoValue");
|
|
700
701
|
expect(XtkCaster._variantStorageAttribute(13)).toBe("memoValue");
|
|
701
702
|
expect(XtkCaster._variantStorageAttribute("memo")).toBe("memoValue");
|
|
702
703
|
expect(XtkCaster._variantStorageAttribute("CDATA")).toBe("memoValue");
|
|
704
|
+
expect(XtkCaster._variantStorageAttribute("blob")).toBe("memoValue");
|
|
705
|
+
expect(XtkCaster._variantStorageAttribute("html")).toBe("memoValue");
|
|
703
706
|
expect(XtkCaster._variantStorageAttribute(1)).toBe("longValue");
|
|
704
707
|
expect(XtkCaster._variantStorageAttribute(2)).toBe("longValue");
|
|
705
708
|
expect(XtkCaster._variantStorageAttribute(3)).toBe("longValue");
|
|
706
709
|
expect(XtkCaster._variantStorageAttribute(15)).toBe("longValue");
|
|
710
|
+
expect(XtkCaster._variantStorageAttribute("byte")).toBe("longValue");
|
|
711
|
+
expect(XtkCaster._variantStorageAttribute("short")).toBe("longValue");
|
|
712
|
+
expect(XtkCaster._variantStorageAttribute("long")).toBe("longValue");
|
|
713
|
+
expect(XtkCaster._variantStorageAttribute("int")).toBe("longValue");
|
|
714
|
+
expect(XtkCaster._variantStorageAttribute("boolean")).toBe("longValue");
|
|
707
715
|
expect(XtkCaster._variantStorageAttribute(4)).toBe("doubleValue");
|
|
708
716
|
expect(XtkCaster._variantStorageAttribute(5)).toBe("doubleValue");
|
|
709
717
|
expect(XtkCaster._variantStorageAttribute("float")).toBe("doubleValue");
|
|
@@ -716,4 +724,93 @@ describe('XtkCaster', function() {
|
|
|
716
724
|
expect(XtkCaster._variantStorageAttribute("date")).toBe("timeStampValue");
|
|
717
725
|
expect(() => { XtkCaster._variantStorageAttribute(777); }).toThrow("Cannot get variant storage");
|
|
718
726
|
});
|
|
727
|
+
|
|
728
|
+
describe("Array tests", () => {
|
|
729
|
+
it("Should return array", () => {
|
|
730
|
+
expect(XtkCaster.asArray(null)).toStrictEqual([]);
|
|
731
|
+
expect(XtkCaster.asArray(undefined)).toStrictEqual([]);
|
|
732
|
+
expect(XtkCaster.asArray(false)).toStrictEqual([false]);
|
|
733
|
+
expect(XtkCaster.asArray("Hello")).toStrictEqual(["Hello"]);
|
|
734
|
+
expect(XtkCaster.asArray([])).toStrictEqual([]);
|
|
735
|
+
expect(XtkCaster.asArray([null])).toStrictEqual([null]);
|
|
736
|
+
})
|
|
737
|
+
|
|
738
|
+
it("Should support arrays", () => {
|
|
739
|
+
expect(XtkCaster.as(null, "array")).toStrictEqual([]);
|
|
740
|
+
expect(XtkCaster.as(undefined, "array")).toStrictEqual([]);
|
|
741
|
+
expect(XtkCaster.as(false, "array")).toStrictEqual([false]);
|
|
742
|
+
expect(XtkCaster.as("Hello", "array")).toStrictEqual(["Hello"]);
|
|
743
|
+
expect(XtkCaster.as([], "array")).toStrictEqual([]);
|
|
744
|
+
expect(XtkCaster.as([null], "array")).toStrictEqual([null]);
|
|
745
|
+
});
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
describe("Timespan test", () => {
|
|
749
|
+
it("Should return timespan", () => {
|
|
750
|
+
expect(XtkCaster.asTimespan(null)).toStrictEqual(0);
|
|
751
|
+
expect(XtkCaster.asTimespan(undefined)).toStrictEqual(0);
|
|
752
|
+
expect(XtkCaster.asTimespan(false)).toStrictEqual(0);
|
|
753
|
+
expect(XtkCaster.asTimespan("Hello")).toStrictEqual(0);
|
|
754
|
+
expect(XtkCaster.asTimespan([])).toStrictEqual(0);
|
|
755
|
+
expect(XtkCaster.asTimespan([null])).toStrictEqual(0);
|
|
756
|
+
expect(XtkCaster.asTimespan(NaN)).toStrictEqual(0);
|
|
757
|
+
expect(XtkCaster.asTimespan(Number.POSITIVE_INFINITY)).toStrictEqual(0);
|
|
758
|
+
expect(XtkCaster.asTimespan(Number.NEGATIVE_INFINITY)).toStrictEqual(0);
|
|
759
|
+
expect(XtkCaster.asTimespan("86400")).toStrictEqual(86400);
|
|
760
|
+
expect(XtkCaster.asTimespan(86400)).toStrictEqual(86400);
|
|
761
|
+
})
|
|
762
|
+
|
|
763
|
+
it("As should support 'timspan'", () => {
|
|
764
|
+
expect(XtkCaster.as(null, "timespan")).toStrictEqual(0);
|
|
765
|
+
expect(XtkCaster.as(undefined, "timespan")).toStrictEqual(0);
|
|
766
|
+
expect(XtkCaster.as(false, "timespan")).toStrictEqual(0);
|
|
767
|
+
expect(XtkCaster.as("Hello", "timespan")).toStrictEqual(0);
|
|
768
|
+
expect(XtkCaster.as([], "timespan")).toStrictEqual(0);
|
|
769
|
+
expect(XtkCaster.as([null], "timespan")).toStrictEqual(0);
|
|
770
|
+
expect(XtkCaster.as("86400", "timespan")).toStrictEqual(86400);
|
|
771
|
+
expect(XtkCaster.as(86400, "timespan")).toStrictEqual(86400);
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
it("As should support type 14", () => {
|
|
775
|
+
expect(XtkCaster.as(null, 14)).toStrictEqual(0);
|
|
776
|
+
expect(XtkCaster.as(undefined, 14)).toStrictEqual(0);
|
|
777
|
+
expect(XtkCaster.as(false, 14)).toStrictEqual(0);
|
|
778
|
+
expect(XtkCaster.as("Hello", 14)).toStrictEqual(0);
|
|
779
|
+
expect(XtkCaster.as([], 14)).toStrictEqual(0);
|
|
780
|
+
expect(XtkCaster.as([null], 14)).toStrictEqual(0);
|
|
781
|
+
expect(XtkCaster.as("86400", 14)).toStrictEqual(86400);
|
|
782
|
+
expect(XtkCaster.as(86400, 14)).toStrictEqual(86400);
|
|
783
|
+
});
|
|
784
|
+
})
|
|
785
|
+
|
|
786
|
+
describe("Other string types", () => {
|
|
787
|
+
it("Type 'html'", () => {
|
|
788
|
+
expect(XtkCaster.as(null, "html")).toStrictEqual("");
|
|
789
|
+
expect(XtkCaster.as(undefined, "html")).toStrictEqual("");
|
|
790
|
+
expect(XtkCaster.as("Hello", "html")).toStrictEqual("Hello");
|
|
791
|
+
expect(XtkCaster.as("0", "html")).toStrictEqual("0");
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
it("Type 'uuid'", () => {
|
|
795
|
+
expect(XtkCaster.as(null, "uuid")).toStrictEqual("");
|
|
796
|
+
expect(XtkCaster.as(undefined, "uuid")).toStrictEqual("");
|
|
797
|
+
expect(XtkCaster.as("Hello", "uuid")).toStrictEqual("Hello");
|
|
798
|
+
expect(XtkCaster.as("0", "uuid")).toStrictEqual("0");
|
|
799
|
+
});
|
|
800
|
+
|
|
801
|
+
it("Type 'blob'", () => {
|
|
802
|
+
expect(XtkCaster.as(null, "blob")).toStrictEqual("");
|
|
803
|
+
expect(XtkCaster.as(undefined, "blob")).toStrictEqual("");
|
|
804
|
+
expect(XtkCaster.as("Hello", "blob")).toStrictEqual("Hello");
|
|
805
|
+
expect(XtkCaster.as("0", "blob")).toStrictEqual("0");
|
|
806
|
+
});
|
|
807
|
+
|
|
808
|
+
it("Type 'int'", () => {
|
|
809
|
+
expect(XtkCaster.as(null, "int")).toStrictEqual(0);
|
|
810
|
+
expect(XtkCaster.as(undefined, "int")).toStrictEqual(0);
|
|
811
|
+
expect(XtkCaster.as("42", "int")).toStrictEqual(42);
|
|
812
|
+
expect(XtkCaster.as("0", "int")).toStrictEqual(0);
|
|
813
|
+
});
|
|
814
|
+
})
|
|
815
|
+
|
|
719
816
|
});
|