Skip to content

Commit

Permalink
Update: provide a generic parse() method to see header(s) and generic…
Browse files Browse the repository at this point in the history
…ally unwrap
  • Loading branch information
linuxwolf committed Sep 22, 2015
1 parent 17880c4 commit ecc8596
Show file tree
Hide file tree
Showing 8 changed files with 834 additions and 1 deletion.
3 changes: 2 additions & 1 deletion lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ module.exports = {
JWE: require("./jwe"),
JWK: require("./jwk"),
JWS: require("./jws"),
util: require("./util")
util: require("./util"),
parse: require("./parse")
};
50 changes: 50 additions & 0 deletions lib/parse/compact.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*!
* parse/compact.js - JOSE Compact Serialization Parser
*
* Copyright (c) 2015 Cisco Systems, Inc. See LICENSE file.
*/
"use strict";

var jose = {
JWE: require("../jwe"),
JWS: require("../jws"),
util: require("../util")
};

function parseCompact(input) {
var parts = input.split(".");

var type,
op;
if (3 === parts.length) {
// JWS
type = "JWS";
op = function(ks) {
return jose.JWS.createVerify(ks).
verify(input);
};
} else if (5 === parts.length) {
// JWE
type = "JWE";
op = function(ks) {
return jose.JWE.createDecrypt(ks).
decrypt(input);
};
} else {
throw new TypeError("invalid jose serialization");
}

// parse header
var header;
header = jose.util.base64url.decode(parts[0], "utf8");
header = JSON.parse(header);
return {
type: type,
format: "compact",
input: input,
header: header,
perform: op
};
}

module.exports = parseCompact;
22 changes: 22 additions & 0 deletions lib/parse/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*!
* parse/index.js - JOSE Parser Entry Point
*
* Copyright (c) 2015 Cisco Systems, Inc. See LICENSE file.
*/
"use strict";

var compact = require("./compact"),
json = require("./json");

var parse = module.exports = function(input) {
if ("string" === typeof input) {
return compact(input);
} else if (input) {
return json(input);
} else {
throw new TypeError("invalid input");
}
};

parse.compact = compact;
parse.json = json;
95 changes: 95 additions & 0 deletions lib/parse/json.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*!
* parse/compact.js - JOSE Compact Serialization Parser
*
* Copyright (c) 2015 Cisco Systems, Inc. See LICENSE file.
*/
"use strict";

var merge = require("../util/merge");

var jose = {
JWE: require("../jwe"),
JWS: require("../jws"),
util: require("../util")
};

function parseJSON(input) {
var type,
op,
headers;

if ("signatures" in input || "signature" in input) {
// JWS
type = "JWS";
op = function(ks) {
return jose.JWS.createVerify(ks).
verify(input);
};
// headers can be (signatures[].protected, signatures[].header, signature.protected, signature.header)
headers = input.signatures ||
[ {
protected: input.protected,
header: input.header,
signature: input.signature
}];
headers = headers.map(function(sig) {
var all = {};
if (sig.header) {
all = merge(all, sig.header);
}

var prot;
if (sig.protected) {
prot = sig.protected;
prot = jose.util.base64url.decode(prot, "utf8");
prot = JSON.parse(prot);
all = merge(all, prot);
}

return all;
});
} else if ("ciphertext" in input) {
// JWE
type = "JWE";
op = function(ks) {
return jose.JWE.createDecrypt(ks).
decrypt(input);
};
// headers can be (protected, unprotected, recipients[].header)
var root = {};
if (input.protected) {
root.protected = input.protected;
root.protected = jose.util.base64url.decode(root.protected, "utf8");
root.protected = JSON.parse(root.protected);
}
if (input.unprotected) {
root.unprotected = input.unprotected;
}

headers = input.recipients || [{}];
headers = headers.map(function(rcpt) {
var all = {};
if (rcpt.header) {
all = merge(all, rcpt.header);
}
if (root.unprotected) {
all = merge(all, root.unprotected);
}
if (root.protected) {
all = merge(all, root.protected);
}

return all;
});
}

return {
type: type,
format: "json",
input: input,
all: headers,
perform: op
};
}

module.exports = parseJSON;
8 changes: 8 additions & 0 deletions test/index-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,12 @@ describe("Public API", function() {
assert.ok(util.utf8.decode);
assert.ok(util.utf8.encode);
});

it("exports parse", function() {
var parse = jose.parse;

assert.strictEqual(typeof parse, "function");
assert.strictEqual(typeof parse.compact, "function");
assert.strictEqual(typeof parse.json, "function");
});
});
62 changes: 62 additions & 0 deletions test/parse/compact-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
*
* Copyright (c) 2015 Cisco Systems, Inc. See LICENSE file.
*/
"use strict";

var chai = require("chai");
var assert = chai.assert;

var cloneDeep = require("lodash.cloneDeep");
var parseCompact = require("../../lib/parse/compact");
var jose = {
JWK: require("../../lib/jwk")
};

var fixtures = {
"jws": cloneDeep(require("jose-cookbook/jws/4_1.rsa_v15_signature.json")),
"jwe": cloneDeep(require("jose-cookbook/jwe/5_1.key_encryption_using_rsa_v15_and_aes-hmac-sha2.json"))
};

describe("parse/compact", function() {
it("parses compact JWS", function() {
var fix = fixtures.jws;
var input = fixtures.jws.output.compact;
var output = parseCompact(input);
assert.strictEqual(output.format, "compact");
assert.strictEqual(output.type, "JWS");
assert.deepEqual(output.header, fix.signing.protected);
assert.strictEqual(output.input, input);

assert.strictEqual(typeof output.perform, "function");
var promise = jose.JWK.asKey(fix.input.key);
promise = promise.then(function(key) {
return output.perform(key);
});
promise = promise.then(function(result) {
assert.strictEqual(result.payload.toString("utf8"),
fix.input.payload);
});
return promise;
});
it("parses compact JWE", function() {
var fix = fixtures.jwe;
var input = fix.output.compact;
var output = parseCompact(input);
assert.strictEqual(output.format, "compact");
assert.strictEqual(output.type, "JWE");
assert.deepEqual(output.header, fix.encrypting_content.protected);
assert.strictEqual(output.input, input);

assert.strictEqual(typeof output.perform, "function");
var promise = jose.JWK.asKey(fix.input.key);
promise = promise.then(function(key) {
return output.perform(key);
});
promise = promise.then(function(result) {
assert.strictEqual(result.plaintext.toString("utf8"),
fix.input.plaintext);
});
return promise;
});
});
Loading

0 comments on commit ecc8596

Please sign in to comment.