Skip to content

Commit ecc8596

Browse files
committed
Update: provide a generic parse() method to see header(s) and generically unwrap
1 parent 17880c4 commit ecc8596

File tree

8 files changed

+834
-1
lines changed

8 files changed

+834
-1
lines changed

lib/index.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ module.exports = {
1414
JWE: require("./jwe"),
1515
JWK: require("./jwk"),
1616
JWS: require("./jws"),
17-
util: require("./util")
17+
util: require("./util"),
18+
parse: require("./parse")
1819
};

lib/parse/compact.js

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*!
2+
* parse/compact.js - JOSE Compact Serialization Parser
3+
*
4+
* Copyright (c) 2015 Cisco Systems, Inc. See LICENSE file.
5+
*/
6+
"use strict";
7+
8+
var jose = {
9+
JWE: require("../jwe"),
10+
JWS: require("../jws"),
11+
util: require("../util")
12+
};
13+
14+
function parseCompact(input) {
15+
var parts = input.split(".");
16+
17+
var type,
18+
op;
19+
if (3 === parts.length) {
20+
// JWS
21+
type = "JWS";
22+
op = function(ks) {
23+
return jose.JWS.createVerify(ks).
24+
verify(input);
25+
};
26+
} else if (5 === parts.length) {
27+
// JWE
28+
type = "JWE";
29+
op = function(ks) {
30+
return jose.JWE.createDecrypt(ks).
31+
decrypt(input);
32+
};
33+
} else {
34+
throw new TypeError("invalid jose serialization");
35+
}
36+
37+
// parse header
38+
var header;
39+
header = jose.util.base64url.decode(parts[0], "utf8");
40+
header = JSON.parse(header);
41+
return {
42+
type: type,
43+
format: "compact",
44+
input: input,
45+
header: header,
46+
perform: op
47+
};
48+
}
49+
50+
module.exports = parseCompact;

lib/parse/index.js

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*!
2+
* parse/index.js - JOSE Parser Entry Point
3+
*
4+
* Copyright (c) 2015 Cisco Systems, Inc. See LICENSE file.
5+
*/
6+
"use strict";
7+
8+
var compact = require("./compact"),
9+
json = require("./json");
10+
11+
var parse = module.exports = function(input) {
12+
if ("string" === typeof input) {
13+
return compact(input);
14+
} else if (input) {
15+
return json(input);
16+
} else {
17+
throw new TypeError("invalid input");
18+
}
19+
};
20+
21+
parse.compact = compact;
22+
parse.json = json;

lib/parse/json.js

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*!
2+
* parse/compact.js - JOSE Compact Serialization Parser
3+
*
4+
* Copyright (c) 2015 Cisco Systems, Inc. See LICENSE file.
5+
*/
6+
"use strict";
7+
8+
var merge = require("../util/merge");
9+
10+
var jose = {
11+
JWE: require("../jwe"),
12+
JWS: require("../jws"),
13+
util: require("../util")
14+
};
15+
16+
function parseJSON(input) {
17+
var type,
18+
op,
19+
headers;
20+
21+
if ("signatures" in input || "signature" in input) {
22+
// JWS
23+
type = "JWS";
24+
op = function(ks) {
25+
return jose.JWS.createVerify(ks).
26+
verify(input);
27+
};
28+
// headers can be (signatures[].protected, signatures[].header, signature.protected, signature.header)
29+
headers = input.signatures ||
30+
[ {
31+
protected: input.protected,
32+
header: input.header,
33+
signature: input.signature
34+
}];
35+
headers = headers.map(function(sig) {
36+
var all = {};
37+
if (sig.header) {
38+
all = merge(all, sig.header);
39+
}
40+
41+
var prot;
42+
if (sig.protected) {
43+
prot = sig.protected;
44+
prot = jose.util.base64url.decode(prot, "utf8");
45+
prot = JSON.parse(prot);
46+
all = merge(all, prot);
47+
}
48+
49+
return all;
50+
});
51+
} else if ("ciphertext" in input) {
52+
// JWE
53+
type = "JWE";
54+
op = function(ks) {
55+
return jose.JWE.createDecrypt(ks).
56+
decrypt(input);
57+
};
58+
// headers can be (protected, unprotected, recipients[].header)
59+
var root = {};
60+
if (input.protected) {
61+
root.protected = input.protected;
62+
root.protected = jose.util.base64url.decode(root.protected, "utf8");
63+
root.protected = JSON.parse(root.protected);
64+
}
65+
if (input.unprotected) {
66+
root.unprotected = input.unprotected;
67+
}
68+
69+
headers = input.recipients || [{}];
70+
headers = headers.map(function(rcpt) {
71+
var all = {};
72+
if (rcpt.header) {
73+
all = merge(all, rcpt.header);
74+
}
75+
if (root.unprotected) {
76+
all = merge(all, root.unprotected);
77+
}
78+
if (root.protected) {
79+
all = merge(all, root.protected);
80+
}
81+
82+
return all;
83+
});
84+
}
85+
86+
return {
87+
type: type,
88+
format: "json",
89+
input: input,
90+
all: headers,
91+
perform: op
92+
};
93+
}
94+
95+
module.exports = parseJSON;

test/index-test.js

+8
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,12 @@ describe("Public API", function() {
6767
assert.ok(util.utf8.decode);
6868
assert.ok(util.utf8.encode);
6969
});
70+
71+
it("exports parse", function() {
72+
var parse = jose.parse;
73+
74+
assert.strictEqual(typeof parse, "function");
75+
assert.strictEqual(typeof parse.compact, "function");
76+
assert.strictEqual(typeof parse.json, "function");
77+
});
7078
});

test/parse/compact-test.js

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
*
3+
* Copyright (c) 2015 Cisco Systems, Inc. See LICENSE file.
4+
*/
5+
"use strict";
6+
7+
var chai = require("chai");
8+
var assert = chai.assert;
9+
10+
var cloneDeep = require("lodash.cloneDeep");
11+
var parseCompact = require("../../lib/parse/compact");
12+
var jose = {
13+
JWK: require("../../lib/jwk")
14+
};
15+
16+
var fixtures = {
17+
"jws": cloneDeep(require("jose-cookbook/jws/4_1.rsa_v15_signature.json")),
18+
"jwe": cloneDeep(require("jose-cookbook/jwe/5_1.key_encryption_using_rsa_v15_and_aes-hmac-sha2.json"))
19+
};
20+
21+
describe("parse/compact", function() {
22+
it("parses compact JWS", function() {
23+
var fix = fixtures.jws;
24+
var input = fixtures.jws.output.compact;
25+
var output = parseCompact(input);
26+
assert.strictEqual(output.format, "compact");
27+
assert.strictEqual(output.type, "JWS");
28+
assert.deepEqual(output.header, fix.signing.protected);
29+
assert.strictEqual(output.input, input);
30+
31+
assert.strictEqual(typeof output.perform, "function");
32+
var promise = jose.JWK.asKey(fix.input.key);
33+
promise = promise.then(function(key) {
34+
return output.perform(key);
35+
});
36+
promise = promise.then(function(result) {
37+
assert.strictEqual(result.payload.toString("utf8"),
38+
fix.input.payload);
39+
});
40+
return promise;
41+
});
42+
it("parses compact JWE", function() {
43+
var fix = fixtures.jwe;
44+
var input = fix.output.compact;
45+
var output = parseCompact(input);
46+
assert.strictEqual(output.format, "compact");
47+
assert.strictEqual(output.type, "JWE");
48+
assert.deepEqual(output.header, fix.encrypting_content.protected);
49+
assert.strictEqual(output.input, input);
50+
51+
assert.strictEqual(typeof output.perform, "function");
52+
var promise = jose.JWK.asKey(fix.input.key);
53+
promise = promise.then(function(key) {
54+
return output.perform(key);
55+
});
56+
promise = promise.then(function(result) {
57+
assert.strictEqual(result.plaintext.toString("utf8"),
58+
fix.input.plaintext);
59+
});
60+
return promise;
61+
});
62+
});

0 commit comments

Comments
 (0)