blob: 9408f0cbf92b9290da862d84d349644d9b7cb7c7 [file] [log] [blame]
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08001// Domain Public by Eric Wendelin http://www.eriwen.com/ (2008)
2// Luke Smith http://lucassmith.name/ (2008)
3// Loic Dachary <loic@dachary.org> (2008)
4// Johan Euphrosine <proppy@aminche.com> (2008)
5// Oyvind Sean Kinsey http://kinsey.no/blog (2010)
6// Victor Homyakov <victor-homyakov@users.sourceforge.net> (2010)
7/*global module, exports, define, ActiveXObject*/
8(function(global, factory) {
9 if (typeof exports === 'object') {
10 // Node
11 module.exports.printStackTrace = factory();
12 } else if (typeof define === 'function' && define.amd) {
13 // AMD
14 define(factory);
15 } else {
16 // Browser globals
17 global.printStackTrace = factory();
Alexander Afanasyev1663a412013-03-02 13:52:00 -080018 }
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080019}(this, function() {
20 /**
21 * Main function giving a function stack trace with a forced or passed in Error
22 *
23 * @cfg {Error} e The error to create a stacktrace from (optional)
24 * @cfg {Boolean} guess If we should try to resolve the names of anonymous functions
25 * @return {Array} of Strings with functions, lines, files, and arguments where possible
Alexander Afanasyev1663a412013-03-02 13:52:00 -080026 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080027 function printStackTrace(options) {
28 options = options || {guess: true};
29 var ex = options.e || null, guess = !!options.guess, mode = options.mode || null;
30 var p = new printStackTrace.implementation(), result = p.run(ex, mode);
31 return (guess) ? p.guessAnonymousFunctions(result) : result;
Alexander Afanasyev1663a412013-03-02 13:52:00 -080032 }
33
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080034 printStackTrace.implementation = function() {
35 };
Alexander Afanasyev1663a412013-03-02 13:52:00 -080036
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080037 printStackTrace.implementation.prototype = {
38 /**
39 * @param {Error} [ex] The error to create a stacktrace from (optional)
40 * @param {String} [mode] Forced mode (optional, mostly for unit tests)
41 */
42 run: function(ex, mode) {
43 ex = ex || this.createException();
44 mode = mode || this.mode(ex);
45 if (mode === 'other') {
46 return this.other(arguments.callee);
47 } else {
48 return this[mode](ex);
49 }
50 },
Alexander Afanasyev1663a412013-03-02 13:52:00 -080051
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080052 createException: function() {
53 try {
54 this.undef();
55 } catch (e) {
56 return e;
57 }
58 },
Alexander Afanasyev1663a412013-03-02 13:52:00 -080059
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080060 /**
61 * Mode could differ for different exception, e.g.
62 * exceptions in Chrome may or may not have arguments or stack.
63 *
64 * @return {String} mode of operation for the exception
65 */
66 mode: function(e) {
67 if (typeof window !== 'undefined' && window.navigator.userAgent.indexOf('PhantomJS') > -1) {
68 return 'phantomjs';
69 }
Alexander Afanasyev1663a412013-03-02 13:52:00 -080070
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080071 if (e['arguments'] && e.stack) {
72 return 'chrome';
73 }
Alexander Afanasyev1663a412013-03-02 13:52:00 -080074
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080075 if (e.stack && e.sourceURL) {
76 return 'safari';
77 }
Alexander Afanasyev1663a412013-03-02 13:52:00 -080078
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080079 if (e.stack && e.number) {
80 return 'ie';
81 }
Alexander Afanasyev1663a412013-03-02 13:52:00 -080082
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080083 if (e.stack && e.fileName) {
84 return 'firefox';
85 }
Alexander Afanasyev1663a412013-03-02 13:52:00 -080086
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080087 if (e.message && e['opera#sourceloc']) {
88 // e.message.indexOf("Backtrace:") > -1 -> opera9
89 // 'opera#sourceloc' in e -> opera9, opera10a
90 // !e.stacktrace -> opera9
91 if (!e.stacktrace) {
92 return 'opera9'; // use e.message
Alexander Afanasyev1663a412013-03-02 13:52:00 -080093 }
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080094 if (e.message.indexOf('\n') > -1 && e.message.split('\n').length > e.stacktrace.split('\n').length) {
95 // e.message may have more stack entries than e.stacktrace
96 return 'opera9'; // use e.message
Alexander Afanasyev1663a412013-03-02 13:52:00 -080097 }
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080098 return 'opera10a'; // use e.stacktrace
99 }
Alexander Afanasyev1663a412013-03-02 13:52:00 -0800100
Alexander Afanasyeve16ed212016-12-25 18:09:44 -0800101 if (e.message && e.stack && e.stacktrace) {
102 // e.stacktrace && e.stack -> opera10b
103 if (e.stacktrace.indexOf("called from line") < 0) {
104 return 'opera10b'; // use e.stacktrace, format differs from 'opera10a'
105 }
106 // e.stacktrace && e.stack -> opera11
107 return 'opera11'; // use e.stacktrace, format differs from 'opera10a', 'opera10b'
108 }
109
110 if (e.stack && !e.fileName) {
111 // Chrome 27 does not have e.arguments as earlier versions,
112 // but still does not have e.fileName as Firefox
113 return 'chrome';
114 }
115
116 return 'other';
117 },
118
119 /**
120 * Given a context, function name, and callback function, overwrite it so that it calls
121 * printStackTrace() first with a callback and then runs the rest of the body.
122 *
123 * @param {Object} context of execution (e.g. window)
124 * @param {String} functionName to instrument
125 * @param {Function} callback function to call with a stack trace on invocation
126 */
127 instrumentFunction: function(context, functionName, callback) {
128 context = context || window;
129 var original = context[functionName];
130 context[functionName] = function instrumented() {
131 callback.call(this, printStackTrace().slice(4));
132 return context[functionName]._instrumented.apply(this, arguments);
133 };
134 context[functionName]._instrumented = original;
135 },
136
137 /**
138 * Given a context and function name of a function that has been
139 * instrumented, revert the function to it's original (non-instrumented)
140 * state.
141 *
142 * @param {Object} context of execution (e.g. window)
143 * @param {String} functionName to de-instrument
144 */
145 deinstrumentFunction: function(context, functionName) {
146 if (context[functionName].constructor === Function &&
147 context[functionName]._instrumented &&
148 context[functionName]._instrumented.constructor === Function) {
149 context[functionName] = context[functionName]._instrumented;
150 }
151 },
152
153 /**
154 * Given an Error object, return a formatted Array based on Chrome's stack string.
155 *
156 * @param e - Error object to inspect
157 * @return Array<String> of function calls, files and line numbers
158 */
159 chrome: function(e) {
160 return (e.stack + '\n')
161 .replace(/^[\s\S]+?\s+at\s+/, ' at ') // remove message
162 .replace(/^\s+(at eval )?at\s+/gm, '') // remove 'at' and indentation
163 .replace(/^([^\(]+?)([\n$])/gm, '{anonymous}() ($1)$2')
164 .replace(/^Object.<anonymous>\s*\(([^\)]+)\)/gm, '{anonymous}() ($1)')
165 .replace(/^(.+) \((.+)\)$/gm, '$1@$2')
166 .split('\n')
167 .slice(0, -1);
168 },
169
170 /**
171 * Given an Error object, return a formatted Array based on Safari's stack string.
172 *
173 * @param e - Error object to inspect
174 * @return Array<String> of function calls, files and line numbers
175 */
176 safari: function(e) {
177 return e.stack.replace(/\[native code\]\n/m, '')
178 .replace(/^(?=\w+Error\:).*$\n/m, '')
179 .replace(/^@/gm, '{anonymous}()@')
180 .split('\n');
181 },
182
183 /**
184 * Given an Error object, return a formatted Array based on IE's stack string.
185 *
186 * @param e - Error object to inspect
187 * @return Array<String> of function calls, files and line numbers
188 */
189 ie: function(e) {
190 return e.stack
191 .replace(/^\s*at\s+(.*)$/gm, '$1')
192 .replace(/^Anonymous function\s+/gm, '{anonymous}() ')
193 .replace(/^(.+)\s+\((.+)\)$/gm, '$1@$2')
194 .split('\n')
195 .slice(1);
196 },
197
198 /**
199 * Given an Error object, return a formatted Array based on Firefox's stack string.
200 *
201 * @param e - Error object to inspect
202 * @return Array<String> of function calls, files and line numbers
203 */
204 firefox: function(e) {
205 return e.stack.replace(/(?:\n@:0)?\s+$/m, '')
206 .replace(/^(?:\((\S*)\))?@/gm, '{anonymous}($1)@')
207 .split('\n');
208 },
209
210 opera11: function(e) {
211 var ANON = '{anonymous}', lineRE = /^.*line (\d+), column (\d+)(?: in (.+))? in (\S+):$/;
212 var lines = e.stacktrace.split('\n'), result = [];
213
214 for (var i = 0, len = lines.length; i < len; i += 2) {
215 var match = lineRE.exec(lines[i]);
216 if (match) {
217 var location = match[4] + ':' + match[1] + ':' + match[2];
218 var fnName = match[3] || "global code";
219 fnName = fnName.replace(/<anonymous function: (\S+)>/, "$1").replace(/<anonymous function>/, ANON);
220 result.push(fnName + '@' + location + ' -- ' + lines[i + 1].replace(/^\s+/, ''));
221 }
222 }
223
224 return result;
225 },
226
227 opera10b: function(e) {
228 // "<anonymous function: run>([arguments not available])@file://localhost/G:/js/stacktrace.js:27\n" +
229 // "printStackTrace([arguments not available])@file://localhost/G:/js/stacktrace.js:18\n" +
230 // "@file://localhost/G:/js/test/functional/testcase1.html:15"
231 var lineRE = /^(.*)@(.+):(\d+)$/;
232 var lines = e.stacktrace.split('\n'), result = [];
233
234 for (var i = 0, len = lines.length; i < len; i++) {
235 var match = lineRE.exec(lines[i]);
236 if (match) {
237 var fnName = match[1] ? (match[1] + '()') : "global code";
238 result.push(fnName + '@' + match[2] + ':' + match[3]);
239 }
240 }
241
242 return result;
243 },
244
245 /**
246 * Given an Error object, return a formatted Array based on Opera 10's stacktrace string.
247 *
248 * @param e - Error object to inspect
249 * @return Array<String> of function calls, files and line numbers
250 */
251 opera10a: function(e) {
252 // " Line 27 of linked script file://localhost/G:/js/stacktrace.js\n"
253 // " Line 11 of inline#1 script in file://localhost/G:/js/test/functional/testcase1.html: In function foo\n"
254 var ANON = '{anonymous}', lineRE = /Line (\d+).*script (?:in )?(\S+)(?:: In function (\S+))?$/i;
255 var lines = e.stacktrace.split('\n'), result = [];
256
257 for (var i = 0, len = lines.length; i < len; i += 2) {
258 var match = lineRE.exec(lines[i]);
259 if (match) {
260 var fnName = match[3] || ANON;
261 result.push(fnName + '()@' + match[2] + ':' + match[1] + ' -- ' + lines[i + 1].replace(/^\s+/, ''));
262 }
263 }
264
265 return result;
266 },
267
268 // Opera 7.x-9.2x only!
269 opera9: function(e) {
270 // " Line 43 of linked script file://localhost/G:/js/stacktrace.js\n"
271 // " Line 7 of inline#1 script in file://localhost/G:/js/test/functional/testcase1.html\n"
272 var ANON = '{anonymous}', lineRE = /Line (\d+).*script (?:in )?(\S+)/i;
273 var lines = e.message.split('\n'), result = [];
274
275 for (var i = 2, len = lines.length; i < len; i += 2) {
276 var match = lineRE.exec(lines[i]);
277 if (match) {
278 result.push(ANON + '()@' + match[2] + ':' + match[1] + ' -- ' + lines[i + 1].replace(/^\s+/, ''));
279 }
280 }
281
282 return result;
283 },
284
285 phantomjs: function(e) {
286 var ANON = '{anonymous}', lineRE = /(\S+) \((\S+)\)/i;
287 var lines = e.stack.split('\n'), result = [];
288
289 for (var i = 1, len = lines.length; i < len; i++) {
290 lines[i] = lines[i].replace(/^\s+at\s+/gm, '');
291 var match = lineRE.exec(lines[i]);
292 if (match) {
293 result.push(match[1] + '()@' + match[2]);
Alexander Afanasyev1663a412013-03-02 13:52:00 -0800294 }
295 else {
Alexander Afanasyeve16ed212016-12-25 18:09:44 -0800296 result.push(ANON + '()@' + lines[i]);
Alexander Afanasyev1663a412013-03-02 13:52:00 -0800297 }
Alexander Afanasyeve16ed212016-12-25 18:09:44 -0800298 }
299
300 return result;
301 },
302
303 // Safari 5-, IE 9-, and others
304 other: function(curr) {
305 var ANON = '{anonymous}', fnRE = /function(?:\s+([\w$]+))?\s*\(/, stack = [], fn, args, maxStackSize = 10;
306 var slice = Array.prototype.slice;
307 while (curr && stack.length < maxStackSize) {
308 fn = fnRE.test(curr.toString()) ? RegExp.$1 || ANON : ANON;
309 try {
310 args = slice.call(curr['arguments'] || []);
311 } catch (e) {
312 args = ['Cannot access arguments: ' + e];
Alexander Afanasyev1663a412013-03-02 13:52:00 -0800313 }
Alexander Afanasyeve16ed212016-12-25 18:09:44 -0800314 stack[stack.length] = fn + '(' + this.stringifyArguments(args) + ')';
315 try {
316 curr = curr.caller;
317 } catch (e) {
318 stack[stack.length] = 'Cannot access caller: ' + e;
319 break;
Alexander Afanasyev1663a412013-03-02 13:52:00 -0800320 }
Alexander Afanasyeve16ed212016-12-25 18:09:44 -0800321 }
322 return stack;
323 },
324
325 /**
326 * Given arguments array as a String, substituting type names for non-string types.
327 *
328 * @param {Arguments,Array} args
329 * @return {String} stringified arguments
330 */
331 stringifyArguments: function(args) {
332 var result = [];
333 var slice = Array.prototype.slice;
334 for (var i = 0; i < args.length; ++i) {
335 var arg = args[i];
336 if (arg === undefined) {
337 result[i] = 'undefined';
338 } else if (arg === null) {
339 result[i] = 'null';
340 } else if (arg.constructor) {
341 // TODO constructor comparison does not work for iframes
342 if (arg.constructor === Array) {
343 if (arg.length < 3) {
344 result[i] = '[' + this.stringifyArguments(arg) + ']';
345 } else {
346 result[i] = '[' + this.stringifyArguments(slice.call(arg, 0, 1)) + '...' + this.stringifyArguments(slice.call(arg, -1)) + ']';
347 }
348 } else if (arg.constructor === Object) {
349 result[i] = '#object';
350 } else if (arg.constructor === Function) {
351 result[i] = '#function';
352 } else if (arg.constructor === String) {
353 result[i] = '"' + arg + '"';
354 } else if (arg.constructor === Number) {
355 result[i] = arg;
356 } else {
357 result[i] = '?';
358 }
Alexander Afanasyev1663a412013-03-02 13:52:00 -0800359 }
Alexander Afanasyeve16ed212016-12-25 18:09:44 -0800360 }
361 return result.join(',');
362 },
363
364 sourceCache: {},
365
366 /**
367 * @return {String} the text from a given URL
368 */
369 ajax: function(url) {
370 var req = this.createXMLHTTPObject();
371 if (req) {
372 try {
373 req.open('GET', url, false);
374 //req.overrideMimeType('text/plain');
375 //req.overrideMimeType('text/javascript');
376 req.send(null);
377 //return req.status == 200 ? req.responseText : '';
378 return req.responseText;
379 } catch (e) {
Alexander Afanasyev1663a412013-03-02 13:52:00 -0800380 }
Alexander Afanasyeve16ed212016-12-25 18:09:44 -0800381 }
382 return '';
383 },
384
385 /**
386 * Try XHR methods in order and store XHR factory.
387 *
388 * @return {XMLHttpRequest} XHR function or equivalent
389 */
390 createXMLHTTPObject: function() {
391 var xmlhttp, XMLHttpFactories = [
392 function() {
393 return new XMLHttpRequest();
394 }, function() {
395 return new ActiveXObject('Msxml2.XMLHTTP');
396 }, function() {
397 return new ActiveXObject('Msxml3.XMLHTTP');
398 }, function() {
399 return new ActiveXObject('Microsoft.XMLHTTP');
400 }
401 ];
402 for (var i = 0; i < XMLHttpFactories.length; i++) {
403 try {
404 xmlhttp = XMLHttpFactories[i]();
405 // Use memoization to cache the factory
406 this.createXMLHTTPObject = XMLHttpFactories[i];
407 return xmlhttp;
408 } catch (e) {
409 }
410 }
411 },
412
413 /**
414 * Given a URL, check if it is in the same domain (so we can get the source
415 * via Ajax).
416 *
417 * @param url {String} source url
418 * @return {Boolean} False if we need a cross-domain request
419 */
420 isSameDomain: function(url) {
421 return typeof location !== "undefined" && url.indexOf(location.hostname) !== -1; // location may not be defined, e.g. when running from nodejs.
422 },
423
424 /**
425 * Get source code from given URL if in the same domain.
426 *
427 * @param url {String} JS source URL
428 * @return {Array} Array of source code lines
429 */
430 getSource: function(url) {
431 // TODO reuse source from script tags?
432 if (!(url in this.sourceCache)) {
433 this.sourceCache[url] = this.ajax(url).split('\n');
434 }
435 return this.sourceCache[url];
436 },
437
438 guessAnonymousFunctions: function(stack) {
439 for (var i = 0; i < stack.length; ++i) {
440 var reStack = /\{anonymous\}\(.*\)@(.*)/,
441 reRef = /^(.*?)(?::(\d+))(?::(\d+))?(?: -- .+)?$/,
442 frame = stack[i], ref = reStack.exec(frame);
443
444 if (ref) {
445 var m = reRef.exec(ref[1]);
446 if (m) { // If falsey, we did not get any file/line information
447 var file = m[1], lineno = m[2], charno = m[3] || 0;
448 if (file && this.isSameDomain(file) && lineno) {
449 var functionName = this.guessAnonymousFunction(file, lineno, charno);
450 stack[i] = frame.replace('{anonymous}', functionName);
451 }
452 }
453 }
454 }
455 return stack;
456 },
457
458 guessAnonymousFunction: function(url, lineNo, charNo) {
459 var ret;
460 try {
461 ret = this.findFunctionName(this.getSource(url), lineNo);
462 } catch (e) {
463 ret = 'getSource failed with url: ' + url + ', exception: ' + e.toString();
464 }
465 return ret;
466 },
467
468 findFunctionName: function(source, lineNo) {
469 // FIXME findFunctionName fails for compressed source
470 // (more than one function on the same line)
471 // function {name}({args}) m[1]=name m[2]=args
472 var reFunctionDeclaration = /function\s+([^(]*?)\s*\(([^)]*)\)/;
473 // {name} = function ({args}) TODO args capture
474 // /['"]?([0-9A-Za-z_]+)['"]?\s*[:=]\s*function(?:[^(]*)/
475 var reFunctionExpression = /['"]?([$_A-Za-z][$_A-Za-z0-9]*)['"]?\s*[:=]\s*function\b/;
476 // {name} = eval()
477 var reFunctionEvaluation = /['"]?([$_A-Za-z][$_A-Za-z0-9]*)['"]?\s*[:=]\s*(?:eval|new Function)\b/;
478 // Walk backwards in the source lines until we find
479 // the line which matches one of the patterns above
480 var code = "", line, maxLines = Math.min(lineNo, 20), m, commentPos;
481 for (var i = 0; i < maxLines; ++i) {
482 // lineNo is 1-based, source[] is 0-based
483 line = source[lineNo - i - 1];
484 commentPos = line.indexOf('//');
485 if (commentPos >= 0) {
486 line = line.substr(0, commentPos);
487 }
488 // TODO check other types of comments? Commented code may lead to false positive
489 if (line) {
490 code = line + code;
491 m = reFunctionExpression.exec(code);
492 if (m && m[1]) {
493 return m[1];
494 }
495 m = reFunctionDeclaration.exec(code);
496 if (m && m[1]) {
497 //return m[1] + "(" + (m[2] || "") + ")";
498 return m[1];
499 }
500 m = reFunctionEvaluation.exec(code);
501 if (m && m[1]) {
502 return m[1];
503 }
504 }
505 }
506 return '(?)';
Alexander Afanasyev1663a412013-03-02 13:52:00 -0800507 }
Alexander Afanasyeve16ed212016-12-25 18:09:44 -0800508 };
Alexander Afanasyev1663a412013-03-02 13:52:00 -0800509
Alexander Afanasyeve16ed212016-12-25 18:09:44 -0800510 return printStackTrace;
511}));
Alexander Afanasyev1663a412013-03-02 13:52:00 -0800512/**
Alexander Afanasyeve16ed212016-12-25 18:09:44 -0800513 * Copyright (C) 2014-2016 Regents of the University of California.
514 * @author: Ryan Bennett
515 *
516 * This program is free software: you can redistribute it and/or modify
517 * it under the terms of the GNU Lesser General Public License as published by
518 * the Free Software Foundation, either version 3 of the License, or
519 * (at your option) any later version.
520 *
521 * This program is distributed in the hope that it will be useful,
522 * but WITHOUT ANY WARRANTY; without even the implied warranty of
523 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
524 * GNU Lesser General Public License for more details.
525 *
526 * You should have received a copy of the GNU Lesser General Public License
527 * along with this program. If not, see <http://www.gnu.org/licenses/>.
528 * A copy of the GNU Lesser General Public License is in the file COPYING.
Alexander Afanasyev1663a412013-03-02 13:52:00 -0800529 */
530
Alexander Afanasyeve16ed212016-12-25 18:09:44 -0800531// define a shim require function so that a node/browserify require calls dont cause errors when ndn-js is used via <script> tag
Alexander Afanasyev1663a412013-03-02 13:52:00 -0800532
Alexander Afanasyeve16ed212016-12-25 18:09:44 -0800533/** @ignore */
534var ndn = ndn || {}
535/** @ignore */
536var exports = ndn;
537
538/** @ignore */
539var module = {}
540/** @ignore */
541function require(){return ndn;}
Alexander Afanasyev1663a412013-03-02 13:52:00 -0800542/**
Alexander Afanasyeve16ed212016-12-25 18:09:44 -0800543 * Copyright (C) 2016 Regents of the University of California.
544 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
545 *
546 * This program is free software: you can redistribute it and/or modify
547 * it under the terms of the GNU Lesser General Public License as published by
548 * the Free Software Foundation, either version 3 of the License, or
549 * (at your option) any later version.
550 *
551 * This program is distributed in the hope that it will be useful,
552 * but WITHOUT ANY WARRANTY; without even the implied warranty of
553 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
554 * GNU Lesser General Public License for more details.
555 *
556 * You should have received a copy of the GNU Lesser General Public License
557 * along with this program. If not, see <http://www.gnu.org/licenses/>.
558 * A copy of the GNU Lesser General Public License is in the file COPYING.
Alexander Afanasyev1663a412013-03-02 13:52:00 -0800559 */
Alexander Afanasyev1663a412013-03-02 13:52:00 -0800560
Alexander Afanasyeve16ed212016-12-25 18:09:44 -0800561// This is included after stacktrace.js and browserify-require.js so that
562// require().printStackTrace works.
Alexander Afanasyev1663a412013-03-02 13:52:00 -0800563
Alexander Afanasyeve16ed212016-12-25 18:09:44 -0800564exports.printStackTrace = printStackTrace;
565/**
566 * This module checks for the availability of various crypto.subtle api's at runtime,
567 * exporting a function that returns the known availability of necessary NDN crypto apis
568 * Copyright (C) 2014-2016 Regents of the University of California.
569 * @author: Ryan Bennett <nomad.ry@gmail.com>
570 *
571 * This program is free software: you can redistribute it and/or modify
572 * it under the terms of the GNU Lesser General Public License as published by
573 * the Free Software Foundation, either version 3 of the License, or
574 * (at your option) any later version.
575 *
576 * This program is distributed in the hope that it will be useful,
577 * but WITHOUT ANY WARRANTY; without even the implied warranty of
578 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
579 * GNU Lesser General Public License for more details.
580 *
581 * You should have received a copy of the GNU Lesser General Public License
582 * along with this program. If not, see <http://www.gnu.org/licenses/>.
583 * A copy of the GNU Lesser General Public License is in the file COPYING.
584 */
Alexander Afanasyev1663a412013-03-02 13:52:00 -0800585
Alexander Afanasyeve16ed212016-12-25 18:09:44 -0800586function DetectSubtleCrypto(){
587 var use = false;
588 var baselineSupport = (
589 (typeof crypto !== 'undefined' && crypto && crypto.subtle)
590 && (
591 (location.protocol === "https:" || "chrome-extension:" || "chrome:")
592 || (location.hostname === "localhost" || location.hostname === "127.0.0.1")
593 )
594 ) ? true : false ;
595 if (baselineSupport) {
596 var algo = { name: "RSASSA-PKCS1-v1_5", modulusLength: 2048, hash:{name:"SHA-256"}, publicExponent: new Uint8Array([0x01, 0x00, 0x01])};
597 var keypair;
598 //try to perform every RSA crypto operation we need, if everything works, set use = true
599 crypto.subtle.generateKey(
600 algo,
601 true, //exportable;
602 ["sign", "verify"]).then(function(key){
603 keypair = key;
604 return crypto.subtle.sign(algo, key.privateKey, new Uint8Array([1,2,3,4,5]));
605 }).then(function(signature){
606 return crypto.subtle.verify(algo, keypair.publicKey, signature, new Uint8Array([1,2,3,4,5]));
607 }).then(function(verified){
608 return crypto.subtle.exportKey("pkcs8",keypair.privateKey);
609 }).then(function(pkcs8){
610 return crypto.subtle.importKey("pkcs8", pkcs8, algo, true, ["sign"]);
611 }).then(function(importedKey){
612 return crypto.subtle.exportKey("spki", keypair.publicKey);
613 }).then(function(spki){
614 return crypto.subtle.importKey("spki", spki, algo, true, ["verify"]);
615 }).then(function(importedKey){
616 var testDigest = new Uint8Array([1,2,3,4,5]);
617 return crypto.subtle.digest({name:"SHA-256"}, testDigest.buffer);
618 }).then(function(result){
619 use = true;
620 }, function(err){
621 console.log("DetectSubtleCrypto encountered error, not using crypto.subtle: ", err)
622 });
Alexander Afanasyev1663a412013-03-02 13:52:00 -0800623 }
Alexander Afanasyeve16ed212016-12-25 18:09:44 -0800624 return function useSubtleCrypto(){
625 return use;
626 }
Alexander Afanasyev1663a412013-03-02 13:52:00 -0800627}
Alexander Afanasyeve16ed212016-12-25 18:09:44 -0800628
629var UseSubtleCrypto = DetectSubtleCrypto();
630
631exports.UseSubtleCrypto = UseSubtleCrypto;
632/*! CryptoJS v3.1.2 core-fix.js
633 * code.google.com/p/crypto-js
634 * (c) 2009-2013 by Jeff Mott. All rights reserved.
635 * code.google.com/p/crypto-js/wiki/License
636 * THIS IS FIX of 'core.js' to fix Hmac issue.
637 * https://code.google.com/p/crypto-js/issues/detail?id=84
638 * https://crypto-js.googlecode.com/svn-history/r667/branches/3.x/src/core.js
639 */
640/**
641 * CryptoJS core components.
642 */
643var CryptoJS = CryptoJS || (function (Math, undefined) {
644 /**
645 * CryptoJS namespace.
646 */
647 var C = {};
648
649 /**
650 * Library namespace.
651 */
652 var C_lib = C.lib = {};
653
654 /**
655 * Base object for prototypal inheritance.
656 */
657 var Base = C_lib.Base = (function () {
658 function F() {}
659
660 return {
661 /**
662 * Creates a new object that inherits from this object.
663 *
664 * @param {Object} overrides Properties to copy into the new object.
665 *
666 * @return {Object} The new object.
667 *
668 * @static
669 *
670 * @example
671 *
672 * var MyType = CryptoJS.lib.Base.extend({
673 * field: 'value',
674 *
675 * method: function () {
676 * }
677 * });
678 */
679 extend: function (overrides) {
680 // Spawn
681 F.prototype = this;
682 var subtype = new F();
683
684 // Augment
685 if (overrides) {
686 subtype.mixIn(overrides);
687 }
688
689 // Create default initializer
690 if (!subtype.hasOwnProperty('init')) {
691 subtype.init = function () {
692 subtype.$super.init.apply(this, arguments);
693 };
694 }
695
696 // Initializer's prototype is the subtype object
697 subtype.init.prototype = subtype;
698
699 // Reference supertype
700 subtype.$super = this;
701
702 return subtype;
703 },
704
705 /**
706 * Extends this object and runs the init method.
707 * Arguments to create() will be passed to init().
708 *
709 * @return {Object} The new object.
710 *
711 * @static
712 *
713 * @example
714 *
715 * var instance = MyType.create();
716 */
717 create: function () {
718 var instance = this.extend();
719 instance.init.apply(instance, arguments);
720
721 return instance;
722 },
723
724 /**
725 * Initializes a newly created object.
726 * Override this method to add some logic when your objects are created.
727 *
728 * @example
729 *
730 * var MyType = CryptoJS.lib.Base.extend({
731 * init: function () {
732 * // ...
733 * }
734 * });
735 */
736 init: function () {
737 },
738
739 /**
740 * Copies properties into this object.
741 *
742 * @param {Object} properties The properties to mix in.
743 *
744 * @example
745 *
746 * MyType.mixIn({
747 * field: 'value'
748 * });
749 */
750 mixIn: function (properties) {
751 for (var propertyName in properties) {
752 if (properties.hasOwnProperty(propertyName)) {
753 this[propertyName] = properties[propertyName];
754 }
755 }
756
757 // IE won't copy toString using the loop above
758 if (properties.hasOwnProperty('toString')) {
759 this.toString = properties.toString;
760 }
761 },
762
763 /**
764 * Creates a copy of this object.
765 *
766 * @return {Object} The clone.
767 *
768 * @example
769 *
770 * var clone = instance.clone();
771 */
772 clone: function () {
773 return this.init.prototype.extend(this);
774 }
775 };
776 }());
777
778 /**
779 * An array of 32-bit words.
780 *
781 * @property {Array} words The array of 32-bit words.
782 * @property {number} sigBytes The number of significant bytes in this word array.
783 */
784 var WordArray = C_lib.WordArray = Base.extend({
785 /**
786 * Initializes a newly created word array.
787 *
788 * @param {Array} words (Optional) An array of 32-bit words.
789 * @param {number} sigBytes (Optional) The number of significant bytes in the words.
790 *
791 * @example
792 *
793 * var wordArray = CryptoJS.lib.WordArray.create();
794 * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]);
795 * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6);
796 */
797 init: function (words, sigBytes) {
798 words = this.words = words || [];
799
800 if (sigBytes != undefined) {
801 this.sigBytes = sigBytes;
802 } else {
803 this.sigBytes = words.length * 4;
804 }
805 },
806
807 /**
808 * Converts this word array to a string.
809 *
810 * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex
811 *
812 * @return {string} The stringified word array.
813 *
814 * @example
815 *
816 * var string = wordArray + '';
817 * var string = wordArray.toString();
818 * var string = wordArray.toString(CryptoJS.enc.Utf8);
819 */
820 toString: function (encoder) {
821 return (encoder || Hex).stringify(this);
822 },
823
824 /**
825 * Concatenates a word array to this word array.
826 *
827 * @param {WordArray} wordArray The word array to append.
828 *
829 * @return {WordArray} This word array.
830 *
831 * @example
832 *
833 * wordArray1.concat(wordArray2);
834 */
835 concat: function (wordArray) {
836 // Shortcuts
837 var thisWords = this.words;
838 var thatWords = wordArray.words;
839 var thisSigBytes = this.sigBytes;
840 var thatSigBytes = wordArray.sigBytes;
841
842 // Clamp excess bits
843 this.clamp();
844
845 // Concat
846 if (thisSigBytes % 4) {
847 // Copy one byte at a time
848 for (var i = 0; i < thatSigBytes; i++) {
849 var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
850 thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8);
851 }
852 } else {
853 // Copy one word at a time
854 for (var i = 0; i < thatSigBytes; i += 4) {
855 thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2];
856 }
857 }
858 this.sigBytes += thatSigBytes;
859
860 // Chainable
861 return this;
862 },
863
864 /**
865 * Removes insignificant bits.
866 *
867 * @example
868 *
869 * wordArray.clamp();
870 */
871 clamp: function () {
872 // Shortcuts
873 var words = this.words;
874 var sigBytes = this.sigBytes;
875
876 // Clamp
877 words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8);
878 words.length = Math.ceil(sigBytes / 4);
879 },
880
881 /**
882 * Creates a copy of this word array.
883 *
884 * @return {WordArray} The clone.
885 *
886 * @example
887 *
888 * var clone = wordArray.clone();
889 */
890 clone: function () {
891 var clone = Base.clone.call(this);
892 clone.words = this.words.slice(0);
893
894 return clone;
895 },
896
897 /**
898 * Creates a word array filled with random bytes.
899 *
900 * @param {number} nBytes The number of random bytes to generate.
901 *
902 * @return {WordArray} The random word array.
903 *
904 * @static
905 *
906 * @example
907 *
908 * var wordArray = CryptoJS.lib.WordArray.random(16);
909 */
910 random: function (nBytes) {
911 var words = [];
912 for (var i = 0; i < nBytes; i += 4) {
913 words.push((Math.random() * 0x100000000) | 0);
914 }
915
916 return new WordArray.init(words, nBytes);
917 }
918 });
919
920 /**
921 * Encoder namespace.
922 */
923 var C_enc = C.enc = {};
924
925 /**
926 * Hex encoding strategy.
927 */
928 var Hex = C_enc.Hex = {
929 /**
930 * Converts a word array to a hex string.
931 *
932 * @param {WordArray} wordArray The word array.
933 *
934 * @return {string} The hex string.
935 *
936 * @static
937 *
938 * @example
939 *
940 * var hexString = CryptoJS.enc.Hex.stringify(wordArray);
941 */
942 stringify: function (wordArray) {
943 // Shortcuts
944 var words = wordArray.words;
945 var sigBytes = wordArray.sigBytes;
946
947 // Convert
948 var hexChars = [];
949 for (var i = 0; i < sigBytes; i++) {
950 var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
951 hexChars.push((bite >>> 4).toString(16));
952 hexChars.push((bite & 0x0f).toString(16));
953 }
954
955 return hexChars.join('');
956 },
957
958 /**
959 * Converts a hex string to a word array.
960 *
961 * @param {string} hexStr The hex string.
962 *
963 * @return {WordArray} The word array.
964 *
965 * @static
966 *
967 * @example
968 *
969 * var wordArray = CryptoJS.enc.Hex.parse(hexString);
970 */
971 parse: function (hexStr) {
972 // Shortcut
973 var hexStrLength = hexStr.length;
974
975 // Convert
976 var words = [];
977 for (var i = 0; i < hexStrLength; i += 2) {
978 words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);
979 }
980
981 return new WordArray.init(words, hexStrLength / 2);
982 }
983 };
984
985 /**
986 * Latin1 encoding strategy.
987 */
988 var Latin1 = C_enc.Latin1 = {
989 /**
990 * Converts a word array to a Latin1 string.
991 *
992 * @param {WordArray} wordArray The word array.
993 *
994 * @return {string} The Latin1 string.
995 *
996 * @static
997 *
998 * @example
999 *
1000 * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray);
1001 */
1002 stringify: function (wordArray) {
1003 // Shortcuts
1004 var words = wordArray.words;
1005 var sigBytes = wordArray.sigBytes;
1006
1007 // Convert
1008 var latin1Chars = [];
1009 for (var i = 0; i < sigBytes; i++) {
1010 var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
1011 latin1Chars.push(String.fromCharCode(bite));
1012 }
1013
1014 return latin1Chars.join('');
1015 },
1016
1017 /**
1018 * Converts a Latin1 string to a word array.
1019 *
1020 * @param {string} latin1Str The Latin1 string.
1021 *
1022 * @return {WordArray} The word array.
1023 *
1024 * @static
1025 *
1026 * @example
1027 *
1028 * var wordArray = CryptoJS.enc.Latin1.parse(latin1String);
1029 */
1030 parse: function (latin1Str) {
1031 // Shortcut
1032 var latin1StrLength = latin1Str.length;
1033
1034 // Convert
1035 var words = [];
1036 for (var i = 0; i < latin1StrLength; i++) {
1037 words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8);
1038 }
1039
1040 return new WordArray.init(words, latin1StrLength);
1041 }
1042 };
1043
1044 /**
1045 * UTF-8 encoding strategy.
1046 */
1047 var Utf8 = C_enc.Utf8 = {
1048 /**
1049 * Converts a word array to a UTF-8 string.
1050 *
1051 * @param {WordArray} wordArray The word array.
1052 *
1053 * @return {string} The UTF-8 string.
1054 *
1055 * @static
1056 *
1057 * @example
1058 *
1059 * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray);
1060 */
1061 stringify: function (wordArray) {
1062 try {
1063 return decodeURIComponent(escape(Latin1.stringify(wordArray)));
1064 } catch (e) {
1065 throw new Error('Malformed UTF-8 data');
1066 }
1067 },
1068
1069 /**
1070 * Converts a UTF-8 string to a word array.
1071 *
1072 * @param {string} utf8Str The UTF-8 string.
1073 *
1074 * @return {WordArray} The word array.
1075 *
1076 * @static
1077 *
1078 * @example
1079 *
1080 * var wordArray = CryptoJS.enc.Utf8.parse(utf8String);
1081 */
1082 parse: function (utf8Str) {
1083 return Latin1.parse(unescape(encodeURIComponent(utf8Str)));
1084 }
1085 };
1086
1087 /**
1088 * Abstract buffered block algorithm template.
1089 *
1090 * The property blockSize must be implemented in a concrete subtype.
1091 *
1092 * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0
1093 */
1094 var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({
1095 /**
1096 * Resets this block algorithm's data buffer to its initial state.
1097 *
1098 * @example
1099 *
1100 * bufferedBlockAlgorithm.reset();
1101 */
1102 reset: function () {
1103 // Initial values
1104 this._data = new WordArray.init();
1105 this._nDataBytes = 0;
1106 },
1107
1108 /**
1109 * Adds new data to this block algorithm's buffer.
1110 *
1111 * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8.
1112 *
1113 * @example
1114 *
1115 * bufferedBlockAlgorithm._append('data');
1116 * bufferedBlockAlgorithm._append(wordArray);
1117 */
1118 _append: function (data) {
1119 // Convert string to WordArray, else assume WordArray already
1120 if (typeof data == 'string') {
1121 data = Utf8.parse(data);
1122 }
1123
1124 // Append
1125 this._data.concat(data);
1126 this._nDataBytes += data.sigBytes;
1127 },
1128
1129 /**
1130 * Processes available data blocks.
1131 *
1132 * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype.
1133 *
1134 * @param {boolean} doFlush Whether all blocks and partial blocks should be processed.
1135 *
1136 * @return {WordArray} The processed data.
1137 *
1138 * @example
1139 *
1140 * var processedData = bufferedBlockAlgorithm._process();
1141 * var processedData = bufferedBlockAlgorithm._process(!!'flush');
1142 */
1143 _process: function (doFlush) {
1144 // Shortcuts
1145 var data = this._data;
1146 var dataWords = data.words;
1147 var dataSigBytes = data.sigBytes;
1148 var blockSize = this.blockSize;
1149 var blockSizeBytes = blockSize * 4;
1150
1151 // Count blocks ready
1152 var nBlocksReady = dataSigBytes / blockSizeBytes;
1153 if (doFlush) {
1154 // Round up to include partial blocks
1155 nBlocksReady = Math.ceil(nBlocksReady);
1156 } else {
1157 // Round down to include only full blocks,
1158 // less the number of blocks that must remain in the buffer
1159 nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0);
1160 }
1161
1162 // Count words ready
1163 var nWordsReady = nBlocksReady * blockSize;
1164
1165 // Count bytes ready
1166 var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes);
1167
1168 // Process blocks
1169 if (nWordsReady) {
1170 for (var offset = 0; offset < nWordsReady; offset += blockSize) {
1171 // Perform concrete-algorithm logic
1172 this._doProcessBlock(dataWords, offset);
1173 }
1174
1175 // Remove processed words
1176 var processedWords = dataWords.splice(0, nWordsReady);
1177 data.sigBytes -= nBytesReady;
1178 }
1179
1180 // Return processed words
1181 return new WordArray.init(processedWords, nBytesReady);
1182 },
1183
1184 /**
1185 * Creates a copy of this object.
1186 *
1187 * @return {Object} The clone.
1188 *
1189 * @example
1190 *
1191 * var clone = bufferedBlockAlgorithm.clone();
1192 */
1193 clone: function () {
1194 var clone = Base.clone.call(this);
1195 clone._data = this._data.clone();
1196
1197 return clone;
1198 },
1199
1200 _minBufferSize: 0
1201 });
1202
1203 /**
1204 * Abstract hasher template.
1205 *
1206 * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits)
1207 */
1208 var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({
1209 /**
1210 * Configuration options.
1211 */
1212 cfg: Base.extend(),
1213
1214 /**
1215 * Initializes a newly created hasher.
1216 *
1217 * @param {Object} cfg (Optional) The configuration options to use for this hash computation.
1218 *
1219 * @example
1220 *
1221 * var hasher = CryptoJS.algo.SHA256.create();
1222 */
1223 init: function (cfg) {
1224 // Apply config defaults
1225 this.cfg = this.cfg.extend(cfg);
1226
1227 // Set initial values
1228 this.reset();
1229 },
1230
1231 /**
1232 * Resets this hasher to its initial state.
1233 *
1234 * @example
1235 *
1236 * hasher.reset();
1237 */
1238 reset: function () {
1239 // Reset data buffer
1240 BufferedBlockAlgorithm.reset.call(this);
1241
1242 // Perform concrete-hasher logic
1243 this._doReset();
1244 },
1245
1246 /**
1247 * Updates this hasher with a message.
1248 *
1249 * @param {WordArray|string} messageUpdate The message to append.
1250 *
1251 * @return {Hasher} This hasher.
1252 *
1253 * @example
1254 *
1255 * hasher.update('message');
1256 * hasher.update(wordArray);
1257 */
1258 update: function (messageUpdate) {
1259 // Append
1260 this._append(messageUpdate);
1261
1262 // Update the hash
1263 this._process();
1264
1265 // Chainable
1266 return this;
1267 },
1268
1269 /**
1270 * Finalizes the hash computation.
1271 * Note that the finalize operation is effectively a destructive, read-once operation.
1272 *
1273 * @param {WordArray|string} messageUpdate (Optional) A final message update.
1274 *
1275 * @return {WordArray} The hash.
1276 *
1277 * @example
1278 *
1279 * var hash = hasher.finalize();
1280 * var hash = hasher.finalize('message');
1281 * var hash = hasher.finalize(wordArray);
1282 */
1283 finalize: function (messageUpdate) {
1284 // Final message update
1285 if (messageUpdate) {
1286 this._append(messageUpdate);
1287 }
1288
1289 // Perform concrete-hasher logic
1290 var hash = this._doFinalize();
1291
1292 return hash;
1293 },
1294
1295 blockSize: 512/32,
1296
1297 /**
1298 * Creates a shortcut function to a hasher's object interface.
1299 *
1300 * @param {Hasher} hasher The hasher to create a helper for.
1301 *
1302 * @return {Function} The shortcut function.
1303 *
1304 * @static
1305 *
1306 * @example
1307 *
1308 * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256);
1309 */
1310 _createHelper: function (hasher) {
1311 return function (message, cfg) {
1312 return new hasher.init(cfg).finalize(message);
1313 };
1314 },
1315
1316 /**
1317 * Creates a shortcut function to the HMAC's object interface.
1318 *
1319 * @param {Hasher} hasher The hasher to use in this HMAC helper.
1320 *
1321 * @return {Function} The shortcut function.
1322 *
1323 * @static
1324 *
1325 * @example
1326 *
1327 * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256);
1328 */
1329 _createHmacHelper: function (hasher) {
1330 return function (message, key) {
1331 return new C_algo.HMAC.init(hasher, key).finalize(message);
1332 };
1333 }
1334 });
1335
1336 /**
1337 * Algorithm namespace.
1338 */
1339 var C_algo = C.algo = {};
1340
1341 return C;
1342}(Math));
1343
1344exports.CryptoJS = CryptoJS;
1345module.exports = exports;
1346/*
1347CryptoJS v3.1.2
1348code.google.com/p/crypto-js
1349(c) 2009-2013 by Jeff Mott. All rights reserved.
1350
1351Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
1352associated documentation files (the "Software"), to deal in the Software without restriction, including
1353without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
1354sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
1355subject to the following conditions:
1356
1357The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
1358
1359code.google.com/p/crypto-js/wiki/License
1360*/
1361
1362var C = require('./core.js').CryptoJS;
1363(function (Math) {
1364 // Shortcuts
1365 var C_lib = C.lib;
1366 var WordArray = C_lib.WordArray;
1367 var Hasher = C_lib.Hasher;
1368 var C_algo = C.algo;
1369
1370 // Initialization and round constants tables
1371 var H = [];
1372 var K = [];
1373
1374 // Compute constants
1375 (function () {
1376 function isPrime(n) {
1377 var sqrtN = Math.sqrt(n);
1378 for (var factor = 2; factor <= sqrtN; factor++) {
1379 if (!(n % factor)) {
1380 return false;
1381 }
1382 }
1383
1384 return true;
1385 }
1386
1387 function getFractionalBits(n) {
1388 return ((n - (n | 0)) * 0x100000000) | 0;
1389 }
1390
1391 var n = 2;
1392 var nPrime = 0;
1393 while (nPrime < 64) {
1394 if (isPrime(n)) {
1395 if (nPrime < 8) {
1396 H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2));
1397 }
1398 K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3));
1399
1400 nPrime++;
1401 }
1402
1403 n++;
1404 }
1405 }());
1406
1407 // Reusable object
1408 var W = [];
1409
1410 /**
1411 * SHA-256 hash algorithm.
1412 */
1413 var SHA256 = C_algo.SHA256 = Hasher.extend({
1414 _doReset: function () {
1415 this._hash = new WordArray.init(H.slice(0));
1416 },
1417
1418 _doProcessBlock: function (M, offset) {
1419 // Shortcut
1420 var H = this._hash.words;
1421
1422 // Working variables
1423 var a = H[0];
1424 var b = H[1];
1425 var c = H[2];
1426 var d = H[3];
1427 var e = H[4];
1428 var f = H[5];
1429 var g = H[6];
1430 var h = H[7];
1431
1432 // Computation
1433 for (var i = 0; i < 64; i++) {
1434 if (i < 16) {
1435 W[i] = M[offset + i] | 0;
1436 } else {
1437 var gamma0x = W[i - 15];
1438 var gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^
1439 ((gamma0x << 14) | (gamma0x >>> 18)) ^
1440 (gamma0x >>> 3);
1441
1442 var gamma1x = W[i - 2];
1443 var gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^
1444 ((gamma1x << 13) | (gamma1x >>> 19)) ^
1445 (gamma1x >>> 10);
1446
1447 W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16];
1448 }
1449
1450 var ch = (e & f) ^ (~e & g);
1451 var maj = (a & b) ^ (a & c) ^ (b & c);
1452
1453 var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22));
1454 var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25));
1455
1456 var t1 = h + sigma1 + ch + K[i] + W[i];
1457 var t2 = sigma0 + maj;
1458
1459 h = g;
1460 g = f;
1461 f = e;
1462 e = (d + t1) | 0;
1463 d = c;
1464 c = b;
1465 b = a;
1466 a = (t1 + t2) | 0;
1467 }
1468
1469 // Intermediate hash value
1470 H[0] = (H[0] + a) | 0;
1471 H[1] = (H[1] + b) | 0;
1472 H[2] = (H[2] + c) | 0;
1473 H[3] = (H[3] + d) | 0;
1474 H[4] = (H[4] + e) | 0;
1475 H[5] = (H[5] + f) | 0;
1476 H[6] = (H[6] + g) | 0;
1477 H[7] = (H[7] + h) | 0;
1478 },
1479
1480 _doFinalize: function () {
1481 // Shortcuts
1482 var data = this._data;
1483 var dataWords = data.words;
1484
1485 var nBitsTotal = this._nDataBytes * 8;
1486 var nBitsLeft = data.sigBytes * 8;
1487
1488 // Add padding
1489 dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
1490 dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);
1491 dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;
1492 data.sigBytes = dataWords.length * 4;
1493
1494 // Hash final blocks
1495 this._process();
1496
1497 // Return final computed hash
1498 return this._hash;
1499 },
1500
1501 clone: function () {
1502 var clone = Hasher.clone.call(this);
1503 clone._hash = this._hash.clone();
1504
1505 return clone;
1506 }
1507 });
1508
1509 /**
1510 * Shortcut function to the hasher's object interface.
1511 *
1512 * @param {WordArray|string} message The message to hash.
1513 *
1514 * @return {WordArray} The hash.
1515 *
1516 * @static
1517 *
1518 * @example
1519 *
1520 * var hash = CryptoJS.SHA256('message');
1521 * var hash = CryptoJS.SHA256(wordArray);
1522 */
1523 C.SHA256 = Hasher._createHelper(SHA256);
1524
1525 /**
1526 * Shortcut function to the HMAC's object interface.
1527 *
1528 * @param {WordArray|string} message The message to hash.
1529 * @param {WordArray|string} key The secret key.
1530 *
1531 * @return {WordArray} The HMAC.
1532 *
1533 * @static
1534 *
1535 * @example
1536 *
1537 * var hmac = CryptoJS.HmacSHA256(message, key);
1538 */
1539 C.HmacSHA256 = Hasher._createHmacHelper(SHA256);
1540}(Math));
1541
1542exports.CryptoJS = C;
1543module.exports = exports;
1544/*
1545CryptoJS v3.1.2
1546code.google.com/p/crypto-js
1547(c) 2009-2013 by Jeff Mott. All rights reserved.
1548code.google.com/p/crypto-js/wiki/License
Alexander Afanasyev1663a412013-03-02 13:52:00 -08001549*/
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08001550(function () {
1551 // Shortcuts
1552 var C = CryptoJS;
1553 var C_lib = C.lib;
1554 var Base = C_lib.Base;
1555 var C_enc = C.enc;
1556 var Utf8 = C_enc.Utf8;
1557 var C_algo = C.algo;
1558
1559 /**
1560 * HMAC algorithm.
1561 */
1562 var HMAC = C_algo.HMAC = Base.extend({
1563 /**
1564 * Initializes a newly created HMAC.
1565 *
1566 * @param {Hasher} hasher The hash algorithm to use.
1567 * @param {WordArray|string} key The secret key.
1568 *
1569 * @example
1570 *
1571 * var hmacHasher = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key);
1572 */
1573 init: function (hasher, key) {
1574 // Init hasher
1575 hasher = this._hasher = new hasher.init();
1576
1577 // Convert string to WordArray, else assume WordArray already
1578 if (typeof key == 'string') {
1579 key = Utf8.parse(key);
1580 }
1581
1582 // Shortcuts
1583 var hasherBlockSize = hasher.blockSize;
1584 var hasherBlockSizeBytes = hasherBlockSize * 4;
1585
1586 // Allow arbitrary length keys
1587 if (key.sigBytes > hasherBlockSizeBytes) {
1588 key = hasher.finalize(key);
1589 }
1590
1591 // Clamp excess bits
1592 key.clamp();
1593
1594 // Clone key for inner and outer pads
1595 var oKey = this._oKey = key.clone();
1596 var iKey = this._iKey = key.clone();
1597
1598 // Shortcuts
1599 var oKeyWords = oKey.words;
1600 var iKeyWords = iKey.words;
1601
1602 // XOR keys with pad constants
1603 for (var i = 0; i < hasherBlockSize; i++) {
1604 oKeyWords[i] ^= 0x5c5c5c5c;
1605 iKeyWords[i] ^= 0x36363636;
1606 }
1607 oKey.sigBytes = iKey.sigBytes = hasherBlockSizeBytes;
1608
1609 // Set initial values
1610 this.reset();
1611 },
1612
1613 /**
1614 * Resets this HMAC to its initial state.
1615 *
1616 * @example
1617 *
1618 * hmacHasher.reset();
1619 */
1620 reset: function () {
1621 // Shortcut
1622 var hasher = this._hasher;
1623
1624 // Reset
1625 hasher.reset();
1626 hasher.update(this._iKey);
1627 },
1628
1629 /**
1630 * Updates this HMAC with a message.
1631 *
1632 * @param {WordArray|string} messageUpdate The message to append.
1633 *
1634 * @return {HMAC} This HMAC instance.
1635 *
1636 * @example
1637 *
1638 * hmacHasher.update('message');
1639 * hmacHasher.update(wordArray);
1640 */
1641 update: function (messageUpdate) {
1642 this._hasher.update(messageUpdate);
1643
1644 // Chainable
1645 return this;
1646 },
1647
1648 /**
1649 * Finalizes the HMAC computation.
1650 * Note that the finalize operation is effectively a destructive, read-once operation.
1651 *
1652 * @param {WordArray|string} messageUpdate (Optional) A final message update.
1653 *
1654 * @return {WordArray} The HMAC.
1655 *
1656 * @example
1657 *
1658 * var hmac = hmacHasher.finalize();
1659 * var hmac = hmacHasher.finalize('message');
1660 * var hmac = hmacHasher.finalize(wordArray);
1661 */
1662 finalize: function (messageUpdate) {
1663 // Shortcut
1664 var hasher = this._hasher;
1665
1666 // Compute HMAC
1667 var innerHash = hasher.finalize(messageUpdate);
1668 hasher.reset();
1669 var hmac = hasher.finalize(this._oKey.clone().concat(innerHash));
1670
1671 return hmac;
1672 }
1673 });
1674}());
1675/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/
Alexander Afanasyev1663a412013-03-02 13:52:00 -08001676 */
Alexander Afanasyev1663a412013-03-02 13:52:00 -08001677var b64map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1678var b64pad="=";
1679
1680function hex2b64(h) {
1681 var i;
1682 var c;
1683 var ret = "";
1684 for(i = 0; i+3 <= h.length; i+=3) {
1685 c = parseInt(h.substring(i,i+3),16);
1686 ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63);
1687 }
1688 if(i+1 == h.length) {
1689 c = parseInt(h.substring(i,i+1),16);
1690 ret += b64map.charAt(c << 2);
1691 }
1692 else if(i+2 == h.length) {
1693 c = parseInt(h.substring(i,i+2),16);
1694 ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4);
1695 }
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08001696 if (b64pad) while((ret.length & 3) > 0) ret += b64pad;
Alexander Afanasyev1663a412013-03-02 13:52:00 -08001697 return ret;
1698}
1699
1700// convert a base64 string to hex
1701function b64tohex(s) {
1702 var ret = ""
1703 var i;
1704 var k = 0; // b64 state, 0-3
1705 var slop;
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08001706 var v;
Alexander Afanasyev1663a412013-03-02 13:52:00 -08001707 for(i = 0; i < s.length; ++i) {
1708 if(s.charAt(i) == b64pad) break;
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08001709 v = b64map.indexOf(s.charAt(i));
Alexander Afanasyev1663a412013-03-02 13:52:00 -08001710 if(v < 0) continue;
1711 if(k == 0) {
1712 ret += int2char(v >> 2);
1713 slop = v & 3;
1714 k = 1;
1715 }
1716 else if(k == 1) {
1717 ret += int2char((slop << 2) | (v >> 4));
1718 slop = v & 0xf;
1719 k = 2;
1720 }
1721 else if(k == 2) {
1722 ret += int2char(slop);
1723 ret += int2char(v >> 2);
1724 slop = v & 3;
1725 k = 3;
1726 }
1727 else {
1728 ret += int2char((slop << 2) | (v >> 4));
1729 ret += int2char(v & 0xf);
1730 k = 0;
1731 }
1732 }
1733 if(k == 1)
1734 ret += int2char(slop << 2);
1735 return ret;
1736}
1737
1738// convert a base64 string to a byte/number array
1739function b64toBA(s) {
1740 //piggyback on b64tohex for now, optimize later
1741 var h = b64tohex(s);
1742 var i;
1743 var a = new Array();
1744 for(i = 0; 2*i < h.length; ++i) {
1745 a[i] = parseInt(h.substring(2*i,2*i+2),16);
1746 }
1747 return a;
1748}
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08001749
1750exports.b64tohex = b64tohex;
1751exports.b64toBA = b64toBA;
1752exports.hex2b64 = hex2b64;
1753
1754module.exports = exports;
1755/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/
1756 */
1757// prng4.js - uses Arcfour as a PRNG
1758
1759function Arcfour() {
1760 this.i = 0;
1761 this.j = 0;
1762 this.S = new Array();
1763}
1764
1765// Initialize arcfour context from key, an array of ints, each from [0..255]
1766function ARC4init(key) {
1767 var i, j, t;
1768 for(i = 0; i < 256; ++i)
1769 this.S[i] = i;
1770 j = 0;
1771 for(i = 0; i < 256; ++i) {
1772 j = (j + this.S[i] + key[i % key.length]) & 255;
1773 t = this.S[i];
1774 this.S[i] = this.S[j];
1775 this.S[j] = t;
1776 }
1777 this.i = 0;
1778 this.j = 0;
1779}
1780
1781function ARC4next() {
1782 var t;
1783 this.i = (this.i + 1) & 255;
1784 this.j = (this.j + this.S[this.i]) & 255;
1785 t = this.S[this.i];
1786 this.S[this.i] = this.S[this.j];
1787 this.S[this.j] = t;
1788 return this.S[(t + this.S[this.i]) & 255];
1789}
1790
1791Arcfour.prototype.init = ARC4init;
1792Arcfour.prototype.next = ARC4next;
1793
1794// Plug in your RNG constructor here
1795function prng_newstate() {
1796 return new Arcfour();
1797}
1798
1799// Pool size must be a multiple of 4 and greater than 32.
1800// An array of bytes the size of the pool will be passed to init()
1801var rng_psize = 256;
1802/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/
1803 */
1804// Random number generator - requires a PRNG backend, e.g. prng4.js
1805
1806// For best results, put code like
1807// <body onClick='rng_seed_time();' onKeyPress='rng_seed_time();'>
1808// in your main HTML document.
1809
1810var rng_state;
1811var rng_pool;
1812var rng_pptr;
1813
1814// Mix in a 32-bit integer into the pool
1815function rng_seed_int(x) {
1816 rng_pool[rng_pptr++] ^= x & 255;
1817 rng_pool[rng_pptr++] ^= (x >> 8) & 255;
1818 rng_pool[rng_pptr++] ^= (x >> 16) & 255;
1819 rng_pool[rng_pptr++] ^= (x >> 24) & 255;
1820 if(rng_pptr >= rng_psize) rng_pptr -= rng_psize;
1821}
1822
1823// Mix in the current time (w/milliseconds) into the pool
1824function rng_seed_time() {
1825 rng_seed_int(new Date().getTime());
1826}
1827
1828// Initialize the pool with junk if needed.
1829if(rng_pool == null) {
1830 rng_pool = new Array();
1831 rng_pptr = 0;
1832 var t;
1833 if(navigator.appName == "Netscape" && navigator.appVersion < "5" && window.crypto) {
1834 // Extract entropy (256 bits) from NS4 RNG if available
1835 var z = window.crypto.random(32);
1836 for(t = 0; t < z.length; ++t)
1837 rng_pool[rng_pptr++] = z.charCodeAt(t) & 255;
1838 }
1839 while(rng_pptr < rng_psize) { // extract some randomness from Math.random()
1840 t = Math.floor(65536 * Math.random());
1841 rng_pool[rng_pptr++] = t >>> 8;
1842 rng_pool[rng_pptr++] = t & 255;
1843 }
1844 rng_pptr = 0;
1845 rng_seed_time();
1846 //rng_seed_int(window.screenX);
1847 //rng_seed_int(window.screenY);
1848}
1849
1850function rng_get_byte() {
1851 if(rng_state == null) {
1852 rng_seed_time();
1853 rng_state = prng_newstate();
1854 rng_state.init(rng_pool);
1855 for(rng_pptr = 0; rng_pptr < rng_pool.length; ++rng_pptr)
1856 rng_pool[rng_pptr] = 0;
1857 rng_pptr = 0;
1858 //rng_pool = null;
1859 }
1860 // TODO: allow reseeding after first request
1861 return rng_state.next();
1862}
1863
1864function rng_get_bytes(ba) {
1865 var i;
1866 for(i = 0; i < ba.length; ++i) ba[i] = rng_get_byte();
1867}
1868
1869function SecureRandom() {}
1870
1871SecureRandom.prototype.nextBytes = rng_get_bytes;
1872/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/
1873 */
Alexander Afanasyev1663a412013-03-02 13:52:00 -08001874// Depends on jsbn.js and rng.js
1875
1876// Version 1.1: support utf-8 encoding in pkcs1pad2
1877
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08001878var intShim = require("jsbn");
1879
Alexander Afanasyev1663a412013-03-02 13:52:00 -08001880// convert a (hex) string to a bignum object
1881function parseBigInt(str,r) {
1882 return new BigInteger(str,r);
1883}
1884
1885function linebrk(s,n) {
1886 var ret = "";
1887 var i = 0;
1888 while(i + n < s.length) {
1889 ret += s.substring(i,i+n) + "\n";
1890 i += n;
1891 }
1892 return ret + s.substring(i,s.length);
1893}
1894
1895function byte2Hex(b) {
1896 if(b < 0x10)
1897 return "0" + b.toString(16);
1898 else
1899 return b.toString(16);
1900}
1901
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08001902// PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint
Alexander Afanasyev1663a412013-03-02 13:52:00 -08001903function pkcs1pad2(s,n) {
1904 if(n < s.length + 11) { // TODO: fix for utf-8
1905 alert("Message too long for RSA");
1906 return null;
1907 }
1908 var ba = new Array();
1909 var i = s.length - 1;
1910 while(i >= 0 && n > 0) {
1911 var c = s.charCodeAt(i--);
1912 if(c < 128) { // encode using utf-8
1913 ba[--n] = c;
1914 }
1915 else if((c > 127) && (c < 2048)) {
1916 ba[--n] = (c & 63) | 128;
1917 ba[--n] = (c >> 6) | 192;
1918 }
1919 else {
1920 ba[--n] = (c & 63) | 128;
1921 ba[--n] = ((c >> 6) & 63) | 128;
1922 ba[--n] = (c >> 12) | 224;
1923 }
1924 }
1925 ba[--n] = 0;
1926 var rng = new SecureRandom();
1927 var x = new Array();
1928 while(n > 2) { // random non-zero pad
1929 x[0] = 0;
1930 while(x[0] == 0) rng.nextBytes(x);
1931 ba[--n] = x[0];
1932 }
1933 ba[--n] = 2;
1934 ba[--n] = 0;
1935 return new BigInteger(ba);
1936}
1937
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08001938// PKCS#1 (OAEP) mask generation function
1939function oaep_mgf1_arr(seed, len, hash)
1940{
1941 var mask = '', i = 0;
1942
1943 while (mask.length < len)
1944 {
1945 mask += hash(String.fromCharCode.apply(String, seed.concat([
1946 (i & 0xff000000) >> 24,
1947 (i & 0x00ff0000) >> 16,
1948 (i & 0x0000ff00) >> 8,
1949 i & 0x000000ff])));
1950 i += 1;
1951 }
1952
1953 return mask;
1954}
1955
1956var SHA1_SIZE = 20;
1957
1958// PKCS#1 (OAEP) pad input string s to n bytes, and return a bigint
1959function oaep_pad(s, n, hash)
1960{
1961 if (s.length + 2 * SHA1_SIZE + 2 > n)
1962 {
1963 throw "Message too long for RSA";
1964 }
1965
1966 var PS = '', i;
1967
1968 for (i = 0; i < n - s.length - 2 * SHA1_SIZE - 2; i += 1)
1969 {
1970 PS += '\x00';
1971 }
1972
1973 var DB = rstr_sha1('') + PS + '\x01' + s;
1974 var seed = new Array(SHA1_SIZE);
1975 new SecureRandom().nextBytes(seed);
1976
1977 var dbMask = oaep_mgf1_arr(seed, DB.length, hash || rstr_sha1);
1978 var maskedDB = [];
1979
1980 for (i = 0; i < DB.length; i += 1)
1981 {
1982 maskedDB[i] = DB.charCodeAt(i) ^ dbMask.charCodeAt(i);
1983 }
1984
1985 var seedMask = oaep_mgf1_arr(maskedDB, seed.length, rstr_sha1);
1986 var maskedSeed = [0];
1987
1988 for (i = 0; i < seed.length; i += 1)
1989 {
1990 maskedSeed[i + 1] = seed[i] ^ seedMask.charCodeAt(i);
1991 }
1992
1993 return new BigInteger(maskedSeed.concat(maskedDB));
1994}
1995
1996// "empty" RSA key constructor
Alexander Afanasyev1663a412013-03-02 13:52:00 -08001997function RSAKey() {
1998 this.n = null;
1999 this.e = 0;
2000 this.d = null;
2001 this.p = null;
2002 this.q = null;
2003 this.dmp1 = null;
2004 this.dmq1 = null;
2005 this.coeff = null;
2006}
2007
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08002008// Set the public key fields N and e from hex strings
Alexander Afanasyev1663a412013-03-02 13:52:00 -08002009function RSASetPublic(N,E) {
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08002010 this.isPublic = true;
2011 if (typeof N !== "string")
2012 {
2013 this.n = N;
2014 this.e = E;
2015 }
2016 else if(N != null && E != null && N.length > 0 && E.length > 0) {
Alexander Afanasyev1663a412013-03-02 13:52:00 -08002017 this.n = parseBigInt(N,16);
2018 this.e = parseInt(E,16);
2019 }
2020 else
2021 alert("Invalid RSA public key");
2022}
2023
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08002024// Perform raw public operation on "x": return x^e (mod n)
Alexander Afanasyev1663a412013-03-02 13:52:00 -08002025function RSADoPublic(x) {
2026 return x.modPowInt(this.e, this.n);
2027}
2028
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08002029// Return the PKCS#1 RSA encryption of "text" as an even-length hex string
Alexander Afanasyev1663a412013-03-02 13:52:00 -08002030function RSAEncrypt(text) {
2031 var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3);
2032 if(m == null) return null;
2033 var c = this.doPublic(m);
2034 if(c == null) return null;
2035 var h = c.toString(16);
2036 if((h.length & 1) == 0) return h; else return "0" + h;
2037}
2038
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08002039// Return the PKCS#1 OAEP RSA encryption of "text" as an even-length hex string
2040function RSAEncryptOAEP(text, hash) {
2041 var m = oaep_pad(text, (this.n.bitLength()+7)>>3, hash);
2042 if(m == null) return null;
2043 var c = this.doPublic(m);
2044 if(c == null) return null;
2045 var h = c.toString(16);
2046 if((h.length & 1) == 0) return h; else return "0" + h;
2047}
2048
Alexander Afanasyev1663a412013-03-02 13:52:00 -08002049// Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string
2050//function RSAEncryptB64(text) {
2051// var h = this.encrypt(text);
2052// if(h) return hex2b64(h); else return null;
2053//}
2054
2055// protected
2056RSAKey.prototype.doPublic = RSADoPublic;
2057
2058// public
2059RSAKey.prototype.setPublic = RSASetPublic;
2060RSAKey.prototype.encrypt = RSAEncrypt;
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08002061RSAKey.prototype.encryptOAEP = RSAEncryptOAEP;
Alexander Afanasyev1663a412013-03-02 13:52:00 -08002062//RSAKey.prototype.encrypt_b64 = RSAEncryptB64;
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08002063
2064RSAKey.prototype.type = "RSA";
2065
2066exports.RSAKey = RSAKey;
2067module.exports = exports;
2068/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/
2069 */
Alexander Afanasyev1663a412013-03-02 13:52:00 -08002070// Depends on rsa.js and jsbn2.js
2071
2072// Version 1.1: support utf-8 decoding in pkcs1unpad2
2073
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08002074var intShim = require("jsbn");
2075var BigInteger = intShim.BigInteger ? intShim.BigInteger : intShim ;
2076var RSAKey = require('./rsa.js').RSAKey;
2077
Alexander Afanasyev1663a412013-03-02 13:52:00 -08002078// Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext
2079function pkcs1unpad2(d,n) {
2080 var b = d.toByteArray();
2081 var i = 0;
2082 while(i < b.length && b[i] == 0) ++i;
2083 if(b.length-i != n-1 || b[i] != 2)
2084 return null;
2085 ++i;
2086 while(b[i] != 0)
2087 if(++i >= b.length) return null;
2088 var ret = "";
2089 while(++i < b.length) {
2090 var c = b[i] & 255;
2091 if(c < 128) { // utf-8 decode
2092 ret += String.fromCharCode(c);
2093 }
2094 else if((c > 191) && (c < 224)) {
2095 ret += String.fromCharCode(((c & 31) << 6) | (b[i+1] & 63));
2096 ++i;
2097 }
2098 else {
2099 ret += String.fromCharCode(((c & 15) << 12) | ((b[i+1] & 63) << 6) | (b[i+2] & 63));
2100 i += 2;
2101 }
2102 }
2103 return ret;
2104}
2105
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08002106// PKCS#1 (OAEP) mask generation function
2107function oaep_mgf1_str(seed, len, hash)
2108{
2109 var mask = '', i = 0;
2110
2111 while (mask.length < len)
2112 {
2113 mask += hash(seed + String.fromCharCode.apply(String, [
2114 (i & 0xff000000) >> 24,
2115 (i & 0x00ff0000) >> 16,
2116 (i & 0x0000ff00) >> 8,
2117 i & 0x000000ff]));
2118 i += 1;
2119 }
2120
2121 return mask;
2122}
2123
2124var SHA1_SIZE = 20;
2125
2126// Undo PKCS#1 (OAEP) padding and, if valid, return the plaintext
2127function oaep_unpad(d, n, hash)
2128{
2129 d = d.toByteArray();
2130
2131 var i;
2132
2133 for (i = 0; i < d.length; i += 1)
2134 {
2135 d[i] &= 0xff;
2136 }
2137
2138 while (d.length < n)
2139 {
2140 d.unshift(0);
2141 }
2142
2143 d = String.fromCharCode.apply(String, d);
2144
2145 if (d.length < 2 * SHA1_SIZE + 2)
2146 {
2147 throw "Cipher too short";
2148 }
2149
2150 var maskedSeed = d.substr(1, SHA1_SIZE)
2151 var maskedDB = d.substr(SHA1_SIZE + 1);
2152
2153 var seedMask = oaep_mgf1_str(maskedDB, SHA1_SIZE, hash || rstr_sha1);
2154 var seed = [], i;
2155
2156 for (i = 0; i < maskedSeed.length; i += 1)
2157 {
2158 seed[i] = maskedSeed.charCodeAt(i) ^ seedMask.charCodeAt(i);
2159 }
2160
2161 var dbMask = oaep_mgf1_str(String.fromCharCode.apply(String, seed),
2162 d.length - SHA1_SIZE, rstr_sha1);
2163
2164 var DB = [];
2165
2166 for (i = 0; i < maskedDB.length; i += 1)
2167 {
2168 DB[i] = maskedDB.charCodeAt(i) ^ dbMask.charCodeAt(i);
2169 }
2170
2171 DB = String.fromCharCode.apply(String, DB);
2172
2173 if (DB.substr(0, SHA1_SIZE) !== rstr_sha1(''))
2174 {
2175 throw "Hash mismatch";
2176 }
2177
2178 DB = DB.substr(SHA1_SIZE);
2179
2180 var first_one = DB.indexOf('\x01');
2181 var last_zero = (first_one != -1) ? DB.substr(0, first_one).lastIndexOf('\x00') : -1;
2182
2183 if (last_zero + 1 != first_one)
2184 {
2185 throw "Malformed data";
2186 }
2187
2188 return DB.substr(first_one + 1);
2189}
2190
Alexander Afanasyev1663a412013-03-02 13:52:00 -08002191// Set the private key fields N, e, and d from hex strings
2192function RSASetPrivate(N,E,D) {
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08002193 this.isPrivate = true;
2194 if (typeof N !== "string")
2195 {
2196 this.n = N;
2197 this.e = E;
2198 this.d = D;
2199 }
2200 else if(N != null && E != null && N.length > 0 && E.length > 0) {
Alexander Afanasyev1663a412013-03-02 13:52:00 -08002201 this.n = parseBigInt(N,16);
2202 this.e = parseInt(E,16);
2203 this.d = parseBigInt(D,16);
2204 }
2205 else
2206 alert("Invalid RSA private key");
2207}
2208
2209// Set the private key fields N, e, d and CRT params from hex strings
2210function RSASetPrivateEx(N,E,D,P,Q,DP,DQ,C) {
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08002211 this.isPrivate = true;
2212 if (N == null) throw "RSASetPrivateEx N == null";
2213 if (E == null) throw "RSASetPrivateEx E == null";
2214 if (N.length == 0) throw "RSASetPrivateEx N.length == 0";
2215 if (E.length == 0) throw "RSASetPrivateEx E.length == 0";
2216
2217 if (N != null && E != null && N.length > 0 && E.length > 0) {
Alexander Afanasyev1663a412013-03-02 13:52:00 -08002218 this.n = parseBigInt(N,16);
2219 this.e = parseInt(E,16);
2220 this.d = parseBigInt(D,16);
2221 this.p = parseBigInt(P,16);
2222 this.q = parseBigInt(Q,16);
2223 this.dmp1 = parseBigInt(DP,16);
2224 this.dmq1 = parseBigInt(DQ,16);
2225 this.coeff = parseBigInt(C,16);
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08002226 } else {
2227 alert("Invalid RSA private key in RSASetPrivateEx");
Alexander Afanasyev1663a412013-03-02 13:52:00 -08002228 }
Alexander Afanasyev1663a412013-03-02 13:52:00 -08002229}
2230
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08002231// Generate a new random private key B bits long, using public expt E
Alexander Afanasyev1663a412013-03-02 13:52:00 -08002232function RSAGenerate(B,E) {
2233 var rng = new SecureRandom();
2234 var qs = B>>1;
2235 this.e = parseInt(E,16);
2236 var ee = new BigInteger(E,16);
2237 for(;;) {
2238 for(;;) {
2239 this.p = new BigInteger(B-qs,1,rng);
2240 if(this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) break;
2241 }
2242 for(;;) {
2243 this.q = new BigInteger(qs,1,rng);
2244 if(this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) break;
2245 }
2246 if(this.p.compareTo(this.q) <= 0) {
2247 var t = this.p;
2248 this.p = this.q;
2249 this.q = t;
2250 }
2251 var p1 = this.p.subtract(BigInteger.ONE); // p1 = p - 1
2252 var q1 = this.q.subtract(BigInteger.ONE); // q1 = q - 1
2253 var phi = p1.multiply(q1);
2254 if(phi.gcd(ee).compareTo(BigInteger.ONE) == 0) {
2255 this.n = this.p.multiply(this.q); // this.n = p * q
2256 this.d = ee.modInverse(phi); // this.d =
2257 this.dmp1 = this.d.mod(p1); // this.dmp1 = d mod (p - 1)
2258 this.dmq1 = this.d.mod(q1); // this.dmq1 = d mod (q - 1)
2259 this.coeff = this.q.modInverse(this.p); // this.coeff = (q ^ -1) mod p
2260 break;
2261 }
2262 }
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08002263 this.isPrivate = true;
Alexander Afanasyev1663a412013-03-02 13:52:00 -08002264}
2265
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08002266// Perform raw private operation on "x": return x^d (mod n)
Alexander Afanasyev1663a412013-03-02 13:52:00 -08002267function RSADoPrivate(x) {
2268 if(this.p == null || this.q == null)
2269 return x.modPow(this.d, this.n);
2270
2271 // TODO: re-calculate any missing CRT params
2272 var xp = x.mod(this.p).modPow(this.dmp1, this.p); // xp=cp?
2273 var xq = x.mod(this.q).modPow(this.dmq1, this.q); // xq=cq?
2274
2275 while(xp.compareTo(xq) < 0)
2276 xp = xp.add(this.p);
2277 // NOTE:
2278 // xp.subtract(xq) => cp -cq
2279 // xp.subtract(xq).multiply(this.coeff).mod(this.p) => (cp - cq) * u mod p = h
2280 // xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq) => cq + (h * q) = M
2281 return xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq);
2282}
2283
2284// Return the PKCS#1 RSA decryption of "ctext".
2285// "ctext" is an even-length hex string and the output is a plain string.
2286function RSADecrypt(ctext) {
2287 var c = parseBigInt(ctext, 16);
2288 var m = this.doPrivate(c);
2289 if(m == null) return null;
2290 return pkcs1unpad2(m, (this.n.bitLength()+7)>>3);
2291}
2292
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08002293// Return the PKCS#1 OAEP RSA decryption of "ctext".
2294// "ctext" is an even-length hex string and the output is a plain string.
2295function RSADecryptOAEP(ctext, hash) {
2296 var c = parseBigInt(ctext, 16);
2297 var m = this.doPrivate(c);
2298 if(m == null) return null;
2299 return oaep_unpad(m, (this.n.bitLength()+7)>>3, hash);
2300}
2301
Alexander Afanasyev1663a412013-03-02 13:52:00 -08002302// Return the PKCS#1 RSA decryption of "ctext".
2303// "ctext" is a Base64-encoded string and the output is a plain string.
2304//function RSAB64Decrypt(ctext) {
2305// var h = b64tohex(ctext);
2306// if(h) return this.decrypt(h); else return null;
2307//}
2308
2309// protected
2310RSAKey.prototype.doPrivate = RSADoPrivate;
2311
2312// public
2313RSAKey.prototype.setPrivate = RSASetPrivate;
2314RSAKey.prototype.setPrivateEx = RSASetPrivateEx;
2315RSAKey.prototype.generate = RSAGenerate;
2316RSAKey.prototype.decrypt = RSADecrypt;
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08002317RSAKey.prototype.decryptOAEP = RSADecryptOAEP;
Alexander Afanasyev1663a412013-03-02 13:52:00 -08002318//RSAKey.prototype.b64_decrypt = RSAB64Decrypt;
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08002319
2320exports.RSAKey = RSAKey;
2321module.exports = exports;
2322/*! crypto-1.1.7.js (c) 2013-2015 Kenji Urushima | kjur.github.com/jsrsasign/license
2323 */
2324/*
2325 * crypto.js - Cryptographic Algorithm Provider class
2326 *
2327 * Copyright (c) 2013-2015 Kenji Urushima (kenji.urushima@gmail.com)
2328 *
2329 * This software is licensed under the terms of the MIT License.
2330 * http://kjur.github.com/jsrsasign/license
2331 *
2332 * The above copyright and license notice shall be
2333 * included in all copies or substantial portions of the Software.
2334 */
2335
2336/**
2337 * @fileOverview
2338 * @name crypto-1.1.js
2339 * @author Kenji Urushima kenji.urushima@gmail.com
2340 * @version 1.1.7 (2015-Oct-11)
2341 * @since jsrsasign 2.2
2342 * @license <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a>
2343 */
2344
2345var CryptoJS = require('./sha256.js').CryptoJS
2346 , intShim = require('jsbn');
2347
2348
2349/**
2350 * kjur's class library name space
2351 * @name KJUR
2352 * @namespace kjur's class library name space
2353 */
2354if (typeof KJUR == "undefined" || !KJUR) KJUR = {};
2355/**
2356 * kjur's cryptographic algorithm provider library name space
2357 * <p>
2358 * This namespace privides following crytpgrahic classes.
2359 * <ul>
2360 * <li>{@link KJUR.crypto.MessageDigest} - Java JCE(cryptograhic extension) style MessageDigest class</li>
2361 * <li>{@link KJUR.crypto.Signature} - Java JCE(cryptograhic extension) style Signature class</li>
2362 * <li>{@link KJUR.crypto.Util} - cryptographic utility functions and properties</li>
2363 * </ul>
2364 * NOTE: Please ignore method summary and document of this namespace. This caused by a bug of jsdoc2.
2365 * </p>
2366 * @name KJUR.crypto
2367 * @namespace
2368 */
2369if (typeof KJUR.crypto == "undefined" || !KJUR.crypto) KJUR.crypto = {};
2370
2371/**
2372 * static object for cryptographic function utilities
2373 * @name KJUR.crypto.Util
2374 * @class static object for cryptographic function utilities
2375 * @property {Array} DIGESTINFOHEAD PKCS#1 DigestInfo heading hexadecimal bytes for each hash algorithms
2376 * @property {Array} DEFAULTPROVIDER associative array of default provider name for each hash and signature algorithms
2377 * @description
2378 */
2379KJUR.crypto.Util = new function() {
2380 this.DIGESTINFOHEAD = {
2381 'sha1': "3021300906052b0e03021a05000414",
2382 'sha224': "302d300d06096086480165030402040500041c",
2383 'sha256': "3031300d060960864801650304020105000420",
2384 'sha384': "3041300d060960864801650304020205000430",
2385 'sha512': "3051300d060960864801650304020305000440",
2386 'md2': "3020300c06082a864886f70d020205000410",
2387 'md5': "3020300c06082a864886f70d020505000410",
2388 'ripemd160': "3021300906052b2403020105000414"
2389 };
2390
2391 /*
2392 * @since crypto 1.1.1
2393 */
2394 this.DEFAULTPROVIDER = {
2395 'md5': 'cryptojs',
2396 'sha1': 'cryptojs',
2397 'sha224': 'cryptojs',
2398 'sha256': 'cryptojs',
2399 'sha384': 'cryptojs',
2400 'sha512': 'cryptojs',
2401 'ripemd160': 'cryptojs',
2402 'hmacmd5': 'cryptojs',
2403 'hmacsha1': 'cryptojs',
2404 'hmacsha224': 'cryptojs',
2405 'hmacsha256': 'cryptojs',
2406 'hmacsha384': 'cryptojs',
2407 'hmacsha512': 'cryptojs',
2408 'hmacripemd160': 'cryptojs',
2409
2410 'MD5withRSA': 'cryptojs/jsrsa',
2411 'SHA1withRSA': 'cryptojs/jsrsa',
2412 'SHA224withRSA': 'cryptojs/jsrsa',
2413 'SHA256withRSA': 'cryptojs/jsrsa',
2414 'SHA384withRSA': 'cryptojs/jsrsa',
2415 'SHA512withRSA': 'cryptojs/jsrsa',
2416 'RIPEMD160withRSA': 'cryptojs/jsrsa',
2417
2418 'MD5withECDSA': 'cryptojs/jsrsa',
2419 'SHA1withECDSA': 'cryptojs/jsrsa',
2420 'SHA224withECDSA': 'cryptojs/jsrsa',
2421 'SHA256withECDSA': 'cryptojs/jsrsa',
2422 'SHA384withECDSA': 'cryptojs/jsrsa',
2423 'SHA512withECDSA': 'cryptojs/jsrsa',
2424 'RIPEMD160withECDSA': 'cryptojs/jsrsa',
2425
2426 'SHA1withDSA': 'cryptojs/jsrsa',
2427 'SHA224withDSA': 'cryptojs/jsrsa',
2428 'SHA256withDSA': 'cryptojs/jsrsa',
2429
2430 'MD5withRSAandMGF1': 'cryptojs/jsrsa',
2431 'SHA1withRSAandMGF1': 'cryptojs/jsrsa',
2432 'SHA224withRSAandMGF1': 'cryptojs/jsrsa',
2433 'SHA256withRSAandMGF1': 'cryptojs/jsrsa',
2434 'SHA384withRSAandMGF1': 'cryptojs/jsrsa',
2435 'SHA512withRSAandMGF1': 'cryptojs/jsrsa',
2436 'RIPEMD160withRSAandMGF1': 'cryptojs/jsrsa'
2437 };
2438
2439 /*
2440 * @since crypto 1.1.2
2441 */
2442 this.CRYPTOJSMESSAGEDIGESTNAME = {
2443 'md5': 'CryptoJS.algo.MD5',
2444 'sha1': 'CryptoJS.algo.SHA1',
2445 'sha224': 'CryptoJS.algo.SHA224',
2446 'sha256': 'CryptoJS.algo.SHA256',
2447 'sha384': 'CryptoJS.algo.SHA384',
2448 'sha512': 'CryptoJS.algo.SHA512',
2449 'ripemd160': 'CryptoJS.algo.RIPEMD160'
2450 };
2451
2452 /**
2453 * get hexadecimal DigestInfo
2454 * @name getDigestInfoHex
2455 * @memberOf KJUR.crypto.Util
2456 * @function
2457 * @param {String} hHash hexadecimal hash value
2458 * @param {String} alg hash algorithm name (ex. 'sha1')
2459 * @return {String} hexadecimal string DigestInfo ASN.1 structure
2460 */
2461 this.getDigestInfoHex = function(hHash, alg) {
2462 if (typeof this.DIGESTINFOHEAD[alg] == "undefined")
2463 throw "alg not supported in Util.DIGESTINFOHEAD: " + alg;
2464 return this.DIGESTINFOHEAD[alg] + hHash;
2465 };
2466
2467 /**
2468 * get PKCS#1 padded hexadecimal DigestInfo
2469 * @name getPaddedDigestInfoHex
2470 * @memberOf KJUR.crypto.Util
2471 * @function
2472 * @param {String} hHash hexadecimal hash value of message to be signed
2473 * @param {String} alg hash algorithm name (ex. 'sha1')
2474 * @param {Integer} keySize key bit length (ex. 1024)
2475 * @return {String} hexadecimal string of PKCS#1 padded DigestInfo
2476 */
2477 this.getPaddedDigestInfoHex = function(hHash, alg, keySize) {
2478 var hDigestInfo = this.getDigestInfoHex(hHash, alg);
2479 var pmStrLen = keySize / 4; // minimum PM length
2480
2481 if (hDigestInfo.length + 22 > pmStrLen) // len(0001+ff(*8)+00+hDigestInfo)=22
2482 throw "key is too short for SigAlg: keylen=" + keySize + "," + alg;
2483
2484 var hHead = "0001";
2485 var hTail = "00" + hDigestInfo;
2486 var hMid = "";
2487 var fLen = pmStrLen - hHead.length - hTail.length;
2488 for (var i = 0; i < fLen; i += 2) {
2489 hMid += "ff";
2490 }
2491 var hPaddedMessage = hHead + hMid + hTail;
2492 return hPaddedMessage;
2493 };
2494
2495 /**
2496 * get hexadecimal hash of string with specified algorithm
2497 * @name hashString
2498 * @memberOf KJUR.crypto.Util
2499 * @function
2500 * @param {String} s input string to be hashed
2501 * @param {String} alg hash algorithm name
2502 * @return {String} hexadecimal string of hash value
2503 * @since 1.1.1
2504 */
2505 this.hashString = function(s, alg) {
2506 var md = new KJUR.crypto.MessageDigest({'alg': alg});
2507 return md.digestString(s);
2508 };
2509
2510 /**
2511 * get hexadecimal hash of hexadecimal string with specified algorithm
2512 * @name hashHex
2513 * @memberOf KJUR.crypto.Util
2514 * @function
2515 * @param {String} sHex input hexadecimal string to be hashed
2516 * @param {String} alg hash algorithm name
2517 * @return {String} hexadecimal string of hash value
2518 * @since 1.1.1
2519 */
2520 this.hashHex = function(sHex, alg) {
2521 var md = new KJUR.crypto.MessageDigest({'alg': alg});
2522 return md.digestHex(sHex);
2523 };
2524
2525 /**
2526 * get hexadecimal SHA1 hash of string
2527 * @name sha1
2528 * @memberOf KJUR.crypto.Util
2529 * @function
2530 * @param {String} s input string to be hashed
2531 * @return {String} hexadecimal string of hash value
2532 * @since 1.0.3
2533 */
2534 this.sha1 = function(s) {
2535 var md = new KJUR.crypto.MessageDigest({'alg':'sha1', 'prov':'cryptojs'});
2536 return md.digestString(s);
2537 };
2538
2539 /**
2540 * get hexadecimal SHA256 hash of string
2541 * @name sha256
2542 * @memberOf KJUR.crypto.Util
2543 * @function
2544 * @param {String} s input string to be hashed
2545 * @return {String} hexadecimal string of hash value
2546 * @since 1.0.3
2547 */
2548 this.sha256 = function(s) {
2549 var md = new KJUR.crypto.MessageDigest({'alg':'sha256', 'prov':'cryptojs'});
2550 return md.digestString(s);
2551 };
2552
2553 this.sha256Hex = function(s) {
2554 var md = new KJUR.crypto.MessageDigest({'alg':'sha256', 'prov':'cryptojs'});
2555 return md.digestHex(s);
2556 };
2557
2558 /**
2559 * get hexadecimal SHA512 hash of string
2560 * @name sha512
2561 * @memberOf KJUR.crypto.Util
2562 * @function
2563 * @param {String} s input string to be hashed
2564 * @return {String} hexadecimal string of hash value
2565 * @since 1.0.3
2566 */
2567 this.sha512 = function(s) {
2568 var md = new KJUR.crypto.MessageDigest({'alg':'sha512', 'prov':'cryptojs'});
2569 return md.digestString(s);
2570 };
2571
2572 this.sha512Hex = function(s) {
2573 var md = new KJUR.crypto.MessageDigest({'alg':'sha512', 'prov':'cryptojs'});
2574 return md.digestHex(s);
2575 };
2576
2577 /**
2578 * get hexadecimal MD5 hash of string
2579 * @name md5
2580 * @memberOf KJUR.crypto.Util
2581 * @function
2582 * @param {String} s input string to be hashed
2583 * @return {String} hexadecimal string of hash value
2584 * @since 1.0.3
2585 */
2586 this.md5 = function(s) {
2587 var md = new KJUR.crypto.MessageDigest({'alg':'md5', 'prov':'cryptojs'});
2588 return md.digestString(s);
2589 };
2590
2591 /**
2592 * get hexadecimal RIPEMD160 hash of string
2593 * @name ripemd160
2594 * @memberOf KJUR.crypto.Util
2595 * @function
2596 * @param {String} s input string to be hashed
2597 * @return {String} hexadecimal string of hash value
2598 * @since 1.0.3
2599 */
2600 this.ripemd160 = function(s) {
2601 var md = new KJUR.crypto.MessageDigest({'alg':'ripemd160', 'prov':'cryptojs'});
2602 return md.digestString(s);
2603 };
2604
2605 /*
2606 * @since 1.1.2
2607 */
2608 this.getCryptoJSMDByName = function(s) {
2609
2610 };
2611};
2612
2613/**
2614 * MessageDigest class which is very similar to java.security.MessageDigest class
2615 * @name KJUR.crypto.MessageDigest
2616 * @class MessageDigest class which is very similar to java.security.MessageDigest class
2617 * @param {Array} params parameters for constructor
2618 * @description
2619 * <br/>
2620 * Currently this supports following algorithm and providers combination:
2621 * <ul>
2622 * <li>md5 - cryptojs</li>
2623 * <li>sha1 - cryptojs</li>
2624 * <li>sha224 - cryptojs</li>
2625 * <li>sha256 - cryptojs</li>
2626 * <li>sha384 - cryptojs</li>
2627 * <li>sha512 - cryptojs</li>
2628 * <li>ripemd160 - cryptojs</li>
2629 * <li>sha256 - sjcl (NEW from crypto.js 1.0.4)</li>
2630 * </ul>
2631 * @example
2632 * // CryptoJS provider sample
2633 * var md = new KJUR.crypto.MessageDigest({alg: "sha1", prov: "cryptojs"});
2634 * md.updateString('aaa')
2635 * var mdHex = md.digest()
2636 *
2637 * // SJCL(Stanford JavaScript Crypto Library) provider sample
2638 * var md = new KJUR.crypto.MessageDigest({alg: "sha256", prov: "sjcl"}); // sjcl supports sha256 only
2639 * md.updateString('aaa')
2640 * var mdHex = md.digest()
2641 */
2642KJUR.crypto.MessageDigest = function(params) {
2643 var md = null;
2644 var algName = null;
2645 var provName = null;
2646
2647 /**
2648 * set hash algorithm and provider
2649 * @name setAlgAndProvider
2650 * @memberOf KJUR.crypto.MessageDigest
2651 * @function
2652 * @param {String} alg hash algorithm name
2653 * @param {String} prov provider name
2654 * @description
2655 * @example
2656 * // for SHA1
2657 * md.setAlgAndProvider('sha1', 'cryptojs');
2658 * // for RIPEMD160
2659 * md.setAlgAndProvider('ripemd160', 'cryptojs');
2660 */
2661 this.setAlgAndProvider = function(alg, prov) {
2662 if (alg != null && prov === undefined) prov = KJUR.crypto.Util.DEFAULTPROVIDER[alg];
2663
2664 // for cryptojs
2665 if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(alg) != -1 &&
2666 prov == 'cryptojs') {
2667 try {
2668 this.md = eval(KJUR.crypto.Util.CRYPTOJSMESSAGEDIGESTNAME[alg]).create();
2669 } catch (ex) {
2670 throw "setAlgAndProvider hash alg set fail alg=" + alg + "/" + ex;
2671 }
2672 this.updateString = function(str) {
2673 this.md.update(str);
2674 };
2675 this.updateHex = function(hex) {
2676 var wHex = CryptoJS.enc.Hex.parse(hex);
2677 this.md.update(wHex);
2678 };
2679 this.digest = function() {
2680 var hash = this.md.finalize();
2681 return hash.toString(CryptoJS.enc.Hex);
2682 };
2683 this.digestString = function(str) {
2684 this.updateString(str);
2685 return this.digest();
2686 };
2687 this.digestHex = function(hex) {
2688 this.updateHex(hex);
2689 return this.digest();
2690 };
2691 }
2692 if (':sha256:'.indexOf(alg) != -1 &&
2693 prov == 'sjcl') {
2694 try {
2695 this.md = new sjcl.hash.sha256();
2696 } catch (ex) {
2697 throw "setAlgAndProvider hash alg set fail alg=" + alg + "/" + ex;
2698 }
2699 this.updateString = function(str) {
2700 this.md.update(str);
2701 };
2702 this.updateHex = function(hex) {
2703 var baHex = sjcl.codec.hex.toBits(hex);
2704 this.md.update(baHex);
2705 };
2706 this.digest = function() {
2707 var hash = this.md.finalize();
2708 return sjcl.codec.hex.fromBits(hash);
2709 };
2710 this.digestString = function(str) {
2711 this.updateString(str);
2712 return this.digest();
2713 };
2714 this.digestHex = function(hex) {
2715 this.updateHex(hex);
2716 return this.digest();
2717 };
2718 }
2719 };
2720
2721 /**
2722 * update digest by specified string
2723 * @name updateString
2724 * @memberOf KJUR.crypto.MessageDigest
2725 * @function
2726 * @param {String} str string to update
2727 * @description
2728 * @example
2729 * md.updateString('New York');
2730 */
2731 this.updateString = function(str) {
2732 throw "updateString(str) not supported for this alg/prov: " + this.algName + "/" + this.provName;
2733 };
2734
2735 /**
2736 * update digest by specified hexadecimal string
2737 * @name updateHex
2738 * @memberOf KJUR.crypto.MessageDigest
2739 * @function
2740 * @param {String} hex hexadecimal string to update
2741 * @description
2742 * @example
2743 * md.updateHex('0afe36');
2744 */
2745 this.updateHex = function(hex) {
2746 throw "updateHex(hex) not supported for this alg/prov: " + this.algName + "/" + this.provName;
2747 };
2748
2749 /**
2750 * completes hash calculation and returns hash result
2751 * @name digest
2752 * @memberOf KJUR.crypto.MessageDigest
2753 * @function
2754 * @description
2755 * @example
2756 * md.digest()
2757 */
2758 this.digest = function() {
2759 throw "digest() not supported for this alg/prov: " + this.algName + "/" + this.provName;
2760 };
2761
2762 /**
2763 * performs final update on the digest using string, then completes the digest computation
2764 * @name digestString
2765 * @memberOf KJUR.crypto.MessageDigest
2766 * @function
2767 * @param {String} str string to final update
2768 * @description
2769 * @example
2770 * md.digestString('aaa')
2771 */
2772 this.digestString = function(str) {
2773 throw "digestString(str) not supported for this alg/prov: " + this.algName + "/" + this.provName;
2774 };
2775
2776 /**
2777 * performs final update on the digest using hexadecimal string, then completes the digest computation
2778 * @name digestHex
2779 * @memberOf KJUR.crypto.MessageDigest
2780 * @function
2781 * @param {String} hex hexadecimal string to final update
2782 * @description
2783 * @example
2784 * md.digestHex('0f2abd')
2785 */
2786 this.digestHex = function(hex) {
2787 throw "digestHex(hex) not supported for this alg/prov: " + this.algName + "/" + this.provName;
2788 };
2789
2790 if (params !== undefined) {
2791 if (params['alg'] !== undefined) {
2792 this.algName = params['alg'];
2793 if (params['prov'] === undefined)
2794 this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName];
2795 this.setAlgAndProvider(this.algName, this.provName);
2796 }
2797 }
2798};
2799
2800/**
2801 * Mac(Message Authentication Code) class which is very similar to java.security.Mac class
2802 * @name KJUR.crypto.Mac
2803 * @class Mac class which is very similar to java.security.Mac class
2804 * @param {Array} params parameters for constructor
2805 * @description
2806 * <br/>
2807 * Currently this supports following algorithm and providers combination:
2808 * <ul>
2809 * <li>hmacmd5 - cryptojs</li>
2810 * <li>hmacsha1 - cryptojs</li>
2811 * <li>hmacsha224 - cryptojs</li>
2812 * <li>hmacsha256 - cryptojs</li>
2813 * <li>hmacsha384 - cryptojs</li>
2814 * <li>hmacsha512 - cryptojs</li>
2815 * </ul>
2816 * NOTE: HmacSHA224 and HmacSHA384 issue was fixed since jsrsasign 4.1.4.
2817 * Please use 'ext/cryptojs-312-core-fix*.js' instead of 'core.js' of original CryptoJS
2818 * to avoid those issue.
2819 * <br/>
2820 * NOTE2: Hmac signature bug was fixed in jsrsasign 4.9.0 by providing CryptoJS
2821 * bug workaround.
2822 * <br/>
2823 * Please see {@link KJUR.crypto.Mac.setPassword}, how to provide password
2824 * in various ways in detail.
2825 * @example
2826 * var mac = new KJUR.crypto.Mac({alg: "HmacSHA1", "pass": "pass"});
2827 * mac.updateString('aaa')
2828 * var macHex = md.doFinal()
2829 *
2830 * // other password representation
2831 * var mac = new KJUR.crypto.Mac({alg: "HmacSHA256", "pass": {"hex": "6161"}});
2832 * var mac = new KJUR.crypto.Mac({alg: "HmacSHA256", "pass": {"utf8": "aa"}});
2833 * var mac = new KJUR.crypto.Mac({alg: "HmacSHA256", "pass": {"rstr": "\x61\x61"}});
2834 * var mac = new KJUR.crypto.Mac({alg: "HmacSHA256", "pass": {"b64": "Mi02/+...a=="}});
2835 * var mac = new KJUR.crypto.Mac({alg: "HmacSHA256", "pass": {"b64u": "Mi02_-...a"}});
2836 */
2837KJUR.crypto.Mac = function(params) {
2838 var mac = null;
2839 var pass = null;
2840 var algName = null;
2841 var provName = null;
2842 var algProv = null;
2843
2844 this.setAlgAndProvider = function(alg, prov) {
2845 alg = alg.toLowerCase();
2846
2847 if (alg == null) alg = "hmacsha1";
2848
2849 alg = alg.toLowerCase();
2850 if (alg.substr(0, 4) != "hmac") {
2851 throw "setAlgAndProvider unsupported HMAC alg: " + alg;
2852 }
2853
2854 if (prov === undefined) prov = KJUR.crypto.Util.DEFAULTPROVIDER[alg];
2855 this.algProv = alg + "/" + prov;
2856
2857 var hashAlg = alg.substr(4);
2858
2859 // for cryptojs
2860 if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(hashAlg) != -1 &&
2861 prov == 'cryptojs') {
2862 try {
2863 var mdObj = eval(KJUR.crypto.Util.CRYPTOJSMESSAGEDIGESTNAME[hashAlg]);
2864 this.mac = CryptoJS.algo.HMAC.create(mdObj, this.pass);
2865 } catch (ex) {
2866 throw "setAlgAndProvider hash alg set fail hashAlg=" + hashAlg + "/" + ex;
2867 }
2868 this.updateString = function(str) {
2869 this.mac.update(str);
2870 };
2871 this.updateHex = function(hex) {
2872 var wHex = CryptoJS.enc.Hex.parse(hex);
2873 this.mac.update(wHex);
2874 };
2875 this.doFinal = function() {
2876 var hash = this.mac.finalize();
2877 return hash.toString(CryptoJS.enc.Hex);
2878 };
2879 this.doFinalString = function(str) {
2880 this.updateString(str);
2881 return this.doFinal();
2882 };
2883 this.doFinalHex = function(hex) {
2884 this.updateHex(hex);
2885 return this.doFinal();
2886 };
2887 }
2888 };
2889
2890 /**
2891 * update digest by specified string
2892 * @name updateString
2893 * @memberOf KJUR.crypto.Mac
2894 * @function
2895 * @param {String} str string to update
2896 * @description
2897 * @example
2898 * md.updateString('New York');
2899 */
2900 this.updateString = function(str) {
2901 throw "updateString(str) not supported for this alg/prov: " + this.algProv;
2902 };
2903
2904 /**
2905 * update digest by specified hexadecimal string
2906 * @name updateHex
2907 * @memberOf KJUR.crypto.Mac
2908 * @function
2909 * @param {String} hex hexadecimal string to update
2910 * @description
2911 * @example
2912 * md.updateHex('0afe36');
2913 */
2914 this.updateHex = function(hex) {
2915 throw "updateHex(hex) not supported for this alg/prov: " + this.algProv;
2916 };
2917
2918 /**
2919 * completes hash calculation and returns hash result
2920 * @name doFinal
2921 * @memberOf KJUR.crypto.Mac
2922 * @function
2923 * @description
2924 * @example
2925 * md.digest()
2926 */
2927 this.doFinal = function() {
2928 throw "digest() not supported for this alg/prov: " + this.algProv;
2929 };
2930
2931 /**
2932 * performs final update on the digest using string, then completes the digest computation
2933 * @name doFinalString
2934 * @memberOf KJUR.crypto.Mac
2935 * @function
2936 * @param {String} str string to final update
2937 * @description
2938 * @example
2939 * md.digestString('aaa')
2940 */
2941 this.doFinalString = function(str) {
2942 throw "digestString(str) not supported for this alg/prov: " + this.algProv;
2943 };
2944
2945 /**
2946 * performs final update on the digest using hexadecimal string,
2947 * then completes the digest computation
2948 * @name doFinalHex
2949 * @memberOf KJUR.crypto.Mac
2950 * @function
2951 * @param {String} hex hexadecimal string to final update
2952 * @description
2953 * @example
2954 * md.digestHex('0f2abd')
2955 */
2956 this.doFinalHex = function(hex) {
2957 throw "digestHex(hex) not supported for this alg/prov: " + this.algProv;
2958 };
2959
2960 /**
2961 * set password for Mac
2962 * @name setPassword
2963 * @memberOf KJUR.crypto.Mac
2964 * @function
2965 * @param {Object} pass password for Mac
2966 * @since crypto 1.1.7 jsrsasign 4.9.0
2967 * @description
2968 * This method will set password for (H)Mac internally.
2969 * Argument 'pass' can be specified as following:
2970 * <ul>
2971 * <li>even length string of 0..9, a..f or A-F: implicitly specified as hexadecimal string</li>
2972 * <li>not above string: implicitly specified as raw string</li>
2973 * <li>{rstr: "\x65\x70"}: explicitly specified as raw string</li>
2974 * <li>{hex: "6570"}: explicitly specified as hexacedimal string</li>
2975 * <li>{utf8: "秘密"}: explicitly specified as UTF8 string</li>
2976 * <li>{b64: "Mi78..=="}: explicitly specified as Base64 string</li>
2977 * <li>{b64u: "Mi7-_"}: explicitly specified as Base64URL string</li>
2978 * </ul>
2979 * It is *STRONGLY RECOMMENDED* that explicit representation of password argument
2980 * to avoid ambiguity. For example string "6161" can mean a string "6161" or
2981 * a hexadecimal string of "aa" (i.e. \x61\x61).
2982 * @example
2983 * mac = KJUR.crypto.Mac({'alg': 'hmacsha256'});
2984 * // set password by implicit raw string
2985 * mac.setPassword("\x65\x70\xb9\x0b");
2986 * mac.setPassword("password");
2987 * // set password by implicit hexadecimal string
2988 * mac.setPassword("6570b90b");
2989 * mac.setPassword("6570B90B");
2990 * // set password by explicit raw string
2991 * mac.setPassword({"rstr": "\x65\x70\xb9\x0b"});
2992 * // set password by explicit hexadecimal string
2993 * mac.setPassword({"hex": "6570b90b"});
2994 * // set password by explicit utf8 string
2995 * mac.setPassword({"utf8": "passwordパスワード");
2996 * // set password by explicit Base64 string
2997 * mac.setPassword({"b64": "Mb+c3f/=="});
2998 * // set password by explicit Base64URL string
2999 * mac.setPassword({"b64u": "Mb-c3f_"});
3000 */
3001 this.setPassword = function(pass) {
3002 // internal this.pass shall be CryptoJS DWord Object for CryptoJS bug
3003 // work around. CrytoJS HMac password can be passed by
3004 // raw string as described in the manual however it doesn't
3005 // work properly in some case. If password was passed
3006 // by CryptoJS DWord which is not described in the manual
3007 // it seems to work. (fixed since crypto 1.1.7)
3008
3009 if (typeof pass == 'string') {
3010 var hPass = pass;
3011 if (pass.length % 2 == 1 || ! pass.match(/^[0-9A-Fa-f]+$/)) { // raw str
3012 hPass = rstrtohex(pass);
3013 }
3014 this.pass = CryptoJS.enc.Hex.parse(hPass);
3015 return;
3016 }
3017
3018 if (typeof pass != 'object')
3019 throw "KJUR.crypto.Mac unsupported password type: " + pass;
3020
3021 var hPass = null;
3022 if (pass.hex !== undefined) {
3023 if (pass.hex.length % 2 != 0 || ! pass.hex.match(/^[0-9A-Fa-f]+$/))
3024 throw "Mac: wrong hex password: " + pass.hex;
3025 hPass = pass.hex;
3026 }
3027 if (pass.utf8 !== undefined) hPass = utf8tohex(pass.utf8);
3028 if (pass.rstr !== undefined) hPass = rstrtohex(pass.rstr);
3029 if (pass.b64 !== undefined) hPass = b64tohex(pass.b64);
3030 if (pass.b64u !== undefined) hPass = b64utohex(pass.b64u);
3031
3032 if (hPass == null)
3033 throw "KJUR.crypto.Mac unsupported password type: " + pass;
3034
3035 this.pass = CryptoJS.enc.Hex.parse(hPass);
3036 };
3037
3038 if (params !== undefined) {
3039 if (params.pass !== undefined) {
3040 this.setPassword(params.pass);
3041 }
3042 if (params.alg !== undefined) {
3043 this.algName = params.alg;
3044 if (params['prov'] === undefined)
3045 this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName];
3046 this.setAlgAndProvider(this.algName, this.provName);
3047 }
3048 }
3049};
3050
3051/**
3052 * Signature class which is very similar to java.security.Signature class
3053 * @name KJUR.crypto.Signature
3054 * @class Signature class which is very similar to java.security.Signature class
3055 * @param {Array} params parameters for constructor
3056 * @property {String} state Current state of this signature object whether 'SIGN', 'VERIFY' or null
3057 * @description
3058 * <br/>
3059 * As for params of constructor's argument, it can be specify following attributes:
3060 * <ul>
3061 * <li>alg - signature algorithm name (ex. {MD5,SHA1,SHA224,SHA256,SHA384,SHA512,RIPEMD160}with{RSA,ECDSA,DSA})</li>
3062 * <li>provider - currently 'cryptojs/jsrsa' only</li>
3063 * </ul>
3064 * <h4>SUPPORTED ALGORITHMS AND PROVIDERS</h4>
3065 * This Signature class supports following signature algorithm and provider names:
3066 * <ul>
3067 * <li>MD5withRSA - cryptojs/jsrsa</li>
3068 * <li>SHA1withRSA - cryptojs/jsrsa</li>
3069 * <li>SHA224withRSA - cryptojs/jsrsa</li>
3070 * <li>SHA256withRSA - cryptojs/jsrsa</li>
3071 * <li>SHA384withRSA - cryptojs/jsrsa</li>
3072 * <li>SHA512withRSA - cryptojs/jsrsa</li>
3073 * <li>RIPEMD160withRSA - cryptojs/jsrsa</li>
3074 * <li>MD5withECDSA - cryptojs/jsrsa</li>
3075 * <li>SHA1withECDSA - cryptojs/jsrsa</li>
3076 * <li>SHA224withECDSA - cryptojs/jsrsa</li>
3077 * <li>SHA256withECDSA - cryptojs/jsrsa</li>
3078 * <li>SHA384withECDSA - cryptojs/jsrsa</li>
3079 * <li>SHA512withECDSA - cryptojs/jsrsa</li>
3080 * <li>RIPEMD160withECDSA - cryptojs/jsrsa</li>
3081 * <li>MD5withRSAandMGF1 - cryptojs/jsrsa</li>
3082 * <li>SHA1withRSAandMGF1 - cryptojs/jsrsa</li>
3083 * <li>SHA224withRSAandMGF1 - cryptojs/jsrsa</li>
3084 * <li>SHA256withRSAandMGF1 - cryptojs/jsrsa</li>
3085 * <li>SHA384withRSAandMGF1 - cryptojs/jsrsa</li>
3086 * <li>SHA512withRSAandMGF1 - cryptojs/jsrsa</li>
3087 * <li>RIPEMD160withRSAandMGF1 - cryptojs/jsrsa</li>
3088 * <li>SHA1withDSA - cryptojs/jsrsa</li>
3089 * <li>SHA224withDSA - cryptojs/jsrsa</li>
3090 * <li>SHA256withDSA - cryptojs/jsrsa</li>
3091 * </ul>
3092 * Here are supported elliptic cryptographic curve names and their aliases for ECDSA:
3093 * <ul>
3094 * <li>secp256k1</li>
3095 * <li>secp256r1, NIST P-256, P-256, prime256v1</li>
3096 * <li>secp384r1, NIST P-384, P-384</li>
3097 * </ul>
3098 * NOTE1: DSA signing algorithm is also supported since crypto 1.1.5.
3099 * <h4>EXAMPLES</h4>
3100 * @example
3101 * // RSA signature generation
3102 * var sig = new KJUR.crypto.Signature({"alg": "SHA1withRSA"});
3103 * sig.init(prvKeyPEM);
3104 * sig.updateString('aaa');
3105 * var hSigVal = sig.sign();
3106 *
3107 * // DSA signature validation
3108 * var sig2 = new KJUR.crypto.Signature({"alg": "SHA1withDSA"});
3109 * sig2.init(certPEM);
3110 * sig.updateString('aaa');
3111 * var isValid = sig2.verify(hSigVal);
3112 *
3113 * // ECDSA signing
3114 * var sig = new KJUR.crypto.Signature({'alg':'SHA1withECDSA'});
3115 * sig.init(prvKeyPEM);
3116 * sig.updateString('aaa');
3117 * var sigValueHex = sig.sign();
3118 *
3119 * // ECDSA verifying
3120 * var sig2 = new KJUR.crypto.Signature({'alg':'SHA1withECDSA'});
3121 * sig.init(certPEM);
3122 * sig.updateString('aaa');
3123 * var isValid = sig.verify(sigValueHex);
3124 */
3125KJUR.crypto.Signature = function(params) {
3126 var prvKey = null; // RSAKey/KJUR.crypto.{ECDSA,DSA} object for signing
3127 var pubKey = null; // RSAKey/KJUR.crypto.{ECDSA,DSA} object for verifying
3128
3129 var md = null; // KJUR.crypto.MessageDigest object
3130 var sig = null;
3131 var algName = null;
3132 var provName = null;
3133 var algProvName = null;
3134 var mdAlgName = null;
3135 var pubkeyAlgName = null; // rsa,ecdsa,rsaandmgf1(=rsapss)
3136 var state = null;
3137 var pssSaltLen = -1;
3138 var initParams = null;
3139
3140 var sHashHex = null; // hex hash value for hex
3141 var hDigestInfo = null;
3142 var hPaddedDigestInfo = null;
3143 var hSign = null;
3144
3145 this._setAlgNames = function() {
3146 if (this.algName.match(/^(.+)with(.+)$/)) {
3147 this.mdAlgName = RegExp.$1.toLowerCase();
3148 this.pubkeyAlgName = RegExp.$2.toLowerCase();
3149 }
3150 };
3151
3152 this._zeroPaddingOfSignature = function(hex, bitLength) {
3153 var s = "";
3154 var nZero = bitLength / 4 - hex.length;
3155 for (var i = 0; i < nZero; i++) {
3156 s = s + "0";
3157 }
3158 return s + hex;
3159 };
3160
3161 /**
3162 * set signature algorithm and provider
3163 * @name setAlgAndProvider
3164 * @memberOf KJUR.crypto.Signature
3165 * @function
3166 * @param {String} alg signature algorithm name
3167 * @param {String} prov provider name
3168 * @description
3169 * @example
3170 * md.setAlgAndProvider('SHA1withRSA', 'cryptojs/jsrsa');
3171 */
3172 this.setAlgAndProvider = function(alg, prov) {
3173 this._setAlgNames();
3174 if (prov != 'cryptojs/jsrsa')
3175 throw "provider not supported: " + prov;
3176
3177 if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(this.mdAlgName) != -1) {
3178 try {
3179 this.md = new KJUR.crypto.MessageDigest({'alg':this.mdAlgName});
3180 } catch (ex) {
3181 throw "setAlgAndProvider hash alg set fail alg=" +
3182 this.mdAlgName + "/" + ex;
3183 }
3184
3185 this.init = function(keyparam, pass) {
3186 var keyObj = null;
3187 try {
3188 if (pass === undefined) {
3189 keyObj = KEYUTIL.getKey(keyparam);
3190 } else {
3191 keyObj = KEYUTIL.getKey(keyparam, pass);
3192 }
3193 } catch (ex) {
3194 throw "init failed:" + ex;
3195 }
3196
3197 if (keyObj.isPrivate === true) {
3198 this.prvKey = keyObj;
3199 this.state = "SIGN";
3200 } else if (keyObj.isPublic === true) {
3201 this.pubKey = keyObj;
3202 this.state = "VERIFY";
3203 } else {
3204 throw "init failed.:" + keyObj;
3205 }
3206 };
3207
3208 this.initSign = function(params) {
3209 if (typeof params['ecprvhex'] == 'string' &&
3210 typeof params['eccurvename'] == 'string') {
3211 this.ecprvhex = params['ecprvhex'];
3212 this.eccurvename = params['eccurvename'];
3213 } else {
3214 this.prvKey = params;
3215 }
3216 this.state = "SIGN";
3217 };
3218
3219 this.initVerifyByPublicKey = function(params) {
3220 if (typeof params['ecpubhex'] == 'string' &&
3221 typeof params['eccurvename'] == 'string') {
3222 this.ecpubhex = params['ecpubhex'];
3223 this.eccurvename = params['eccurvename'];
3224 } else if (params instanceof KJUR.crypto.ECDSA) {
3225 this.pubKey = params;
3226 } else if (params instanceof RSAKey) {
3227 this.pubKey = params;
3228 }
3229 this.state = "VERIFY";
3230 };
3231
3232 this.initVerifyByCertificatePEM = function(certPEM) {
3233 var x509 = new X509();
3234 x509.readCertPEM(certPEM);
3235 this.pubKey = x509.subjectPublicKeyRSA;
3236 this.state = "VERIFY";
3237 };
3238
3239 this.updateString = function(str) {
3240 this.md.updateString(str);
3241 };
3242
3243 this.updateHex = function(hex) {
3244 this.md.updateHex(hex);
3245 };
3246
3247 this.sign = function() {
3248 this.sHashHex = this.md.digest();
3249 if (typeof this.ecprvhex != "undefined" &&
3250 typeof this.eccurvename != "undefined") {
3251 var ec = new KJUR.crypto.ECDSA({'curve': this.eccurvename});
3252 this.hSign = ec.signHex(this.sHashHex, this.ecprvhex);
3253 } else if (this.prvKey instanceof RSAKey &&
3254 this.pubkeyAlgName == "rsaandmgf1") {
3255 this.hSign = this.prvKey.signWithMessageHashPSS(this.sHashHex,
3256 this.mdAlgName,
3257 this.pssSaltLen);
3258 } else if (this.prvKey instanceof RSAKey &&
3259 this.pubkeyAlgName == "rsa") {
3260 this.hSign = this.prvKey.signWithMessageHash(this.sHashHex,
3261 this.mdAlgName);
3262 } else if (this.prvKey instanceof KJUR.crypto.ECDSA) {
3263 this.hSign = this.prvKey.signWithMessageHash(this.sHashHex);
3264 } else if (this.prvKey instanceof KJUR.crypto.DSA) {
3265 this.hSign = this.prvKey.signWithMessageHash(this.sHashHex);
3266 } else {
3267 throw "Signature: unsupported public key alg: " + this.pubkeyAlgName;
3268 }
3269 return this.hSign;
3270 };
3271 this.signString = function(str) {
3272 this.updateString(str);
3273 return this.sign();
3274 };
3275 this.signHex = function(hex) {
3276 this.updateHex(hex);
3277 return this.sign();
3278 };
3279 this.verify = function(hSigVal) {
3280 this.sHashHex = this.md.digest();
3281 if (typeof this.ecpubhex != "undefined" &&
3282 typeof this.eccurvename != "undefined") {
3283 var ec = new KJUR.crypto.ECDSA({curve: this.eccurvename});
3284 return ec.verifyHex(this.sHashHex, hSigVal, this.ecpubhex);
3285 } else if (this.pubKey instanceof RSAKey &&
3286 this.pubkeyAlgName == "rsaandmgf1") {
3287 return this.pubKey.verifyWithMessageHashPSS(this.sHashHex, hSigVal,
3288 this.mdAlgName,
3289 this.pssSaltLen);
3290 } else if (this.pubKey instanceof RSAKey &&
3291 this.pubkeyAlgName == "rsa") {
3292 return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal);
3293 } else if (this.pubKey instanceof KJUR.crypto.ECDSA) {
3294 return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal);
3295 } else if (this.pubKey instanceof KJUR.crypto.DSA) {
3296 return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal);
3297 } else {
3298 throw "Signature: unsupported public key alg: " + this.pubkeyAlgName;
3299 }
3300 };
3301 }
3302 };
3303
3304 /**
3305 * Initialize this object for signing or verifying depends on key
3306 * @name init
3307 * @memberOf KJUR.crypto.Signature
3308 * @function
3309 * @param {Object} key specifying public or private key as plain/encrypted PKCS#5/8 PEM file, certificate PEM or {@link RSAKey}, {@link KJUR.crypto.DSA} or {@link KJUR.crypto.ECDSA} object
3310 * @param {String} pass (OPTION) passcode for encrypted private key
3311 * @since crypto 1.1.3
3312 * @description
3313 * This method is very useful initialize method for Signature class since
3314 * you just specify key then this method will automatically initialize it
3315 * using {@link KEYUTIL.getKey} method.
3316 * As for 'key', following argument type are supported:
3317 * <h5>signing</h5>
3318 * <ul>
3319 * <li>PEM formatted PKCS#8 encrypted RSA/ECDSA private key concluding "BEGIN ENCRYPTED PRIVATE KEY"</li>
3320 * <li>PEM formatted PKCS#5 encrypted RSA/DSA private key concluding "BEGIN RSA/DSA PRIVATE KEY" and ",ENCRYPTED"</li>
3321 * <li>PEM formatted PKCS#8 plain RSA/ECDSA private key concluding "BEGIN PRIVATE KEY"</li>
3322 * <li>PEM formatted PKCS#5 plain RSA/DSA private key concluding "BEGIN RSA/DSA PRIVATE KEY" without ",ENCRYPTED"</li>
3323 * <li>RSAKey object of private key</li>
3324 * <li>KJUR.crypto.ECDSA object of private key</li>
3325 * <li>KJUR.crypto.DSA object of private key</li>
3326 * </ul>
3327 * <h5>verification</h5>
3328 * <ul>
3329 * <li>PEM formatted PKCS#8 RSA/EC/DSA public key concluding "BEGIN PUBLIC KEY"</li>
3330 * <li>PEM formatted X.509 certificate with RSA/EC/DSA public key concluding
3331 * "BEGIN CERTIFICATE", "BEGIN X509 CERTIFICATE" or "BEGIN TRUSTED CERTIFICATE".</li>
3332 * <li>RSAKey object of public key</li>
3333 * <li>KJUR.crypto.ECDSA object of public key</li>
3334 * <li>KJUR.crypto.DSA object of public key</li>
3335 * </ul>
3336 * @example
3337 * sig.init(sCertPEM)
3338 */
3339 this.init = function(key, pass) {
3340 throw "init(key, pass) not supported for this alg:prov=" +
3341 this.algProvName;
3342 };
3343
3344 /**
3345 * Initialize this object for verifying with a public key
3346 * @name initVerifyByPublicKey
3347 * @memberOf KJUR.crypto.Signature
3348 * @function
3349 * @param {Object} param RSAKey object of public key or associative array for ECDSA
3350 * @since 1.0.2
3351 * @deprecated from crypto 1.1.5. please use init() method instead.
3352 * @description
3353 * Public key information will be provided as 'param' parameter and the value will be
3354 * following:
3355 * <ul>
3356 * <li>{@link RSAKey} object for RSA verification</li>
3357 * <li>associative array for ECDSA verification
3358 * (ex. <code>{'ecpubhex': '041f..', 'eccurvename': 'secp256r1'}</code>)
3359 * </li>
3360 * </ul>
3361 * @example
3362 * sig.initVerifyByPublicKey(rsaPrvKey)
3363 */
3364 this.initVerifyByPublicKey = function(rsaPubKey) {
3365 throw "initVerifyByPublicKey(rsaPubKeyy) not supported for this alg:prov=" +
3366 this.algProvName;
3367 };
3368
3369 /**
3370 * Initialize this object for verifying with a certficate
3371 * @name initVerifyByCertificatePEM
3372 * @memberOf KJUR.crypto.Signature
3373 * @function
3374 * @param {String} certPEM PEM formatted string of certificate
3375 * @since 1.0.2
3376 * @deprecated from crypto 1.1.5. please use init() method instead.
3377 * @description
3378 * @example
3379 * sig.initVerifyByCertificatePEM(certPEM)
3380 */
3381 this.initVerifyByCertificatePEM = function(certPEM) {
3382 throw "initVerifyByCertificatePEM(certPEM) not supported for this alg:prov=" +
3383 this.algProvName;
3384 };
3385
3386 /**
3387 * Initialize this object for signing
3388 * @name initSign
3389 * @memberOf KJUR.crypto.Signature
3390 * @function
3391 * @param {Object} param RSAKey object of public key or associative array for ECDSA
3392 * @deprecated from crypto 1.1.5. please use init() method instead.
3393 * @description
3394 * Private key information will be provided as 'param' parameter and the value will be
3395 * following:
3396 * <ul>
3397 * <li>{@link RSAKey} object for RSA signing</li>
3398 * <li>associative array for ECDSA signing
3399 * (ex. <code>{'ecprvhex': '1d3f..', 'eccurvename': 'secp256r1'}</code>)</li>
3400 * </ul>
3401 * @example
3402 * sig.initSign(prvKey)
3403 */
3404 this.initSign = function(prvKey) {
3405 throw "initSign(prvKey) not supported for this alg:prov=" + this.algProvName;
3406 };
3407
3408 /**
3409 * Updates the data to be signed or verified by a string
3410 * @name updateString
3411 * @memberOf KJUR.crypto.Signature
3412 * @function
3413 * @param {String} str string to use for the update
3414 * @description
3415 * @example
3416 * sig.updateString('aaa')
3417 */
3418 this.updateString = function(str) {
3419 throw "updateString(str) not supported for this alg:prov=" + this.algProvName;
3420 };
3421
3422 /**
3423 * Updates the data to be signed or verified by a hexadecimal string
3424 * @name updateHex
3425 * @memberOf KJUR.crypto.Signature
3426 * @function
3427 * @param {String} hex hexadecimal string to use for the update
3428 * @description
3429 * @example
3430 * sig.updateHex('1f2f3f')
3431 */
3432 this.updateHex = function(hex) {
3433 throw "updateHex(hex) not supported for this alg:prov=" + this.algProvName;
3434 };
3435
3436 /**
3437 * Returns the signature bytes of all data updates as a hexadecimal string
3438 * @name sign
3439 * @memberOf KJUR.crypto.Signature
3440 * @function
3441 * @return the signature bytes as a hexadecimal string
3442 * @description
3443 * @example
3444 * var hSigValue = sig.sign()
3445 */
3446 this.sign = function() {
3447 throw "sign() not supported for this alg:prov=" + this.algProvName;
3448 };
3449
3450 /**
3451 * performs final update on the sign using string, then returns the signature bytes of all data updates as a hexadecimal string
3452 * @name signString
3453 * @memberOf KJUR.crypto.Signature
3454 * @function
3455 * @param {String} str string to final update
3456 * @return the signature bytes of a hexadecimal string
3457 * @description
3458 * @example
3459 * var hSigValue = sig.signString('aaa')
3460 */
3461 this.signString = function(str) {
3462 throw "digestString(str) not supported for this alg:prov=" + this.algProvName;
3463 };
3464
3465 /**
3466 * performs final update on the sign using hexadecimal string, then returns the signature bytes of all data updates as a hexadecimal string
3467 * @name signHex
3468 * @memberOf KJUR.crypto.Signature
3469 * @function
3470 * @param {String} hex hexadecimal string to final update
3471 * @return the signature bytes of a hexadecimal string
3472 * @description
3473 * @example
3474 * var hSigValue = sig.signHex('1fdc33')
3475 */
3476 this.signHex = function(hex) {
3477 throw "digestHex(hex) not supported for this alg:prov=" + this.algProvName;
3478 };
3479
3480 /**
3481 * verifies the passed-in signature.
3482 * @name verify
3483 * @memberOf KJUR.crypto.Signature
3484 * @function
3485 * @param {String} str string to final update
3486 * @return {Boolean} true if the signature was verified, otherwise false
3487 * @description
3488 * @example
3489 * var isValid = sig.verify('1fbcefdca4823a7(snip)')
3490 */
3491 this.verify = function(hSigVal) {
3492 throw "verify(hSigVal) not supported for this alg:prov=" + this.algProvName;
3493 };
3494
3495 this.initParams = params;
3496
3497 if (params !== undefined) {
3498 if (params['alg'] !== undefined) {
3499 this.algName = params['alg'];
3500 if (params['prov'] === undefined) {
3501 this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName];
3502 } else {
3503 this.provName = params['prov'];
3504 }
3505 this.algProvName = this.algName + ":" + this.provName;
3506 this.setAlgAndProvider(this.algName, this.provName);
3507 this._setAlgNames();
3508 }
3509
3510 if (params['psssaltlen'] !== undefined) this.pssSaltLen = params['psssaltlen'];
3511
3512 if (params['prvkeypem'] !== undefined) {
3513 if (params['prvkeypas'] !== undefined) {
3514 throw "both prvkeypem and prvkeypas parameters not supported";
3515 } else {
3516 try {
3517 var prvKey = new RSAKey();
3518 prvKey.readPrivateKeyFromPEMString(params['prvkeypem']);
3519 this.initSign(prvKey);
3520 } catch (ex) {
3521 throw "fatal error to load pem private key: " + ex;
3522 }
3523 }
3524 }
3525 }
3526};
3527
3528/**
3529 * static object for cryptographic function utilities
3530 * @name KJUR.crypto.OID
3531 * @class static object for cryptography related OIDs
3532 * @property {Array} oidhex2name key value of hexadecimal OID and its name
3533 * (ex. '2a8648ce3d030107' and 'secp256r1')
3534 * @since crypto 1.1.3
3535 * @description
3536 */
3537
3538
3539KJUR.crypto.OID = new function() {
3540 this.oidhex2name = {
3541 '2a864886f70d010101': 'rsaEncryption',
3542 '2a8648ce3d0201': 'ecPublicKey',
3543 '2a8648ce380401': 'dsa',
3544 '2a8648ce3d030107': 'secp256r1',
3545 '2b8104001f': 'secp192k1',
3546 '2b81040021': 'secp224r1',
3547 '2b8104000a': 'secp256k1',
3548 '2b81040023': 'secp521r1',
3549 '2b81040022': 'secp384r1',
3550 '2a8648ce380403': 'SHA1withDSA', // 1.2.840.10040.4.3
3551 '608648016503040301': 'SHA224withDSA', // 2.16.840.1.101.3.4.3.1
3552 '608648016503040302': 'SHA256withDSA' // 2.16.840.1.101.3.4.3.2
3553 };
3554};
3555
3556exports.KJUR = KJUR;
3557module.exports = exports;
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003558/*! rsapem-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
3559 */
3560//
3561// rsa-pem.js - adding function for reading/writing PKCS#1 PEM private key
3562// to RSAKey class.
3563//
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003564// version: 1.1.1 (2013-Apr-12)
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003565//
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003566// Copyright (c) 2010-2013 Kenji Urushima (kenji.urushima@gmail.com)
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003567//
3568// This software is licensed under the terms of the MIT License.
3569// http://kjur.github.com/jsrsasign/license/
3570//
3571// The above copyright and license notice shall be
3572// included in all copies or substantial portions of the Software.
3573//
3574//
3575// Depends on:
3576//
3577//
3578//
3579// _RSApem_pemToBase64(sPEM)
3580//
3581// removing PEM header, PEM footer and space characters including
3582// new lines from PEM formatted RSA private key string.
3583//
3584
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003585/**
3586 * @fileOverview
3587 * @name rsapem-1.1.js
3588 * @author Kenji Urushima kenji.urushima@gmail.com
3589 * @version 1.1
3590 * @license <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a>
3591 */
3592
3593var ASN1HEX = require('./asn1hex-1.1.js').ASN1HEX;
3594var b64tohex = require('./base64.js').b64tohex;
3595var RSAKey = require('./rsa2.js').RSAKey;
3596
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003597function _rsapem_pemToBase64(sPEMPrivateKey) {
3598 var s = sPEMPrivateKey;
3599 s = s.replace("-----BEGIN RSA PRIVATE KEY-----", "");
3600 s = s.replace("-----END RSA PRIVATE KEY-----", "");
3601 s = s.replace(/[ \n]+/g, "");
3602 return s;
3603}
3604
3605function _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey) {
3606 var a = new Array();
3607 var v1 = ASN1HEX.getStartPosOfV_AtObj(hPrivateKey, 0);
3608 var n1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, v1);
3609 var e1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, n1);
3610 var d1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, e1);
3611 var p1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, d1);
3612 var q1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, p1);
3613 var dp1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, q1);
3614 var dq1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dp1);
3615 var co1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dq1);
3616 a.push(v1, n1, e1, d1, p1, q1, dp1, dq1, co1);
3617 return a;
3618}
3619
3620function _rsapem_getHexValueArrayOfChildrenFromHex(hPrivateKey) {
3621 var posArray = _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey);
3622 var v = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[0]);
3623 var n = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[1]);
3624 var e = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[2]);
3625 var d = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[3]);
3626 var p = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[4]);
3627 var q = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[5]);
3628 var dp = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[6]);
3629 var dq = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[7]);
3630 var co = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[8]);
3631 var a = new Array();
3632 a.push(v, n, e, d, p, q, dp, dq, co);
3633 return a;
3634}
3635
3636/**
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003637 * read RSA private key from a ASN.1 hexadecimal string
3638 * @name readPrivateKeyFromASN1HexString
3639 * @memberOf RSAKey#
3640 * @function
3641 * @param {String} keyHex ASN.1 hexadecimal string of PKCS#1 private key.
3642 * @since 1.1.1
3643 */
3644function _rsapem_readPrivateKeyFromASN1HexString(keyHex) {
3645 var a = _rsapem_getHexValueArrayOfChildrenFromHex(keyHex);
3646 this.setPrivateEx(a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]);
3647}
3648
3649/**
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003650 * read PKCS#1 private key from a string
3651 * @name readPrivateKeyFromPEMString
3652 * @memberOf RSAKey#
3653 * @function
3654 * @param {String} keyPEM string of PKCS#1 private key.
3655 */
3656function _rsapem_readPrivateKeyFromPEMString(keyPEM) {
3657 var keyB64 = _rsapem_pemToBase64(keyPEM);
3658 var keyHex = b64tohex(keyB64) // depends base64.js
3659 var a = _rsapem_getHexValueArrayOfChildrenFromHex(keyHex);
3660 this.setPrivateEx(a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]);
3661}
3662
3663RSAKey.prototype.readPrivateKeyFromPEMString = _rsapem_readPrivateKeyFromPEMString;
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003664RSAKey.prototype.readPrivateKeyFromASN1HexString = _rsapem_readPrivateKeyFromASN1HexString;
3665
3666exports.RSAKey = RSAKey;
3667module.exports = exports;
3668/*! rsasign-1.2.7.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003669 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003670/*
3671 * rsa-sign.js - adding signing functions to RSAKey class.
3672 *
3673 * version: 1.2.7 (2013 Aug 25)
3674 *
3675 * Copyright (c) 2010-2013 Kenji Urushima (kenji.urushima@gmail.com)
3676 *
3677 * This software is licensed under the terms of the MIT License.
3678 * http://kjur.github.com/jsrsasign/license/
3679 *
3680 * The above copyright and license notice shall be
3681 * included in all copies or substantial portions of the Software.
3682 */
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003683
3684/**
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003685 * @fileOverview
3686 * @name rsasign-1.2.js
3687 * @author Kenji Urushima kenji.urushima@gmail.com
3688 * @version rsasign 1.2.7
3689 * @license <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a>
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003690 */
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003691
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003692var intShim = require('jsbn');
3693var BigInteger = intShim.BigInteger ? intShim.BigInteger : intShim;
3694var RSAKey = require('./rsapem-1.1.js').RSAKey
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003695
3696var _RE_HEXDECONLY = new RegExp("");
3697_RE_HEXDECONLY.compile("[^0-9a-f]", "gi");
3698
3699// ========================================================================
3700// Signature Generation
3701// ========================================================================
3702
3703function _rsasign_getHexPaddedDigestInfoForString(s, keySize, hashAlg) {
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003704 var hashFunc = function(s) { return KJUR.crypto.Util.hashString(s, hashAlg); };
3705 var sHashHex = hashFunc(s);
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003706
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003707 return KJUR.crypto.Util.getPaddedDigestInfoHex(sHashHex, hashAlg, keySize);
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003708}
3709
3710function _zeroPaddingOfSignature(hex, bitLength) {
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003711 var s = "";
3712 var nZero = bitLength / 4 - hex.length;
3713 for (var i = 0; i < nZero; i++) {
3714 s = s + "0";
3715 }
3716 return s + hex;
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003717}
3718
3719/**
3720 * sign for a message string with RSA private key.<br/>
3721 * @name signString
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003722 * @memberOf RSAKey
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003723 * @function
3724 * @param {String} s message string to be signed.
3725 * @param {String} hashAlg hash algorithm name for signing.<br/>
3726 * @return returns hexadecimal string of signature value.
3727 */
3728function _rsasign_signString(s, hashAlg) {
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003729 var hashFunc = function(s) { return KJUR.crypto.Util.hashString(s, hashAlg); };
3730 var sHashHex = hashFunc(s);
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003731
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003732 return this.signWithMessageHash(sHashHex, hashAlg);
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003733}
3734
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003735/**
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003736 * sign hash value of message to be signed with RSA private key.<br/>
3737 * @name signWithMessageHash
3738 * @memberOf RSAKey
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003739 * @function
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003740 * @param {String} sHashHex hexadecimal string of hash value of message to be signed.
3741 * @param {String} hashAlg hash algorithm name for signing.<br/>
3742 * @return returns hexadecimal string of signature value.
3743 * @since rsasign 1.2.6
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003744 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003745function _rsasign_signWithMessageHash(sHashHex, hashAlg) {
3746 var hPM = KJUR.crypto.Util.getPaddedDigestInfoHex(sHashHex, hashAlg, this.n.bitLength());
3747 var biPaddedMessage = parseBigInt(hPM, 16);
3748 var biSign = this.doPrivate(biPaddedMessage);
3749 var hexSign = biSign.toString(16);
3750 return _zeroPaddingOfSignature(hexSign, this.n.bitLength());
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003751}
3752
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003753function _rsasign_signStringWithSHA1(s) {
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003754 return _rsasign_signString.call(this, s, 'sha1');
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003755}
3756
3757function _rsasign_signStringWithSHA256(s) {
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003758 return _rsasign_signString.call(this, s, 'sha256');
3759}
3760
3761// PKCS#1 (PSS) mask generation function
3762function pss_mgf1_str(seed, len, hash) {
3763 var mask = '', i = 0;
3764
3765 while (mask.length < len) {
3766 mask += hextorstr(hash(rstrtohex(seed + String.fromCharCode.apply(String, [
3767 (i & 0xff000000) >> 24,
3768 (i & 0x00ff0000) >> 16,
3769 (i & 0x0000ff00) >> 8,
3770 i & 0x000000ff]))));
3771 i += 1;
3772 }
3773
3774 return mask;
3775}
3776
3777/**
3778 * sign for a message string with RSA private key by PKCS#1 PSS signing.<br/>
3779 * @name signStringPSS
3780 * @memberOf RSAKey
3781 * @function
3782 * @param {String} s message string to be signed.
3783 * @param {String} hashAlg hash algorithm name for signing.
3784 * @param {Integer} sLen salt byte length from 0 to (keybytelen - hashbytelen - 2).
3785 * There are two special values:
3786 * <ul>
3787 * <li>-1: sets the salt length to the digest length</li>
3788 * <li>-2: sets the salt length to maximum permissible value
3789 * (i.e. keybytelen - hashbytelen - 2)</li>
3790 * </ul>
3791 * DEFAULT is -1. (NOTE: OpenSSL's default is -2.)
3792 * @return returns hexadecimal string of signature value.
3793 */
3794function _rsasign_signStringPSS(s, hashAlg, sLen) {
3795 var hashFunc = function(sHex) { return KJUR.crypto.Util.hashHex(sHex, hashAlg); }
3796 var hHash = hashFunc(rstrtohex(s));
3797
3798 if (sLen === undefined) sLen = -1;
3799 return this.signWithMessageHashPSS(hHash, hashAlg, sLen);
3800}
3801
3802/**
3803 * sign hash value of message with RSA private key by PKCS#1 PSS signing.<br/>
3804 * @name signWithMessageHashPSS
3805 * @memberOf RSAKey
3806 * @function
3807 * @param {String} hHash hexadecimal hash value of message to be signed.
3808 * @param {String} hashAlg hash algorithm name for signing.
3809 * @param {Integer} sLen salt byte length from 0 to (keybytelen - hashbytelen - 2).
3810 * There are two special values:
3811 * <ul>
3812 * <li>-1: sets the salt length to the digest length</li>
3813 * <li>-2: sets the salt length to maximum permissible value
3814 * (i.e. keybytelen - hashbytelen - 2)</li>
3815 * </ul>
3816 * DEFAULT is -1. (NOTE: OpenSSL's default is -2.)
3817 * @return returns hexadecimal string of signature value.
3818 * @since rsasign 1.2.6
3819 */
3820function _rsasign_signWithMessageHashPSS(hHash, hashAlg, sLen) {
3821 var mHash = hextorstr(hHash);
3822 var hLen = mHash.length;
3823 var emBits = this.n.bitLength() - 1;
3824 var emLen = Math.ceil(emBits / 8);
3825 var i;
3826 var hashFunc = function(sHex) { return KJUR.crypto.Util.hashHex(sHex, hashAlg); }
3827
3828 if (sLen === -1 || sLen === undefined) {
3829 sLen = hLen; // same as hash length
3830 } else if (sLen === -2) {
3831 sLen = emLen - hLen - 2; // maximum
3832 } else if (sLen < -2) {
3833 throw "invalid salt length";
3834 }
3835
3836 if (emLen < (hLen + sLen + 2)) {
3837 throw "data too long";
3838 }
3839
3840 var salt = '';
3841
3842 if (sLen > 0) {
3843 salt = new Array(sLen);
3844 new SecureRandom().nextBytes(salt);
3845 salt = String.fromCharCode.apply(String, salt);
3846 }
3847
3848 var H = hextorstr(hashFunc(rstrtohex('\x00\x00\x00\x00\x00\x00\x00\x00' + mHash + salt)));
3849 var PS = [];
3850
3851 for (i = 0; i < emLen - sLen - hLen - 2; i += 1) {
3852 PS[i] = 0x00;
3853 }
3854
3855 var DB = String.fromCharCode.apply(String, PS) + '\x01' + salt;
3856 var dbMask = pss_mgf1_str(H, DB.length, hashFunc);
3857 var maskedDB = [];
3858
3859 for (i = 0; i < DB.length; i += 1) {
3860 maskedDB[i] = DB.charCodeAt(i) ^ dbMask.charCodeAt(i);
3861 }
3862
3863 var mask = (0xff00 >> (8 * emLen - emBits)) & 0xff;
3864 maskedDB[0] &= ~mask;
3865
3866 for (i = 0; i < hLen; i++) {
3867 maskedDB.push(H.charCodeAt(i));
3868 }
3869
3870 maskedDB.push(0xbc);
3871
3872 return _zeroPaddingOfSignature(this.doPrivate(new BigInteger(maskedDB)).toString(16),
3873 this.n.bitLength());
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003874}
3875
3876// ========================================================================
3877// Signature Verification
3878// ========================================================================
3879
3880function _rsasign_getDecryptSignatureBI(biSig, hN, hE) {
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003881 var rsa = new RSAKey();
3882 rsa.setPublic(hN, hE);
3883 var biDecryptedSig = rsa.doPublic(biSig);
3884 return biDecryptedSig;
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003885}
3886
3887function _rsasign_getHexDigestInfoFromSig(biSig, hN, hE) {
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003888 var biDecryptedSig = _rsasign_getDecryptSignatureBI(biSig, hN, hE);
3889 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
3890 return hDigestInfo;
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003891}
3892
3893function _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo) {
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003894 for (var algName in KJUR.crypto.Util.DIGESTINFOHEAD) {
3895 var head = KJUR.crypto.Util.DIGESTINFOHEAD[algName];
3896 var len = head.length;
3897 if (hDigestInfo.substring(0, len) == head) {
3898 var a = [algName, hDigestInfo.substring(len)];
3899 return a;
3900 }
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003901 }
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003902 return [];
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003903}
3904
3905function _rsasign_verifySignatureWithArgs(sMsg, biSig, hN, hE) {
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003906 var hDigestInfo = _rsasign_getHexDigestInfoFromSig(biSig, hN, hE);
3907 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
3908 if (digestInfoAry.length == 0) return false;
3909 var algName = digestInfoAry[0];
3910 var diHashValue = digestInfoAry[1];
3911 var ff = function(s) { return KJUR.crypto.Util.hashString(s, algName); };
3912 var msgHashValue = ff(sMsg);
3913 return (diHashValue == msgHashValue);
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003914}
3915
3916function _rsasign_verifyHexSignatureForMessage(hSig, sMsg) {
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003917 var biSig = parseBigInt(hSig, 16);
3918 var result = _rsasign_verifySignatureWithArgs(sMsg, biSig,
3919 this.n.toString(16),
3920 this.e.toString(16));
3921 return result;
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003922}
3923
3924/**
3925 * verifies a sigature for a message string with RSA public key.<br/>
3926 * @name verifyString
3927 * @memberOf RSAKey#
3928 * @function
3929 * @param {String} sMsg message string to be verified.
3930 * @param {String} hSig hexadecimal string of siganture.<br/>
3931 * non-hexadecimal charactors including new lines will be ignored.
3932 * @return returns 1 if valid, otherwise 0
3933 */
3934function _rsasign_verifyString(sMsg, hSig) {
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003935 hSig = hSig.replace(_RE_HEXDECONLY, '');
3936 hSig = hSig.replace(/[ \n]+/g, "");
3937 var biSig = parseBigInt(hSig, 16);
3938 if (biSig.bitLength() > this.n.bitLength()) return 0;
3939 var biDecryptedSig = this.doPublic(biSig);
3940 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
3941 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003942
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003943 if (digestInfoAry.length == 0) return false;
3944 var algName = digestInfoAry[0];
3945 var diHashValue = digestInfoAry[1];
3946 var ff = function(s) { return KJUR.crypto.Util.hashString(s, algName); };
3947 var msgHashValue = ff(sMsg);
3948 return (diHashValue == msgHashValue);
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003949}
3950
3951/**
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003952 * verifies a sigature for a message string with RSA public key.<br/>
3953 * @name verifyWithMessageHash
3954 * @memberOf RSAKey
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003955 * @function
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003956 * @param {String} sHashHex hexadecimal hash value of message to be verified.
3957 * @param {String} hSig hexadecimal string of siganture.<br/>
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003958 * non-hexadecimal charactors including new lines will be ignored.
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003959 * @return returns 1 if valid, otherwise 0
3960 * @since rsasign 1.2.6
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003961 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003962function _rsasign_verifyWithMessageHash(sHashHex, hSig) {
3963 hSig = hSig.replace(_RE_HEXDECONLY, '');
3964 hSig = hSig.replace(/[ \n]+/g, "");
3965 var biSig = parseBigInt(hSig, 16);
3966 if (biSig.bitLength() > this.n.bitLength()) return 0;
3967 var biDecryptedSig = this.doPublic(biSig);
3968 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
3969 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
3970
3971 if (digestInfoAry.length == 0) return false;
3972 var algName = digestInfoAry[0];
3973 var diHashValue = digestInfoAry[1];
3974 return (diHashValue == sHashHex);
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003975}
3976
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003977/**
3978 * verifies a sigature for a message string with RSA public key by PKCS#1 PSS sign.<br/>
3979 * @name verifyStringPSS
3980 * @memberOf RSAKey
3981 * @function
3982 * @param {String} sMsg message string to be verified.
3983 * @param {String} hSig hexadecimal string of signature value
3984 * @param {String} hashAlg hash algorithm name
3985 * @param {Integer} sLen salt byte length from 0 to (keybytelen - hashbytelen - 2).
3986 * There are two special values:
3987 * <ul>
3988 * <li>-1: sets the salt length to the digest length</li>
3989 * <li>-2: sets the salt length to maximum permissible value
3990 * (i.e. keybytelen - hashbytelen - 2)</li>
3991 * </ul>
3992 * DEFAULT is -1. (NOTE: OpenSSL's default is -2.)
3993 * @return returns true if valid, otherwise false
3994 */
3995function _rsasign_verifyStringPSS(sMsg, hSig, hashAlg, sLen) {
3996 var hashFunc = function(sHex) { return KJUR.crypto.Util.hashHex(sHex, hashAlg); };
3997 var hHash = hashFunc(rstrtohex(sMsg));
Alexander Afanasyev1663a412013-03-02 13:52:00 -08003998
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08003999 if (sLen === undefined) sLen = -1;
4000 return this.verifyWithMessageHashPSS(hHash, hSig, hashAlg, sLen);
4001}
4002
4003/**
4004 * verifies a sigature for a hash value of message string with RSA public key by PKCS#1 PSS sign.<br/>
4005 * @name verifyWithMessageHashPSS
4006 * @memberOf RSAKey
4007 * @function
4008 * @param {String} hHash hexadecimal hash value of message string to be verified.
4009 * @param {String} hSig hexadecimal string of signature value
4010 * @param {String} hashAlg hash algorithm name
4011 * @param {Integer} sLen salt byte length from 0 to (keybytelen - hashbytelen - 2).
4012 * There are two special values:
4013 * <ul>
4014 * <li>-1: sets the salt length to the digest length</li>
4015 * <li>-2: sets the salt length to maximum permissible value
4016 * (i.e. keybytelen - hashbytelen - 2)</li>
4017 * </ul>
4018 * DEFAULT is -1 (NOTE: OpenSSL's default is -2.)
4019 * @return returns true if valid, otherwise false
4020 * @since rsasign 1.2.6
4021 */
4022function _rsasign_verifyWithMessageHashPSS(hHash, hSig, hashAlg, sLen) {
4023 var biSig = new BigInteger(hSig, 16);
4024
4025 if (biSig.bitLength() > this.n.bitLength()) {
4026 return false;
4027 }
4028
4029 var hashFunc = function(sHex) { return KJUR.crypto.Util.hashHex(sHex, hashAlg); };
4030 var mHash = hextorstr(hHash);
4031 var hLen = mHash.length;
4032 var emBits = this.n.bitLength() - 1;
4033 var emLen = Math.ceil(emBits / 8);
4034 var i;
4035
4036 if (sLen === -1 || sLen === undefined) {
4037 sLen = hLen; // same as hash length
4038 } else if (sLen === -2) {
4039 sLen = emLen - hLen - 2; // recover
4040 } else if (sLen < -2) {
4041 throw "invalid salt length";
4042 }
4043
4044 if (emLen < (hLen + sLen + 2)) {
4045 throw "data too long";
4046 }
4047
4048 var em = this.doPublic(biSig).toByteArray();
4049
4050 for (i = 0; i < em.length; i += 1) {
4051 em[i] &= 0xff;
4052 }
4053
4054 while (em.length < emLen) {
4055 em.unshift(0);
4056 }
4057
4058 if (em[emLen -1] !== 0xbc) {
4059 throw "encoded message does not end in 0xbc";
4060 }
4061
4062 em = String.fromCharCode.apply(String, em);
4063
4064 var maskedDB = em.substr(0, emLen - hLen - 1);
4065 var H = em.substr(maskedDB.length, hLen);
4066
4067 var mask = (0xff00 >> (8 * emLen - emBits)) & 0xff;
4068
4069 if ((maskedDB.charCodeAt(0) & mask) !== 0) {
4070 throw "bits beyond keysize not zero";
4071 }
4072
4073 var dbMask = pss_mgf1_str(H, maskedDB.length, hashFunc);
4074 var DB = [];
4075
4076 for (i = 0; i < maskedDB.length; i += 1) {
4077 DB[i] = maskedDB.charCodeAt(i) ^ dbMask.charCodeAt(i);
4078 }
4079
4080 DB[0] &= ~mask;
4081
4082 var checkLen = emLen - hLen - sLen - 2;
4083
4084 for (i = 0; i < checkLen; i += 1) {
4085 if (DB[i] !== 0x00) {
4086 throw "leftmost octets not zero";
4087 }
4088 }
4089
4090 if (DB[checkLen] !== 0x01) {
4091 throw "0x01 marker not found";
4092 }
4093
4094 return H === hextorstr(hashFunc(rstrtohex('\x00\x00\x00\x00\x00\x00\x00\x00' + mHash +
4095 String.fromCharCode.apply(String, DB.slice(-sLen)))));
4096}
4097
4098RSAKey.prototype.signWithMessageHash = _rsasign_signWithMessageHash;
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004099RSAKey.prototype.signString = _rsasign_signString;
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004100RSAKey.prototype.signStringWithSHA1 = _rsasign_signStringWithSHA1;
4101RSAKey.prototype.signStringWithSHA256 = _rsasign_signStringWithSHA256;
4102RSAKey.prototype.sign = _rsasign_signString;
4103RSAKey.prototype.signWithSHA1 = _rsasign_signStringWithSHA1;
4104RSAKey.prototype.signWithSHA256 = _rsasign_signStringWithSHA256;
4105
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004106RSAKey.prototype.signWithMessageHashPSS = _rsasign_signWithMessageHashPSS;
4107RSAKey.prototype.signStringPSS = _rsasign_signStringPSS;
4108RSAKey.prototype.signPSS = _rsasign_signStringPSS;
4109RSAKey.SALT_LEN_HLEN = -1;
4110RSAKey.SALT_LEN_MAX = -2;
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004111
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004112RSAKey.prototype.verifyWithMessageHash = _rsasign_verifyWithMessageHash;
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004113RSAKey.prototype.verifyString = _rsasign_verifyString;
4114RSAKey.prototype.verifyHexSignatureForMessage = _rsasign_verifyHexSignatureForMessage;
4115RSAKey.prototype.verify = _rsasign_verifyString;
4116RSAKey.prototype.verifyHexSignatureForByteArrayMessage = _rsasign_verifyHexSignatureForMessage;
4117
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004118RSAKey.prototype.verifyWithMessageHashPSS = _rsasign_verifyWithMessageHashPSS;
4119RSAKey.prototype.verifyStringPSS = _rsasign_verifyStringPSS;
4120RSAKey.prototype.verifyPSS = _rsasign_verifyStringPSS;
4121RSAKey.SALT_LEN_RECOVER = -2;
4122
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004123/**
4124 * @name RSAKey
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004125 * @class key of RSA public key algorithm
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004126 * @description Tom Wu's RSA Key class and extension
4127 */
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004128
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004129exports.RSAKey = RSAKey;
4130module.exports = exports;
4131/*! ecdsa-modified-1.0.4.js (c) Stephan Thomas, Kenji Urushima | github.com/bitcoinjs/bitcoinjs-lib/blob/master/LICENSE
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004132 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004133/*
4134 * ecdsa-modified.js - modified Bitcoin.ECDSA class
4135 *
4136 * Copyright (c) 2013 Stefan Thomas (github.com/justmoon)
4137 * Kenji Urushima (kenji.urushima@gmail.com)
4138 * LICENSE
4139 * https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/LICENSE
4140 */
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004141
4142/**
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004143 * @fileOverview
4144 * @name ecdsa-modified-1.0.js
4145 * @author Stefan Thomas (github.com/justmoon) and Kenji Urushima (kenji.urushima@gmail.com)
4146 * @version 1.0.4 (2013-Oct-06)
4147 * @since jsrsasign 4.0
4148 * @license <a href="https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/LICENSE">MIT License</a>
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004149 */
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004150
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004151if (typeof KJUR == "undefined" || !KJUR) KJUR = {};
4152if (typeof KJUR.crypto == "undefined" || !KJUR.crypto) KJUR.crypto = {};
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004153
4154/**
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004155 * class for EC key generation, ECDSA signing and verifcation
4156 * @name KJUR.crypto.ECDSA
4157 * @class class for EC key generation, ECDSA signing and verifcation
4158 * @description
4159 * <p>
4160 * CAUTION: Most of the case, you don't need to use this class except
4161 * for generating an EC key pair. Please use {@link KJUR.crypto.Signature} class instead.
4162 * </p>
4163 * <p>
4164 * This class was originally developped by Stefan Thomas for Bitcoin JavaScript library.
4165 * (See {@link https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/src/ecdsa.js})
4166 * Currently this class supports following named curves and their aliases.
4167 * <ul>
4168 * <li>secp256r1, NIST P-256, P-256, prime256v1 (*)</li>
4169 * <li>secp256k1 (*)</li>
4170 * <li>secp384r1, NIST P-384, P-384 (*)</li>
4171 * </ul>
4172 * </p>
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004173 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004174KJUR.crypto.ECDSA = function(params) {
4175 var curveName = "secp256r1"; // curve name default
4176 var ecparams = null;
4177 var prvKeyHex = null;
4178 var pubKeyHex = null;
4179
4180 var rng = new SecureRandom();
4181
4182 var P_OVER_FOUR = null;
4183
4184 this.type = "EC";
4185
4186 function implShamirsTrick(P, k, Q, l) {
4187 var m = Math.max(k.bitLength(), l.bitLength());
4188 var Z = P.add2D(Q);
4189 var R = P.curve.getInfinity();
4190
4191 for (var i = m - 1; i >= 0; --i) {
4192 R = R.twice2D();
4193
4194 R.z = BigInteger.ONE;
4195
4196 if (k.testBit(i)) {
4197 if (l.testBit(i)) {
4198 R = R.add2D(Z);
4199 } else {
4200 R = R.add2D(P);
4201 }
4202 } else {
4203 if (l.testBit(i)) {
4204 R = R.add2D(Q);
4205 }
4206 }
4207 }
4208
4209 return R;
4210 };
4211
4212 //===========================
4213 // PUBLIC METHODS
4214 //===========================
4215 this.getBigRandom = function (limit) {
4216 return new BigInteger(limit.bitLength(), rng)
4217 .mod(limit.subtract(BigInteger.ONE))
4218 .add(BigInteger.ONE)
4219 ;
4220 };
4221
4222 this.setNamedCurve = function(curveName) {
4223 this.ecparams = KJUR.crypto.ECParameterDB.getByName(curveName);
4224 this.prvKeyHex = null;
4225 this.pubKeyHex = null;
4226 this.curveName = curveName;
4227 }
4228
4229 this.setPrivateKeyHex = function(prvKeyHex) {
4230 this.isPrivate = true;
4231 this.prvKeyHex = prvKeyHex;
4232 }
4233
4234 this.setPublicKeyHex = function(pubKeyHex) {
4235 this.isPublic = true;
4236 this.pubKeyHex = pubKeyHex;
4237 }
4238
4239 /**
4240 * generate a EC key pair
4241 * @name generateKeyPairHex
4242 * @memberOf KJUR.crypto.ECDSA
4243 * @function
4244 * @return {Array} associative array of hexadecimal string of private and public key
4245 * @since ecdsa-modified 1.0.1
4246 * @example
4247 * var ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1'});
4248 * var keypair = ec.generateKeyPairHex();
4249 * var pubhex = keypair.ecpubhex; // hexadecimal string of EC private key (=d)
4250 * var prvhex = keypair.ecprvhex; // hexadecimal string of EC public key
4251 */
4252 this.generateKeyPairHex = function() {
4253 var biN = this.ecparams['n'];
4254 var biPrv = this.getBigRandom(biN);
4255 var epPub = this.ecparams['G'].multiply(biPrv);
4256 var biX = epPub.getX().toBigInteger();
4257 var biY = epPub.getY().toBigInteger();
4258
4259 var charlen = this.ecparams['keylen'] / 4;
4260 var hPrv = ("0000000000" + biPrv.toString(16)).slice(- charlen);
4261 var hX = ("0000000000" + biX.toString(16)).slice(- charlen);
4262 var hY = ("0000000000" + biY.toString(16)).slice(- charlen);
4263 var hPub = "04" + hX + hY;
4264
4265 this.setPrivateKeyHex(hPrv);
4266 this.setPublicKeyHex(hPub);
4267 return {'ecprvhex': hPrv, 'ecpubhex': hPub};
4268 };
4269
4270 this.signWithMessageHash = function(hashHex) {
4271 return this.signHex(hashHex, this.prvKeyHex);
4272 };
4273
4274 /**
4275 * signing to message hash
4276 * @name signHex
4277 * @memberOf KJUR.crypto.ECDSA
4278 * @function
4279 * @param {String} hashHex hexadecimal string of hash value of signing message
4280 * @param {String} privHex hexadecimal string of EC private key
4281 * @return {String} hexadecimal string of ECDSA signature
4282 * @since ecdsa-modified 1.0.1
4283 * @example
4284 * var ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1'});
4285 * var sigValue = ec.signHex(hash, prvKey);
4286 */
4287 this.signHex = function (hashHex, privHex) {
4288 var d = new BigInteger(privHex, 16);
4289 var n = this.ecparams['n'];
4290 var e = new BigInteger(hashHex, 16);
4291
4292 do {
4293 var k = this.getBigRandom(n);
4294 var G = this.ecparams['G'];
4295 var Q = G.multiply(k);
4296 var r = Q.getX().toBigInteger().mod(n);
4297 } while (r.compareTo(BigInteger.ZERO) <= 0);
4298
4299 var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n);
4300
4301 return KJUR.crypto.ECDSA.biRSSigToASN1Sig(r, s);
4302 };
4303
4304 this.sign = function (hash, priv) {
4305 var d = priv;
4306 var n = this.ecparams['n'];
4307 var e = BigInteger.fromByteArrayUnsigned(hash);
4308
4309 do {
4310 var k = this.getBigRandom(n);
4311 var G = this.ecparams['G'];
4312 var Q = G.multiply(k);
4313 var r = Q.getX().toBigInteger().mod(n);
4314 } while (r.compareTo(BigInteger.ZERO) <= 0);
4315
4316 var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n);
4317 return this.serializeSig(r, s);
4318 };
4319
4320 this.verifyWithMessageHash = function(hashHex, sigHex) {
4321 return this.verifyHex(hashHex, sigHex, this.pubKeyHex);
4322 };
4323
4324 /**
4325 * verifying signature with message hash and public key
4326 * @name verifyHex
4327 * @memberOf KJUR.crypto.ECDSA
4328 * @function
4329 * @param {String} hashHex hexadecimal string of hash value of signing message
4330 * @param {String} sigHex hexadecimal string of signature value
4331 * @param {String} pubkeyHex hexadecimal string of public key
4332 * @return {Boolean} true if the signature is valid, otherwise false
4333 * @since ecdsa-modified 1.0.1
4334 * @example
4335 * var ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1'});
4336 * var result = ec.verifyHex(msgHashHex, sigHex, pubkeyHex);
4337 */
4338 this.verifyHex = function(hashHex, sigHex, pubkeyHex) {
4339 var r,s;
4340
4341 var obj = KJUR.crypto.ECDSA.parseSigHex(sigHex);
4342 r = obj.r;
4343 s = obj.s;
4344
4345 var Q;
4346 Q = ECPointFp.decodeFromHex(this.ecparams['curve'], pubkeyHex);
4347 var e = new BigInteger(hashHex, 16);
4348
4349 return this.verifyRaw(e, r, s, Q);
4350 };
4351
4352 this.verify = function (hash, sig, pubkey) {
4353 var r,s;
4354 if (Bitcoin.Util.isArray(sig)) {
4355 var obj = this.parseSig(sig);
4356 r = obj.r;
4357 s = obj.s;
4358 } else if ("object" === typeof sig && sig.r && sig.s) {
4359 r = sig.r;
4360 s = sig.s;
4361 } else {
4362 throw "Invalid value for signature";
4363 }
4364
4365 var Q;
4366 if (pubkey instanceof ECPointFp) {
4367 Q = pubkey;
4368 } else if (Bitcoin.Util.isArray(pubkey)) {
4369 Q = ECPointFp.decodeFrom(this.ecparams['curve'], pubkey);
4370 } else {
4371 throw "Invalid format for pubkey value, must be byte array or ECPointFp";
4372 }
4373 var e = BigInteger.fromByteArrayUnsigned(hash);
4374
4375 return this.verifyRaw(e, r, s, Q);
4376 };
4377
4378 this.verifyRaw = function (e, r, s, Q) {
4379 var n = this.ecparams['n'];
4380 var G = this.ecparams['G'];
4381
4382 if (r.compareTo(BigInteger.ONE) < 0 ||
4383 r.compareTo(n) >= 0)
4384 return false;
4385
4386 if (s.compareTo(BigInteger.ONE) < 0 ||
4387 s.compareTo(n) >= 0)
4388 return false;
4389
4390 var c = s.modInverse(n);
4391
4392 var u1 = e.multiply(c).mod(n);
4393 var u2 = r.multiply(c).mod(n);
4394
4395 // TODO(!!!): For some reason Shamir's trick isn't working with
4396 // signed message verification!? Probably an implementation
4397 // error!
4398 //var point = implShamirsTrick(G, u1, Q, u2);
4399 var point = G.multiply(u1).add(Q.multiply(u2));
4400
4401 var v = point.getX().toBigInteger().mod(n);
4402
4403 return v.equals(r);
4404 };
4405
4406 /**
4407 * Serialize a signature into DER format.
4408 *
4409 * Takes two BigIntegers representing r and s and returns a byte array.
4410 */
4411 this.serializeSig = function (r, s) {
4412 var rBa = r.toByteArraySigned();
4413 var sBa = s.toByteArraySigned();
4414
4415 var sequence = [];
4416 sequence.push(0x02); // INTEGER
4417 sequence.push(rBa.length);
4418 sequence = sequence.concat(rBa);
4419
4420 sequence.push(0x02); // INTEGER
4421 sequence.push(sBa.length);
4422 sequence = sequence.concat(sBa);
4423
4424 sequence.unshift(sequence.length);
4425 sequence.unshift(0x30); // SEQUENCE
4426 return sequence;
4427 };
4428
4429 /**
4430 * Parses a byte array containing a DER-encoded signature.
4431 *
4432 * This function will return an object of the form:
4433 *
4434 * {
4435 * r: BigInteger,
4436 * s: BigInteger
4437 * }
4438 */
4439 this.parseSig = function (sig) {
4440 var cursor;
4441 if (sig[0] != 0x30)
4442 throw new Error("Signature not a valid DERSequence");
4443
4444 cursor = 2;
4445 if (sig[cursor] != 0x02)
4446 throw new Error("First element in signature must be a DERInteger");;
4447 var rBa = sig.slice(cursor+2, cursor+2+sig[cursor+1]);
4448
4449 cursor += 2+sig[cursor+1];
4450 if (sig[cursor] != 0x02)
4451 throw new Error("Second element in signature must be a DERInteger");
4452 var sBa = sig.slice(cursor+2, cursor+2+sig[cursor+1]);
4453
4454 cursor += 2+sig[cursor+1];
4455
4456 //if (cursor != sig.length)
4457 // throw new Error("Extra bytes in signature");
4458
4459 var r = BigInteger.fromByteArrayUnsigned(rBa);
4460 var s = BigInteger.fromByteArrayUnsigned(sBa);
4461
4462 return {r: r, s: s};
4463 };
4464
4465 this.parseSigCompact = function (sig) {
4466 if (sig.length !== 65) {
4467 throw "Signature has the wrong length";
4468 }
4469
4470 // Signature is prefixed with a type byte storing three bits of
4471 // information.
4472 var i = sig[0] - 27;
4473 if (i < 0 || i > 7) {
4474 throw "Invalid signature type";
4475 }
4476
4477 var n = this.ecparams['n'];
4478 var r = BigInteger.fromByteArrayUnsigned(sig.slice(1, 33)).mod(n);
4479 var s = BigInteger.fromByteArrayUnsigned(sig.slice(33, 65)).mod(n);
4480
4481 return {r: r, s: s, i: i};
4482 };
4483
4484 /*
4485 * Recover a public key from a signature.
4486 *
4487 * See SEC 1: Elliptic Curve Cryptography, section 4.1.6, "Public
4488 * Key Recovery Operation".
4489 *
4490 * http://www.secg.org/download/aid-780/sec1-v2.pdf
4491 */
4492 /*
4493 recoverPubKey: function (r, s, hash, i) {
4494 // The recovery parameter i has two bits.
4495 i = i & 3;
4496
4497 // The less significant bit specifies whether the y coordinate
4498 // of the compressed point is even or not.
4499 var isYEven = i & 1;
4500
4501 // The more significant bit specifies whether we should use the
4502 // first or second candidate key.
4503 var isSecondKey = i >> 1;
4504
4505 var n = this.ecparams['n'];
4506 var G = this.ecparams['G'];
4507 var curve = this.ecparams['curve'];
4508 var p = curve.getQ();
4509 var a = curve.getA().toBigInteger();
4510 var b = curve.getB().toBigInteger();
4511
4512 // We precalculate (p + 1) / 4 where p is if the field order
4513 if (!P_OVER_FOUR) {
4514 P_OVER_FOUR = p.add(BigInteger.ONE).divide(BigInteger.valueOf(4));
4515 }
4516
4517 // 1.1 Compute x
4518 var x = isSecondKey ? r.add(n) : r;
4519
4520 // 1.3 Convert x to point
4521 var alpha = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p);
4522 var beta = alpha.modPow(P_OVER_FOUR, p);
4523
4524 var xorOdd = beta.isEven() ? (i % 2) : ((i+1) % 2);
4525 // If beta is even, but y isn't or vice versa, then convert it,
4526 // otherwise we're done and y == beta.
4527 var y = (beta.isEven() ? !isYEven : isYEven) ? beta : p.subtract(beta);
4528
4529 // 1.4 Check that nR is at infinity
4530 var R = new ECPointFp(curve,
4531 curve.fromBigInteger(x),
4532 curve.fromBigInteger(y));
4533 R.validate();
4534
4535 // 1.5 Compute e from M
4536 var e = BigInteger.fromByteArrayUnsigned(hash);
4537 var eNeg = BigInteger.ZERO.subtract(e).mod(n);
4538
4539 // 1.6 Compute Q = r^-1 (sR - eG)
4540 var rInv = r.modInverse(n);
4541 var Q = implShamirsTrick(R, s, G, eNeg).multiply(rInv);
4542
4543 Q.validate();
4544 if (!this.verifyRaw(e, r, s, Q)) {
4545 throw "Pubkey recovery unsuccessful";
4546 }
4547
4548 var pubKey = new Bitcoin.ECKey();
4549 pubKey.pub = Q;
4550 return pubKey;
4551 },
4552 */
4553
4554 /*
4555 * Calculate pubkey extraction parameter.
4556 *
4557 * When extracting a pubkey from a signature, we have to
4558 * distinguish four different cases. Rather than putting this
4559 * burden on the verifier, Bitcoin includes a 2-bit value with the
4560 * signature.
4561 *
4562 * This function simply tries all four cases and returns the value
4563 * that resulted in a successful pubkey recovery.
4564 */
4565 /*
4566 calcPubkeyRecoveryParam: function (address, r, s, hash) {
4567 for (var i = 0; i < 4; i++) {
4568 try {
4569 var pubkey = Bitcoin.ECDSA.recoverPubKey(r, s, hash, i);
4570 if (pubkey.getBitcoinAddress().toString() == address) {
4571 return i;
4572 }
4573 } catch (e) {}
4574 }
4575 throw "Unable to find valid recovery factor";
4576 }
4577 */
4578
4579 if (params !== undefined) {
4580 if (params['curve'] !== undefined) {
4581 this.curveName = params['curve'];
4582 }
4583 }
4584 if (this.curveName === undefined) this.curveName = curveName;
4585 this.setNamedCurve(this.curveName);
4586 if (params !== undefined) {
4587 if (params['prv'] !== undefined) this.setPrivateKeyHex(params['prv']);
4588 if (params['pub'] !== undefined) this.setPublicKeyHex(params['pub']);
4589 }
4590};
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004591
4592/**
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004593 * parse ASN.1 DER encoded ECDSA signature
4594 * @name parseSigHex
4595 * @memberOf KJUR.crypto.ECDSA
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004596 * @function
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004597 * @static
4598 * @param {String} sigHex hexadecimal string of ECDSA signature value
4599 * @return {Array} associative array of signature field r and s of BigInteger
4600 * @since ecdsa-modified 1.0.1
4601 * @example
4602 * var ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1'});
4603 * var sig = ec.parseSigHex('30...');
4604 * var biR = sig.r; // BigInteger object for 'r' field of signature.
4605 * var biS = sig.s; // BigInteger object for 's' field of signature.
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004606 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004607KJUR.crypto.ECDSA.parseSigHex = function(sigHex) {
4608 var p = KJUR.crypto.ECDSA.parseSigHexInHexRS(sigHex);
4609 var biR = new BigInteger(p.r, 16);
4610 var biS = new BigInteger(p.s, 16);
4611
4612 return {'r': biR, 's': biS};
4613};
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004614
4615/**
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004616 * parse ASN.1 DER encoded ECDSA signature
4617 * @name parseSigHexInHexRS
4618 * @memberOf KJUR.crypto.ECDSA
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004619 * @function
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004620 * @static
4621 * @param {String} sigHex hexadecimal string of ECDSA signature value
4622 * @return {Array} associative array of signature field r and s in hexadecimal
4623 * @since ecdsa-modified 1.0.3
4624 * @example
4625 * var ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1'});
4626 * var sig = ec.parseSigHexInHexRS('30...');
4627 * var hR = sig.r; // hexadecimal string for 'r' field of signature.
4628 * var hS = sig.s; // hexadecimal string for 's' field of signature.
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004629 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004630KJUR.crypto.ECDSA.parseSigHexInHexRS = function(sigHex) {
4631 // 1. ASN.1 Sequence Check
4632 if (sigHex.substr(0, 2) != "30")
4633 throw "signature is not a ASN.1 sequence";
4634
4635 // 2. Items of ASN.1 Sequence Check
4636 var a = ASN1HEX.getPosArrayOfChildren_AtObj(sigHex, 0);
4637 if (a.length != 2)
4638 throw "number of signature ASN.1 sequence elements seem wrong";
4639
4640 // 3. Integer check
4641 var iTLV1 = a[0];
4642 var iTLV2 = a[1];
4643 if (sigHex.substr(iTLV1, 2) != "02")
4644 throw "1st item of sequene of signature is not ASN.1 integer";
4645 if (sigHex.substr(iTLV2, 2) != "02")
4646 throw "2nd item of sequene of signature is not ASN.1 integer";
4647
4648 // 4. getting value
4649 var hR = ASN1HEX.getHexOfV_AtObj(sigHex, iTLV1);
4650 var hS = ASN1HEX.getHexOfV_AtObj(sigHex, iTLV2);
4651
4652 return {'r': hR, 's': hS};
4653};
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004654
4655/**
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004656 * convert hexadecimal ASN.1 encoded signature to concatinated signature
4657 * @name asn1SigToConcatSig
4658 * @memberOf KJUR.crypto.ECDSA
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004659 * @function
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004660 * @static
4661 * @param {String} asn1Hex hexadecimal string of ASN.1 encoded ECDSA signature value
4662 * @return {String} r-s concatinated format of ECDSA signature value
4663 * @since ecdsa-modified 1.0.3
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004664 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004665KJUR.crypto.ECDSA.asn1SigToConcatSig = function(asn1Sig) {
4666 var pSig = KJUR.crypto.ECDSA.parseSigHexInHexRS(asn1Sig);
4667 var hR = pSig.r;
4668 var hS = pSig.s;
4669
4670 if (hR.substr(0, 2) == "00" && (((hR.length / 2) * 8) % (16 * 8)) == 8)
4671 hR = hR.substr(2);
4672
4673 if (hS.substr(0, 2) == "00" && (((hS.length / 2) * 8) % (16 * 8)) == 8)
4674 hS = hS.substr(2);
4675
4676 if ((((hR.length / 2) * 8) % (16 * 8)) != 0)
4677 throw "unknown ECDSA sig r length error";
4678
4679 if ((((hS.length / 2) * 8) % (16 * 8)) != 0)
4680 throw "unknown ECDSA sig s length error";
4681
4682 return hR + hS;
4683};
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004684
4685/**
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004686 * convert hexadecimal concatinated signature to ASN.1 encoded signature
4687 * @name concatSigToASN1Sig
4688 * @memberOf KJUR.crypto.ECDSA
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004689 * @function
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004690 * @static
4691 * @param {String} concatSig r-s concatinated format of ECDSA signature value
4692 * @return {String} hexadecimal string of ASN.1 encoded ECDSA signature value
4693 * @since ecdsa-modified 1.0.3
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004694 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004695KJUR.crypto.ECDSA.concatSigToASN1Sig = function(concatSig) {
4696 if ((((concatSig.length / 2) * 8) % (16 * 8)) != 0)
4697 throw "unknown ECDSA concatinated r-s sig length error";
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004698
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004699 var hR = concatSig.substr(0, concatSig.length / 2);
4700 var hS = concatSig.substr(concatSig.length / 2);
4701 return KJUR.crypto.ECDSA.hexRSSigToASN1Sig(hR, hS);
4702};
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004703
4704/**
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004705 * convert hexadecimal R and S value of signature to ASN.1 encoded signature
4706 * @name hexRSSigToASN1Sig
4707 * @memberOf KJUR.crypto.ECDSA
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004708 * @function
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004709 * @static
4710 * @param {String} hR hexadecimal string of R field of ECDSA signature value
4711 * @param {String} hS hexadecimal string of S field of ECDSA signature value
4712 * @return {String} hexadecimal string of ASN.1 encoded ECDSA signature value
4713 * @since ecdsa-modified 1.0.3
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004714 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004715KJUR.crypto.ECDSA.hexRSSigToASN1Sig = function(hR, hS) {
4716 var biR = new BigInteger(hR, 16);
4717 var biS = new BigInteger(hS, 16);
4718 return KJUR.crypto.ECDSA.biRSSigToASN1Sig(biR, biS);
4719};
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004720
4721/**
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004722 * convert R and S BigInteger object of signature to ASN.1 encoded signature
4723 * @name biRSSigToASN1Sig
4724 * @memberOf KJUR.crypto.ECDSA
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004725 * @function
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004726 * @static
4727 * @param {BigInteger} biR BigInteger object of R field of ECDSA signature value
4728 * @param {BigInteger} biS BIgInteger object of S field of ECDSA signature value
4729 * @return {String} hexadecimal string of ASN.1 encoded ECDSA signature value
4730 * @since ecdsa-modified 1.0.3
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004731 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004732KJUR.crypto.ECDSA.biRSSigToASN1Sig = function(biR, biS) {
4733 var derR = new KJUR.asn1.DERInteger({'bigint': biR});
4734 var derS = new KJUR.asn1.DERInteger({'bigint': biS});
4735 var derSeq = new KJUR.asn1.DERSequence({'array': [derR, derS]});
4736 return derSeq.getEncodedHex();
4737};
4738
4739/*! asn1hex-1.1.6.js (c) 2012-2015 Kenji Urushima | kjur.github.com/jsrsasign/license
4740 */
4741/*
4742 * asn1hex.js - Hexadecimal represented ASN.1 string library
4743 *
4744 * Copyright (c) 2010-2015 Kenji Urushima (kenji.urushima@gmail.com)
4745 *
4746 * This software is licensed under the terms of the MIT License.
4747 * http://kjur.github.com/jsrsasign/license/
4748 *
4749 * The above copyright and license notice shall be
4750 * included in all copies or substantial portions of the Software.
4751 */
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004752
4753/**
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004754 * @fileOverview
4755 * @name asn1hex-1.1.js
4756 * @author Kenji Urushima kenji.urushima@gmail.com
4757 * @version asn1hex 1.1.6 (2015-Jun-11)
4758 * @license <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a>
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004759 */
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004760
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004761/*
4762 * MEMO:
4763 * f('3082025b02...', 2) ... 82025b ... 3bytes
4764 * f('020100', 2) ... 01 ... 1byte
4765 * f('0203001...', 2) ... 03 ... 1byte
4766 * f('02818003...', 2) ... 8180 ... 2bytes
4767 * f('3080....0000', 2) ... 80 ... -1
4768 *
4769 * Requirements:
4770 * - ASN.1 type octet length MUST be 1.
4771 * (i.e. ASN.1 primitives like SET, SEQUENCE, INTEGER, OCTETSTRING ...)
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004772 */
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004773
4774/**
4775 * ASN.1 DER encoded hexadecimal string utility class
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004776 * @name ASN1HEX
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004777 * @class ASN.1 DER encoded hexadecimal string utility class
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004778 * @since jsrsasign 1.1
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004779 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004780var intShim = require('jsbn');
Alexander Afanasyev1663a412013-03-02 13:52:00 -08004781
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08004782var ASN1HEX = new function() {
4783 /**
4784 * get byte length for ASN.1 L(length) bytes
4785 * @name getByteLengthOfL_AtObj
4786 * @memberOf ASN1HEX
4787 * @function
4788 * @param {String} s hexadecimal string of ASN.1 DER encoded data
4789 * @param {Number} pos string index
4790 * @return byte length for ASN.1 L(length) bytes
4791 */
4792 this.getByteLengthOfL_AtObj = function(s, pos) {
4793 if (s.substring(pos + 2, pos + 3) != '8') return 1;
4794 var i = parseInt(s.substring(pos + 3, pos + 4));
4795 if (i == 0) return -1; // length octet '80' indefinite length
4796 if (0 < i && i < 10) return i + 1; // including '8?' octet;
4797 return -2; // malformed format
4798 };
4799
4800 /**
4801 * get hexadecimal string for ASN.1 L(length) bytes
4802 * @name getHexOfL_AtObj
4803 * @memberOf ASN1HEX
4804 * @function
4805 * @param {String} s hexadecimal string of ASN.1 DER encoded data
4806 * @param {Number} pos string index
4807 * @return {String} hexadecimal string for ASN.1 L(length) bytes
4808 */
4809 this.getHexOfL_AtObj = function(s, pos) {
4810 var len = this.getByteLengthOfL_AtObj(s, pos);
4811 if (len < 1) return '';
4812 return s.substring(pos + 2, pos + 2 + len * 2);
4813 };
4814
4815 // getting ASN.1 length value at the position 'idx' of
4816 // hexa decimal string 's'.
4817 //
4818 // f('3082025b02...', 0) ... 82025b ... ???
4819 // f('020100', 0) ... 01 ... 1
4820 // f('0203001...', 0) ... 03 ... 3
4821 // f('02818003...', 0) ... 8180 ... 128
4822 /**
4823 * get integer value of ASN.1 length for ASN.1 data
4824 * @name getIntOfL_AtObj
4825 * @memberOf ASN1HEX
4826 * @function
4827 * @param {String} s hexadecimal string of ASN.1 DER encoded data
4828 * @param {Number} pos string index
4829 * @return ASN.1 L(length) integer value
4830 */
4831 this.getIntOfL_AtObj = function(s, pos) {
4832 var hLength = this.getHexOfL_AtObj(s, pos);
4833 if (hLength == '') return -1;
4834 var bi;
4835 if (parseInt(hLength.substring(0, 1)) < 8) {
4836 bi = new BigInteger(hLength, 16);
4837 } else {
4838 bi = new BigInteger(hLength.substring(2), 16);
4839 }
4840 return bi.intValue();
4841 };
4842
4843 /**
4844 * get ASN.1 value starting string position for ASN.1 object refered by index 'idx'.
4845 * @name getStartPosOfV_AtObj
4846 * @memberOf ASN1HEX
4847 * @function
4848 * @param {String} s hexadecimal string of ASN.1 DER encoded data
4849 * @param {Number} pos string index
4850 */
4851 this.getStartPosOfV_AtObj = function(s, pos) {
4852 var l_len = this.getByteLengthOfL_AtObj(s, pos);
4853 if (l_len < 0) return l_len;
4854 return pos + (l_len + 1) * 2;
4855 };
4856
4857 /**
4858 * get hexadecimal string of ASN.1 V(value)
4859 * @name getHexOfV_AtObj
4860 * @memberOf ASN1HEX
4861 * @function
4862 * @param {String} s hexadecimal string of ASN.1 DER encoded data
4863 * @param {Number} pos string index
4864 * @return {String} hexadecimal string of ASN.1 value.
4865 */
4866 this.getHexOfV_AtObj = function(s, pos) {
4867 var pos1 = this.getStartPosOfV_AtObj(s, pos);
4868 var len = this.getIntOfL_AtObj(s, pos);
4869 return s.substring(pos1, pos1 + len * 2);
4870 };
4871
4872 /**
4873 * get hexadecimal string of ASN.1 TLV at
4874 * @name getHexOfTLV_AtObj
4875 * @memberOf ASN1HEX
4876 * @function
4877 * @param {String} s hexadecimal string of ASN.1 DER encoded data
4878 * @param {Number} pos string index
4879 * @return {String} hexadecimal string of ASN.1 TLV.
4880 * @since 1.1
4881 */
4882 this.getHexOfTLV_AtObj = function(s, pos) {
4883 var hT = s.substr(pos, 2);
4884 var hL = this.getHexOfL_AtObj(s, pos);
4885 var hV = this.getHexOfV_AtObj(s, pos);
4886 return hT + hL + hV;
4887 };
4888
4889 /**
4890 * get next sibling starting index for ASN.1 object string
4891 * @name getPosOfNextSibling_AtObj
4892 * @memberOf ASN1HEX
4893 * @function
4894 * @param {String} s hexadecimal string of ASN.1 DER encoded data
4895 * @param {Number} pos string index
4896 * @return next sibling starting index for ASN.1 object string
4897 */
4898 this.getPosOfNextSibling_AtObj = function(s, pos) {
4899 var pos1 = this.getStartPosOfV_AtObj(s, pos);
4900 var len = this.getIntOfL_AtObj(s, pos);
4901 return pos1 + len * 2;
4902 };
4903
4904 /**
4905 * get array of indexes of child ASN.1 objects
4906 * @name getPosArrayOfChildren_AtObj
4907 * @memberOf ASN1HEX
4908 * @function
4909 * @param {String} s hexadecimal string of ASN.1 DER encoded data
4910 * @param {Number} start string index of ASN.1 object
4911 * @return {Array of Number} array of indexes for childen of ASN.1 objects
4912 */
4913 this.getPosArrayOfChildren_AtObj = function(h, pos) {
4914 var a = new Array();
4915 var p0 = this.getStartPosOfV_AtObj(h, pos);
4916 a.push(p0);
4917
4918 var len = this.getIntOfL_AtObj(h, pos);
4919 var p = p0;
4920 var k = 0;
4921 while (1) {
4922 var pNext = this.getPosOfNextSibling_AtObj(h, p);
4923 if (pNext == null || (pNext - p0 >= (len * 2))) break;
4924 if (k >= 200) break;
4925
4926 a.push(pNext);
4927 p = pNext;
4928
4929 k++;
4930 }
4931
4932 return a;
4933 };
4934
4935 /**
4936 * get string index of nth child object of ASN.1 object refered by h, idx
4937 * @name getNthChildIndex_AtObj
4938 * @memberOf ASN1HEX
4939 * @function
4940 * @param {String} h hexadecimal string of ASN.1 DER encoded data
4941 * @param {Number} idx start string index of ASN.1 object
4942 * @param {Number} nth for child
4943 * @return {Number} string index of nth child.
4944 * @since 1.1
4945 */
4946 this.getNthChildIndex_AtObj = function(h, idx, nth) {
4947 var a = this.getPosArrayOfChildren_AtObj(h, idx);
4948 return a[nth];
4949 };
4950
4951 // ========== decendant methods ==============================
4952 /**
4953 * get string index of nth child object of ASN.1 object refered by h, idx
4954 * @name getDecendantIndexByNthList
4955 * @memberOf ASN1HEX
4956 * @function
4957 * @param {String} h hexadecimal string of ASN.1 DER encoded data
4958 * @param {Number} currentIndex start string index of ASN.1 object
4959 * @param {Array of Number} nthList array list of nth
4960 * @return {Number} string index refered by nthList
4961 * @since 1.1
4962 * @example
4963 * The "nthList" is a index list of structured ASN.1 object
4964 * reference. Here is a sample structure and "nthList"s which
4965 * refers each objects.
4966 *
4967 * SQUENCE -
4968 * SEQUENCE - [0]
4969 * IA5STRING 000 - [0, 0]
4970 * UTF8STRING 001 - [0, 1]
4971 * SET - [1]
4972 * IA5STRING 010 - [1, 0]
4973 * UTF8STRING 011 - [1, 1]
4974 */
4975 this.getDecendantIndexByNthList = function(h, currentIndex, nthList) {
4976 if (nthList.length == 0) {
4977 return currentIndex;
4978 }
4979 var firstNth = nthList.shift();
4980 var a = this.getPosArrayOfChildren_AtObj(h, currentIndex);
4981 return this.getDecendantIndexByNthList(h, a[firstNth], nthList);
4982 };
4983
4984 /**
4985 * get hexadecimal string of ASN.1 TLV refered by current index and nth index list.
4986 * @name getDecendantHexTLVByNthList
4987 * @memberOf ASN1HEX
4988 * @function
4989 * @param {String} h hexadecimal string of ASN.1 DER encoded data
4990 * @param {Number} currentIndex start string index of ASN.1 object
4991 * @param {Array of Number} nthList array list of nth
4992 * @return {Number} hexadecimal string of ASN.1 TLV refered by nthList
4993 * @since 1.1
4994 */
4995 this.getDecendantHexTLVByNthList = function(h, currentIndex, nthList) {
4996 var idx = this.getDecendantIndexByNthList(h, currentIndex, nthList);
4997 return this.getHexOfTLV_AtObj(h, idx);
4998 };
4999
5000 /**
5001 * get hexadecimal string of ASN.1 V refered by current index and nth index list.
5002 * @name getDecendantHexVByNthList
5003 * @memberOf ASN1HEX
5004 * @function
5005 * @param {String} h hexadecimal string of ASN.1 DER encoded data
5006 * @param {Number} currentIndex start string index of ASN.1 object
5007 * @param {Array of Number} nthList array list of nth
5008 * @return {Number} hexadecimal string of ASN.1 V refered by nthList
5009 * @since 1.1
5010 */
5011 this.getDecendantHexVByNthList = function(h, currentIndex, nthList) {
5012 var idx = this.getDecendantIndexByNthList(h, currentIndex, nthList);
5013 return this.getHexOfV_AtObj(h, idx);
5014 };
5015};
5016
5017/*
5018 * @since asn1hex 1.1.4
Alexander Afanasyev1663a412013-03-02 13:52:00 -08005019 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08005020ASN1HEX.getVbyList = function(h, currentIndex, nthList, checkingTag) {
5021 var idx = this.getDecendantIndexByNthList(h, currentIndex, nthList);
5022 if (idx === undefined) {
5023 throw "can't find nthList object";
5024 }
5025 if (checkingTag !== undefined) {
5026 if (h.substr(idx, 2) != checkingTag) {
5027 throw "checking tag doesn't match: " +
5028 h.substr(idx,2) + "!=" + checkingTag;
5029 }
5030 }
5031 return this.getHexOfV_AtObj(h, idx);
5032};
Alexander Afanasyev1663a412013-03-02 13:52:00 -08005033
5034/**
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08005035 * get OID string from hexadecimal encoded value
5036 * @name hextooidstr
5037 * @memberOf ASN1HEX
Alexander Afanasyev1663a412013-03-02 13:52:00 -08005038 * @function
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08005039 * @param {String} hex hexadecmal string of ASN.1 DER encoded OID value
5040 * @return {String} OID string (ex. '1.2.3.4.567')
5041 * @since asn1hex 1.1.5
Alexander Afanasyev1663a412013-03-02 13:52:00 -08005042 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08005043ASN1HEX.hextooidstr = function(hex) {
5044 var zeroPadding = function(s, len) {
5045 if (s.length >= len) return s;
5046 return new Array(len - s.length + 1).join('0') + s;
5047 };
5048
5049 var a = [];
5050
5051 // a[0], a[1]
5052 var hex0 = hex.substr(0, 2);
5053 var i0 = parseInt(hex0, 16);
5054 a[0] = new String(Math.floor(i0 / 40));
5055 a[1] = new String(i0 % 40);
5056
5057 // a[2]..a[n]
5058 var hex1 = hex.substr(2);
5059 var b = [];
5060 for (var i = 0; i < hex1.length / 2; i++) {
5061 b.push(parseInt(hex1.substr(i * 2, 2), 16));
5062 }
5063 var c = [];
5064 var cbin = "";
5065 for (var i = 0; i < b.length; i++) {
5066 if (b[i] & 0x80) {
5067 cbin = cbin + zeroPadding((b[i] & 0x7f).toString(2), 7);
5068 } else {
5069 cbin = cbin + zeroPadding((b[i] & 0x7f).toString(2), 7);
5070 c.push(new String(parseInt(cbin, 2)));
5071 cbin = "";
5072 }
5073 }
5074
5075 var s = a.join(".");
5076 if (c.length > 0) s = s + "." + c.join(".");
5077 return s;
5078};
Alexander Afanasyev1663a412013-03-02 13:52:00 -08005079
5080/**
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08005081 * get string of simple ASN.1 dump from hexadecimal ASN.1 data
5082 * @name dump
5083 * @memberOf ASN1HEX
Alexander Afanasyev1663a412013-03-02 13:52:00 -08005084 * @function
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08005085 * @param {String} hex hexadecmal string of ASN.1 data
5086 * @param {Array} associative array of flags for dump (OPTION)
5087 * @param {Number} idx string index for starting dump (OPTION)
5088 * @param {String} indent string (OPTION)
5089 * @return {String} string of simple ASN.1 dump
5090 * @since jsrsasign 4.8.3 asn1hex 1.1.6
5091 * @description
5092 * This method will get an ASN.1 dump from
5093 * hexadecmal string of ASN.1 DER encoded data.
5094 * Here are features:
5095 * <ul>
5096 * <li>ommit long hexadecimal string</li>
5097 * <li>dump encapsulated OCTET STRING (good for X.509v3 extensions)</li>
5098 * <li>structured/primitive context specific tag support (i.e. [0], [3] ...)</li>
5099 * <li>automatic decode for implicit primitive context specific tag
5100 * (good for X.509v3 extension value)
5101 * <ul>
5102 * <li>if hex starts '68747470'(i.e. http) it is decoded as utf8 encoded string.</li>
5103 * <li>if it is in 'subjectAltName' extension value and is '[2]'(dNSName) tag
5104 * value will be encoded as utf8 string</li>
5105 * <li>otherwise it shows as hexadecimal string</li>
5106 * </ul>
5107 * </li>
5108 * </ul>
5109 * @example
5110 * // ASN.1 INTEGER
5111 * ASN1HEX.dump('0203012345')
5112 * &darr;
5113 * INTEGER 012345
5114 * // ASN.1 Object Identifier
5115 * ASN1HEX.dump('06052b0e03021a')
5116 * &darr;
5117 * ObjectIdentifier sha1 (1 3 14 3 2 26)
5118 * // ASN.1 SEQUENCE
5119 * ASN1HEX.dump('3006020101020102')
5120 * &darr;
5121 * SEQUENCE
5122 * INTEGER 01
5123 * INTEGER 02
5124 * // ASN.1 DUMP FOR X.509 CERTIFICATE
5125 * ASN1HEX.dump(X509.pemToHex(certPEM))
5126 * &darr;
5127 * SEQUENCE
5128 * SEQUENCE
5129 * [0]
5130 * INTEGER 02
5131 * INTEGER 0c009310d206dbe337553580118ddc87
5132 * SEQUENCE
5133 * ObjectIdentifier SHA256withRSA (1 2 840 113549 1 1 11)
5134 * NULL
5135 * SEQUENCE
5136 * SET
5137 * SEQUENCE
5138 * ObjectIdentifier countryName (2 5 4 6)
5139 * PrintableString 'US'
5140 * :
Alexander Afanasyev1663a412013-03-02 13:52:00 -08005141 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08005142ASN1HEX.dump = function(hex, flags, idx, indent) {
5143 var _skipLongHex = function(hex, limitNumOctet) {
5144 if (hex.length <= limitNumOctet * 2) {
5145 return hex;
5146 } else {
5147 var s = hex.substr(0, limitNumOctet) +
5148 "..(total " + hex.length / 2 + "bytes).." +
5149 hex.substr(hex.length - limitNumOctet, limitNumOctet);
5150 return s;
5151 };
5152 };
5153
5154 if (flags === undefined) flags = { "ommit_long_octet": 32 };
5155 if (idx === undefined) idx = 0;
5156 if (indent === undefined) indent = "";
5157 var skipLongHex = flags.ommit_long_octet;
5158
5159 if (hex.substr(idx, 2) == "01") {
5160 var v = ASN1HEX.getHexOfV_AtObj(hex, idx);
5161 if (v == "00") {
5162 return indent + "BOOLEAN FALSE\n";
5163 } else {
5164 return indent + "BOOLEAN TRUE\n";
5165 }
5166 }
5167 if (hex.substr(idx, 2) == "02") {
5168 var v = ASN1HEX.getHexOfV_AtObj(hex, idx);
5169 return indent + "INTEGER " + _skipLongHex(v, skipLongHex) + "\n";
5170 }
5171 if (hex.substr(idx, 2) == "03") {
5172 var v = ASN1HEX.getHexOfV_AtObj(hex, idx);
5173 return indent + "BITSTRING " + _skipLongHex(v, skipLongHex) + "\n";
5174 }
5175 if (hex.substr(idx, 2) == "04") {
5176 var v = ASN1HEX.getHexOfV_AtObj(hex, idx);
5177 if (ASN1HEX.isASN1HEX(v)) {
5178 var s = indent + "OCTETSTRING, encapsulates\n";
5179 s = s + ASN1HEX.dump(v, flags, 0, indent + " ");
5180 return s;
5181 } else {
5182 return indent + "OCTETSTRING " + _skipLongHex(v, skipLongHex) + "\n";
5183 }
5184 }
5185 if (hex.substr(idx, 2) == "05") {
5186 return indent + "NULL\n";
5187 }
5188 if (hex.substr(idx, 2) == "06") {
5189 var hV = ASN1HEX.getHexOfV_AtObj(hex, idx);
5190 var oidDot = KJUR.asn1.ASN1Util.oidHexToInt(hV);
5191 var oidName = KJUR.asn1.x509.OID.oid2name(oidDot);
5192 var oidSpc = oidDot.replace(/\./g, ' ');
5193 if (oidName != '') {
5194 return indent + "ObjectIdentifier " + oidName + " (" + oidSpc + ")\n";
5195 } else {
5196 return indent + "ObjectIdentifier (" + oidSpc + ")\n";
5197 }
5198 }
5199 if (hex.substr(idx, 2) == "0c") {
5200 return indent + "UTF8String '" + hextoutf8(ASN1HEX.getHexOfV_AtObj(hex, idx)) + "'\n";
5201 }
5202 if (hex.substr(idx, 2) == "13") {
5203 return indent + "PrintableString '" + hextoutf8(ASN1HEX.getHexOfV_AtObj(hex, idx)) + "'\n";
5204 }
5205 if (hex.substr(idx, 2) == "14") {
5206 return indent + "TeletexString '" + hextoutf8(ASN1HEX.getHexOfV_AtObj(hex, idx)) + "'\n";
5207 }
5208 if (hex.substr(idx, 2) == "16") {
5209 return indent + "IA5String '" + hextoutf8(ASN1HEX.getHexOfV_AtObj(hex, idx)) + "'\n";
5210 }
5211 if (hex.substr(idx, 2) == "17") {
5212 return indent + "UTCTime " + hextoutf8(ASN1HEX.getHexOfV_AtObj(hex, idx)) + "\n";
5213 }
5214 if (hex.substr(idx, 2) == "18") {
5215 return indent + "GeneralizedTime " + hextoutf8(ASN1HEX.getHexOfV_AtObj(hex, idx)) + "\n";
5216 }
5217 if (hex.substr(idx, 2) == "30") {
5218 if (hex.substr(idx, 4) == "3000") {
5219 return indent + "SEQUENCE {}\n";
5220 }
5221
5222 var s = indent + "SEQUENCE\n";
5223 var aIdx = ASN1HEX.getPosArrayOfChildren_AtObj(hex, idx);
5224
5225 var flagsTemp = flags;
5226
5227 if ((aIdx.length == 2 || aIdx.length == 3) &&
5228 hex.substr(aIdx[0], 2) == "06" &&
5229 hex.substr(aIdx[aIdx.length - 1], 2) == "04") { // supposed X.509v3 extension
5230 var oidHex = ASN1HEX.getHexOfV_AtObj(hex, aIdx[0]);
5231 var oidDot = KJUR.asn1.ASN1Util.oidHexToInt(oidHex);
5232 var oidName = KJUR.asn1.x509.OID.oid2name(oidDot);
5233
5234 var flagsClone = JSON.parse(JSON.stringify(flags));
5235 flagsClone.x509ExtName = oidName;
5236 flagsTemp = flagsClone;
5237 }
5238
5239 for (var i = 0; i < aIdx.length; i++) {
5240 s = s + ASN1HEX.dump(hex, flagsTemp, aIdx[i], indent + " ");
5241 }
5242 return s;
5243 }
5244 if (hex.substr(idx, 2) == "31") {
5245 var s = indent + "SET\n";
5246 var aIdx = ASN1HEX.getPosArrayOfChildren_AtObj(hex, idx);
5247 for (var i = 0; i < aIdx.length; i++) {
5248 s = s + ASN1HEX.dump(hex, flags, aIdx[i], indent + " ");
5249 }
5250 return s;
5251 }
5252 var tag = parseInt(hex.substr(idx, 2), 16);
5253 if ((tag & 128) != 0) { // context specific
5254 var tagNumber = tag & 31;
5255 if ((tag & 32) != 0) { // structured tag
5256 var s = indent + "[" + tagNumber + "]\n";
5257 var aIdx = ASN1HEX.getPosArrayOfChildren_AtObj(hex, idx);
5258 for (var i = 0; i < aIdx.length; i++) {
5259 s = s + ASN1HEX.dump(hex, flags, aIdx[i], indent + " ");
5260 }
5261 return s;
5262 } else { // primitive tag
5263 var v = ASN1HEX.getHexOfV_AtObj(hex, idx);
5264 if (v.substr(0, 8) == "68747470") { // http
5265 v = hextoutf8(v);
5266 }
5267 if (flags.x509ExtName === "subjectAltName" &&
5268 tagNumber == 2) {
5269 v = hextoutf8(v);
5270 }
5271
5272 var s = indent + "[" + tagNumber + "] " + v + "\n";
5273 return s;
5274 }
5275 }
5276 return indent + "UNKNOWN(" + hex.substr(idx, 2) + ") " + ASN1HEX.getHexOfV_AtObj(hex, idx) + "\n";
5277};
Alexander Afanasyev1663a412013-03-02 13:52:00 -08005278
5279/**
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08005280 * check wheather the string is ASN.1 hexadecimal string or not
5281 * @name isASN1HEX
5282 * @memberOf ASN1HEX
Alexander Afanasyev1663a412013-03-02 13:52:00 -08005283 * @function
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08005284 * @param {String} hex string to check whether it is hexadecmal string for ASN.1 DER or not
5285 * @return {Boolean} true if it is hexadecimal string of ASN.1 data otherwise false
5286 * @since jsrsasign 4.8.3 asn1hex 1.1.6
5287 * @description
5288 * This method checks wheather the argument 'hex' is a hexadecimal string of
5289 * ASN.1 data or not.
5290 * @example
5291 * ASN1HEX.isASN1HEX('0203012345') &rarr; true // PROPER ASN.1 INTEGER
5292 * ASN1HEX.isASN1HEX('0203012345ff') &rarr; false // TOO LONG VALUE
5293 * ASN1HEX.isASN1HEX('02030123') &rarr; false // TOO SHORT VALUE
5294 * ASN1HEX.isASN1HEX('fa3bcd') &rarr; false // WRONG FOR ASN.1
Alexander Afanasyev1663a412013-03-02 13:52:00 -08005295 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08005296ASN1HEX.isASN1HEX = function(hex) {
5297 if (hex.length % 2 == 1) return false;
5298
5299 var intL = ASN1HEX.getIntOfL_AtObj(hex, 0);
5300 var tV = hex.substr(0, 2);
5301 var lV = ASN1HEX.getHexOfL_AtObj(hex, 0);
5302 var hVLength = hex.length - tV.length - lV.length;
5303 if (hVLength == intL * 2) return true;
5304
5305 return false;
5306};
5307
5308exports.ASN1HEX = ASN1HEX;
5309module.exports = exports;
5310/*! x509-1.1.6.js (c) 2012-2015 Kenji Urushima | kjur.github.com/jsrsasign/license
5311 */
5312/*
5313 * x509.js - X509 class to read subject public key from certificate.
5314 *
5315 * Copyright (c) 2010-2015 Kenji Urushima (kenji.urushima@gmail.com)
5316 *
5317 * This software is licensed under the terms of the MIT License.
5318 * http://kjur.github.com/jsrsasign/license
5319 *
5320 * The above copyright and license notice shall be
5321 * included in all copies or substantial portions of the Software.
5322 */
Alexander Afanasyev1663a412013-03-02 13:52:00 -08005323
5324/**
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08005325 * @fileOverview
5326 * @name x509-1.1.js
5327 * @author Kenji Urushima kenji.urushima@gmail.com
5328 * @version x509 1.1.6 (2015-May-20)
5329 * @since jsrsasign 1.x.x
5330 * @license <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a>
Alexander Afanasyev1663a412013-03-02 13:52:00 -08005331 */
Alexander Afanasyev1663a412013-03-02 13:52:00 -08005332
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08005333/*
5334 * Depends:
5335 * base64.js
5336 * rsa.js
5337 * asn1hex.js
Alexander Afanasyev1663a412013-03-02 13:52:00 -08005338 */
Alexander Afanasyev1663a412013-03-02 13:52:00 -08005339
5340/**
5341 * X.509 certificate class.<br/>
5342 * @class X.509 certificate class
5343 * @property {RSAKey} subjectPublicKeyRSA Tom Wu's RSAKey object
5344 * @property {String} subjectPublicKeyRSA_hN hexadecimal string for modulus of RSA public key
5345 * @property {String} subjectPublicKeyRSA_hE hexadecimal string for public exponent of RSA public key
5346 * @property {String} hex hexacedimal string for X.509 certificate.
5347 * @author Kenji Urushima
5348 * @version 1.0.1 (08 May 2012)
5349 * @see <a href="http://kjur.github.com/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a>
5350 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08005351
5352var b64tohex = require('./base64.js').b64tohex;
5353var RSAKey = require('./rsa.js').RSAKey;
5354var ASN1HEX = require('./asn1hex-1.1.js').ASN1HEX;
5355
Alexander Afanasyev1663a412013-03-02 13:52:00 -08005356function X509() {
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08005357 this.subjectPublicKeyRSA = null;
5358 this.subjectPublicKeyRSA_hN = null;
5359 this.subjectPublicKeyRSA_hE = null;
5360 this.hex = null;
Alexander Afanasyev1663a412013-03-02 13:52:00 -08005361
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08005362 // ===== get basic fields from hex =====================================
Alexander Afanasyev1663a412013-03-02 13:52:00 -08005363
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08005364 /**
5365 * get hexadecimal string of serialNumber field of certificate.<br/>
5366 * @name getSerialNumberHex
5367 * @memberOf X509#
5368 * @function
5369 */
5370 this.getSerialNumberHex = function() {
5371 return ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 1]);
5372 };
5373
5374 /**
5375 * get hexadecimal string of issuer field TLV of certificate.<br/>
5376 * @name getIssuerHex
5377 * @memberOf X509#
5378 * @function
5379 */
5380 this.getIssuerHex = function() {
5381 return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]);
5382 };
5383
5384 /**
5385 * get string of issuer field of certificate.<br/>
5386 * @name getIssuerString
5387 * @memberOf X509#
5388 * @function
5389 */
5390 this.getIssuerString = function() {
5391 return X509.hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]));
5392 };
5393
5394 /**
5395 * get hexadecimal string of subject field of certificate.<br/>
5396 * @name getSubjectHex
5397 * @memberOf X509#
5398 * @function
5399 */
5400 this.getSubjectHex = function() {
5401 return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]);
5402 };
5403
5404 /**
5405 * get string of subject field of certificate.<br/>
5406 * @name getSubjectString
5407 * @memberOf X509#
5408 * @function
5409 */
5410 this.getSubjectString = function() {
5411 return X509.hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]));
5412 };
5413
5414 /**
5415 * get notBefore field string of certificate.<br/>
5416 * @name getNotBefore
5417 * @memberOf X509#
5418 * @function
5419 */
5420 this.getNotBefore = function() {
5421 var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 0]);
5422 s = s.replace(/(..)/g, "%$1");
5423 s = decodeURIComponent(s);
5424 return s;
5425 };
5426
5427 /**
5428 * get notAfter field string of certificate.<br/>
5429 * @name getNotAfter
5430 * @memberOf X509#
5431 * @function
5432 */
5433 this.getNotAfter = function() {
5434 var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 1]);
5435 s = s.replace(/(..)/g, "%$1");
5436 s = decodeURIComponent(s);
5437 return s;
5438 };
5439
5440 // ===== read certificate public key ==========================
5441
5442 // ===== read certificate =====================================
5443 /**
5444 * read PEM formatted X.509 certificate from string.<br/>
5445 * @name readCertPEM
5446 * @memberOf X509#
5447 * @function
5448 * @param {String} sCertPEM string for PEM formatted X.509 certificate
5449 */
5450 this.readCertPEM = function(sCertPEM) {
5451 var hCert = X509.pemToHex(sCertPEM);
5452 var a = X509.getPublicKeyHexArrayFromCertHex(hCert);
5453 var rsa = new RSAKey();
5454 rsa.setPublic(a[0], a[1]);
5455 this.subjectPublicKeyRSA = rsa;
5456 this.subjectPublicKeyRSA_hN = a[0];
5457 this.subjectPublicKeyRSA_hE = a[1];
5458 this.hex = hCert;
5459 };
5460
5461 this.readCertPEMWithoutRSAInit = function(sCertPEM) {
5462 var hCert = X509.pemToHex(sCertPEM);
5463 var a = X509.getPublicKeyHexArrayFromCertHex(hCert);
5464 this.subjectPublicKeyRSA.setPublic(a[0], a[1]);
5465 this.subjectPublicKeyRSA_hN = a[0];
5466 this.subjectPublicKeyRSA_hE = a[1];
5467 this.hex = hCert;
5468 };
5469};
5470
5471X509.pemToBase64 = function(sCertPEM) {
5472 var s = sCertPEM;
5473 s = s.replace("-----BEGIN CERTIFICATE-----", "");
5474 s = s.replace("-----END CERTIFICATE-----", "");
5475 s = s.replace(/[ \n]+/g, "");
5476 return s;
5477};
5478
5479X509.pemToHex = function(sCertPEM) {
5480 var b64Cert = X509.pemToBase64(sCertPEM);
5481 var hCert = b64tohex(b64Cert);
5482 return hCert;
5483};
5484
5485// NOTE: Without BITSTRING encapsulation.
5486X509.getSubjectPublicKeyPosFromCertHex = function(hCert) {
5487 var pInfo = X509.getSubjectPublicKeyInfoPosFromCertHex(hCert);
5488 if (pInfo == -1) return -1;
5489 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pInfo);
5490 if (a.length != 2) return -1;
5491 var pBitString = a[1];
5492 if (hCert.substring(pBitString, pBitString + 2) != '03') return -1;
5493 var pBitStringV = ASN1HEX.getStartPosOfV_AtObj(hCert, pBitString);
5494
5495 if (hCert.substring(pBitStringV, pBitStringV + 2) != '00') return -1;
5496 return pBitStringV + 2;
5497};
5498
5499// NOTE: privateKeyUsagePeriod field of X509v2 not supported.
5500// NOTE: v1 and v3 supported
5501X509.getSubjectPublicKeyInfoPosFromCertHex = function(hCert) {
5502 var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
5503 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pTbsCert);
5504 if (a.length < 1) return -1;
5505 if (hCert.substring(a[0], a[0] + 10) == "a003020102") { // v3
5506 if (a.length < 6) return -1;
5507 return a[6];
5508 } else {
5509 if (a.length < 5) return -1;
5510 return a[5];
5511 }
5512};
5513
5514X509.getPublicKeyHexArrayFromCertHex = function(hCert) {
5515 var p = X509.getSubjectPublicKeyPosFromCertHex(hCert);
5516 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, p);
5517 if (a.length != 2) return [];
5518 var hN = ASN1HEX.getHexOfV_AtObj(hCert, a[0]);
5519 var hE = ASN1HEX.getHexOfV_AtObj(hCert, a[1]);
5520 if (hN != null && hE != null) {
5521 return [hN, hE];
5522 } else {
5523 return [];
5524 }
5525};
5526
5527X509.getHexTbsCertificateFromCert = function(hCert) {
5528 var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
5529 return pTbsCert;
5530};
5531
5532X509.getPublicKeyHexArrayFromCertPEM = function(sCertPEM) {
5533 var hCert = X509.pemToHex(sCertPEM);
5534 var a = X509.getPublicKeyHexArrayFromCertHex(hCert);
5535 return a;
5536};
5537
5538X509.hex2dn = function(hDN) {
5539 var s = "";
5540 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hDN, 0);
5541 for (var i = 0; i < a.length; i++) {
5542 var hRDN = ASN1HEX.getHexOfTLV_AtObj(hDN, a[i]);
5543 s = s + "/" + X509.hex2rdn(hRDN);
5544 }
5545 return s;
5546};
5547
5548X509.hex2rdn = function(hRDN) {
5549 var hType = ASN1HEX.getDecendantHexTLVByNthList(hRDN, 0, [0, 0]);
5550 var hValue = ASN1HEX.getDecendantHexVByNthList(hRDN, 0, [0, 1]);
5551 var type = "";
5552 try { type = X509.DN_ATTRHEX[hType]; } catch (ex) { type = hType; }
5553 hValue = hValue.replace(/(..)/g, "%$1");
5554 var value = decodeURIComponent(hValue);
5555 return type + "=" + value;
5556};
5557
5558X509.DN_ATTRHEX = {
5559 "0603550406": "C",
5560 "060355040a": "O",
5561 "060355040b": "OU",
5562 "0603550403": "CN",
5563 "0603550405": "SN",
5564 "0603550408": "ST",
5565 "0603550407": "L"
5566};
5567
5568/**
5569 * get RSAKey/ECDSA public key object from PEM certificate string
5570 * @name getPublicKeyFromCertPEM
5571 * @memberOf X509
5572 * @function
5573 * @param {String} sCertPEM PEM formatted RSA/ECDSA/DSA X.509 certificate
5574 * @return returns RSAKey/KJUR.crypto.{ECDSA,DSA} object of public key
5575 * @since x509 1.1.1
5576 * @description
5577 * NOTE: DSA is also supported since x509 1.1.2.
5578 */
5579X509.getPublicKeyFromCertPEM = function(sCertPEM) {
5580 var info = X509.getPublicKeyInfoPropOfCertPEM(sCertPEM);
5581
5582 if (info.algoid == "2a864886f70d010101") { // RSA
5583 var aRSA = KEYUTIL.parsePublicRawRSAKeyHex(info.keyhex);
5584 var key = new RSAKey();
5585 key.setPublic(aRSA.n, aRSA.e);
5586 return key;
5587 } else if (info.algoid == "2a8648ce3d0201") { // ECC
5588 var curveName = KJUR.crypto.OID.oidhex2name[info.algparam];
5589 var key = new KJUR.crypto.ECDSA({'curve': curveName, 'info': info.keyhex});
5590 key.setPublicKeyHex(info.keyhex);
5591 return key;
5592 } else if (info.algoid == "2a8648ce380401") { // DSA 1.2.840.10040.4.1
5593 var p = ASN1HEX.getVbyList(info.algparam, 0, [0], "02");
5594 var q = ASN1HEX.getVbyList(info.algparam, 0, [1], "02");
5595 var g = ASN1HEX.getVbyList(info.algparam, 0, [2], "02");
5596 var y = ASN1HEX.getHexOfV_AtObj(info.keyhex, 0);
5597 y = y.substr(2);
5598 var key = new KJUR.crypto.DSA();
5599 key.setPublic(new BigInteger(p, 16),
5600 new BigInteger(q, 16),
5601 new BigInteger(g, 16),
5602 new BigInteger(y, 16));
5603 return key;
5604 } else {
5605 throw "unsupported key";
5606 }
5607};
5608
5609/**
5610 * get public key information from PEM certificate
5611 * @name getPublicKeyInfoPropOfCertPEM
5612 * @memberOf X509
5613 * @function
5614 * @param {String} sCertPEM string of PEM formatted certificate
5615 * @return {Hash} hash of information for public key
5616 * @since x509 1.1.1
5617 * @description
5618 * Resulted associative array has following properties:
5619 * <ul>
5620 * <li>algoid - hexadecimal string of OID of asymmetric key algorithm</li>
5621 * <li>algparam - hexadecimal string of OID of ECC curve name or null</li>
5622 * <li>keyhex - hexadecimal string of key in the certificate</li>
5623 * </ul>
5624 * @since x509 1.1.1
5625 */
5626X509.getPublicKeyInfoPropOfCertPEM = function(sCertPEM) {
5627 var result = {};
5628 result.algparam = null;
5629 var hCert = X509.pemToHex(sCertPEM);
5630
5631 // 1. Certificate ASN.1
5632 var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, 0);
5633 if (a1.length != 3)
5634 throw "malformed X.509 certificate PEM (code:001)"; // not 3 item of seq Cert
5635
5636 // 2. tbsCertificate
5637 if (hCert.substr(a1[0], 2) != "30")
5638 throw "malformed X.509 certificate PEM (code:002)"; // tbsCert not seq
5639
5640 var a2 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a1[0]);
5641
5642 // 3. subjectPublicKeyInfo
5643 if (a2.length < 7)
5644 throw "malformed X.509 certificate PEM (code:003)"; // no subjPubKeyInfo
5645
5646 var a3 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a2[6]);
5647
5648 if (a3.length != 2)
5649 throw "malformed X.509 certificate PEM (code:004)"; // not AlgId and PubKey
5650
5651 // 4. AlgId
5652 var a4 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a3[0]);
5653
5654 if (a4.length != 2)
5655 throw "malformed X.509 certificate PEM (code:005)"; // not 2 item in AlgId
5656
5657 result.algoid = ASN1HEX.getHexOfV_AtObj(hCert, a4[0]);
5658
5659 if (hCert.substr(a4[1], 2) == "06") { // EC
5660 result.algparam = ASN1HEX.getHexOfV_AtObj(hCert, a4[1]);
5661 } else if (hCert.substr(a4[1], 2) == "30") { // DSA
5662 result.algparam = ASN1HEX.getHexOfTLV_AtObj(hCert, a4[1]);
5663 }
5664
5665 // 5. Public Key Hex
5666 if (hCert.substr(a3[1], 2) != "03")
5667 throw "malformed X.509 certificate PEM (code:006)"; // not bitstring
5668
5669 var unusedBitAndKeyHex = ASN1HEX.getHexOfV_AtObj(hCert, a3[1]);
5670 result.keyhex = unusedBitAndKeyHex.substr(2);
5671
5672 return result;
5673};
5674
5675/**
5676 * get position of subjectPublicKeyInfo field from HEX certificate
5677 * @name getPublicKeyInfoPosOfCertHEX
5678 * @memberOf X509
5679 * @function
5680 * @param {String} hCert hexadecimal string of certificate
5681 * @return {Integer} position in hexadecimal string
5682 * @since x509 1.1.4
5683 * @description
5684 * get position for SubjectPublicKeyInfo field in the hexadecimal string of
5685 * certificate.
5686 */
5687X509.getPublicKeyInfoPosOfCertHEX = function(hCert) {
5688 // 1. Certificate ASN.1
5689 var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, 0);
5690 if (a1.length != 3)
5691 throw "malformed X.509 certificate PEM (code:001)"; // not 3 item of seq Cert
5692
5693 // 2. tbsCertificate
5694 if (hCert.substr(a1[0], 2) != "30")
5695 throw "malformed X.509 certificate PEM (code:002)"; // tbsCert not seq
5696
5697 var a2 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a1[0]);
5698
5699 // 3. subjectPublicKeyInfo
5700 if (a2.length < 7)
5701 throw "malformed X.509 certificate PEM (code:003)"; // no subjPubKeyInfo
5702
5703 return a2[6];
5704};
5705
5706/**
5707 * get array of X.509 V3 extension value information in hex string of certificate
5708 * @name getV3ExtInfoListOfCertHex
5709 * @memberOf X509
5710 * @function
5711 * @param {String} hCert hexadecimal string of X.509 certificate binary
5712 * @return {Array} array of result object by {@link X509.getV3ExtInfoListOfCertHex}
5713 * @since x509 1.1.5
5714 * @description
5715 * This method will get all extension information of a X.509 certificate.
5716 * Items of resulting array has following properties:
5717 * <ul>
5718 * <li>posTLV - index of ASN.1 TLV for the extension. same as 'pos' argument.</li>
5719 * <li>oid - dot noted string of extension oid (ex. 2.5.29.14)</li>
5720 * <li>critical - critical flag value for this extension</li>
5721 * <li>posV - index of ASN.1 TLV for the extension value.
5722 * This is a position of a content of ENCAPSULATED OCTET STRING.</li>
5723 * </ul>
5724 * @example
5725 * hCert = X509.pemToHex(certGithubPEM);
5726 * a = X509.getV3ExtInfoListOfCertHex(hCert);
5727 * // Then a will be an array of like following:
5728 * [{posTLV: 1952, oid: "2.5.29.35", critical: false, posV: 1968},
5729 * {posTLV: 1974, oid: "2.5.29.19", critical: true, posV: 1986}, ...]
5730 */
5731X509.getV3ExtInfoListOfCertHex = function(hCert) {
5732 // 1. Certificate ASN.1
5733 var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, 0);
5734 if (a1.length != 3)
5735 throw "malformed X.509 certificate PEM (code:001)"; // not 3 item of seq Cert
5736
5737 // 2. tbsCertificate
5738 if (hCert.substr(a1[0], 2) != "30")
5739 throw "malformed X.509 certificate PEM (code:002)"; // tbsCert not seq
5740
5741 var a2 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a1[0]);
5742
5743 // 3. v3Extension EXPLICIT Tag [3]
5744 // ver, seri, alg, iss, validity, subj, spki, (iui,) (sui,) ext
5745 if (a2.length < 8)
5746 throw "malformed X.509 certificate PEM (code:003)"; // tbsCert num field too short
5747
5748 if (hCert.substr(a2[7], 2) != "a3")
5749 throw "malformed X.509 certificate PEM (code:004)"; // not [3] tag
5750
5751 var a3 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a2[7]);
5752 if (a3.length != 1)
5753 throw "malformed X.509 certificate PEM (code:005)"; // [3]tag numChild!=1
5754
5755 // 4. v3Extension SEQUENCE
5756 if (hCert.substr(a3[0], 2) != "30")
5757 throw "malformed X.509 certificate PEM (code:006)"; // not SEQ
5758
5759 var a4 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a3[0]);
5760
5761 // 5. v3Extension item position
5762 var numExt = a4.length;
5763 var aInfo = new Array(numExt);
5764 for (var i = 0; i < numExt; i++) {
5765 aInfo[i] = X509.getV3ExtItemInfo_AtObj(hCert, a4[i]);
5766 }
5767 return aInfo;
5768};
5769
5770/**
5771 * get X.509 V3 extension value information at the specified position
5772 * @name getV3ExtItemInfo_AtObj
5773 * @memberOf X509
5774 * @function
5775 * @param {String} hCert hexadecimal string of X.509 certificate binary
5776 * @param {Integer} pos index of hexadecimal string for the extension
5777 * @return {Object} properties for the extension
5778 * @since x509 1.1.5
5779 * @description
5780 * This method will get some information of a X.509 V extension
5781 * which is referred by an index of hexadecimal string of X.509
5782 * certificate.
5783 * Resulting object has following properties:
5784 * <ul>
5785 * <li>posTLV - index of ASN.1 TLV for the extension. same as 'pos' argument.</li>
5786 * <li>oid - dot noted string of extension oid (ex. 2.5.29.14)</li>
5787 * <li>critical - critical flag value for this extension</li>
5788 * <li>posV - index of ASN.1 TLV for the extension value.
5789 * This is a position of a content of ENCAPSULATED OCTET STRING.</li>
5790 * </ul>
5791 * This method is used by {@link X509.getV3ExtInfoListOfCertHex} internally.
5792 */
5793X509.getV3ExtItemInfo_AtObj = function(hCert, pos) {
5794 var info = {};
5795
5796 // posTLV - extension TLV
5797 info.posTLV = pos;
5798
5799 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pos);
5800 if (a.length != 2 && a.length != 3)
5801 throw "malformed X.509v3 Ext (code:001)"; // oid,(critical,)val
5802
5803 // oid - extension OID
5804 if (hCert.substr(a[0], 2) != "06")
5805 throw "malformed X.509v3 Ext (code:002)"; // not OID "06"
5806 var valueHex = ASN1HEX.getHexOfV_AtObj(hCert, a[0]);
5807 info.oid = ASN1HEX.hextooidstr(valueHex);
5808
5809 // critical - extension critical flag
5810 info.critical = false; // critical false by default
5811 if (a.length == 3) info.critical = true;
5812
5813 // posV - content TLV position of encapsulated
5814 // octet string of V3 extension value.
5815 var posExtV = a[a.length - 1];
5816 if (hCert.substr(posExtV, 2) != "04")
5817 throw "malformed X.509v3 Ext (code:003)"; // not EncapOctet "04"
5818 info.posV = ASN1HEX.getStartPosOfV_AtObj(hCert, posExtV);
5819
5820 return info;
5821};
5822
5823/**
5824 * get X.509 V3 extension value ASN.1 TLV for specified oid or name
5825 * @name getHexOfTLV_V3ExtValue
5826 * @memberOf X509
5827 * @function
5828 * @param {String} hCert hexadecimal string of X.509 certificate binary
5829 * @param {String} oidOrName oid or name for extension (ex. 'keyUsage' or '2.5.29.15')
5830 * @return {String} hexadecimal string of extension ASN.1 TLV
5831 * @since x509 1.1.6
5832 * @description
5833 * This method will get X.509v3 extension value of ASN.1 TLV
5834 * which is specifyed by extension name or oid.
5835 * @example
5836 * hExtValue = X509.getHexOfTLV_V3ExtValue(hCert, "keyUsage");
5837 * // hExtValue will be such like '030205a0'.
5838 */
5839X509.getHexOfTLV_V3ExtValue = function(hCert, oidOrName) {
5840 var pos = X509.getPosOfTLV_V3ExtValue(hCert, oidOrName);
5841 if (pos == -1) return '';
5842 return ASN1HEX.getHexOfTLV_AtObj(hCert, pos);
5843};
5844
5845/**
5846 * get X.509 V3 extension value ASN.1 V for specified oid or name
5847 * @name getHexOfV_V3ExtValue
5848 * @memberOf X509
5849 * @function
5850 * @param {String} hCert hexadecimal string of X.509 certificate binary
5851 * @param {String} oidOrName oid or name for extension (ex. 'keyUsage' or '2.5.29.15')
5852 * @return {String} hexadecimal string of extension ASN.1 TLV
5853 * @since x509 1.1.6
5854 * @description
5855 * This method will get X.509v3 extension value of ASN.1 value
5856 * which is specifyed by extension name or oid.
5857 * If there is no such extension in the certificate,
5858 * it returns empty string (i.e. '').
5859 * Available extension names and oids are defined
5860 * in the {@link KJUR.asn1.x509.OID} class.
5861 * @example
5862 * hExtValue = X509.getHexOfV_V3ExtValue(hCert, "keyUsage");
5863 * // hExtValue will be such like '05a0'.
5864 */
5865X509.getHexOfV_V3ExtValue = function(hCert, oidOrName) {
5866 var pos = X509.getPosOfTLV_V3ExtValue(hCert, oidOrName);
5867 if (pos == -1) return '';
5868 return ASN1HEX.getHexOfV_AtObj(hCert, pos);
5869};
5870
5871/**
5872 * get index in the certificate hexa string for specified oid or name specified extension
5873 * @name getPosOfTLV_V3ExtValue
5874 * @memberOf X509
5875 * @function
5876 * @param {String} hCert hexadecimal string of X.509 certificate binary
5877 * @param {String} oidOrName oid or name for extension (ex. 'keyUsage' or '2.5.29.15')
5878 * @return {Integer} index in the hexadecimal string of certficate for specified extension
5879 * @since x509 1.1.6
5880 * @description
5881 * This method will get X.509v3 extension value of ASN.1 V(value)
5882 * which is specifyed by extension name or oid.
5883 * If there is no such extension in the certificate,
5884 * it returns empty string (i.e. '').
5885 * Available extension names and oids are defined
5886 * in the {@link KJUR.asn1.x509.OID} class.
5887 * @example
5888 * idx = X509.getPosOfV_V3ExtValue(hCert, "keyUsage");
5889 * // The 'idx' will be index in the string for keyUsage value ASN.1 TLV.
5890 */
5891X509.getPosOfTLV_V3ExtValue = function(hCert, oidOrName) {
5892 var oid = oidOrName;
5893 if (! oidOrName.match(/^[0-9.]+$/)) oid = KJUR.asn1.x509.OID.name2oid(oidOrName);
5894 if (oid == '') return -1;
5895
5896 var infoList = X509.getV3ExtInfoListOfCertHex(hCert);
5897 for (var i = 0; i < infoList.length; i++) {
5898 var info = infoList[i];
5899 if (info.oid == oid) return info.posV;
5900 }
5901 return -1;
5902};
5903
5904X509.KEYUSAGE_NAME = [
5905 "digitalSignature",
5906 "nonRepudiation",
5907 "keyEncipherment",
5908 "dataEncipherment",
5909 "keyAgreement",
5910 "keyCertSign",
5911 "cRLSign",
5912 "encipherOnly",
5913 "decipherOnly"
5914];
5915
5916/**
5917 * get KeyUsage extension value as binary string in the certificate
5918 * @name getExtKeyUsageBin
5919 * @memberOf X509
5920 * @function
5921 * @param {String} hCert hexadecimal string of X.509 certificate binary
5922 * @return {String} binary string of key usage bits (ex. '101')
5923 * @since x509 1.1.6
5924 * @description
5925 * This method will get key usage extension value
5926 * as binary string such like '101'.
5927 * Key usage bits definition is in the RFC 5280.
5928 * If there is no key usage extension in the certificate,
5929 * it returns empty string (i.e. '').
5930 * @example
5931 * bKeyUsage = X509.getExtKeyUsageBin(hCert);
5932 * // bKeyUsage will be such like '101'.
5933 * // 1 - digitalSignature
5934 * // 0 - nonRepudiation
5935 * // 1 - keyEncipherment
5936 */
5937X509.getExtKeyUsageBin = function(hCert) {
5938 var hKeyUsage = X509.getHexOfV_V3ExtValue(hCert, "keyUsage");
5939 if (hKeyUsage == '') return '';
5940 if (hKeyUsage.length % 2 != 0 || hKeyUsage.length <= 2)
5941 throw "malformed key usage value";
5942 var unusedBits = parseInt(hKeyUsage.substr(0, 2));
5943 var bKeyUsage = parseInt(hKeyUsage.substr(2), 16).toString(2);
5944 return bKeyUsage.substr(0, bKeyUsage.length - unusedBits);
5945};
5946
5947/**
5948 * get KeyUsage extension value as names in the certificate
5949 * @name getExtKeyUsageString
5950 * @memberOf X509
5951 * @function
5952 * @param {String} hCert hexadecimal string of X.509 certificate binary
5953 * @return {String} comma separated string of key usage
5954 * @since x509 1.1.6
5955 * @description
5956 * This method will get key usage extension value
5957 * as comma separated string of usage names.
5958 * If there is no key usage extension in the certificate,
5959 * it returns empty string (i.e. '').
5960 * @example
5961 * sKeyUsage = X509.getExtKeyUsageString(hCert);
5962 * // sKeyUsage will be such like 'digitalSignature,keyEncipherment'.
5963 */
5964X509.getExtKeyUsageString = function(hCert) {
5965 var bKeyUsage = X509.getExtKeyUsageBin(hCert);
5966 var a = new Array();
5967 for (var i = 0; i < bKeyUsage.length; i++) {
5968 if (bKeyUsage.substr(i, 1) == "1") a.push(X509.KEYUSAGE_NAME[i]);
5969 }
5970 return a.join(",");
5971};
5972
5973/**
5974 * get AuthorityInfoAccess extension value in the certificate as associative array
5975 * @name getExtAIAInfo
5976 * @memberOf X509
5977 * @function
5978 * @param {String} hCert hexadecimal string of X.509 certificate binary
5979 * @return {Object} associative array of AIA extension properties
5980 * @since x509 1.1.6
5981 * @description
5982 * This method will get authority info access value
5983 * as associate array which has following properties:
5984 * <ul>
5985 * <li>ocsp - array of string for OCSP responder URL</li>
5986 * <li>caissuer - array of string for caIssuer value (i.e. CA certificates URL)</li>
5987 * </ul>
5988 * If there is no key usage extension in the certificate,
5989 * it returns null;
5990 * @example
5991 * oAIA = X509.getExtAIAInfo(hCert);
5992 * // result will be such like:
5993 * // oAIA.ocsp = ["http://ocsp.foo.com"];
5994 * // oAIA.caissuer = ["http://rep.foo.com/aaa.p8m"];
5995 */
5996X509.getExtAIAInfo = function(hCert) {
5997 var result = {};
5998 result.ocsp = [];
5999 result.caissuer = [];
6000 var pos1 = X509.getPosOfTLV_V3ExtValue(hCert, "authorityInfoAccess");
6001 if (pos1 == -1) return null;
6002 if (hCert.substr(pos1, 2) != "30") // extnValue SEQUENCE
6003 throw "malformed AIA Extn Value";
6004
6005 var posAccDescList = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pos1);
6006 for (var i = 0; i < posAccDescList.length; i++) {
6007 var p = posAccDescList[i];
6008 var posAccDescChild = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, p);
6009 if (posAccDescChild.length != 2)
6010 throw "malformed AccessDescription of AIA Extn";
6011 var pOID = posAccDescChild[0];
6012 var pName = posAccDescChild[1];
6013 if (ASN1HEX.getHexOfV_AtObj(hCert, pOID) == "2b06010505073001") {
6014 if (hCert.substr(pName, 2) == "86") {
6015 result.ocsp.push(hextoutf8(ASN1HEX.getHexOfV_AtObj(hCert, pName)));
6016 }
6017 }
6018 if (ASN1HEX.getHexOfV_AtObj(hCert, pOID) == "2b06010505073002") {
6019 if (hCert.substr(pName, 2) == "86") {
6020 result.caissuer.push(hextoutf8(ASN1HEX.getHexOfV_AtObj(hCert, pName)));
6021 }
6022 }
6023 }
6024 return result;
6025};
6026
6027/*
6028 X509.prototype.readCertPEM = _x509_readCertPEM;
6029 X509.prototype.readCertPEMWithoutRSAInit = _x509_readCertPEMWithoutRSAInit;
6030 X509.prototype.getSerialNumberHex = _x509_getSerialNumberHex;
6031 X509.prototype.getIssuerHex = _x509_getIssuerHex;
6032 X509.prototype.getSubjectHex = _x509_getSubjectHex;
6033 X509.prototype.getIssuerString = _x509_getIssuerString;
6034 X509.prototype.getSubjectString = _x509_getSubjectString;
6035 X509.prototype.getNotBefore = _x509_getNotBefore;
6036 X509.prototype.getNotAfter = _x509_getNotAfter;
6037*/
6038
6039exports.X509 = X509;
6040module.exports = exports;
6041/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/
6042 */
Alexander Afanasyev1663a412013-03-02 13:52:00 -08006043// Copyright (c) 2005 Tom Wu
6044// All Rights Reserved.
6045// See "LICENSE" for details.
6046
6047// Basic JavaScript BN library - subset useful for RSA encryption.
6048
6049// Bits per digit
6050var dbits;
6051
6052// JavaScript engine analysis
6053var canary = 0xdeadbeefcafe;
6054var j_lm = ((canary&0xffffff)==0xefcafe);
6055
6056// (public) Constructor
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08006057var BigInteger = function BigInteger(a,b,c) {
Alexander Afanasyev1663a412013-03-02 13:52:00 -08006058 if(a != null)
6059 if("number" == typeof a) this.fromNumber(a,b,c);
6060 else if(b == null && "string" != typeof a) this.fromString(a,256);
6061 else this.fromString(a,b);
6062}
6063
6064// return new, unset BigInteger
6065function nbi() { return new BigInteger(null); }
6066
6067// am: Compute w_j += (x*this_i), propagate carries,
6068// c is initial carry, returns final carry.
6069// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
6070// We need to select the fastest one that works in this environment.
6071
6072// am1: use a single mult and divide to get the high bits,
6073// max digit bits should be 26 because
6074// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
6075function am1(i,x,w,j,c,n) {
6076 while(--n >= 0) {
6077 var v = x*this[i++]+w[j]+c;
6078 c = Math.floor(v/0x4000000);
6079 w[j++] = v&0x3ffffff;
6080 }
6081 return c;
6082}
6083// am2 avoids a big mult-and-extract completely.
6084// Max digit bits should be <= 30 because we do bitwise ops
6085// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
6086function am2(i,x,w,j,c,n) {
6087 var xl = x&0x7fff, xh = x>>15;
6088 while(--n >= 0) {
6089 var l = this[i]&0x7fff;
6090 var h = this[i++]>>15;
6091 var m = xh*l+h*xl;
6092 l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff);
6093 c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);
6094 w[j++] = l&0x3fffffff;
6095 }
6096 return c;
6097}
6098// Alternately, set max digit bits to 28 since some
6099// browsers slow down when dealing with 32-bit numbers.
6100function am3(i,x,w,j,c,n) {
6101 var xl = x&0x3fff, xh = x>>14;
6102 while(--n >= 0) {
6103 var l = this[i]&0x3fff;
6104 var h = this[i++]>>14;
6105 var m = xh*l+h*xl;
6106 l = xl*l+((m&0x3fff)<<14)+w[j]+c;
6107 c = (l>>28)+(m>>14)+xh*h;
6108 w[j++] = l&0xfffffff;
6109 }
6110 return c;
6111}
6112if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
6113 BigInteger.prototype.am = am2;
6114 dbits = 30;
6115}
6116else if(j_lm && (navigator.appName != "Netscape")) {
6117 BigInteger.prototype.am = am1;
6118 dbits = 26;
6119}
6120else { // Mozilla/Netscape seems to prefer am3
6121 BigInteger.prototype.am = am3;
6122 dbits = 28;
6123}
6124
6125BigInteger.prototype.DB = dbits;
6126BigInteger.prototype.DM = ((1<<dbits)-1);
6127BigInteger.prototype.DV = (1<<dbits);
6128
6129var BI_FP = 52;
6130BigInteger.prototype.FV = Math.pow(2,BI_FP);
6131BigInteger.prototype.F1 = BI_FP-dbits;
6132BigInteger.prototype.F2 = 2*dbits-BI_FP;
6133
6134// Digit conversions
6135var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
6136var BI_RC = new Array();
6137var rr,vv;
6138rr = "0".charCodeAt(0);
6139for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
6140rr = "a".charCodeAt(0);
6141for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
6142rr = "A".charCodeAt(0);
6143for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
6144
6145function int2char(n) { return BI_RM.charAt(n); }
6146function intAt(s,i) {
6147 var c = BI_RC[s.charCodeAt(i)];
6148 return (c==null)?-1:c;
6149}
6150
6151// (protected) copy this to r
6152function bnpCopyTo(r) {
6153 for(var i = this.t-1; i >= 0; --i) r[i] = this[i];
6154 r.t = this.t;
6155 r.s = this.s;
6156}
6157
6158// (protected) set from integer value x, -DV <= x < DV
6159function bnpFromInt(x) {
6160 this.t = 1;
6161 this.s = (x<0)?-1:0;
6162 if(x > 0) this[0] = x;
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08006163 else if(x < -1) this[0] = x+this.DV;
Alexander Afanasyev1663a412013-03-02 13:52:00 -08006164 else this.t = 0;
6165}
6166
6167// return bigint initialized to value
6168function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
6169
6170// (protected) set from string and radix
6171function bnpFromString(s,b) {
6172 var k;
6173 if(b == 16) k = 4;
6174 else if(b == 8) k = 3;
6175 else if(b == 256) k = 8; // byte array
6176 else if(b == 2) k = 1;
6177 else if(b == 32) k = 5;
6178 else if(b == 4) k = 2;
6179 else { this.fromRadix(s,b); return; }
6180 this.t = 0;
6181 this.s = 0;
6182 var i = s.length, mi = false, sh = 0;
6183 while(--i >= 0) {
6184 var x = (k==8)?s[i]&0xff:intAt(s,i);
6185 if(x < 0) {
6186 if(s.charAt(i) == "-") mi = true;
6187 continue;
6188 }
6189 mi = false;
6190 if(sh == 0)
6191 this[this.t++] = x;
6192 else if(sh+k > this.DB) {
6193 this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<<sh;
6194 this[this.t++] = (x>>(this.DB-sh));
6195 }
6196 else
6197 this[this.t-1] |= x<<sh;
6198 sh += k;
6199 if(sh >= this.DB) sh -= this.DB;
6200 }
6201 if(k == 8 && (s[0]&0x80) != 0) {
6202 this.s = -1;
6203 if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh;
6204 }
6205 this.clamp();
6206 if(mi) BigInteger.ZERO.subTo(this,this);
6207}
6208
6209// (protected) clamp off excess high words
6210function bnpClamp() {
6211 var c = this.s&this.DM;
6212 while(this.t > 0 && this[this.t-1] == c) --this.t;
6213}
6214
6215// (public) return string representation in given radix
6216function bnToString(b) {
6217 if(this.s < 0) return "-"+this.negate().toString(b);
6218 var k;
6219 if(b == 16) k = 4;
6220 else if(b == 8) k = 3;
6221 else if(b == 2) k = 1;
6222 else if(b == 32) k = 5;
6223 else if(b == 4) k = 2;
6224 else return this.toRadix(b);
6225 var km = (1<<k)-1, d, m = false, r = "", i = this.t;
6226 var p = this.DB-(i*this.DB)%k;
6227 if(i-- > 0) {
6228 if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); }
6229 while(i >= 0) {
6230 if(p < k) {
6231 d = (this[i]&((1<<p)-1))<<(k-p);
6232 d |= this[--i]>>(p+=this.DB-k);
6233 }
6234 else {
6235 d = (this[i]>>(p-=k))&km;
6236 if(p <= 0) { p += this.DB; --i; }
6237 }
6238 if(d > 0) m = true;
6239 if(m) r += int2char(d);
6240 }
6241 }
6242 return m?r:"0";
6243}
6244
6245// (public) -this
6246function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }
6247
6248// (public) |this|
6249function bnAbs() { return (this.s<0)?this.negate():this; }
6250
6251// (public) return + if this > a, - if this < a, 0 if equal
6252function bnCompareTo(a) {
6253 var r = this.s-a.s;
6254 if(r != 0) return r;
6255 var i = this.t;
6256 r = i-a.t;
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08006257 if(r != 0) return (this.s<0)?-r:r;
Alexander Afanasyev1663a412013-03-02 13:52:00 -08006258 while(--i >= 0) if((r=this[i]-a[i]) != 0) return r;
6259 return 0;
6260}
6261
6262// returns bit length of the integer x
6263function nbits(x) {
6264 var r = 1, t;
6265 if((t=x>>>16) != 0) { x = t; r += 16; }
6266 if((t=x>>8) != 0) { x = t; r += 8; }
6267 if((t=x>>4) != 0) { x = t; r += 4; }
6268 if((t=x>>2) != 0) { x = t; r += 2; }
6269 if((t=x>>1) != 0) { x = t; r += 1; }
6270 return r;
6271}
6272
6273// (public) return the number of bits in "this"
6274function bnBitLength() {
6275 if(this.t <= 0) return 0;
6276 return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM));
6277}
6278
6279// (protected) r = this << n*DB
6280function bnpDLShiftTo(n,r) {
6281 var i;
6282 for(i = this.t-1; i >= 0; --i) r[i+n] = this[i];
6283 for(i = n-1; i >= 0; --i) r[i] = 0;
6284 r.t = this.t+n;
6285 r.s = this.s;
6286}
6287
6288// (protected) r = this >> n*DB
6289function bnpDRShiftTo(n,r) {
6290 for(var i = n; i < this.t; ++i) r[i-n] = this[i];
6291 r.t = Math.max(this.t-n,0);
6292 r.s = this.s;
6293}
6294
6295// (protected) r = this << n
6296function bnpLShiftTo(n,r) {
6297 var bs = n%this.DB;
6298 var cbs = this.DB-bs;
6299 var bm = (1<<cbs)-1;
6300 var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i;
6301 for(i = this.t-1; i >= 0; --i) {
6302 r[i+ds+1] = (this[i]>>cbs)|c;
6303 c = (this[i]&bm)<<bs;
6304 }
6305 for(i = ds-1; i >= 0; --i) r[i] = 0;
6306 r[ds] = c;
6307 r.t = this.t+ds+1;
6308 r.s = this.s;
6309 r.clamp();
6310}
6311
6312// (protected) r = this >> n
6313function bnpRShiftTo(n,r) {
6314 r.s = this.s;
6315 var ds = Math.floor(n/this.DB);
6316 if(ds >= this.t) { r.t = 0; return; }
6317 var bs = n%this.DB;
6318 var cbs = this.DB-bs;
6319 var bm = (1<<bs)-1;
6320 r[0] = this[ds]>>bs;
6321 for(var i = ds+1; i < this.t; ++i) {
6322 r[i-ds-1] |= (this[i]&bm)<<cbs;
6323 r[i-ds] = this[i]>>bs;
6324 }
6325 if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs;
6326 r.t = this.t-ds;
6327 r.clamp();
6328}
6329
6330// (protected) r = this - a
6331function bnpSubTo(a,r) {
6332 var i = 0, c = 0, m = Math.min(a.t,this.t);
6333 while(i < m) {
6334 c += this[i]-a[i];
6335 r[i++] = c&this.DM;
6336 c >>= this.DB;
6337 }
6338 if(a.t < this.t) {
6339 c -= a.s;
6340 while(i < this.t) {
6341 c += this[i];
6342 r[i++] = c&this.DM;
6343 c >>= this.DB;
6344 }
6345 c += this.s;
6346 }
6347 else {
6348 c += this.s;
6349 while(i < a.t) {
6350 c -= a[i];
6351 r[i++] = c&this.DM;
6352 c >>= this.DB;
6353 }
6354 c -= a.s;
6355 }
6356 r.s = (c<0)?-1:0;
6357 if(c < -1) r[i++] = this.DV+c;
6358 else if(c > 0) r[i++] = c;
6359 r.t = i;
6360 r.clamp();
6361}
6362
6363// (protected) r = this * a, r != this,a (HAC 14.12)
6364// "this" should be the larger one if appropriate.
6365function bnpMultiplyTo(a,r) {
6366 var x = this.abs(), y = a.abs();
6367 var i = x.t;
6368 r.t = i+y.t;
6369 while(--i >= 0) r[i] = 0;
6370 for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t);
6371 r.s = 0;
6372 r.clamp();
6373 if(this.s != a.s) BigInteger.ZERO.subTo(r,r);
6374}
6375
6376// (protected) r = this^2, r != this (HAC 14.16)
6377function bnpSquareTo(r) {
6378 var x = this.abs();
6379 var i = r.t = 2*x.t;
6380 while(--i >= 0) r[i] = 0;
6381 for(i = 0; i < x.t-1; ++i) {
6382 var c = x.am(i,x[i],r,2*i,0,1);
6383 if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) {
6384 r[i+x.t] -= x.DV;
6385 r[i+x.t+1] = 1;
6386 }
6387 }
6388 if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1);
6389 r.s = 0;
6390 r.clamp();
6391}
6392
6393// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
6394// r != q, this != m. q or r may be null.
6395function bnpDivRemTo(m,q,r) {
6396 var pm = m.abs();
6397 if(pm.t <= 0) return;
6398 var pt = this.abs();
6399 if(pt.t < pm.t) {
6400 if(q != null) q.fromInt(0);
6401 if(r != null) this.copyTo(r);
6402 return;
6403 }
6404 if(r == null) r = nbi();
6405 var y = nbi(), ts = this.s, ms = m.s;
6406 var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus
6407 if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }
6408 else { pm.copyTo(y); pt.copyTo(r); }
6409 var ys = y.t;
6410 var y0 = y[ys-1];
6411 if(y0 == 0) return;
6412 var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);
6413 var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
6414 var i = r.t, j = i-ys, t = (q==null)?nbi():q;
6415 y.dlShiftTo(j,t);
6416 if(r.compareTo(t) >= 0) {
6417 r[r.t++] = 1;
6418 r.subTo(t,r);
6419 }
6420 BigInteger.ONE.dlShiftTo(ys,t);
6421 t.subTo(y,y); // "negative" y so we can replace sub with am later
6422 while(y.t < ys) y[y.t++] = 0;
6423 while(--j >= 0) {
6424 // Estimate quotient digit
6425 var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);
6426 if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out
6427 y.dlShiftTo(j,t);
6428 r.subTo(t,r);
6429 while(r[i] < --qd) r.subTo(t,r);
6430 }
6431 }
6432 if(q != null) {
6433 r.drShiftTo(ys,q);
6434 if(ts != ms) BigInteger.ZERO.subTo(q,q);
6435 }
6436 r.t = ys;
6437 r.clamp();
6438 if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder
6439 if(ts < 0) BigInteger.ZERO.subTo(r,r);
6440}
6441
6442// (public) this mod a
6443function bnMod(a) {
6444 var r = nbi();
6445 this.abs().divRemTo(a,null,r);
6446 if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);
6447 return r;
6448}
6449
6450// Modular reduction using "classic" algorithm
6451function Classic(m) { this.m = m; }
6452function cConvert(x) {
6453 if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
6454 else return x;
6455}
6456function cRevert(x) { return x; }
6457function cReduce(x) { x.divRemTo(this.m,null,x); }
6458function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
6459function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
6460
6461Classic.prototype.convert = cConvert;
6462Classic.prototype.revert = cRevert;
6463Classic.prototype.reduce = cReduce;
6464Classic.prototype.mulTo = cMulTo;
6465Classic.prototype.sqrTo = cSqrTo;
6466
6467// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
6468// justification:
6469// xy == 1 (mod m)
6470// xy = 1+km
6471// xy(2-xy) = (1+km)(1-km)
6472// x[y(2-xy)] = 1-k^2m^2
6473// x[y(2-xy)] == 1 (mod m^2)
6474// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
6475// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
6476// JS multiply "overflows" differently from C/C++, so care is needed here.
6477function bnpInvDigit() {
6478 if(this.t < 1) return 0;
6479 var x = this[0];
6480 if((x&1) == 0) return 0;
6481 var y = x&3; // y == 1/x mod 2^2
6482 y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4
6483 y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8
6484 y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16
6485 // last step - calculate inverse mod DV directly;
6486 // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
6487 y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits
6488 // we really want the negative inverse, and -DV < y < DV
6489 return (y>0)?this.DV-y:-y;
6490}
6491
6492// Montgomery reduction
6493function Montgomery(m) {
6494 this.m = m;
6495 this.mp = m.invDigit();
6496 this.mpl = this.mp&0x7fff;
6497 this.mph = this.mp>>15;
6498 this.um = (1<<(m.DB-15))-1;
6499 this.mt2 = 2*m.t;
6500}
6501
6502// xR mod m
6503function montConvert(x) {
6504 var r = nbi();
6505 x.abs().dlShiftTo(this.m.t,r);
6506 r.divRemTo(this.m,null,r);
6507 if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);
6508 return r;
6509}
6510
6511// x/R mod m
6512function montRevert(x) {
6513 var r = nbi();
6514 x.copyTo(r);
6515 this.reduce(r);
6516 return r;
6517}
6518
6519// x = x/R mod m (HAC 14.32)
6520function montReduce(x) {
6521 while(x.t <= this.mt2) // pad x so am has enough room later
6522 x[x.t++] = 0;
6523 for(var i = 0; i < this.m.t; ++i) {
6524 // faster way of calculating u0 = x[i]*mp mod DV
6525 var j = x[i]&0x7fff;
6526 var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM;
6527 // use am to combine the multiply-shift-add into one call
6528 j = i+this.m.t;
6529 x[j] += this.m.am(0,u0,x,i,0,this.m.t);
6530 // propagate carry
6531 while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; }
6532 }
6533 x.clamp();
6534 x.drShiftTo(this.m.t,x);
6535 if(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
6536}
6537
6538// r = "x^2/R mod m"; x != r
6539function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
6540
6541// r = "xy/R mod m"; x,y != r
6542function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
6543
6544Montgomery.prototype.convert = montConvert;
6545Montgomery.prototype.revert = montRevert;
6546Montgomery.prototype.reduce = montReduce;
6547Montgomery.prototype.mulTo = montMulTo;
6548Montgomery.prototype.sqrTo = montSqrTo;
6549
6550// (protected) true iff this is even
6551function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; }
6552
6553// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
6554function bnpExp(e,z) {
6555 if(e > 0xffffffff || e < 1) return BigInteger.ONE;
6556 var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1;
6557 g.copyTo(r);
6558 while(--i >= 0) {
6559 z.sqrTo(r,r2);
6560 if((e&(1<<i)) > 0) z.mulTo(r2,g,r);
6561 else { var t = r; r = r2; r2 = t; }
6562 }
6563 return z.revert(r);
6564}
6565
6566// (public) this^e % m, 0 <= e < 2^32
6567function bnModPowInt(e,m) {
6568 var z;
6569 if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
6570 return this.exp(e,z);
6571}
6572
6573// protected
6574BigInteger.prototype.copyTo = bnpCopyTo;
6575BigInteger.prototype.fromInt = bnpFromInt;
6576BigInteger.prototype.fromString = bnpFromString;
6577BigInteger.prototype.clamp = bnpClamp;
6578BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
6579BigInteger.prototype.drShiftTo = bnpDRShiftTo;
6580BigInteger.prototype.lShiftTo = bnpLShiftTo;
6581BigInteger.prototype.rShiftTo = bnpRShiftTo;
6582BigInteger.prototype.subTo = bnpSubTo;
6583BigInteger.prototype.multiplyTo = bnpMultiplyTo;
6584BigInteger.prototype.squareTo = bnpSquareTo;
6585BigInteger.prototype.divRemTo = bnpDivRemTo;
6586BigInteger.prototype.invDigit = bnpInvDigit;
6587BigInteger.prototype.isEven = bnpIsEven;
6588BigInteger.prototype.exp = bnpExp;
6589
6590// public
6591BigInteger.prototype.toString = bnToString;
6592BigInteger.prototype.negate = bnNegate;
6593BigInteger.prototype.abs = bnAbs;
6594BigInteger.prototype.compareTo = bnCompareTo;
6595BigInteger.prototype.bitLength = bnBitLength;
6596BigInteger.prototype.mod = bnMod;
6597BigInteger.prototype.modPowInt = bnModPowInt;
6598
6599// "constants"
6600BigInteger.ZERO = nbv(0);
6601BigInteger.ONE = nbv(1);
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08006602/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/
6603 */
Alexander Afanasyev1663a412013-03-02 13:52:00 -08006604// Copyright (c) 2005-2009 Tom Wu
6605// All Rights Reserved.
6606// See "LICENSE" for details.
6607
6608// Extended JavaScript BN functions, required for RSA private ops.
6609
6610// Version 1.1: new BigInteger("0", 10) returns "proper" zero
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08006611// Version 1.2: square() API, isProbablePrime fix
Alexander Afanasyev1663a412013-03-02 13:52:00 -08006612
6613// (public)
6614function bnClone() { var r = nbi(); this.copyTo(r); return r; }
6615
6616// (public) return value as integer
6617function bnIntValue() {
6618 if(this.s < 0) {
6619 if(this.t == 1) return this[0]-this.DV;
6620 else if(this.t == 0) return -1;
6621 }
6622 else if(this.t == 1) return this[0];
6623 else if(this.t == 0) return 0;
6624 // assumes 16 < DB < 32
6625 return ((this[1]&((1<<(32-this.DB))-1))<<this.DB)|this[0];
6626}
6627
6628// (public) return value as byte
6629function bnByteValue() { return (this.t==0)?this.s:(this[0]<<24)>>24; }
6630
6631// (public) return value as short (assumes DB>=16)
6632function bnShortValue() { return (this.t==0)?this.s:(this[0]<<16)>>16; }
6633
6634// (protected) return x s.t. r^x < DV
6635function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); }
6636
6637// (public) 0 if this == 0, 1 if this > 0
6638function bnSigNum() {
6639 if(this.s < 0) return -1;
6640 else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
6641 else return 1;
6642}
6643
6644// (protected) convert to radix string
6645function bnpToRadix(b) {
6646 if(b == null) b = 10;
6647 if(this.signum() == 0 || b < 2 || b > 36) return "0";
6648 var cs = this.chunkSize(b);
6649 var a = Math.pow(b,cs);
6650 var d = nbv(a), y = nbi(), z = nbi(), r = "";
6651 this.divRemTo(d,y,z);
6652 while(y.signum() > 0) {
6653 r = (a+z.intValue()).toString(b).substr(1) + r;
6654 y.divRemTo(d,y,z);
6655 }
6656 return z.intValue().toString(b) + r;
6657}
6658
6659// (protected) convert from radix string
6660function bnpFromRadix(s,b) {
6661 this.fromInt(0);
6662 if(b == null) b = 10;
6663 var cs = this.chunkSize(b);
6664 var d = Math.pow(b,cs), mi = false, j = 0, w = 0;
6665 for(var i = 0; i < s.length; ++i) {
6666 var x = intAt(s,i);
6667 if(x < 0) {
6668 if(s.charAt(i) == "-" && this.signum() == 0) mi = true;
6669 continue;
6670 }
6671 w = b*w+x;
6672 if(++j >= cs) {
6673 this.dMultiply(d);
6674 this.dAddOffset(w,0);
6675 j = 0;
6676 w = 0;
6677 }
6678 }
6679 if(j > 0) {
6680 this.dMultiply(Math.pow(b,j));
6681 this.dAddOffset(w,0);
6682 }
6683 if(mi) BigInteger.ZERO.subTo(this,this);
6684}
6685
6686// (protected) alternate constructor
6687function bnpFromNumber(a,b,c) {
6688 if("number" == typeof b) {
6689 // new BigInteger(int,int,RNG)
6690 if(a < 2) this.fromInt(1);
6691 else {
6692 this.fromNumber(a,c);
6693 if(!this.testBit(a-1)) // force MSB set
6694 this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this);
6695 if(this.isEven()) this.dAddOffset(1,0); // force odd
6696 while(!this.isProbablePrime(b)) {
6697 this.dAddOffset(2,0);
6698 if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this);
6699 }
6700 }
6701 }
6702 else {
6703 // new BigInteger(int,RNG)
6704 var x = new Array(), t = a&7;
6705 x.length = (a>>3)+1;
6706 b.nextBytes(x);
6707 if(t > 0) x[0] &= ((1<<t)-1); else x[0] = 0;
6708 this.fromString(x,256);
6709 }
6710}
6711
6712// (public) convert to bigendian byte array
6713function bnToByteArray() {
6714 var i = this.t, r = new Array();
6715 r[0] = this.s;
6716 var p = this.DB-(i*this.DB)%8, d, k = 0;
6717 if(i-- > 0) {
6718 if(p < this.DB && (d = this[i]>>p) != (this.s&this.DM)>>p)
6719 r[k++] = d|(this.s<<(this.DB-p));
6720 while(i >= 0) {
6721 if(p < 8) {
6722 d = (this[i]&((1<<p)-1))<<(8-p);
6723 d |= this[--i]>>(p+=this.DB-8);
6724 }
6725 else {
6726 d = (this[i]>>(p-=8))&0xff;
6727 if(p <= 0) { p += this.DB; --i; }
6728 }
6729 if((d&0x80) != 0) d |= -256;
6730 if(k == 0 && (this.s&0x80) != (d&0x80)) ++k;
6731 if(k > 0 || d != this.s) r[k++] = d;
6732 }
6733 }
6734 return r;
6735}
6736
6737function bnEquals(a) { return(this.compareTo(a)==0); }
6738function bnMin(a) { return(this.compareTo(a)<0)?this:a; }
6739function bnMax(a) { return(this.compareTo(a)>0)?this:a; }
6740
6741// (protected) r = this op a (bitwise)
6742function bnpBitwiseTo(a,op,r) {
6743 var i, f, m = Math.min(a.t,this.t);
6744 for(i = 0; i < m; ++i) r[i] = op(this[i],a[i]);
6745 if(a.t < this.t) {
6746 f = a.s&this.DM;
6747 for(i = m; i < this.t; ++i) r[i] = op(this[i],f);
6748 r.t = this.t;
6749 }
6750 else {
6751 f = this.s&this.DM;
6752 for(i = m; i < a.t; ++i) r[i] = op(f,a[i]);
6753 r.t = a.t;
6754 }
6755 r.s = op(this.s,a.s);
6756 r.clamp();
6757}
6758
6759// (public) this & a
6760function op_and(x,y) { return x&y; }
6761function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; }
6762
6763// (public) this | a
6764function op_or(x,y) { return x|y; }
6765function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; }
6766
6767// (public) this ^ a
6768function op_xor(x,y) { return x^y; }
6769function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; }
6770
6771// (public) this & ~a
6772function op_andnot(x,y) { return x&~y; }
6773function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; }
6774
6775// (public) ~this
6776function bnNot() {
6777 var r = nbi();
6778 for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i];
6779 r.t = this.t;
6780 r.s = ~this.s;
6781 return r;
6782}
6783
6784// (public) this << n
6785function bnShiftLeft(n) {
6786 var r = nbi();
6787 if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r);
6788 return r;
6789}
6790
6791// (public) this >> n
6792function bnShiftRight(n) {
6793 var r = nbi();
6794 if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r);
6795 return r;
6796}
6797
6798// return index of lowest 1-bit in x, x < 2^31
6799function lbit(x) {
6800 if(x == 0) return -1;
6801 var r = 0;
6802 if((x&0xffff) == 0) { x >>= 16; r += 16; }
6803 if((x&0xff) == 0) { x >>= 8; r += 8; }
6804 if((x&0xf) == 0) { x >>= 4; r += 4; }
6805 if((x&3) == 0) { x >>= 2; r += 2; }
6806 if((x&1) == 0) ++r;
6807 return r;
6808}
6809
6810// (public) returns index of lowest 1-bit (or -1 if none)
6811function bnGetLowestSetBit() {
6812 for(var i = 0; i < this.t; ++i)
6813 if(this[i] != 0) return i*this.DB+lbit(this[i]);
6814 if(this.s < 0) return this.t*this.DB;
6815 return -1;
6816}
6817
6818// return number of 1 bits in x
6819function cbit(x) {
6820 var r = 0;
6821 while(x != 0) { x &= x-1; ++r; }
6822 return r;
6823}
6824
6825// (public) return number of set bits
6826function bnBitCount() {
6827 var r = 0, x = this.s&this.DM;
6828 for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x);
6829 return r;
6830}
6831
6832// (public) true iff nth bit is set
6833function bnTestBit(n) {
6834 var j = Math.floor(n/this.DB);
6835 if(j >= this.t) return(this.s!=0);
6836 return((this[j]&(1<<(n%this.DB)))!=0);
6837}
6838
6839// (protected) this op (1<<n)
6840function bnpChangeBit(n,op) {
6841 var r = BigInteger.ONE.shiftLeft(n);
6842 this.bitwiseTo(r,op,r);
6843 return r;
6844}
6845
6846// (public) this | (1<<n)
6847function bnSetBit(n) { return this.changeBit(n,op_or); }
6848
6849// (public) this & ~(1<<n)
6850function bnClearBit(n) { return this.changeBit(n,op_andnot); }
6851
6852// (public) this ^ (1<<n)
6853function bnFlipBit(n) { return this.changeBit(n,op_xor); }
6854
6855// (protected) r = this + a
6856function bnpAddTo(a,r) {
6857 var i = 0, c = 0, m = Math.min(a.t,this.t);
6858 while(i < m) {
6859 c += this[i]+a[i];
6860 r[i++] = c&this.DM;
6861 c >>= this.DB;
6862 }
6863 if(a.t < this.t) {
6864 c += a.s;
6865 while(i < this.t) {
6866 c += this[i];
6867 r[i++] = c&this.DM;
6868 c >>= this.DB;
6869 }
6870 c += this.s;
6871 }
6872 else {
6873 c += this.s;
6874 while(i < a.t) {
6875 c += a[i];
6876 r[i++] = c&this.DM;
6877 c >>= this.DB;
6878 }
6879 c += a.s;
6880 }
6881 r.s = (c<0)?-1:0;
6882 if(c > 0) r[i++] = c;
6883 else if(c < -1) r[i++] = this.DV+c;
6884 r.t = i;
6885 r.clamp();
6886}
6887
6888// (public) this + a
6889function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; }
6890
6891// (public) this - a
6892function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; }
6893
6894// (public) this * a
6895function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; }
6896
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08006897// (public) this^2
6898function bnSquare() { var r = nbi(); this.squareTo(r); return r; }
6899
Alexander Afanasyev1663a412013-03-02 13:52:00 -08006900// (public) this / a
6901function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; }
6902
6903// (public) this % a
6904function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; }
6905
6906// (public) [this/a,this%a]
6907function bnDivideAndRemainder(a) {
6908 var q = nbi(), r = nbi();
6909 this.divRemTo(a,q,r);
6910 return new Array(q,r);
6911}
6912
6913// (protected) this *= n, this >= 0, 1 < n < DV
6914function bnpDMultiply(n) {
6915 this[this.t] = this.am(0,n-1,this,0,0,this.t);
6916 ++this.t;
6917 this.clamp();
6918}
6919
6920// (protected) this += n << w words, this >= 0
6921function bnpDAddOffset(n,w) {
6922 if(n == 0) return;
6923 while(this.t <= w) this[this.t++] = 0;
6924 this[w] += n;
6925 while(this[w] >= this.DV) {
6926 this[w] -= this.DV;
6927 if(++w >= this.t) this[this.t++] = 0;
6928 ++this[w];
6929 }
6930}
6931
6932// A "null" reducer
6933function NullExp() {}
6934function nNop(x) { return x; }
6935function nMulTo(x,y,r) { x.multiplyTo(y,r); }
6936function nSqrTo(x,r) { x.squareTo(r); }
6937
6938NullExp.prototype.convert = nNop;
6939NullExp.prototype.revert = nNop;
6940NullExp.prototype.mulTo = nMulTo;
6941NullExp.prototype.sqrTo = nSqrTo;
6942
6943// (public) this^e
6944function bnPow(e) { return this.exp(e,new NullExp()); }
6945
6946// (protected) r = lower n words of "this * a", a.t <= n
6947// "this" should be the larger one if appropriate.
6948function bnpMultiplyLowerTo(a,n,r) {
6949 var i = Math.min(this.t+a.t,n);
6950 r.s = 0; // assumes a,this >= 0
6951 r.t = i;
6952 while(i > 0) r[--i] = 0;
6953 var j;
6954 for(j = r.t-this.t; i < j; ++i) r[i+this.t] = this.am(0,a[i],r,i,0,this.t);
6955 for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a[i],r,i,0,n-i);
6956 r.clamp();
6957}
6958
6959// (protected) r = "this * a" without lower n words, n > 0
6960// "this" should be the larger one if appropriate.
6961function bnpMultiplyUpperTo(a,n,r) {
6962 --n;
6963 var i = r.t = this.t+a.t-n;
6964 r.s = 0; // assumes a,this >= 0
6965 while(--i >= 0) r[i] = 0;
6966 for(i = Math.max(n-this.t,0); i < a.t; ++i)
6967 r[this.t+i-n] = this.am(n-i,a[i],r,0,0,this.t+i-n);
6968 r.clamp();
6969 r.drShiftTo(1,r);
6970}
6971
6972// Barrett modular reduction
6973function Barrett(m) {
6974 // setup Barrett
6975 this.r2 = nbi();
6976 this.q3 = nbi();
6977 BigInteger.ONE.dlShiftTo(2*m.t,this.r2);
6978 this.mu = this.r2.divide(m);
6979 this.m = m;
6980}
6981
6982function barrettConvert(x) {
6983 if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m);
6984 else if(x.compareTo(this.m) < 0) return x;
6985 else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; }
6986}
6987
6988function barrettRevert(x) { return x; }
6989
6990// x = x mod m (HAC 14.42)
6991function barrettReduce(x) {
6992 x.drShiftTo(this.m.t-1,this.r2);
6993 if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); }
6994 this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3);
6995 this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);
6996 while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1);
6997 x.subTo(this.r2,x);
6998 while(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
6999}
7000
7001// r = x^2 mod m; x != r
7002function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
7003
7004// r = x*y mod m; x,y != r
7005function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
7006
7007Barrett.prototype.convert = barrettConvert;
7008Barrett.prototype.revert = barrettRevert;
7009Barrett.prototype.reduce = barrettReduce;
7010Barrett.prototype.mulTo = barrettMulTo;
7011Barrett.prototype.sqrTo = barrettSqrTo;
7012
7013// (public) this^e % m (HAC 14.85)
7014function bnModPow(e,m) {
7015 var i = e.bitLength(), k, r = nbv(1), z;
7016 if(i <= 0) return r;
7017 else if(i < 18) k = 1;
7018 else if(i < 48) k = 3;
7019 else if(i < 144) k = 4;
7020 else if(i < 768) k = 5;
7021 else k = 6;
7022 if(i < 8)
7023 z = new Classic(m);
7024 else if(m.isEven())
7025 z = new Barrett(m);
7026 else
7027 z = new Montgomery(m);
7028
7029 // precomputation
7030 var g = new Array(), n = 3, k1 = k-1, km = (1<<k)-1;
7031 g[1] = z.convert(this);
7032 if(k > 1) {
7033 var g2 = nbi();
7034 z.sqrTo(g[1],g2);
7035 while(n <= km) {
7036 g[n] = nbi();
7037 z.mulTo(g2,g[n-2],g[n]);
7038 n += 2;
7039 }
7040 }
7041
7042 var j = e.t-1, w, is1 = true, r2 = nbi(), t;
7043 i = nbits(e[j])-1;
7044 while(j >= 0) {
7045 if(i >= k1) w = (e[j]>>(i-k1))&km;
7046 else {
7047 w = (e[j]&((1<<(i+1))-1))<<(k1-i);
7048 if(j > 0) w |= e[j-1]>>(this.DB+i-k1);
7049 }
7050
7051 n = k;
7052 while((w&1) == 0) { w >>= 1; --n; }
7053 if((i -= n) < 0) { i += this.DB; --j; }
7054 if(is1) { // ret == 1, don't bother squaring or multiplying it
7055 g[w].copyTo(r);
7056 is1 = false;
7057 }
7058 else {
7059 while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; }
7060 if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; }
7061 z.mulTo(r2,g[w],r);
7062 }
7063
7064 while(j >= 0 && (e[j]&(1<<i)) == 0) {
7065 z.sqrTo(r,r2); t = r; r = r2; r2 = t;
7066 if(--i < 0) { i = this.DB-1; --j; }
7067 }
7068 }
7069 return z.revert(r);
7070}
7071
7072// (public) gcd(this,a) (HAC 14.54)
7073function bnGCD(a) {
7074 var x = (this.s<0)?this.negate():this.clone();
7075 var y = (a.s<0)?a.negate():a.clone();
7076 if(x.compareTo(y) < 0) { var t = x; x = y; y = t; }
7077 var i = x.getLowestSetBit(), g = y.getLowestSetBit();
7078 if(g < 0) return x;
7079 if(i < g) g = i;
7080 if(g > 0) {
7081 x.rShiftTo(g,x);
7082 y.rShiftTo(g,y);
7083 }
7084 while(x.signum() > 0) {
7085 if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x);
7086 if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y);
7087 if(x.compareTo(y) >= 0) {
7088 x.subTo(y,x);
7089 x.rShiftTo(1,x);
7090 }
7091 else {
7092 y.subTo(x,y);
7093 y.rShiftTo(1,y);
7094 }
7095 }
7096 if(g > 0) y.lShiftTo(g,y);
7097 return y;
7098}
7099
7100// (protected) this % n, n < 2^26
7101function bnpModInt(n) {
7102 if(n <= 0) return 0;
7103 var d = this.DV%n, r = (this.s<0)?n-1:0;
7104 if(this.t > 0)
7105 if(d == 0) r = this[0]%n;
7106 else for(var i = this.t-1; i >= 0; --i) r = (d*r+this[i])%n;
7107 return r;
7108}
7109
7110// (public) 1/this % m (HAC 14.61)
7111function bnModInverse(m) {
7112 var ac = m.isEven();
7113 if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
7114 var u = m.clone(), v = this.clone();
7115 var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
7116 while(u.signum() != 0) {
7117 while(u.isEven()) {
7118 u.rShiftTo(1,u);
7119 if(ac) {
7120 if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); }
7121 a.rShiftTo(1,a);
7122 }
7123 else if(!b.isEven()) b.subTo(m,b);
7124 b.rShiftTo(1,b);
7125 }
7126 while(v.isEven()) {
7127 v.rShiftTo(1,v);
7128 if(ac) {
7129 if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); }
7130 c.rShiftTo(1,c);
7131 }
7132 else if(!d.isEven()) d.subTo(m,d);
7133 d.rShiftTo(1,d);
7134 }
7135 if(u.compareTo(v) >= 0) {
7136 u.subTo(v,u);
7137 if(ac) a.subTo(c,a);
7138 b.subTo(d,b);
7139 }
7140 else {
7141 v.subTo(u,v);
7142 if(ac) c.subTo(a,c);
7143 d.subTo(b,d);
7144 }
7145 }
7146 if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
7147 if(d.compareTo(m) >= 0) return d.subtract(m);
7148 if(d.signum() < 0) d.addTo(m,d); else return d;
7149 if(d.signum() < 0) return d.add(m); else return d;
7150}
7151
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08007152var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997];
Alexander Afanasyev1663a412013-03-02 13:52:00 -08007153var lplim = (1<<26)/lowprimes[lowprimes.length-1];
7154
7155// (public) test primality with certainty >= 1-.5^t
7156function bnIsProbablePrime(t) {
7157 var i, x = this.abs();
7158 if(x.t == 1 && x[0] <= lowprimes[lowprimes.length-1]) {
7159 for(i = 0; i < lowprimes.length; ++i)
7160 if(x[0] == lowprimes[i]) return true;
7161 return false;
7162 }
7163 if(x.isEven()) return false;
7164 i = 1;
7165 while(i < lowprimes.length) {
7166 var m = lowprimes[i], j = i+1;
7167 while(j < lowprimes.length && m < lplim) m *= lowprimes[j++];
7168 m = x.modInt(m);
7169 while(i < j) if(m%lowprimes[i++] == 0) return false;
7170 }
7171 return x.millerRabin(t);
7172}
7173
7174// (protected) true if probably prime (HAC 4.24, Miller-Rabin)
7175function bnpMillerRabin(t) {
7176 var n1 = this.subtract(BigInteger.ONE);
7177 var k = n1.getLowestSetBit();
7178 if(k <= 0) return false;
7179 var r = n1.shiftRight(k);
7180 t = (t+1)>>1;
7181 if(t > lowprimes.length) t = lowprimes.length;
7182 var a = nbi();
7183 for(var i = 0; i < t; ++i) {
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08007184 //Pick bases at random, instead of starting at 2
7185 a.fromInt(lowprimes[Math.floor(Math.random()*lowprimes.length)]);
Alexander Afanasyev1663a412013-03-02 13:52:00 -08007186 var y = a.modPow(r,this);
7187 if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
7188 var j = 1;
7189 while(j++ < k && y.compareTo(n1) != 0) {
7190 y = y.modPowInt(2,this);
7191 if(y.compareTo(BigInteger.ONE) == 0) return false;
7192 }
7193 if(y.compareTo(n1) != 0) return false;
7194 }
7195 }
7196 return true;
7197}
7198
7199// protected
7200BigInteger.prototype.chunkSize = bnpChunkSize;
7201BigInteger.prototype.toRadix = bnpToRadix;
7202BigInteger.prototype.fromRadix = bnpFromRadix;
7203BigInteger.prototype.fromNumber = bnpFromNumber;
7204BigInteger.prototype.bitwiseTo = bnpBitwiseTo;
7205BigInteger.prototype.changeBit = bnpChangeBit;
7206BigInteger.prototype.addTo = bnpAddTo;
7207BigInteger.prototype.dMultiply = bnpDMultiply;
7208BigInteger.prototype.dAddOffset = bnpDAddOffset;
7209BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo;
7210BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo;
7211BigInteger.prototype.modInt = bnpModInt;
7212BigInteger.prototype.millerRabin = bnpMillerRabin;
7213
7214// public
7215BigInteger.prototype.clone = bnClone;
7216BigInteger.prototype.intValue = bnIntValue;
7217BigInteger.prototype.byteValue = bnByteValue;
7218BigInteger.prototype.shortValue = bnShortValue;
7219BigInteger.prototype.signum = bnSigNum;
7220BigInteger.prototype.toByteArray = bnToByteArray;
7221BigInteger.prototype.equals = bnEquals;
7222BigInteger.prototype.min = bnMin;
7223BigInteger.prototype.max = bnMax;
7224BigInteger.prototype.and = bnAnd;
7225BigInteger.prototype.or = bnOr;
7226BigInteger.prototype.xor = bnXor;
7227BigInteger.prototype.andNot = bnAndNot;
7228BigInteger.prototype.not = bnNot;
7229BigInteger.prototype.shiftLeft = bnShiftLeft;
7230BigInteger.prototype.shiftRight = bnShiftRight;
7231BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit;
7232BigInteger.prototype.bitCount = bnBitCount;
7233BigInteger.prototype.testBit = bnTestBit;
7234BigInteger.prototype.setBit = bnSetBit;
7235BigInteger.prototype.clearBit = bnClearBit;
7236BigInteger.prototype.flipBit = bnFlipBit;
7237BigInteger.prototype.add = bnAdd;
7238BigInteger.prototype.subtract = bnSubtract;
7239BigInteger.prototype.multiply = bnMultiply;
7240BigInteger.prototype.divide = bnDivide;
7241BigInteger.prototype.remainder = bnRemainder;
7242BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder;
7243BigInteger.prototype.modPow = bnModPow;
7244BigInteger.prototype.modInverse = bnModInverse;
7245BigInteger.prototype.pow = bnPow;
7246BigInteger.prototype.gcd = bnGCD;
7247BigInteger.prototype.isProbablePrime = bnIsProbablePrime;
7248
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08007249// JSBN-specific extension
7250BigInteger.prototype.square = bnSquare;
7251
Alexander Afanasyev1663a412013-03-02 13:52:00 -08007252// BigInteger interfaces not implemented in jsbn:
7253
7254// BigInteger(int signum, byte[] magnitude)
7255// double doubleValue()
7256// float floatValue()
7257// int hashCode()
7258// long longValue()
7259// static BigInteger valueOf(long val)
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08007260
7261exports.BigInteger = BigInteger;
7262module.exports = exports;
Alexander Afanasyev1663a412013-03-02 13:52:00 -08007263/**
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08007264 * Copyright (C) 2013-2016 Regents of the University of California.
7265 * @author: Wentao Shang
7266 *
7267 * This program is free software: you can redistribute it and/or modify
7268 * it under the terms of the GNU Lesser General Public License as published by
7269 * the Free Software Foundation, either version 3 of the License, or
7270 * (at your option) any later version.
7271 *
7272 * This program is distributed in the hope that it will be useful,
7273 * but WITHOUT ANY WARRANTY; without even the implied warranty of
7274 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7275 * GNU Lesser General Public License for more details.
7276 *
7277 * You should have received a copy of the GNU Lesser General Public License
7278 * along with this program. If not, see <http://www.gnu.org/licenses/>.
7279 * A copy of the GNU Lesser General Public License is in the file COPYING.
Alexander Afanasyev1663a412013-03-02 13:52:00 -08007280 */
7281
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08007282/** @ignore */
7283var ASN1HEX = require('../contrib/securityLib/asn1hex-1.1.js').ASN1HEX /** @ignore */
7284var KJUR = require('../contrib/securityLib/crypto-1.0.js').KJUR /** @ignore */
7285var RSAKey = require('../contrib/securityLib/rsasign-1.2.js').RSAKey /** @ignore */
7286var b64tohex = require('../contrib/securityLib/base64.js').b64tohex
Alexander Afanasyev1663a412013-03-02 13:52:00 -08007287
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08007288// Library namespace
7289/** @ignore */
7290var ndn = ndn || {};
Alexander Afanasyev1663a412013-03-02 13:52:00 -08007291
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08007292/** @ignore */
7293var exports = ndn;
7294
7295// Factory method to create hasher objects
7296exports.createHash = function(alg)
7297{
7298 if (alg != 'sha256')
7299 throw new Error('createHash: unsupported algorithm.');
7300
7301 var obj = {};
7302
7303 obj.md = new KJUR.crypto.MessageDigest({alg: "sha256", prov: "cryptojs"});
7304
7305 obj.update = function(buf) {
7306 this.md.updateHex(buf.toString('hex'));
7307 };
7308
7309 obj.digest = function(encoding) {
7310 var hexDigest = this.md.digest();
7311 if (encoding == 'hex')
7312 return hexDigest;
7313 else if (encoding == 'base64')
7314 return new Buffer(hexDigest, 'hex').toString('base64');
7315 else
7316 return new Buffer(hexDigest, 'hex');
7317 };
7318
7319 return obj;
Alexander Afanasyev1663a412013-03-02 13:52:00 -08007320};
7321
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08007322// Factory method to create HMAC objects.
7323exports.createHmac = function(algorithm, key)
7324{
7325 if (algorithm !== 'sha256')
7326 throw new Error('createHmac: unsupported algorithm.');
7327
7328 var obj = {};
7329
7330 obj.md = new KJUR.crypto.Mac({alg: "HmacSHA256", pass: {hex: key.toString('hex')}});
7331
7332 obj.update = function(buf) {
7333 this.md.updateHex(buf.toString('hex'));
7334 };
7335
7336 obj.digest = function(encoding) {
7337 var hexDigest = this.md.doFinal();
7338 if (encoding == 'hex')
7339 return hexDigest;
7340 else if (encoding == 'base64')
7341 return new Buffer(hexDigest, 'hex').toString('base64');
7342 else
7343 return new Buffer(hexDigest, 'hex');
7344 };
7345
7346 return obj;
7347};
7348
7349// Factory method to create RSA signer objects
7350exports.createSign = function(alg)
7351{
7352 if (alg != 'RSA-SHA256')
7353 throw new Error('createSign: unsupported algorithm.');
7354
7355 var obj = {};
7356
7357 obj.arr = [];
7358
7359 obj.update = function(buf) {
7360 this.arr.push(buf);
7361 };
7362
7363 obj.sign = function(keypem) {
7364 var rsa = new RSAKey();
7365 rsa.readPrivateKeyFromPEMString(keypem);
7366 var signer = new KJUR.crypto.Signature({alg: "SHA256withRSA", prov: "cryptojs/jsrsa"});
7367 signer.initSign(rsa);
7368 for (var i = 0; i < this.arr.length; ++i)
7369 signer.updateHex(this.arr[i].toString('hex'));
7370
7371 return new Buffer(signer.sign(), 'hex');
7372 };
7373
7374 return obj;
7375};
7376
7377// Factory method to create RSA verifier objects
7378exports.createVerify = function(alg)
7379{
7380 if (alg != 'RSA-SHA256')
7381 throw new Error('createSign: unsupported algorithm.');
7382
7383 var obj = {};
7384
7385 obj.arr = [];
7386
7387 obj.update = function(buf) {
7388 this.arr.push(buf);
7389 };
7390
7391 var getSubjectPublicKeyPosFromHex = function(hPub) {
7392 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hPub, 0);
7393 if (a.length != 2)
7394 return -1;
7395 var pBitString = a[1];
7396 if (hPub.substring(pBitString, pBitString + 2) != '03')
7397 return -1;
7398 var pBitStringV = ASN1HEX.getStartPosOfV_AtObj(hPub, pBitString);
7399 if (hPub.substring(pBitStringV, pBitStringV + 2) != '00')
7400 return -1;
7401 return pBitStringV + 2;
7402 };
7403
7404 var publicKeyPemToDer = function(publicKeyPem) {
7405 // Remove the '-----XXX-----' from the beginning and the end of the public
7406 // key and also remove any \n in the public key string.
7407 var lines = publicKeyPem.split('\n');
7408 var pub = "";
7409 for (var i = 1; i < lines.length - 1; i++)
7410 pub += lines[i];
7411 return new Buffer(pub, 'base64');
7412 }
7413
7414 var readPublicDER = function(pub_der) {
7415 var hex = pub_der.toString('hex');
7416 var p = getSubjectPublicKeyPosFromHex(hex);
7417 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hex, p);
7418 if (a.length != 2)
7419 return null;
7420 var hN = ASN1HEX.getHexOfV_AtObj(hex, a[0]);
7421 var hE = ASN1HEX.getHexOfV_AtObj(hex, a[1]);
7422 var rsaKey = new RSAKey();
7423 rsaKey.setPublic(hN, hE);
7424 return rsaKey;
7425 };
7426
7427 obj.verify = function(keypem, sig) {
7428 var rsa = readPublicDER(publicKeyPemToDer(keypem));
7429 var signer = new KJUR.crypto.Signature({alg: "SHA256withRSA", prov: "cryptojs/jsrsa"});
7430 signer.initVerifyByPublicKey(rsa);
7431 for (var i = 0; i < this.arr.length; i++)
7432 signer.updateHex(this.arr[i].toString('hex'));
7433 var hSig = sig.toString('hex');
7434 return signer.verify(hSig);
7435 };
7436
7437 return obj;
7438};
7439
7440exports.randomBytes = function(size)
7441{
7442 // TODO: Use a cryptographic random number generator.
7443 var result = new Buffer(size);
7444 for (var i = 0; i < size; ++i)
7445 result[i] = Math.floor(Math.random() * 256);
7446 return result;
7447};
7448
7449// contrib/feross/buffer.js needs base64.toByteArray. Define it here so that
7450// we don't have to include the entire base64 module.
7451exports.toByteArray = function(str) {
7452 var hex = b64tohex(str);
7453 var result = [];
7454 hex.replace(/(..)/g, function(ss) {
7455 result.push(parseInt(ss, 16));
7456 });
7457 return result;
7458};
7459
7460module.exports = exports
7461// After this we include contrib/feross/buffer.js to define the Buffer class.
7462var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
7463var base64js = {};
7464
7465;(function (exports) {
7466 'use strict';
7467
7468 var Arr = (typeof Uint8Array !== 'undefined')
7469 ? Uint8Array
7470 : Array
7471
7472 var PLUS = '+'.charCodeAt(0)
7473 var SLASH = '/'.charCodeAt(0)
7474 var NUMBER = '0'.charCodeAt(0)
7475 var LOWER = 'a'.charCodeAt(0)
7476 var UPPER = 'A'.charCodeAt(0)
7477
7478 function decode (elt) {
7479 var code = elt.charCodeAt(0)
7480 if (code === PLUS)
7481 return 62 // '+'
7482 if (code === SLASH)
7483 return 63 // '/'
7484 if (code < NUMBER)
7485 return -1 //no match
7486 if (code < NUMBER + 10)
7487 return code - NUMBER + 26 + 26
7488 if (code < UPPER + 26)
7489 return code - UPPER
7490 if (code < LOWER + 26)
7491 return code - LOWER + 26
7492 }
7493
7494 function b64ToByteArray (b64) {
7495 var i, j, l, tmp, placeHolders, arr
7496
7497 if (b64.length % 4 > 0) {
7498 throw new Error('Invalid string. Length must be a multiple of 4')
7499 }
7500
7501 // the number of equal signs (place holders)
7502 // if there are two placeholders, than the two characters before it
7503 // represent one byte
7504 // if there is only one, then the three characters before it represent 2 bytes
7505 // this is just a cheap hack to not do indexOf twice
7506 var len = b64.length
7507 placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0
7508
7509 // base64 is 4/3 + up to two characters of the original data
7510 arr = new Arr(b64.length * 3 / 4 - placeHolders)
7511
7512 // if there are placeholders, only get up to the last complete 4 chars
7513 l = placeHolders > 0 ? b64.length - 4 : b64.length
7514
7515 var L = 0
7516
7517 function push (v) {
7518 arr[L++] = v
7519 }
7520
7521 for (i = 0, j = 0; i < l; i += 4, j += 3) {
7522 tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))
7523 push((tmp & 0xFF0000) >> 16)
7524 push((tmp & 0xFF00) >> 8)
7525 push(tmp & 0xFF)
7526 }
7527
7528 if (placeHolders === 2) {
7529 tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)
7530 push(tmp & 0xFF)
7531 } else if (placeHolders === 1) {
7532 tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)
7533 push((tmp >> 8) & 0xFF)
7534 push(tmp & 0xFF)
7535 }
7536
7537 return arr
7538 }
7539
7540 function uint8ToBase64 (uint8) {
7541 var i,
7542 extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes
7543 output = "",
7544 temp, length
7545
7546 function encode (num) {
7547 return lookup.charAt(num)
7548 }
7549
7550 function tripletToBase64 (num) {
7551 return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)
7552 }
7553
7554 // go through the array every three bytes, we'll deal with trailing stuff later
7555 for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {
7556 temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])
7557 output += tripletToBase64(temp)
7558 }
7559
7560 // pad the end with zeros, but make sure to not forget the extra bytes
7561 switch (extraBytes) {
7562 case 1:
7563 temp = uint8[uint8.length - 1]
7564 output += encode(temp >> 2)
7565 output += encode((temp << 4) & 0x3F)
7566 output += '=='
7567 break
7568 case 2:
7569 temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])
7570 output += encode(temp >> 10)
7571 output += encode((temp >> 4) & 0x3F)
7572 output += encode((temp << 2) & 0x3F)
7573 output += '='
7574 break
7575 }
7576
7577 return output
7578 }
7579
7580 exports.toByteArray = b64ToByteArray
7581 exports.fromByteArray = uint8ToBase64
7582})(base64js);
7583var ieee = {};
7584
7585ieee.read = function(buffer, offset, isLE, mLen, nBytes) {
7586 var e, m,
7587 eLen = nBytes * 8 - mLen - 1,
7588 eMax = (1 << eLen) - 1,
7589 eBias = eMax >> 1,
7590 nBits = -7,
7591 i = isLE ? (nBytes - 1) : 0,
7592 d = isLE ? -1 : 1,
7593 s = buffer[offset + i];
7594
7595 i += d;
7596
7597 e = s & ((1 << (-nBits)) - 1);
7598 s >>= (-nBits);
7599 nBits += eLen;
7600 for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8);
7601
7602 m = e & ((1 << (-nBits)) - 1);
7603 e >>= (-nBits);
7604 nBits += mLen;
7605 for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8);
7606
7607 if (e === 0) {
7608 e = 1 - eBias;
7609 } else if (e === eMax) {
7610 return m ? NaN : ((s ? -1 : 1) * Infinity);
7611 } else {
7612 m = m + Math.pow(2, mLen);
7613 e = e - eBias;
7614 }
7615 return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
7616};
7617
7618ieee.write = function(buffer, value, offset, isLE, mLen, nBytes) {
7619 var e, m, c,
7620 eLen = nBytes * 8 - mLen - 1,
7621 eMax = (1 << eLen) - 1,
7622 eBias = eMax >> 1,
7623 rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0),
7624 i = isLE ? 0 : (nBytes - 1),
7625 d = isLE ? 1 : -1,
7626 s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0;
7627
7628 value = Math.abs(value);
7629
7630 if (isNaN(value) || value === Infinity) {
7631 m = isNaN(value) ? 1 : 0;
7632 e = eMax;
7633 } else {
7634 e = Math.floor(Math.log(value) / Math.LN2);
7635 if (value * (c = Math.pow(2, -e)) < 1) {
7636 e--;
7637 c *= 2;
7638 }
7639 if (e + eBias >= 1) {
7640 value += rt / c;
7641 } else {
7642 value += rt * Math.pow(2, 1 - eBias);
7643 }
7644 if (value * c >= 2) {
7645 e++;
7646 c /= 2;
7647 }
7648
7649 if (e + eBias >= eMax) {
7650 m = 0;
7651 e = eMax;
7652 } else if (e + eBias >= 1) {
7653 m = (value * c - 1) * Math.pow(2, mLen);
7654 e = e + eBias;
7655 } else {
7656 m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
7657 e = 0;
7658 }
7659 }
7660
7661 for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8);
7662
7663 e = (e << mLen) | m;
7664 eLen += mLen;
7665 for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8);
7666
7667 buffer[offset + i - d] |= s * 128;
7668};
7669
7670exports.ieee = ieee;
7671/**
7672 * The buffer module from node.js, for the browser.
7673 * @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
7674 *
7675 * Copyright (C) 2013 Feross Aboukhadijeh, and other contributors.
7676 *
7677 * Permission is hereby granted, free of charge, to any person obtaining a copy
7678 * of this software and associated documentation files (the "Software"), to deal
7679 * in the Software without restriction, including without limitation the rights
7680 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7681 * copies of the Software, and to permit persons to whom the Software is
7682 * furnished to do so, subject to the following conditions:
7683 *
7684 * The above copyright notice and this permission notice shall be included in
7685 * all copies or substantial portions of the Software.
7686 *
7687 * @license MIT
7688 */
7689
7690var base64 = base64js;
7691var ieee754 = require('./ieee754.js').ieee
7692
7693exports.Buffer = Buffer
7694exports.SlowBuffer = Buffer
7695exports.INSPECT_MAX_BYTES = 50
7696Buffer.poolSize = 8192
7697
7698/**
7699 * If `Buffer._useTypedArrays`:
7700 * === true Use Uint8Array implementation (fastest)
7701 * === false Use Object implementation (compatible down to IE6)
7702 */
7703Buffer._useTypedArrays = (function () {
7704 // Detect if browser supports Typed Arrays. Supported browsers are IE 10+, Firefox 4+,
7705 // Chrome 7+, Safari 5.1+, Opera 11.6+, iOS 4.2+. If the browser does not support adding
7706 // properties to `Uint8Array` instances, then that's the same as no `Uint8Array` support
7707 // because we need to be able to add all the node Buffer API methods. This is an issue
7708 // in Firefox 4-29. Now fixed: https://bugzilla.mozilla.org/show_bug.cgi?id=695438
7709 try {
7710 var buf = new ArrayBuffer(0)
7711 var arr = new Uint8Array(buf)
7712 arr.foo = function () { return 42 }
7713 return 42 === arr.foo() &&
7714 typeof arr.subarray === 'function' // Chrome 9-10 lack `subarray`
7715 } catch (e) {
7716 return false
7717 }
7718})()
7719
7720/**
7721 * Class: Buffer
7722 * =============
7723 *
7724 * The Buffer constructor returns instances of `Uint8Array` that are augmented
7725 * with function properties for all the node `Buffer` API functions. We use
7726 * `Uint8Array` so that square bracket notation works as expected -- it returns
7727 * a single octet.
7728 *
7729 * By augmenting the instances, we can avoid modifying the `Uint8Array`
7730 * prototype.
7731 */
7732function Buffer (subject, encoding, noZero) {
7733 if (!(this instanceof Buffer))
7734 return new Buffer(subject, encoding, noZero)
7735
7736 var type = typeof subject
7737
7738 // Workaround: node's base64 implementation allows for non-padded strings
7739 // while base64-js does not.
7740 if (encoding === 'base64' && type === 'string') {
7741 subject = Buffer.stringtrim(subject)
7742 while (subject.length % 4 !== 0) {
7743 subject = subject + '='
7744 }
7745 }
7746
7747 // Find the length
7748 var length
7749 if (type === 'number')
7750 length = Buffer.coerce(subject)
7751 else if (type === 'string')
7752 length = Buffer.byteLength(subject, encoding)
7753 else if (type === 'object')
7754 length = Buffer.coerce(subject.length) // assume that object is array-like
7755 else
7756 throw new Error('First argument needs to be a number, array or string.')
7757
7758 var buf
7759 if (Buffer._useTypedArrays) {
7760 // Preferred: Return an augmented `Uint8Array` instance for best performance
7761 buf = Buffer._augment(new Uint8Array(length))
7762 } else {
7763 // Fallback: Return THIS instance of Buffer (created by `new`)
7764 buf = this
7765 buf.length = length
7766 buf._isBuffer = true
7767 }
7768
7769 var i
7770 if (Buffer._useTypedArrays && typeof subject.byteLength === 'number') {
7771 // Speed optimization -- use set if we're copying from a typed array
7772 buf._set(subject)
7773 } else if (Buffer.isArrayish(subject)) {
7774 // Treat array-ish objects as a byte array
7775 if (Buffer.isBuffer(subject)) {
7776 for (i = 0; i < length; i++)
7777 buf[i] = subject.readUInt8(i)
7778 } else {
7779 for (i = 0; i < length; i++)
7780 buf[i] = ((subject[i] % 256) + 256) % 256
7781 }
7782 } else if (type === 'string') {
7783 buf.write(subject, 0, encoding)
7784 } else if (type === 'number' && !Buffer._useTypedArrays && !noZero) {
7785 for (i = 0; i < length; i++) {
7786 buf[i] = 0
7787 }
7788 }
7789
7790 return buf
7791}
7792
7793// STATIC METHODS
7794// ==============
7795
7796Buffer.isEncoding = function (encoding) {
7797 switch (String(encoding).toLowerCase()) {
7798 case 'hex':
7799 case 'utf8':
7800 case 'utf-8':
7801 case 'ascii':
7802 case 'binary':
7803 case 'base64':
7804 case 'raw':
7805 case 'ucs2':
7806 case 'ucs-2':
7807 case 'utf16le':
7808 case 'utf-16le':
7809 return true
7810 default:
7811 return false
7812 }
7813}
7814
7815Buffer.isBuffer = function (b) {
7816 return !!(b !== null && b !== undefined && b._isBuffer)
7817}
7818
7819Buffer.byteLength = function (str, encoding) {
7820 var ret
7821 str = str.toString()
7822 switch (encoding || 'utf8') {
7823 case 'hex':
7824 ret = str.length / 2
7825 break
7826 case 'utf8':
7827 case 'utf-8':
7828 ret = Buffer.utf8ToBytes(str).length
7829 break
7830 case 'ascii':
7831 case 'binary':
7832 case 'raw':
7833 ret = str.length
7834 break
7835 case 'base64':
7836 ret = Buffer.base64ToBytes(str).length
7837 break
7838 case 'ucs2':
7839 case 'ucs-2':
7840 case 'utf16le':
7841 case 'utf-16le':
7842 ret = str.length * 2
7843 break
7844 default:
7845 throw new Error('Unknown encoding')
7846 }
7847 return ret
7848}
7849
7850Buffer.concat = function (list, totalLength) {
7851 Buffer.assert(Buffer.isArray(list), 'Usage: Buffer.concat(list[, length])')
7852
7853 if (list.length === 0) {
7854 return new Buffer(0)
7855 } else if (list.length === 1) {
7856 return list[0]
7857 }
7858
7859 var i
7860 if (totalLength === undefined) {
7861 totalLength = 0
7862 for (i = 0; i < list.length; i++) {
7863 totalLength += list[i].length
7864 }
7865 }
7866
7867 var buf = new Buffer(totalLength)
7868 var pos = 0
7869 for (i = 0; i < list.length; i++) {
7870 var item = list[i]
7871 item.copy(buf, pos)
7872 pos += item.length
7873 }
7874 return buf
7875}
7876
7877Buffer.compare = function (a, b) {
7878 Buffer.assert(Buffer.isBuffer(a) && Buffer.isBuffer(b), 'Arguments must be Buffers')
7879 var x = a.length
7880 var y = b.length
7881 for (var i = 0, len = Math.min(x, y); i < len && a[i] === b[i]; i++) {}
7882 if (i !== len) {
7883 x = a[i]
7884 y = b[i]
7885 }
7886 if (x < y) {
7887 return -1
7888 }
7889 if (y < x) {
7890 return 1
7891 }
7892 return 0
7893}
7894
7895// BUFFER INSTANCE METHODS
7896// =======================
7897
7898Buffer.hexWrite = function(buf, string, offset, length) {
7899 offset = Number(offset) || 0
7900 var remaining = buf.length - offset
7901 if (!length) {
7902 length = remaining
7903 } else {
7904 length = Number(length)
7905 if (length > remaining) {
7906 length = remaining
7907 }
7908 }
7909
7910 // must be an even number of digits
7911 var strLen = string.length
7912 Buffer.assert(strLen % 2 === 0, 'Invalid hex string')
7913
7914 if (length > strLen / 2) {
7915 length = strLen / 2
7916 }
7917 for (var i = 0; i < length; i++) {
7918 var b = parseInt(string.substr(i * 2, 2), 16)
7919 Buffer.assert(!isNaN(b), 'Invalid hex string')
7920 buf[offset + i] = b
7921 }
7922 return i
7923}
7924
7925Buffer.utf8Write = function(buf, string, offset, length) {
7926 var charsWritten = Buffer.blitBuffer(Buffer.utf8ToBytes(string), buf, offset, length)
7927 return charsWritten
7928}
7929
7930Buffer.asciiWrite = function(buf, string, offset, length) {
7931 var charsWritten = Buffer.blitBuffer(Buffer.asciiToBytes(string), buf, offset, length)
7932 return charsWritten
7933}
7934
7935Buffer.binaryWrite = function(buf, string, offset, length) {
7936 return Buffer.asciiWrite(buf, string, offset, length)
7937}
7938
7939Buffer.base64Write = function(buf, string, offset, length) {
7940 var charsWritten = Buffer.blitBuffer(Buffer.base64ToBytes(string), buf, offset, length)
7941 return charsWritten
7942}
7943
7944Buffer.utf16leWrite = function(buf, string, offset, length) {
7945 var charsWritten = Buffer.blitBuffer(Buffer.utf16leToBytes(string), buf, offset, length)
7946 return charsWritten
7947}
7948
7949Buffer.prototype.write = function (string, offset, length, encoding) {
7950 // Support both (string, offset, length, encoding)
7951 // and the legacy (string, encoding, offset, length)
7952 if (isFinite(offset)) {
7953 if (!isFinite(length)) {
7954 encoding = length
7955 length = undefined
7956 }
7957 } else { // legacy
7958 var swap = encoding
7959 encoding = offset
7960 offset = length
7961 length = swap
7962 }
7963
7964 offset = Number(offset) || 0
7965 var remaining = this.length - offset
7966 if (!length) {
7967 length = remaining
7968 } else {
7969 length = Number(length)
7970 if (length > remaining) {
7971 length = remaining
7972 }
7973 }
7974 encoding = String(encoding || 'utf8').toLowerCase()
7975
7976 var ret
7977 switch (encoding) {
7978 case 'hex':
7979 ret = Buffer.hexWrite(this, string, offset, length)
7980 break
7981 case 'utf8':
7982 case 'utf-8':
7983 ret = Buffer.utf8Write(this, string, offset, length)
7984 break
7985 case 'ascii':
7986 ret = Buffer.asciiWrite(this, string, offset, length)
7987 break
7988 case 'binary':
7989 ret = Buffer.binaryWrite(this, string, offset, length)
7990 break
7991 case 'base64':
7992 ret = Buffer.base64Write(this, string, offset, length)
7993 break
7994 case 'ucs2':
7995 case 'ucs-2':
7996 case 'utf16le':
7997 case 'utf-16le':
7998 ret = Buffer.utf16leWrite(this, string, offset, length)
7999 break
8000 default:
8001 throw new Error('Unknown encoding')
8002 }
8003 return ret
8004}
8005
8006Buffer.prototype.toString = function (encoding, start, end) {
8007 var self = this
8008
8009 encoding = String(encoding || 'utf8').toLowerCase()
8010 start = Number(start) || 0
8011 end = (end === undefined) ? self.length : Number(end)
8012
8013 // Fastpath empty strings
8014 if (end === start)
8015 return ''
8016
8017 var ret
8018 switch (encoding) {
8019 case 'hex':
8020 ret = Buffer.hexSlice(self, start, end)
8021 break
8022 case 'utf8':
8023 case 'utf-8':
8024 ret = Buffer.utf8Slice(self, start, end)
8025 break
8026 case 'ascii':
8027 ret = Buffer.asciiSlice(self, start, end)
8028 break
8029 case 'binary':
8030 ret = Buffer.binarySlice(self, start, end)
8031 break
8032 case 'base64':
8033 ret = Buffer.base64Slice(self, start, end)
8034 break
8035 case 'ucs2':
8036 case 'ucs-2':
8037 case 'utf16le':
8038 case 'utf-16le':
8039 ret = utf16leSlice(self, start, end)
8040 break
8041 default:
8042 throw new Error('Unknown encoding')
8043 }
8044 return ret
8045}
8046
8047Buffer.prototype.toJSON = function () {
8048 return {
8049 type: 'Buffer',
8050 data: Array.prototype.slice.call(this._arr || this, 0)
8051 }
8052}
8053
8054Buffer.prototype.equals = function (b) {
8055 Buffer.assert(Buffer.isBuffer(b), 'Argument must be a Buffer')
8056 return Buffer.compare(this, b) === 0
8057}
8058
8059Buffer.prototype.compare = function (b) {
8060 Buffer.assert(Buffer.isBuffer(b), 'Argument must be a Buffer')
8061 return Buffer.compare(this, b)
8062}
8063
8064// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
8065Buffer.prototype.copy = function (target, target_start, start, end) {
8066 var source = this
8067
8068 if (!start) start = 0
8069 if (!end && end !== 0) end = this.length
8070 if (!target_start) target_start = 0
8071
8072 // Copy 0 bytes; we're done
8073 if (end === start) return
8074 if (target.length === 0 || source.length === 0) return
8075
8076 // Fatal error conditions
8077 Buffer.assert(end >= start, 'sourceEnd < sourceStart')
8078 Buffer.assert(target_start >= 0 && target_start < target.length,
8079 'targetStart out of bounds')
8080 Buffer.assert(start >= 0 && start < source.length, 'sourceStart out of bounds')
8081 Buffer.assert(end >= 0 && end <= source.length, 'sourceEnd out of bounds')
8082
8083 // Are we oob?
8084 if (end > this.length)
8085 end = this.length
8086 if (target.length - target_start < end - start)
8087 end = target.length - target_start + start
8088
8089 var len = end - start
8090
8091 if (len < 100 || !Buffer._useTypedArrays) {
8092 for (var i = 0; i < len; i++) {
8093 target[i + target_start] = this[i + start]
8094 }
8095 } else {
8096 target._set(this.subarray(start, start + len), target_start)
8097 }
8098}
8099
8100Buffer.base64Slice = function(buf, start, end) {
8101 if (start === 0 && end === buf.length) {
8102 return base64.fromByteArray(buf)
8103 } else {
8104 return base64.fromByteArray(buf.slice(start, end))
8105 }
8106}
8107
8108Buffer.utf8Slice = function(buf, start, end) {
8109 var res = ''
8110 var tmp = ''
8111 end = Math.min(buf.length, end)
8112
8113 for (var i = start; i < end; i++) {
8114 if (buf[i] <= 0x7F) {
8115 res += Buffer.decodeUtf8Char(tmp) + String.fromCharCode(buf[i])
8116 tmp = ''
8117 } else {
8118 tmp += '%' + buf[i].toString(16)
8119 }
8120 }
8121
8122 return res + Buffer.decodeUtf8Char(tmp)
8123}
8124
8125Buffer.asciiSlice = function(buf, start, end) {
8126 var ret = ''
8127 end = Math.min(buf.length, end)
8128
8129 for (var i = start; i < end; i++) {
8130 ret += String.fromCharCode(buf[i])
8131 }
8132 return ret
8133}
8134
8135Buffer.binarySlice = function(buf, start, end) {
8136 return Buffer.asciiSlice(buf, start, end)
8137}
8138
8139Buffer.hexSlice = function(buf, start, end) {
8140 var len = buf.length
8141
8142 if (!start || start < 0) start = 0
8143 if (!end || end < 0 || end > len) end = len
8144
8145 var out = ''
8146 for (var i = start; i < end; i++) {
8147 out += Buffer.toHex(buf[i])
8148 }
8149 return out
8150}
8151
8152function utf16leSlice (buf, start, end) {
8153 var bytes = buf.slice(start, end)
8154 var res = ''
8155 for (var i = 0; i < bytes.length; i += 2) {
8156 res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)
8157 }
8158 return res
8159}
8160
8161Buffer.prototype.slice = function (start, end) {
8162 var len = this.length
8163 start = Buffer.clamp(start, len, 0)
8164 end = Buffer.clamp(end, len, len)
8165
8166 if (Buffer._useTypedArrays) {
8167 return Buffer._augment(this.subarray(start, end))
8168 } else {
8169 var sliceLen = end - start
8170 var newBuf = new Buffer(sliceLen, undefined, true)
8171 for (var i = 0; i < sliceLen; i++) {
8172 newBuf[i] = this[i + start]
8173 }
8174 return newBuf
8175 }
8176}
8177
8178// `get` will be removed in Node 0.13+
8179Buffer.prototype.get = function (offset) {
8180 console.log('.get() is deprecated. Access using array indexes instead.')
8181 return this.readUInt8(offset)
8182}
8183
8184// `set` will be removed in Node 0.13+
8185Buffer.prototype.set = function (v, offset) {
8186 console.log('.set() is deprecated. Access using array indexes instead.')
8187 return this.writeUInt8(v, offset)
8188}
8189
8190Buffer.prototype.readUInt8 = function (offset, noAssert) {
8191 if (!noAssert) {
8192 Buffer.assert(offset !== undefined && offset !== null, 'missing offset')
8193 Buffer.assert(offset < this.length, 'Trying to read beyond buffer length')
8194 }
8195
8196 if (offset >= this.length)
8197 return
8198
8199 return this[offset]
8200}
8201
8202Buffer.readUInt16 = function(buf, offset, littleEndian, noAssert) {
8203 if (!noAssert) {
8204 Buffer.assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
8205 Buffer.assert(offset !== undefined && offset !== null, 'missing offset')
8206 Buffer.assert(offset + 1 < buf.length, 'Trying to read beyond buffer length')
8207 }
8208
8209 var len = buf.length
8210 if (offset >= len)
8211 return
8212
8213 var val
8214 if (littleEndian) {
8215 val = buf[offset]
8216 if (offset + 1 < len)
8217 val |= buf[offset + 1] << 8
8218 } else {
8219 val = buf[offset] << 8
8220 if (offset + 1 < len)
8221 val |= buf[offset + 1]
8222 }
8223 return val
8224}
8225
8226Buffer.prototype.readUInt16LE = function (offset, noAssert) {
8227 return Buffer.readUInt16(this, offset, true, noAssert)
8228}
8229
8230Buffer.prototype.readUInt16BE = function (offset, noAssert) {
8231 return Buffer.readUInt16(this, offset, false, noAssert)
8232}
8233
8234Buffer.readUInt32 = function(buf, offset, littleEndian, noAssert) {
8235 if (!noAssert) {
8236 Buffer.assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
8237 Buffer.assert(offset !== undefined && offset !== null, 'missing offset')
8238 Buffer.assert(offset + 3 < buf.length, 'Trying to read beyond buffer length')
8239 }
8240
8241 var len = buf.length
8242 if (offset >= len)
8243 return
8244
8245 var val
8246 if (littleEndian) {
8247 if (offset + 2 < len)
8248 val = buf[offset + 2] << 16
8249 if (offset + 1 < len)
8250 val |= buf[offset + 1] << 8
8251 val |= buf[offset]
8252 if (offset + 3 < len)
8253 val = val + (buf[offset + 3] << 24 >>> 0)
8254 } else {
8255 if (offset + 1 < len)
8256 val = buf[offset + 1] << 16
8257 if (offset + 2 < len)
8258 val |= buf[offset + 2] << 8
8259 if (offset + 3 < len)
8260 val |= buf[offset + 3]
8261 val = val + (buf[offset] << 24 >>> 0)
8262 }
8263 return val
8264}
8265
8266Buffer.prototype.readUInt32LE = function (offset, noAssert) {
8267 return Buffer.readUInt32(this, offset, true, noAssert)
8268}
8269
8270Buffer.prototype.readUInt32BE = function (offset, noAssert) {
8271 return Buffer.readUInt32(this, offset, false, noAssert)
8272}
8273
8274Buffer.prototype.readInt8 = function (offset, noAssert) {
8275 if (!noAssert) {
8276 Buffer.assert(offset !== undefined && offset !== null,
8277 'missing offset')
8278 Buffer.assert(offset < this.length, 'Trying to read beyond buffer length')
8279 }
8280
8281 if (offset >= this.length)
8282 return
8283
8284 var neg = this[offset] & 0x80
8285 if (neg)
8286 return (0xff - this[offset] + 1) * -1
8287 else
8288 return this[offset]
8289}
8290
8291Buffer.readInt16 = function(buf, offset, littleEndian, noAssert) {
8292 if (!noAssert) {
8293 Buffer.assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
8294 Buffer.assert(offset !== undefined && offset !== null, 'missing offset')
8295 Buffer.assert(offset + 1 < buf.length, 'Trying to read beyond buffer length')
8296 }
8297
8298 var len = buf.length
8299 if (offset >= len)
8300 return
8301
8302 var val = Buffer.readUInt16(buf, offset, littleEndian, true)
8303 var neg = val & 0x8000
8304 if (neg)
8305 return (0xffff - val + 1) * -1
8306 else
8307 return val
8308}
8309
8310Buffer.prototype.readInt16LE = function (offset, noAssert) {
8311 return Buffer.readInt16(this, offset, true, noAssert)
8312}
8313
8314Buffer.prototype.readInt16BE = function (offset, noAssert) {
8315 return Buffer.readInt16(this, offset, false, noAssert)
8316}
8317
8318Buffer.readInt32 = function(buf, offset, littleEndian, noAssert) {
8319 if (!noAssert) {
8320 Buffer.assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
8321 Buffer.assert(offset !== undefined && offset !== null, 'missing offset')
8322 Buffer.assert(offset + 3 < buf.length, 'Trying to read beyond buffer length')
8323 }
8324
8325 var len = buf.length
8326 if (offset >= len)
8327 return
8328
8329 var val = Buffer.readUInt32(buf, offset, littleEndian, true)
8330 var neg = val & 0x80000000
8331 if (neg)
8332 return (0xffffffff - val + 1) * -1
8333 else
8334 return val
8335}
8336
8337Buffer.prototype.readInt32LE = function (offset, noAssert) {
8338 return Buffer.readInt32(this, offset, true, noAssert)
8339}
8340
8341Buffer.prototype.readInt32BE = function (offset, noAssert) {
8342 return Buffer.readInt32(this, offset, false, noAssert)
8343}
8344
8345Buffer.readFloat = function(buf, offset, littleEndian, noAssert) {
8346 if (!noAssert) {
8347 Buffer.assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
8348 Buffer.assert(offset + 3 < buf.length, 'Trying to read beyond buffer length')
8349 }
8350
8351 return ieee754.read(buf, offset, littleEndian, 23, 4)
8352}
8353
8354Buffer.prototype.readFloatLE = function (offset, noAssert) {
8355 return Buffer.readFloat(this, offset, true, noAssert)
8356}
8357
8358Buffer.prototype.readFloatBE = function (offset, noAssert) {
8359 return Buffer.readFloat(this, offset, false, noAssert)
8360}
8361
8362Buffer.readDouble = function(buf, offset, littleEndian, noAssert) {
8363 if (!noAssert) {
8364 Buffer.assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
8365 Buffer.assert(offset + 7 < buf.length, 'Trying to read beyond buffer length')
8366 }
8367
8368 return ieee754.read(buf, offset, littleEndian, 52, 8)
8369}
8370
8371Buffer.prototype.readDoubleLE = function (offset, noAssert) {
8372 return Buffer.readDouble(this, offset, true, noAssert)
8373}
8374
8375Buffer.prototype.readDoubleBE = function (offset, noAssert) {
8376 return Buffer.readDouble(this, offset, false, noAssert)
8377}
8378
8379Buffer.prototype.writeUInt8 = function (value, offset, noAssert) {
8380 if (!noAssert) {
8381 Buffer.assert(value !== undefined && value !== null, 'missing value')
8382 Buffer.assert(offset !== undefined && offset !== null, 'missing offset')
8383 Buffer.assert(offset < this.length, 'trying to write beyond buffer length')
8384 Buffer.verifuint(value, 0xff)
8385 }
8386
8387 if (offset >= this.length) return
8388
8389 this[offset] = value
8390 return offset + 1
8391}
8392
8393Buffer.writeUInt16 = function(buf, value, offset, littleEndian, noAssert) {
8394 if (!noAssert) {
8395 Buffer.assert(value !== undefined && value !== null, 'missing value')
8396 Buffer.assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
8397 Buffer.assert(offset !== undefined && offset !== null, 'missing offset')
8398 Buffer.assert(offset + 1 < buf.length, 'trying to write beyond buffer length')
8399 Buffer.verifuint(value, 0xffff)
8400 }
8401
8402 var len = buf.length
8403 if (offset >= len)
8404 return
8405
8406 for (var i = 0, j = Math.min(len - offset, 2); i < j; i++) {
8407 buf[offset + i] =
8408 (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>
8409 (littleEndian ? i : 1 - i) * 8
8410 }
8411 return offset + 2
8412}
8413
8414Buffer.prototype.writeUInt16LE = function (value, offset, noAssert) {
8415 return Buffer.writeUInt16(this, value, offset, true, noAssert)
8416}
8417
8418Buffer.prototype.writeUInt16BE = function (value, offset, noAssert) {
8419 return Buffer.writeUInt16(this, value, offset, false, noAssert)
8420}
8421
8422Buffer.writeUInt32 = function(buf, value, offset, littleEndian, noAssert) {
8423 if (!noAssert) {
8424 Buffer.assert(value !== undefined && value !== null, 'missing value')
8425 Buffer.assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
8426 Buffer.assert(offset !== undefined && offset !== null, 'missing offset')
8427 Buffer.assert(offset + 3 < buf.length, 'trying to write beyond buffer length')
8428 Buffer.verifuint(value, 0xffffffff)
8429 }
8430
8431 var len = buf.length
8432 if (offset >= len)
8433 return
8434
8435 for (var i = 0, j = Math.min(len - offset, 4); i < j; i++) {
8436 buf[offset + i] =
8437 (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff
8438 }
8439 return offset + 4
8440}
8441
8442Buffer.prototype.writeUInt32LE = function (value, offset, noAssert) {
8443 return Buffer.writeUInt32(this, value, offset, true, noAssert)
8444}
8445
8446Buffer.prototype.writeUInt32BE = function (value, offset, noAssert) {
8447 return Buffer.writeUInt32(this, value, offset, false, noAssert)
8448}
8449
8450Buffer.prototype.writeInt8 = function (value, offset, noAssert) {
8451 if (!noAssert) {
8452 Buffer.assert(value !== undefined && value !== null, 'missing value')
8453 Buffer.assert(offset !== undefined && offset !== null, 'missing offset')
8454 Buffer.assert(offset < this.length, 'Trying to write beyond buffer length')
8455 Buffer.verifsint(value, 0x7f, -0x80)
8456 }
8457
8458 if (offset >= this.length)
8459 return
8460
8461 if (value >= 0)
8462 this.writeUInt8(value, offset, noAssert)
8463 else
8464 this.writeUInt8(0xff + value + 1, offset, noAssert)
8465 return offset + 1
8466}
8467
8468Buffer.writeInt16 = function(buf, value, offset, littleEndian, noAssert) {
8469 if (!noAssert) {
8470 Buffer.assert(value !== undefined && value !== null, 'missing value')
8471 Buffer.assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
8472 Buffer.assert(offset !== undefined && offset !== null, 'missing offset')
8473 Buffer.assert(offset + 1 < buf.length, 'Trying to write beyond buffer length')
8474 Buffer.verifsint(value, 0x7fff, -0x8000)
8475 }
8476
8477 var len = buf.length
8478 if (offset >= len)
8479 return
8480
8481 if (value >= 0)
8482 Buffer.writeUInt16(buf, value, offset, littleEndian, noAssert)
8483 else
8484 Buffer.writeUInt16(buf, 0xffff + value + 1, offset, littleEndian, noAssert)
8485 return offset + 2
8486}
8487
8488Buffer.prototype.writeInt16LE = function (value, offset, noAssert) {
8489 return Buffer.writeInt16(this, value, offset, true, noAssert)
8490}
8491
8492Buffer.prototype.writeInt16BE = function (value, offset, noAssert) {
8493 return Buffer.writeInt16(this, value, offset, false, noAssert)
8494}
8495
8496Buffer.writeInt32 = function(buf, value, offset, littleEndian, noAssert) {
8497 if (!noAssert) {
8498 Buffer.assert(value !== undefined && value !== null, 'missing value')
8499 Buffer.assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
8500 Buffer.assert(offset !== undefined && offset !== null, 'missing offset')
8501 Buffer.assert(offset + 3 < buf.length, 'Trying to write beyond buffer length')
8502 Buffer.verifsint(value, 0x7fffffff, -0x80000000)
8503 }
8504
8505 var len = buf.length
8506 if (offset >= len)
8507 return
8508
8509 if (value >= 0)
8510 Buffer.writeUInt32(buf, value, offset, littleEndian, noAssert)
8511 else
8512 Buffer.writeUInt32(buf, 0xffffffff + value + 1, offset, littleEndian, noAssert)
8513 return offset + 4
8514}
8515
8516Buffer.prototype.writeInt32LE = function (value, offset, noAssert) {
8517 return Buffer.writeInt32(this, value, offset, true, noAssert)
8518}
8519
8520Buffer.prototype.writeInt32BE = function (value, offset, noAssert) {
8521 return Buffer.writeInt32(this, value, offset, false, noAssert)
8522}
8523
8524Buffer.writeFloat = function(buf, value, offset, littleEndian, noAssert) {
8525 if (!noAssert) {
8526 Buffer.assert(value !== undefined && value !== null, 'missing value')
8527 Buffer.assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
8528 Buffer.assert(offset !== undefined && offset !== null, 'missing offset')
8529 Buffer.assert(offset + 3 < buf.length, 'Trying to write beyond buffer length')
8530 Buffer.verifIEEE754(value, 3.4028234663852886e+38, -3.4028234663852886e+38)
8531 }
8532
8533 var len = buf.length
8534 if (offset >= len)
8535 return
8536
8537 ieee754.write(buf, value, offset, littleEndian, 23, 4)
8538 return offset + 4
8539}
8540
8541Buffer.prototype.writeFloatLE = function (value, offset, noAssert) {
8542 return Buffer.writeFloat(this, value, offset, true, noAssert)
8543}
8544
8545Buffer.prototype.writeFloatBE = function (value, offset, noAssert) {
8546 return Buffer.writeFloat(this, value, offset, false, noAssert)
8547}
8548
8549Buffer.writeDouble = function(buf, value, offset, littleEndian, noAssert) {
8550 if (!noAssert) {
8551 Buffer.assert(value !== undefined && value !== null, 'missing value')
8552 Buffer.assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
8553 Buffer.assert(offset !== undefined && offset !== null, 'missing offset')
8554 Buffer.assert(offset + 7 < buf.length,
8555 'Trying to write beyond buffer length')
8556 Buffer.verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308)
8557 }
8558
8559 var len = buf.length
8560 if (offset >= len)
8561 return
8562
8563 ieee754.write(buf, value, offset, littleEndian, 52, 8)
8564 return offset + 8
8565}
8566
8567Buffer.prototype.writeDoubleLE = function (value, offset, noAssert) {
8568 return Buffer.writeDouble(this, value, offset, true, noAssert)
8569}
8570
8571Buffer.prototype.writeDoubleBE = function (value, offset, noAssert) {
8572 return Buffer.writeDouble(this, value, offset, false, noAssert)
8573}
8574
8575// fill(value, start=0, end=buffer.length)
8576Buffer.prototype.fill = function (value, start, end) {
8577 if (!value) value = 0
8578 if (!start) start = 0
8579 if (!end) end = this.length
8580
8581 Buffer.assert(end >= start, 'end < start')
8582
8583 // Fill 0 bytes; we're done
8584 if (end === start) return
8585 if (this.length === 0) return
8586
8587 Buffer.assert(start >= 0 && start < this.length, 'start out of bounds')
8588 Buffer.assert(end >= 0 && end <= this.length, 'end out of bounds')
8589
8590 var i
8591 if (typeof value === 'number') {
8592 for (i = start; i < end; i++) {
8593 this[i] = value
8594 }
8595 } else {
8596 var bytes = Buffer.utf8ToBytes(value.toString())
8597 var len = bytes.length
8598 for (i = start; i < end; i++) {
8599 this[i] = bytes[i % len]
8600 }
8601 }
8602
8603 return this
8604}
8605
8606Buffer.prototype.inspect = function () {
8607 var out = []
8608 var len = this.length
8609 for (var i = 0; i < len; i++) {
8610 out[i] = Buffer.toHex(this[i])
8611 if (i === exports.INSPECT_MAX_BYTES) {
8612 out[i + 1] = '...'
8613 break
8614 }
8615 }
8616 return '<Buffer ' + out.join(' ') + '>'
8617}
8618
8619/**
8620 * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance.
8621 * Added in Node 0.12. Only available in browsers that support ArrayBuffer.
8622 */
8623Buffer.prototype.toArrayBuffer = function () {
8624 if (typeof Uint8Array !== 'undefined') {
8625 if (Buffer._useTypedArrays) {
8626 return (new Buffer(this)).buffer
8627 } else {
8628 var buf = new Uint8Array(this.length)
8629 for (var i = 0, len = buf.length; i < len; i += 1) {
8630 buf[i] = this[i]
8631 }
8632 return buf.buffer
8633 }
8634 } else {
8635 throw new Error('Buffer.toArrayBuffer not supported in this browser')
8636 }
8637}
8638
8639// HELPER FUNCTIONS
8640// ================
8641
8642var BP = Buffer.prototype
8643
8644/**
8645 * Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods
8646 */
8647Buffer._augment = function (arr) {
8648 arr._isBuffer = true
8649
8650 // save reference to original Uint8Array get/set methods before overwriting
8651 arr._get = arr.get
8652 arr._set = arr.set
8653
8654 // deprecated, will be removed in node 0.13+
8655 arr.get = BP.get
8656 arr.set = BP.set
8657
8658 arr.write = BP.write
8659 arr.toString = BP.toString
8660 arr.toLocaleString = BP.toString
8661 arr.toJSON = BP.toJSON
8662 arr.equals = BP.equals
8663 arr.compare = BP.compare
8664 arr.copy = BP.copy
8665 arr.slice = BP.slice
8666 arr.readUInt8 = BP.readUInt8
8667 arr.readUInt16LE = BP.readUInt16LE
8668 arr.readUInt16BE = BP.readUInt16BE
8669 arr.readUInt32LE = BP.readUInt32LE
8670 arr.readUInt32BE = BP.readUInt32BE
8671 arr.readInt8 = BP.readInt8
8672 arr.readInt16LE = BP.readInt16LE
8673 arr.readInt16BE = BP.readInt16BE
8674 arr.readInt32LE = BP.readInt32LE
8675 arr.readInt32BE = BP.readInt32BE
8676 arr.readFloatLE = BP.readFloatLE
8677 arr.readFloatBE = BP.readFloatBE
8678 arr.readDoubleLE = BP.readDoubleLE
8679 arr.readDoubleBE = BP.readDoubleBE
8680 arr.writeUInt8 = BP.writeUInt8
8681 arr.writeUInt16LE = BP.writeUInt16LE
8682 arr.writeUInt16BE = BP.writeUInt16BE
8683 arr.writeUInt32LE = BP.writeUInt32LE
8684 arr.writeUInt32BE = BP.writeUInt32BE
8685 arr.writeInt8 = BP.writeInt8
8686 arr.writeInt16LE = BP.writeInt16LE
8687 arr.writeInt16BE = BP.writeInt16BE
8688 arr.writeInt32LE = BP.writeInt32LE
8689 arr.writeInt32BE = BP.writeInt32BE
8690 arr.writeFloatLE = BP.writeFloatLE
8691 arr.writeFloatBE = BP.writeFloatBE
8692 arr.writeDoubleLE = BP.writeDoubleLE
8693 arr.writeDoubleBE = BP.writeDoubleBE
8694 arr.fill = BP.fill
8695 arr.inspect = BP.inspect
8696 arr.toArrayBuffer = BP.toArrayBuffer
8697
8698 return arr
8699}
8700
8701Buffer.stringtrim = function(str) {
8702 if (str.trim) return str.trim()
8703 return str.replace(/^\s+|\s+$/g, '')
8704}
8705
8706// slice(start, end)
8707Buffer.clamp = function(index, len, defaultValue) {
8708 if (typeof index !== 'number') return defaultValue
8709 index = ~~index; // Coerce to integer.
8710 if (index >= len) return len
8711 if (index >= 0) return index
8712 index += len
8713 if (index >= 0) return index
8714 return 0
8715}
8716
8717Buffer.coerce = function(length) {
8718 // Coerce length to a number (possibly NaN), round up
8719 // in case it's fractional (e.g. 123.456) then do a
8720 // double negate to coerce a NaN to 0. Easy, right?
8721 length = ~~Math.ceil(+length)
8722 return length < 0 ? 0 : length
8723}
8724
8725Buffer.isArray = function(subject) {
8726 return (Array.isArray || function (subject) {
8727 return Object.prototype.toString.call(subject) === '[object Array]'
8728 })(subject)
8729}
8730
8731Buffer.isArrayish = function(subject) {
8732 return Buffer.isArray(subject) || Buffer.isBuffer(subject) ||
8733 subject && typeof subject === 'object' &&
8734 typeof subject.length === 'number'
8735}
8736
8737Buffer.toHex = function(n) {
8738 if (n < 16) return '0' + n.toString(16)
8739 return n.toString(16)
8740}
8741
8742Buffer.utf8ToBytes = function(str) {
8743 var byteArray = []
8744 for (var i = 0; i < str.length; i++) {
8745 var b = str.charCodeAt(i)
8746 if (b <= 0x7F) {
8747 byteArray.push(b)
8748 } else {
8749 var start = i
8750 if (b >= 0xD800 && b <= 0xDFFF) i++
8751 var h = encodeURIComponent(str.slice(start, i+1)).substr(1).split('%')
8752 for (var j = 0; j < h.length; j++) {
8753 byteArray.push(parseInt(h[j], 16))
8754 }
8755 }
8756 }
8757 return byteArray
8758}
8759
8760Buffer.asciiToBytes = function(str) {
8761 var byteArray = []
8762 for (var i = 0; i < str.length; i++) {
8763 // Node's code seems to be doing this and not & 0x7F..
8764 byteArray.push(str.charCodeAt(i) & 0xFF)
8765 }
8766 return byteArray
8767}
8768
8769Buffer.utf16leToBytes = function(str) {
8770 var c, hi, lo
8771 var byteArray = []
8772 for (var i = 0; i < str.length; i++) {
8773 c = str.charCodeAt(i)
8774 hi = c >> 8
8775 lo = c % 256
8776 byteArray.push(lo)
8777 byteArray.push(hi)
8778 }
8779
8780 return byteArray
8781}
8782
8783Buffer.base64ToBytes = function(str) {
8784 return base64.toByteArray(str)
8785}
8786
8787Buffer.blitBuffer = function(src, dst, offset, length) {
8788 for (var i = 0; i < length; i++) {
8789 if ((i + offset >= dst.length) || (i >= src.length))
8790 break
8791 dst[i + offset] = src[i]
8792 }
8793 return i
8794}
8795
8796Buffer.decodeUtf8Char = function(str) {
8797 try {
8798 return decodeURIComponent(str)
8799 } catch (err) {
8800 return String.fromCharCode(0xFFFD) // UTF 8 invalid char
8801 }
8802}
Alexander Afanasyev1663a412013-03-02 13:52:00 -08008803
8804/*
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08008805 * We have to make sure that the value is a valid integer. This means that it
8806 * is non-negative. It has no fractional component and that it does not
8807 * exceed the maximum allowed value.
Alexander Afanasyev1663a412013-03-02 13:52:00 -08008808 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -08008809Buffer.verifuint = function(value, max) {
8810 Buffer.assert(typeof value === 'number', 'cannot write a non-number as a number')
8811 Buffer.assert(value >= 0, 'specified a negative value for writing an unsigned value')
8812 Buffer.assert(value <= max, 'value is larger than maximum value for type')
8813 Buffer.assert(Math.floor(value) === value, 'value has a fractional component')
8814}
8815
8816Buffer.verifsint = function(value, max, min) {
8817 Buffer.assert(typeof value === 'number', 'cannot write a non-number as a number')
8818 Buffer.assert(value <= max, 'value larger than maximum allowed value')
8819 Buffer.assert(value >= min, 'value smaller than minimum allowed value')
8820 Buffer.assert(Math.floor(value) === value, 'value has a fractional component')
8821}
8822
8823Buffer.verifIEEE754 = function(value, max, min) {
8824 Buffer.assert(typeof value === 'number', 'cannot write a non-number as a number')
8825 Buffer.assert(value <= max, 'value larger than maximum allowed value')
8826 Buffer.assert(value >= min, 'value smaller than minimum allowed value')
8827}
8828
8829Buffer.assert = function(test, message) {
8830 if (!test) throw new Error(message || 'Failed assertion')
8831}
8832/**
8833 * Copyright (C) 2013-2016 Regents of the University of California.
8834 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
8835 *
8836 * This program is free software: you can redistribute it and/or modify
8837 * it under the terms of the GNU Lesser General Public License as published by
8838 * the Free Software Foundation, either version 3 of the License, or
8839 * (at your option) any later version.
8840 *
8841 * This program is distributed in the hope that it will be useful,
8842 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8843 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8844 * GNU Lesser General Public License for more details.
8845 *
8846 * You should have received a copy of the GNU Lesser General Public License
8847 * along with this program. If not, see <http://www.gnu.org/licenses/>.
8848 * A copy of the GNU Lesser General Public License is in the file COPYING.
8849 */
8850
8851/**
8852 * The Log class holds the global static variable LOG.
8853 */
8854var Log = function Log()
8855{
8856}
8857
8858exports.Log = Log;
8859
8860/**
8861 * LOG is the level for logging debugging statements. 0 means no log messages.
8862 * @type Number
8863 */
8864Log.LOG = 0;
8865/**
8866 * Encapsulate a Buffer and support dynamic reallocation.
8867 * Copyright (C) 2015-2016 Regents of the University of California.
8868 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
8869 *
8870 * This program is free software: you can redistribute it and/or modify
8871 * it under the terms of the GNU Lesser General Public License as published by
8872 * the Free Software Foundation, either version 3 of the License, or
8873 * (at your option) any later version.
8874 *
8875 * This program is distributed in the hope that it will be useful,
8876 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8877 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8878 * GNU Lesser General Public License for more details.
8879 *
8880 * You should have received a copy of the GNU Lesser General Public License
8881 * along with this program. If not, see <http://www.gnu.org/licenses/>.
8882 * A copy of the GNU Lesser General Public License is in the file COPYING.
8883 */
8884
8885/** @ignore */
8886var printStackTrace = require('../../contrib/stacktrace/stacktrace.js').printStackTrace;
8887
8888/**
8889 * NdnCommon has static NDN utility methods and constants.
8890 * @constructor
8891 */
8892var NdnCommon = {};
8893
8894exports.NdnCommon = NdnCommon;
8895
8896/**
8897 * The practical limit of the size of a network-layer packet. If a packet is
8898 * larger than this, the library or application MAY drop it. This constant is
8899 * defined in this low-level class so that internal code can use it, but
8900 * applications should use the static API method
8901 * Face.getMaxNdnPacketSize() which is equivalent.
8902 */
8903NdnCommon.MAX_NDN_PACKET_SIZE = 8800;
8904
8905/**
8906 * Get the error message plus its stack trace.
8907 * @param {Error} error The error object.
8908 * @return {string} The error message, plus the stack trace with each line
8909 * separated by '\n'.
8910 */
8911NdnCommon.getErrorWithStackTrace = function(error)
8912{
8913 return error + '\n' + printStackTrace({e: error}).join('\n');
8914};
8915
8916/**
8917 * Check for Indexed DB support and call onComplete with the result as described
8918 * below. This has to use an onComplete callback since IndexedDB is async.
8919 * @param {function} onComplete This calls onComplete(haveIndexedDb) where
8920 * haveIndexedDb is true if the browser has Indexed DB support, otherwise false.
8921 */
8922NdnCommon.checkIndexedDb = function(onComplete)
8923{
8924 try {
8925 var database = new Dexie("test-Dexie-support");
8926 database.version(1).stores({});
8927 database.open();
8928
8929 // Give Dexie a little time to open.
8930 setTimeout(function() {
8931 try {
8932 onComplete(database.isOpen());
8933 } catch (ex) {
8934 onComplete(false);
8935 }
8936 }, 200);
8937 } catch (ex) {
8938 onComplete(false);
8939 }
8940};
8941/**
8942 * Copyright (C) 2015-2016 Regents of the University of California.
8943 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
8944 *
8945 * This program is free software: you can redistribute it and/or modify
8946 * it under the terms of the GNU Lesser General Public License as published by
8947 * the Free Software Foundation, either version 3 of the License, or
8948 * (at your option) any later version.
8949 *
8950 * This program is distributed in the hope that it will be useful,
8951 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8952 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8953 * GNU Lesser General Public License for more details.
8954 *
8955 * You should have received a copy of the GNU Lesser General Public License
8956 * along with this program. If not, see <http://www.gnu.org/licenses/>.
8957 * A copy of the GNU Lesser General Public License is in the file COPYING.
8958 */
8959
8960/** @ignore */
8961var NdnCommon = require('./ndn-common.js').NdnCommon;
8962
8963/**
8964 * An ExponentialReExpress uses an internal onTimeout to express the interest again
8965 * with double the interestLifetime. See ExponentialReExpress.makeOnTimeout,
8966 * which you should call instead of the private constructor.
8967 * Create a new ExponentialReExpress where onTimeout expresses the interest
8968 * again with double the interestLifetime. If the interesLifetime goes
8969 * over settings.maxInterestLifetime, then call the given onTimeout. If this
8970 * internally gets onData, just call the given onData.
8971 * @constructor
8972 */
8973var ExponentialReExpress = function ExponentialReExpress
8974 (face, onData, onTimeout, settings)
8975{
8976 settings = (settings || {});
8977 this.face = face;
8978 this.callerOnData = onData;
8979 this.callerOnTimeout = onTimeout;
8980
8981 this.maxInterestLifetime = (settings.maxInterestLifetime || 16000);
8982};
8983
8984exports.ExponentialReExpress = ExponentialReExpress;
8985
8986/**
8987 * Return a callback to use in expressInterest for onTimeout which will express
8988 * the interest again with double the interestLifetime. If the interesLifetime
8989 * goes over maxInterestLifetime (see settings below), then call the provided
8990 * onTimeout. If a Data packet is received, this calls the provided onData.
8991 * Use it like this:
8992 * var onData = function() { ... };
8993 * var onTimeout = function() { ... };
8994 * face.expressInterest
8995 * (interest, onData,
8996 * ExponentialReExpress.makeOnTimeout(face, onData, onTimeout));
8997 * @param {Face} face This calls face.expressInterest.
8998 * @param {function} onData When a matching data packet is received, this calls
8999 * onData(interest, data) where interest is the interest given to
9000 * expressInterest and data is the received Data object. This is normally the
9001 * same onData you initially passed to expressInterest.
9002 * NOTE: The library will log any exceptions thrown by this callback, but for
9003 * better error handling the callback should catch and properly handle any
9004 * exceptions.
9005 * @param {function} onTimeout If the interesLifetime goes over
9006 * maxInterestLifetime, this calls onTimeout(interest). However, if onTimeout is
9007 * null, this does not use it.
9008 * NOTE: The library will log any exceptions thrown by this callback, but for
9009 * better error handling the callback should catch and properly handle any
9010 * exceptions.
9011 * @param {Object} settings (optional) If not null, an associative array with
9012 * the following defaults:
9013 * {
9014 * maxInterestLifetime: 16000 // milliseconds
9015 * }
9016 * @return {function} The onTimeout callback to pass to expressInterest.
9017 */
9018ExponentialReExpress.makeOnTimeout = function(face, onData, onTimeout, settings)
9019{
9020 var reExpress = new ExponentialReExpress(face, onData, onTimeout, settings);
9021 return function(interest) { reExpress.onTimeout(interest); };
9022};
9023
9024ExponentialReExpress.prototype.onTimeout = function(interest)
9025{
9026 var interestLifetime = interest.getInterestLifetimeMilliseconds();
9027 if (interestLifetime == null) {
9028 // Can't re-express.
9029 if (this.callerOnTimeout) {
9030 try {
9031 this.callerOnTimeout(interest);
9032 } catch (ex) {
9033 console.log("Error in onTimeout: " + NdnCommon.getErrorWithStackTrace(ex));
9034 }
9035 }
9036 return;
9037 }
9038
9039 var nextInterestLifetime = interestLifetime * 2;
9040 if (nextInterestLifetime > this.maxInterestLifetime) {
9041 if (this.callerOnTimeout) {
9042 try {
9043 this.callerOnTimeout(interest);
9044 } catch (ex) {
9045 console.log("Error in onTimeout: " + NdnCommon.getErrorWithStackTrace(ex));
9046 }
9047 }
9048 return;
9049 }
9050
9051 var nextInterest = interest.clone();
9052 nextInterest.setInterestLifetimeMilliseconds(nextInterestLifetime);
9053 var thisObject = this;
9054 this.face.expressInterest
9055 (nextInterest, this.callerOnData,
9056 function(localInterest) { thisObject.onTimeout(localInterest); });
9057};
9058/**
9059 * Copyright (C) 2013 Regents of the University of California.
9060 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
9061 *
9062 * This program is free software: you can redistribute it and/or modify
9063 * it under the terms of the GNU Lesser General Public License as published by
9064 * the Free Software Foundation, either version 3 of the License, or
9065 * (at your option) any later version.
9066 *
9067 * This program is distributed in the hope that it will be useful,
9068 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9069 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9070 * GNU Lesser General Public License for more details.
9071 *
9072 * You should have received a copy of the GNU Lesser General Public License
9073 * along with this program. If not, see <http://www.gnu.org/licenses/>.
9074 * A copy of the GNU Lesser General Public License is in the file COPYING.
9075 */
9076
9077/**
9078 * A Blob holds an immutable byte array implemented as a Buffer. This should be
9079 * treated like a string which is a pointer to an immutable string. (It is OK to
9080 * pass a pointer to the string because the new owner can’t change the bytes of
9081 * the string.) Blob does not inherit from Buffer. Instead you must call buf()
9082 * to get the byte array which reminds you that you should not change the
9083 * contents. Also remember that buf() can return null.
9084 * @param {Blob|Buffer|Array<number>} value (optional) If value is a Blob, take
9085 * another pointer to the Buffer without copying. If value is a Buffer or byte
9086 * array, copy to create a new Buffer. If omitted, buf() will return null.
9087 * @param {boolean} copy (optional) If true, copy the contents of
9088 * value into a new Buffer. If false, just use the existing value without
9089 * copying. If omitted, then copy the contents (unless value is already a Blob).
9090 * IMPORTANT: If copy is false, if you keep a pointer to the value then you must
9091 * treat the value as immutable and promise not to change it.
9092 * @constructor
9093 */
9094var Blob = function Blob(value, copy)
9095{
9096 if (copy == null)
9097 copy = true;
9098
9099 if (value == null)
9100 this.buffer = null;
9101 else if (typeof value === 'object' && value instanceof Blob)
9102 // Use the existing buffer. Don't need to check for copy.
9103 this.buffer = value.buffer;
9104 else {
9105 if (typeof value === 'string')
9106 // Convert from a string to utf-8 byte encoding.
9107 this.buffer = new Buffer(value, 'utf8');
9108 else {
9109 if (copy)
9110 // We are copying, so just make another Buffer.
9111 this.buffer = new Buffer(value);
9112 else {
9113 if (Buffer.isBuffer(value))
9114 // We can use as-is.
9115 this.buffer = value;
9116 else
9117 // We need a Buffer, so copy.
9118 this.buffer = new Buffer(value);
9119 }
9120 }
9121 }
9122
9123 // Set the length to be "JavaScript-like".
9124 this.length = this.buffer != null ? this.buffer.length : 0;
9125};
9126
9127exports.Blob = Blob;
9128
9129/**
9130 * Return the length of the immutable byte array.
9131 * @return {number} The length of the array. If buf() is null, return 0.
9132 */
9133Blob.prototype.size = function()
9134{
9135 if (this.buffer != null)
9136 return this.buffer.length;
9137 else
9138 return 0;
9139};
9140
9141/**
9142 * Return the immutable byte array. DO NOT change the contents of the Buffer.
9143 * If you need to change it, make a copy.
9144 * @return {Buffer} The Buffer holding the immutable byte array, or null.
9145 */
9146Blob.prototype.buf = function()
9147{
9148 return this.buffer;
9149};
9150
9151/**
9152 * Return true if the array is null, otherwise false.
9153 * @return {boolean} True if the array is null.
9154 */
9155Blob.prototype.isNull = function()
9156{
9157 return this.buffer == null;
9158};
9159
9160/**
9161 * Return the hex representation of the bytes in the byte array.
9162 * @return {string} The hex string.
9163 */
9164Blob.prototype.toHex = function()
9165{
9166 if (this.buffer == null)
9167 return "";
9168 else
9169 return this.buffer.toString('hex');
9170};
9171
9172/**
9173 * Decode the byte array as UTF8 and return the Unicode string.
9174 * @return A unicode string, or "" if the buffer is null.
9175 */
9176Blob.prototype.toString = function()
9177{
9178 if (this.buffer == null)
9179 return "";
9180 else
9181 return this.buffer.toString('utf8');
9182};
9183
9184/**
9185 * Check if the value of this Blob equals the other blob.
9186 * @param {Blob} other The other Blob to check.
9187 * @return {boolean} if this isNull and other isNull or if the bytes of this
9188 * blob equal the bytes of the other.
9189 */
9190Blob.prototype.equals = function(other)
9191{
9192 if (this.isNull())
9193 return other.isNull();
9194 else if (other.isNull())
9195 return false;
9196 else {
9197 if (this.buffer.length != other.buffer.length)
9198 return false;
9199
9200 for (var i = 0; i < this.buffer.length; ++i) {
9201 if (this.buffer[i] != other.buffer[i])
9202 return false;
9203 }
9204
9205 return true;
9206 }
9207};
9208/**
9209 * Copyright (C) 2013 Regents of the University of California.
9210 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
9211 *
9212 * This program is free software: you can redistribute it and/or modify
9213 * it under the terms of the GNU Lesser General Public License as published by
9214 * the Free Software Foundation, either version 3 of the License, or
9215 * (at your option) any later version.
9216 *
9217 * This program is distributed in the hope that it will be useful,
9218 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9219 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9220 * GNU Lesser General Public License for more details.
9221 *
9222 * You should have received a copy of the GNU Lesser General Public License
9223 * along with this program. If not, see <http://www.gnu.org/licenses/>.
9224 * A copy of the GNU Lesser General Public License is in the file COPYING.
9225 */
9226
9227/** @ignore */
9228var Blob = require('./blob.js').Blob;
9229
9230/**
9231 * A SignedBlob extends Blob to keep the offsets of a signed portion (e.g., the
9232 * bytes of Data packet). This inherits from Blob, including Blob.size and Blob.buf.
9233 * @param {Blob|Buffer|Array<number>} value (optional) If value is a Blob, take
9234 * another pointer to the Buffer without copying. If value is a Buffer or byte
9235 * array, copy to create a new Buffer. If omitted, buf() will return null.
9236 * @param {number} signedPortionBeginOffset (optional) The offset in the
9237 * encoding of the beginning of the signed portion. If omitted, set to 0.
9238 * @param {number} signedPortionEndOffset (optional) The offset in the encoding
9239 * of the end of the signed portion. If omitted, set to 0.
9240 * @constructor
9241 */
9242var SignedBlob = function SignedBlob(value, signedPortionBeginOffset, signedPortionEndOffset)
9243{
9244 // Call the base constructor.
9245 Blob.call(this, value);
9246
9247 if (this.buffer == null) {
9248 this.signedPortionBeginOffset = 0;
9249 this.signedPortionEndOffset = 0;
9250 }
9251 else if (typeof value === 'object' && value instanceof SignedBlob) {
9252 // Copy the SignedBlob, allowing override for offsets.
9253 this.signedPortionBeginOffset = signedPortionBeginOffset == null ?
9254 value.signedPortionBeginOffset : signedPortionBeginOffset;
9255 this.signedPortionEndOffset = signedPortionEndOffset == null ?
9256 value.signedPortionEndOffset : signedPortionEndOffset;
9257 }
9258 else {
9259 this.signedPortionBeginOffset = signedPortionBeginOffset || 0;
9260 this.signedPortionEndOffset = signedPortionEndOffset || 0;
9261 }
9262
9263 if (this.buffer == null)
9264 this.signedBuffer = null;
9265 else
9266 this.signedBuffer = this.buffer.slice
9267 (this.signedPortionBeginOffset, this.signedPortionEndOffset);
9268};
9269
9270SignedBlob.prototype = new Blob();
9271SignedBlob.prototype.name = "SignedBlob";
9272
9273exports.SignedBlob = SignedBlob;
9274
9275/**
9276 * Return the length of the signed portion of the immutable byte array.
9277 * @return {number} The length of the signed portion. If signedBuf() is null,
9278 * return 0.
9279 */
9280SignedBlob.prototype.signedSize = function()
9281{
9282 if (this.signedBuffer != null)
9283 return this.signedBuffer.length;
9284 else
9285 return 0;
9286};
9287
9288/**
9289 * Return a the signed portion of the immutable byte array.
9290 * @return {Buffer} A slice into the Buffer which is the signed portion.
9291 * If the pointer to the array is null, return null.
9292 */
9293SignedBlob.prototype.signedBuf = function() { return this.signedBuffer; };
9294
9295/**
9296 * Return the offset in the array of the beginning of the signed portion.
9297 * @return {number} The offset in the array.
9298 */
9299SignedBlob.prototype.getSignedPortionBeginOffset = function()
9300{
9301 return this.signedPortionBeginOffset;
9302};
9303
9304/**
9305 * Return the offset in the array of the end of the signed portion.
9306 * @return {number} The offset in the array.
9307 */
9308SignedBlob.prototype.getSignedPortionEndOffset = function()
9309{
9310 return this.signedPortionEndOffset;
9311};
9312/**
9313 * Encapsulate a Buffer and support dynamic reallocation.
9314 * Copyright (C) 2013-2016 Regents of the University of California.
9315 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
9316 *
9317 * This program is free software: you can redistribute it and/or modify
9318 * it under the terms of the GNU Lesser General Public License as published by
9319 * the Free Software Foundation, either version 3 of the License, or
9320 * (at your option) any later version.
9321 *
9322 * This program is distributed in the hope that it will be useful,
9323 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9324 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9325 * GNU Lesser General Public License for more details.
9326 *
9327 * You should have received a copy of the GNU Lesser General Public License
9328 * along with this program. If not, see <http://www.gnu.org/licenses/>.
9329 * A copy of the GNU Lesser General Public License is in the file COPYING.
9330 */
9331
9332/**
9333 * Create a DynamicBuffer where this.array is a Buffer of size length.
9334 * To access the array, use this.array or call slice.
9335 * @constructor
9336 * @param {number} length the initial length of the array. If null, use a default.
9337 */
9338var DynamicBuffer = function DynamicBuffer(length)
9339{
9340 if (!length)
9341 length = 16;
9342
9343 this.array = new Buffer(length);
9344};
9345
9346exports.DynamicBuffer = DynamicBuffer;
9347
9348/**
9349 * Ensure that this.array has the length, reallocate and copy if necessary.
9350 * Update the length of this.array which may be greater than length.
9351 * @param {number} length The minimum length for the array.
9352 */
9353DynamicBuffer.prototype.ensureLength = function(length)
9354{
9355 if (this.array.length >= length)
9356 return;
9357
9358 // See if double is enough.
9359 var newLength = this.array.length * 2;
9360 if (length > newLength)
9361 // The needed length is much greater, so use it.
9362 newLength = length;
9363
9364 var newArray = new Buffer(newLength);
9365 this.array.copy(newArray);
9366 this.array = newArray;
9367};
9368
9369/**
9370 * Copy the value to this.array at offset, reallocating if necessary.
9371 * @param {Buffer} value The buffer to copy.
9372 * @param {number} offset The offset in the buffer to start copying into.
9373 * @return {number} The new offset which is offset + value.length.
9374 */
9375DynamicBuffer.prototype.copy = function(value, offset)
9376{
9377 this.ensureLength(value.length + offset);
9378
9379 if (Buffer.isBuffer(value))
9380 value.copy(this.array, offset);
9381 else
9382 // Need to make value a Buffer to copy.
9383 new Buffer(value).copy(this.array, offset);
9384
9385 return offset + value.length;
9386};
9387
9388/**
9389 * Ensure that this.array has the length. If necessary, reallocate the array
9390 * and shift existing data to the back of the new array.
9391 * Update the length of this.array which may be greater than length.
9392 * @param {number} length The minimum length for the array.
9393 */
9394DynamicBuffer.prototype.ensureLengthFromBack = function(length)
9395{
9396 if (this.array.length >= length)
9397 return;
9398
9399 // See if double is enough.
9400 var newLength = this.array.length * 2;
9401 if (length > newLength)
9402 // The needed length is much greater, so use it.
9403 newLength = length;
9404
9405 var newArray = new Buffer(newLength);
9406 // Copy to the back of newArray.
9407 this.array.copy(newArray, newArray.length - this.array.length);
9408 this.array = newArray;
9409};
9410
9411/**
9412 * First call ensureLengthFromBack to make sure the bytearray has
9413 * offsetFromBack bytes, then copy value into the array starting
9414 * offsetFromBack bytes from the back of the array.
9415 * @param {Buffer} value The buffer to copy.
9416 * @param {number} offsetFromBack The offset from the back of the array to start
9417 * copying.
9418 */
9419DynamicBuffer.prototype.copyFromBack = function(value, offsetFromBack)
9420{
9421 this.ensureLengthFromBack(offsetFromBack);
9422
9423 if (Buffer.isBuffer(value))
9424 value.copy(this.array, this.array.length - offsetFromBack);
9425 else
9426 // Need to make value a Buffer to copy.
9427 new Buffer(value).copy(this.array, this.array.length - offsetFromBack);
9428};
9429
9430/**
9431 * Return this.array.slice(begin, end);
9432 * @param {number} begin The begin index for the slice.
9433 * @param {number} end (optional) The end index for the slice.
9434 * @return {Buffer} The buffer slice.
9435 */
9436DynamicBuffer.prototype.slice = function(begin, end)
9437{
9438 if (end == undefined)
9439 return this.array.slice(begin);
9440 else
9441 return this.array.slice(begin, end);
9442};
9443/**
9444 * Copyright (C) 2014-2016 Regents of the University of California.
9445 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
9446 *
9447 * This program is free software: you can redistribute it and/or modify
9448 * it under the terms of the GNU Lesser General Public License as published by
9449 * the Free Software Foundation, either version 3 of the License, or
9450 * (at your option) any later version.
9451 *
9452 * This program is distributed in the hope that it will be useful,
9453 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9454 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9455 * GNU Lesser General Public License for more details.
9456 *
9457 * You should have received a copy of the GNU Lesser General Public License
9458 * along with this program. If not, see <http://www.gnu.org/licenses/>.
9459 * A copy of the GNU Lesser General Public License is in the file COPYING.
9460 */
9461
9462/**
9463 * A ChangeCounter keeps a target object whose change count is tracked by a
9464 * local change count. You can set to a new target which updates the local
9465 * change count, and you can call checkChanged to check if the target (or one of
9466 * the target's targets) has been changed. The target object must have a method
9467 * getChangeCount.
9468 *
9469 * Create a new ChangeCounter to track the given target. If target is not null,
9470 * this sets the local change counter to target.getChangeCount().
9471 * @param {object} target The target to track, as an object with the method
9472 * getChangeCount().
9473 * @constructor
9474 */
9475var ChangeCounter = function ChangeCounter(target)
9476{
9477 this.target = target;
9478 this.changeCount = (target == null ? 0 : target.getChangeCount());
9479};
9480
9481exports.ChangeCounter = ChangeCounter;
9482
9483/**
9484 * Get the target object. If the target is changed, then checkChanged will
9485 * detect it.
9486 * @return {object} The target, as an object with the method
9487 * getChangeCount().
9488 */
9489ChangeCounter.prototype.get = function()
9490{
9491 return this.target;
9492};
9493
9494/**
9495 * Set the target to the given target. If target is not null, this sets the
9496 * local change counter to target.getChangeCount().
9497 * @param {object} target The target to track, as an object with the method
9498 * getChangeCount().
9499 */
9500ChangeCounter.prototype.set = function(target)
9501{
9502 this.target = target;
9503 this.changeCount = (target == null ? 0 : target.getChangeCount());
9504};
9505
9506/**
9507 * If the target's change count is different than the local change count, then
9508 * update the local change count and return true. Otherwise return false,
9509 * meaning that the target has not changed. Also, if the target is null,
9510 * simply return false. This is useful since the target (or one of the target's
9511 * targets) may be changed and you need to find out.
9512 * @return {boolean} True if the change count has been updated, false if not.
9513 */
9514ChangeCounter.prototype.checkChanged = function()
9515{
9516 if (this.target == null)
9517 return false;
9518
9519 var targetChangeCount = this.target.getChangeCount();
9520 if (this.changeCount != targetChangeCount) {
9521 this.changeCount = targetChangeCount;
9522 return true;
9523 }
9524 else
9525 return false;
9526};
9527/**
9528 * Copyright (C) 2015-2016 Regents of the University of California.
9529 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
9530 *
9531 * This program is free software: you can redistribute it and/or modify
9532 * it under the terms of the GNU Lesser General Public License as published by
9533 * the Free Software Foundation, either version 3 of the License, or
9534 * (at your option) any later version.
9535 *
9536 * This program is distributed in the hope that it will be useful,
9537 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9538 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9539 * GNU Lesser General Public License for more details.
9540 *
9541 * You should have received a copy of the GNU Lesser General Public License
9542 * along with this program. If not, see <http://www.gnu.org/licenses/>.
9543 * A copy of the GNU Lesser General Public License is in the file COPYING.
9544 */
9545
9546/** @ignore */
9547var NdnCommon = require('./ndn-common.js').NdnCommon;
9548
9549/**
9550 * A SyncPromise is a promise which is immediately fulfilled or rejected, used
9551 * to return a promise in synchronous code.
9552 * This private constructor creates a SyncPromise fulfilled or rejected with the
9553 * given value. You should normally not call this constructor but call
9554 * SyncPromise.resolve or SyncPromise.reject. Note that we don't need a
9555 * constructor like SyncPromise(function(resolve, reject)) because this would be
9556 * for scheduling the function to be called later, which we don't do.
9557 * @param {any} value If isRejected is false, this is the value of the fulfilled
9558 * promise, else if isRejected is true, this is the error.
9559 * @param {boolean} isRejected True to create a promise in the rejected state,
9560 * where value is the error.
9561 * @constructor
9562 */
9563var SyncPromise = function SyncPromise(value, isRejected)
9564{
9565 this.value = value;
9566 this.isRejected = isRejected;
9567};
9568
9569exports.SyncPromise = SyncPromise;
9570
9571/**
9572 * If this promise is fulfilled, immediately call onFulfilled with the fulfilled
9573 * value as described below. Otherwise, if this promise is rejected, immediately
9574 * call onRejected with the error as described below.
9575 * @param {function} (optional) onFulfilled If this promise is fulfilled, this
9576 * calls onFulfilled(value) with the value of this promise and returns the
9577 * result. The function should return a promise. To use all synchronous code,
9578 * onFulfilled should return SyncPromise.resolve(newValue).
9579 * @param {function} (optional) onRejected If this promise is rejected, this
9580 * calls onRejected(err) with the error value of this promise and returns the
9581 * result. The function should return a promise. To use all synchronous code,
9582 * onFulfilled should return SyncPromise.resolve(newValue) (or throw an
9583 * exception).
9584 * @return {Promise|SyncPromise} If this promise is fulfilled, return the result
9585 * of calling onFulfilled(value). Note that this does not create a promise which
9586 * is scheduled to execute later. Rather it immediately calls onFulfilled which
9587 * should return a promise. But if onFulfilled is undefined, simply return this
9588 * promise to pass it forward. If this promise is rejected, return the result of
9589 * calling onRejected(err) with the error value. But if onRejected is undefined,
9590 * simply return this promise to pass it forward. However, if onFulfilled or
9591 * onRejected throws an exception, then return a new SyncPromise in the rejected
9592 * state with the exception.
9593 */
9594SyncPromise.prototype.then = function(onFulfilled, onRejected)
9595{
9596 if (this.isRejected) {
9597 if (onRejected) {
9598 try {
9599 return onRejected(this.value);
9600 }
9601 catch(err) {
9602 return new SyncPromise(err, true);
9603 }
9604 }
9605 else
9606 // Pass the error forward.
9607 return this;
9608 }
9609 else {
9610 if (onFulfilled) {
9611 try {
9612 return onFulfilled(this.value);
9613 }
9614 catch(err) {
9615 return new SyncPromise(err, true);
9616 }
9617 }
9618 else
9619 // Pass the fulfilled value forward.
9620 return this;
9621 }
9622};
9623
9624/**
9625 * Call this.then(undefined, onRejected) and return the result. If this promise
9626 * is rejected then onRejected will process it. If this promise is fulfilled,
9627 * this simply passes it forward.
9628 */
9629SyncPromise.prototype.catch = function(onRejected)
9630{
9631 return this.then(undefined, onRejected);
9632};
9633
9634/**
9635 * Return a new SyncPromise which is already fulfilled to the given value.
9636 * @param {any} value The value of the promise.
9637 */
9638SyncPromise.resolve = function(value)
9639{
9640 return new SyncPromise(value, false);
9641};
9642
9643/**
9644 * Return a new SyncPromise which is already rejected with the given error.
9645 * @param {any} err The error for the rejected promise.
9646 */
9647SyncPromise.reject = function(err)
9648{
9649 return new SyncPromise(err, true);
9650};
9651
9652/**
9653 * This static method checks if the promise is a SyncPromise and immediately
9654 * returns its value or throws the error if promise is rejected. If promise is
9655 * not a SyncPromise, this throws an exception since it is not possible to
9656 * immediately get the value. This can be used with "promise-based" code which
9657 * you expect to always return a SyncPromise to operate in synchronous mode.
9658 * @param {SyncPromise} promise The SyncPromise with the value to get.
9659 * @return {any} The value of the promise.
9660 * @throws Error If promise is not a SyncPromise.
9661 * @throws any If promise is a SyncPromise in the rejected state, this throws
9662 * the error.
9663 */
9664SyncPromise.getValue = function(promise)
9665{
9666 if (promise instanceof SyncPromise) {
9667 if (promise.isRejected)
9668 throw promise.value;
9669 else
9670 return promise.value;
9671 }
9672 else
9673 throw new Error("Cannot return immediately because promise is not a SyncPromise");
9674};
9675
9676/**
9677 * This can be called with complete(onComplete, promise) or
9678 * complete(onComplete, onError, promise) to handle both synchronous and
9679 * asynchronous code based on whether the caller supplies the onComlete callback.
9680 * If onComplete is defined, call promise.then with a function which calls
9681 * onComplete(value) when fulfilled (possibly in asynchronous mode). If
9682 * onComplete is undefined, then we are in synchronous mode so return
9683 * SyncPromise.getValue(promise) which will throw an exception if the promise is
9684 * not a SyncPromise (or is a SyncPromise in the rejected state).
9685 * @param {function} onComplete If defined, this calls promise.then to fulfill
9686 * the promise, then calls onComplete(value) with the value of the promise.
9687 * If onComplete is undefined, the return value is described below.
9688 * NOTE: The library will log any exceptions thrown by this callback, but for
9689 * better error handling the callback should catch and properly handle any
9690 * exceptions.
9691 * @param {function} onError (optional) If defined, then onComplete must be
9692 * defined and if there is an error when this calls promise.then, this calls
9693 * onError(err) with the value of the error. If onComplete is undefined, then
9694 * onError is ignored and this will call SyncPromise.getValue(promise) which may
9695 * throw an exception.
9696 * NOTE: The library will log any exceptions thrown by this callback, but for
9697 * better error handling the callback should catch and properly handle any
9698 * exceptions.
9699 * @param {Promise|SyncPromise} promise If onComplete is defined, this calls
9700 * promise.then. Otherwise, this calls SyncPromise.getValue(promise).
9701 * @return {any} If onComplete is undefined, return SyncPromise.getValue(promise).
9702 * Otherwise, if onComplete is supplied then return undefined and use
9703 * onComplete as described above.
9704 * @throws Error If onComplete is undefined and promise is not a SyncPromise.
9705 * @throws any If onComplete is undefined and promise is a SyncPromise in the
9706 * rejected state.
9707 */
9708SyncPromise.complete = function(onComplete, onErrorOrPromise, promise)
9709{
9710 var onError;
9711 if (promise)
9712 onError = onErrorOrPromise;
9713 else {
9714 promise = onErrorOrPromise;
9715 onError = null;
9716 }
9717
9718 if (onComplete)
9719 promise
9720 .then(function(value) {
9721 try {
9722 onComplete(value);
9723 } catch (ex) {
9724 console.log("Error in onComplete: " + NdnCommon.getErrorWithStackTrace(ex));
9725 }
9726 }, function(err) {
9727 if (onError) {
9728 try {
9729 onError(err);
9730 } catch (ex) {
9731 console.log("Error in onError: " + NdnCommon.getErrorWithStackTrace(ex));
9732 }
9733 }
9734 else {
9735 if (promise instanceof SyncPromise)
9736 throw err;
9737 else
9738 // We are in an async promise callback, so a thrown exception won't
9739 // reach the caller. Just log it.
9740 console.log("Uncaught exception from a Promise: " +
9741 NdnCommon.getErrorWithStackTrace(err));
9742 }
9743 });
9744 else
9745 return SyncPromise.getValue(promise);
9746};
9747/**
9748 * This class contains utilities to help parse the data
9749 *
9750 * Copyright (C) 2013-2016 Regents of the University of California.
9751 * @author: Meki Cheraoui
9752 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
9753 *
9754 * This program is free software: you can redistribute it and/or modify
9755 * it under the terms of the GNU Lesser General Public License as published by
9756 * the Free Software Foundation, either version 3 of the License, or
9757 * (at your option) any later version.
9758 *
9759 * This program is distributed in the hope that it will be useful,
9760 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9761 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9762 * GNU Lesser General Public License for more details.
9763 *
9764 * You should have received a copy of the GNU Lesser General Public License
9765 * along with this program. If not, see <http://www.gnu.org/licenses/>.
9766 * A copy of the GNU Lesser General Public License is in the file COPYING.
9767 */
9768
9769/**
9770 * A DataUtils has static methods for converting data.
9771 * @constructor
9772 */
9773var DataUtils = {};
9774
9775exports.DataUtils = DataUtils;
9776
9777/*
9778 * NOTE THIS IS CURRENTLY NOT BEING USED
9779 *
9780 */
9781
9782DataUtils.keyStr = "ABCDEFGHIJKLMNOP" +
9783 "QRSTUVWXYZabcdef" +
9784 "ghijklmnopqrstuv" +
9785 "wxyz0123456789+/" +
9786 "=";
9787
9788/**
9789 * Raw String to Base 64
9790 */
9791DataUtils.stringtoBase64 = function stringtoBase64(input)
9792{
9793 //input = escape(input);
9794 var output = "";
9795 var chr1, chr2, chr3 = "";
9796 var enc1, enc2, enc3, enc4 = "";
9797 var i = 0;
9798
9799 do {
9800 chr1 = input.charCodeAt(i++);
9801 chr2 = input.charCodeAt(i++);
9802 chr3 = input.charCodeAt(i++);
9803
9804 enc1 = chr1 >> 2;
9805 enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
9806 enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
9807 enc4 = chr3 & 63;
9808
9809 if (isNaN(chr2))
9810 enc3 = enc4 = 64;
9811 else if (isNaN(chr3))
9812 enc4 = 64;
9813
9814 output = output +
9815 DataUtils.keyStr.charAt(enc1) +
9816 DataUtils.keyStr.charAt(enc2) +
9817 DataUtils.keyStr.charAt(enc3) +
9818 DataUtils.keyStr.charAt(enc4);
9819 chr1 = chr2 = chr3 = "";
9820 enc1 = enc2 = enc3 = enc4 = "";
9821 } while (i < input.length);
9822
9823 return output;
9824};
9825
9826/**
9827 * Base 64 to Raw String
9828 */
9829DataUtils.base64toString = function base64toString(input)
9830{
9831 var output = "";
9832 var chr1, chr2, chr3 = "";
9833 var enc1, enc2, enc3, enc4 = "";
9834 var i = 0;
9835
9836 // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
9837 var base64test = /[^A-Za-z0-9\+\/\=]/g;
9838 /* Test for invalid characters. */
9839 if (base64test.exec(input)) {
9840 alert("There were invalid base64 characters in the input text.\n" +
9841 "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" +
9842 "Expect errors in decoding.");
9843 }
9844
9845 input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
9846
9847 do {
9848 enc1 = DataUtils.keyStr.indexOf(input.charAt(i++));
9849 enc2 = DataUtils.keyStr.indexOf(input.charAt(i++));
9850 enc3 = DataUtils.keyStr.indexOf(input.charAt(i++));
9851 enc4 = DataUtils.keyStr.indexOf(input.charAt(i++));
9852
9853 chr1 = (enc1 << 2) | (enc2 >> 4);
9854 chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
9855 chr3 = ((enc3 & 3) << 6) | enc4;
9856
9857 output = output + String.fromCharCode(chr1);
9858
9859 if (enc3 != 64)
9860 output = output + String.fromCharCode(chr2);
9861
9862 if (enc4 != 64)
9863 output = output + String.fromCharCode(chr3);
9864
9865 chr1 = chr2 = chr3 = "";
9866 enc1 = enc2 = enc3 = enc4 = "";
9867 } while (i < input.length);
9868
9869 return output;
9870};
9871
9872/**
9873 * Buffer to Hex String
9874 */
9875DataUtils.toHex = function(buffer)
9876{
9877 return buffer.toString('hex');
9878};
9879
9880/**
9881 * Raw string to hex string.
9882 */
9883DataUtils.stringToHex = function(args)
9884{
9885 var ret = "";
9886 for (var i = 0; i < args.length; ++i) {
9887 var value = args.charCodeAt(i);
9888 ret += (value < 16 ? "0" : "") + value.toString(16);
9889 }
9890 return ret;
9891};
9892
9893/**
9894 * Buffer to raw string.
9895 */
9896DataUtils.toString = function(buffer)
9897{
9898 return buffer.toString('binary');
9899};
9900
9901/**
9902 * Hex String to Buffer.
9903 */
9904DataUtils.toNumbers = function(str)
9905{
9906 return new Buffer(str, 'hex');
9907};
9908
9909/**
9910 * Hex String to raw string.
9911 */
9912DataUtils.hexToRawString = function(str)
9913{
9914 if (typeof str =='string') {
9915 var ret = "";
9916 str.replace(/(..)/g, function(s) {
9917 ret += String.fromCharCode(parseInt(s, 16));
9918 });
9919 return ret;
9920 }
9921};
9922
9923/**
9924 * Raw String to Buffer.
9925 */
9926DataUtils.toNumbersFromString = function(str)
9927{
9928 return new Buffer(str, 'binary');
9929};
9930
9931/**
9932 * If value is a string, then interpret it as a raw string and convert to
9933 * a Buffer. Otherwise assume it is a Buffer or array type and just return it.
9934 * @param {string|any} value
9935 * @return {Buffer}
9936 */
9937DataUtils.toNumbersIfString = function(value)
9938{
9939 if (typeof value === 'string')
9940 return new Buffer(value, 'binary');
9941 else
9942 return value;
9943};
9944
9945/**
9946 * Encode str as utf8 and return as Buffer.
9947 */
9948DataUtils.stringToUtf8Array = function(str)
9949{
9950 return new Buffer(str, 'utf8');
9951};
9952
9953/**
9954 * arrays is an array of Buffer. Return a new Buffer which is the concatenation of all.
9955 */
9956DataUtils.concatArrays = function(arrays)
9957{
9958 return Buffer.concat(arrays);
9959};
9960
9961// TODO: Take Buffer and use TextDecoder when available.
9962DataUtils.decodeUtf8 = function(utftext)
9963{
9964 var string = "";
9965 var i = 0;
9966 var c = 0;
9967 var c1 = 0;
9968 var c2 = 0;
9969
9970 while (i < utftext.length) {
9971 c = utftext.charCodeAt(i);
9972
9973 if (c < 128) {
9974 string += String.fromCharCode(c);
9975 i++;
9976 }
9977 else if (c > 191 && c < 224) {
9978 c2 = utftext.charCodeAt(i + 1);
9979 string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
9980 i += 2;
9981 }
9982 else {
9983 c2 = utftext.charCodeAt(i+1);
9984 var c3 = utftext.charCodeAt(i+2);
9985 string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
9986 i += 3;
9987 }
9988 }
9989
9990 return string;
9991};
9992
9993/**
9994 * Return true if a1 and a2 are the same length with equal elements.
9995 */
9996DataUtils.arraysEqual = function(a1, a2)
9997{
9998 // A simple sanity check that it is an array.
9999 if (!a1.slice)
10000 throw new Error("DataUtils.arraysEqual: a1 is not an array");
10001 if (!a2.slice)
10002 throw new Error("DataUtils.arraysEqual: a2 is not an array");
10003
10004 if (a1.length != a2.length)
10005 return false;
10006
10007 for (var i = 0; i < a1.length; ++i) {
10008 if (a1[i] != a2[i])
10009 return false;
10010 }
10011
10012 return true;
10013};
10014
10015/**
10016 * Convert the big endian Buffer to an unsigned int.
10017 * Don't check for overflow.
10018 */
10019DataUtils.bigEndianToUnsignedInt = function(bytes)
10020{
10021 var result = 0;
10022 for (var i = 0; i < bytes.length; ++i) {
10023 // Multiply by 0x100 instead of shift by 8 because << is restricted to 32 bits.
10024 result *= 0x100;
10025 result += bytes[i];
10026 }
10027 return result;
10028};
10029
10030/**
10031 * Convert the int value to a new big endian Buffer and return.
10032 * If value is 0 or negative, return new Buffer(0).
10033 */
10034DataUtils.nonNegativeIntToBigEndian = function(value)
10035{
10036 value = Math.round(value);
10037 if (value <= 0)
10038 return new Buffer(0);
10039
10040 // Assume value is not over 64 bits.
10041 var size = 8;
10042 var result = new Buffer(size);
10043 var i = 0;
10044 while (value != 0) {
10045 ++i;
10046 result[size - i] = value & 0xff;
10047 // Divide by 0x100 and floor instead of shift by 8 because >> is restricted to 32 bits.
10048 value = Math.floor(value / 0x100);
10049 }
10050 return result.slice(size - i, size);
10051};
10052
10053/**
10054 * Modify array to randomly shuffle the elements.
10055 */
10056DataUtils.shuffle = function(array)
10057{
10058 for (var i = array.length - 1; i >= 1; --i) {
10059 // j is from 0 to i.
10060 var j = Math.floor(Math.random() * (i + 1));
10061 var temp = array[i];
10062 array[i] = array[j];
10063 array[j] = temp;
10064 }
10065};
10066
10067/**
10068 * Decode the base64-encoded private key PEM and return the binary DER.
10069 * @param {string} The PEM-encoded private key.
10070 * @return {Buffer} The binary DER.
10071 *
10072 */
10073DataUtils.privateKeyPemToDer = function(privateKeyPem)
10074{
10075 // Remove the '-----XXX-----' from the beginning and the end of the key and
10076 // also remove any \n in the key string.
10077 var lines = privateKeyPem.split('\n');
10078 var privateKey = "";
10079 for (var i = 1; i < lines.length - 1; i++)
10080 privateKey += lines[i];
10081
10082 return new Buffer(privateKey, 'base64');
10083};
10084/**
10085 * Copyright (C) 2014-2016 Regents of the University of California.
10086 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
10087 *
10088 * This program is free software: you can redistribute it and/or modify
10089 * it under the terms of the GNU Lesser General Public License as published by
10090 * the Free Software Foundation, either version 3 of the License, or
10091 * (at your option) any later version.
10092 *
10093 * This program is distributed in the hope that it will be useful,
10094 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10095 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10096 * GNU Lesser General Public License for more details.
10097 *
10098 * You should have received a copy of the GNU Lesser General Public License
10099 * along with this program. If not, see <http://www.gnu.org/licenses/>.
10100 * A copy of the GNU Lesser General Public License is in the file COPYING.
10101 */
10102
10103/**
10104 * Create a new DecodingException wrapping the given error object.
10105 * Call with: throw new DecodingException(new Error("message")).
10106 * @constructor
10107 * @param {Error} error The exception created with new Error.
10108 */
10109function DecodingException(error)
10110{
10111 if (error) {
10112 error.__proto__ = DecodingException.prototype;
10113 return error;
10114 }
10115}
10116DecodingException.prototype = new Error();
10117DecodingException.prototype.name = "DecodingException";
10118
10119exports.DecodingException = DecodingException;
10120/**
10121 * Copyright (C) 2014-2016 Regents of the University of California.
10122 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
10123 *
10124 * This program is free software: you can redistribute it and/or modify
10125 * it under the terms of the GNU Lesser General Public License as published by
10126 * the Free Software Foundation, either version 3 of the License, or
10127 * (at your option) any later version.
10128 *
10129 * This program is distributed in the hope that it will be useful,
10130 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10131 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10132 * GNU Lesser General Public License for more details.
10133 *
10134 * You should have received a copy of the GNU Lesser General Public License
10135 * along with this program. If not, see <http://www.gnu.org/licenses/>.
10136 * A copy of the GNU Lesser General Public License is in the file COPYING.
10137 */
10138
10139/**
10140 * The Tlv class has static type codes for the NDN-TLV wire format.
10141 * @constructor
10142 */
10143var Tlv = function Tlv()
10144{
10145};
10146
10147exports.Tlv = Tlv;
10148
10149Tlv.Interest = 5;
10150Tlv.Data = 6;
10151Tlv.Name = 7;
10152Tlv.ImplicitSha256DigestComponent = 1;
10153Tlv.NameComponent = 8;
10154Tlv.Selectors = 9;
10155Tlv.Nonce = 10;
10156// <Unassigned> = 11;
10157Tlv.InterestLifetime = 12;
10158Tlv.MinSuffixComponents = 13;
10159Tlv.MaxSuffixComponents = 14;
10160Tlv.PublisherPublicKeyLocator = 15;
10161Tlv.Exclude = 16;
10162Tlv.ChildSelector = 17;
10163Tlv.MustBeFresh = 18;
10164Tlv.Any = 19;
10165Tlv.MetaInfo = 20;
10166Tlv.Content = 21;
10167Tlv.SignatureInfo = 22;
10168Tlv.SignatureValue = 23;
10169Tlv.ContentType = 24;
10170Tlv.FreshnessPeriod = 25;
10171Tlv.FinalBlockId = 26;
10172Tlv.SignatureType = 27;
10173Tlv.KeyLocator = 28;
10174Tlv.KeyLocatorDigest = 29;
10175Tlv.SelectedDelegation = 32;
10176Tlv.FaceInstance = 128;
10177Tlv.ForwardingEntry = 129;
10178Tlv.StatusResponse = 130;
10179Tlv.Action = 131;
10180Tlv.FaceID = 132;
10181Tlv.IPProto = 133;
10182Tlv.Host = 134;
10183Tlv.Port = 135;
10184Tlv.MulticastInterface = 136;
10185Tlv.MulticastTTL = 137;
10186Tlv.ForwardingFlags = 138;
10187Tlv.StatusCode = 139;
10188Tlv.StatusText = 140;
10189
10190Tlv.SignatureType_DigestSha256 = 0;
10191Tlv.SignatureType_SignatureSha256WithRsa = 1;
10192Tlv.SignatureType_SignatureSha256WithEcdsa = 3;
10193Tlv.SignatureType_SignatureHmacWithSha256 = 4;
10194
10195Tlv.ContentType_Default = 0;
10196Tlv.ContentType_Link = 1;
10197Tlv.ContentType_Key = 2;
10198
10199Tlv.NfdCommand_ControlResponse = 101;
10200Tlv.NfdCommand_StatusCode = 102;
10201Tlv.NfdCommand_StatusText = 103;
10202
10203Tlv.ControlParameters_ControlParameters = 104;
10204Tlv.ControlParameters_FaceId = 105;
10205Tlv.ControlParameters_Uri = 114;
10206Tlv.ControlParameters_LocalControlFeature = 110;
10207Tlv.ControlParameters_Origin = 111;
10208Tlv.ControlParameters_Cost = 106;
10209Tlv.ControlParameters_Flags = 108;
10210Tlv.ControlParameters_Strategy = 107;
10211Tlv.ControlParameters_ExpirationPeriod = 109;
10212
10213Tlv.LpPacket_LpPacket = 100;
10214Tlv.LpPacket_Fragment = 80;
10215Tlv.LpPacket_Sequence = 81;
10216Tlv.LpPacket_FragIndex = 82;
10217Tlv.LpPacket_FragCount = 83;
10218Tlv.LpPacket_Nack = 800;
10219Tlv.LpPacket_NackReason = 801;
10220Tlv.LpPacket_NextHopFaceId = 816;
10221Tlv.LpPacket_IncomingFaceId = 817;
10222Tlv.LpPacket_CachePolicy = 820;
10223Tlv.LpPacket_CachePolicyType = 821;
10224Tlv.LpPacket_IGNORE_MIN = 800;
10225Tlv.LpPacket_IGNORE_MAX = 959;
10226
10227Tlv.Link_Preference = 30;
10228Tlv.Link_Delegation = 31;
10229
10230Tlv.Encrypt_EncryptedContent = 130;
10231Tlv.Encrypt_EncryptionAlgorithm = 131;
10232Tlv.Encrypt_EncryptedPayload = 132;
10233Tlv.Encrypt_InitialVector = 133;
10234
10235// For RepetitiveInterval.
10236Tlv.Encrypt_StartDate = 134;
10237Tlv.Encrypt_EndDate = 135;
10238Tlv.Encrypt_IntervalStartHour = 136;
10239Tlv.Encrypt_IntervalEndHour = 137;
10240Tlv.Encrypt_NRepeats = 138;
10241Tlv.Encrypt_RepeatUnit = 139;
10242Tlv.Encrypt_RepetitiveInterval = 140;
10243
10244// For Schedule.
10245Tlv.Encrypt_WhiteIntervalList = 141;
10246Tlv.Encrypt_BlackIntervalList = 142;
10247Tlv.Encrypt_Schedule = 143;
10248
10249/**
10250 * Strip off the lower 32 bits of x and divide by 2^32, returning the "high
10251 * bytes" above 32 bits. This is necessary because JavaScript << and >> are
10252 * restricted to 32 bits.
10253 * (This could be a general function, but we define it here so that the
10254 * Tlv encoder/decoder is self-contained.)
10255 * @param {number} x
10256 * @return {number}
10257 */
10258Tlv.getHighBytes = function(x)
10259{
10260 // Don't use floor because we expect the caller to use & and >> on the result
10261 // which already strip off the fraction.
10262 return (x - (x % 0x100000000)) / 0x100000000;
10263};
10264/**
10265 * Copyright (C) 2014-2016 Regents of the University of California.
10266 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
10267 *
10268 * This program is free software: you can redistribute it and/or modify
10269 * it under the terms of the GNU Lesser General Public License as published by
10270 * the Free Software Foundation, either version 3 of the License, or
10271 * (at your option) any later version.
10272 *
10273 * This program is distributed in the hope that it will be useful,
10274 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10275 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10276 * GNU Lesser General Public License for more details.
10277 *
10278 * You should have received a copy of the GNU Lesser General Public License
10279 * along with this program. If not, see <http://www.gnu.org/licenses/>.
10280 * A copy of the GNU Lesser General Public License is in the file COPYING.
10281 */
10282
10283/** @ignore */
10284var DynamicBuffer = require('../../util/dynamic-buffer.js').DynamicBuffer; /** @ignore */
10285var Tlv = require('./tlv.js').Tlv;
10286
10287/**
10288 * Create a new TlvEncoder with an initialCapacity for the encoding buffer.
10289 * @constructor
10290 * @param {number} initialCapacity (optional) The initial capacity of the
10291 * encoding buffer. If omitted, use a default value.
10292 */
10293var TlvEncoder = function TlvEncoder(initialCapacity)
10294{
10295 initialCapacity = initialCapacity || 16;
10296 this.output = new DynamicBuffer(initialCapacity);
10297 // length is the number of bytes that have been written to the back of
10298 // this.output.array.
10299 this.length = 0;
10300};
10301
10302exports.TlvEncoder = TlvEncoder;
10303
10304/**
10305 * Get the number of bytes that have been written to the output. You can
10306 * save this number, write sub TLVs, then subtract the new length from this
10307 * to get the total length of the sub TLVs.
10308 * @return {number} The number of bytes that have been written to the output.
10309 */
10310TlvEncoder.prototype.getLength = function()
10311{
10312 return this.length;
10313};
10314
10315/**
10316 * Encode varNumber as a VAR-NUMBER in NDN-TLV and write it to this.output just
10317 * before this.length from the back. Advance this.length.
10318 * @param {number} varNumber The non-negative number to encode.
10319 */
10320TlvEncoder.prototype.writeVarNumber = function(varNumber)
10321{
10322 if (varNumber < 253) {
10323 this.length += 1;
10324 this.output.ensureLengthFromBack(this.length);
10325 this.output.array[this.output.array.length - this.length] = varNumber & 0xff;
10326 }
10327 else if (varNumber <= 0xffff) {
10328 this.length += 3;
10329 this.output.ensureLengthFromBack(this.length);
10330 var offset = this.output.array.length - this.length;
10331 this.output.array[offset] = 253;
10332 this.output.array[offset + 1] = (varNumber >> 8) & 0xff;
10333 this.output.array[offset + 2] = varNumber & 0xff;
10334 }
10335 else if (varNumber <= 0xffffffff) {
10336 this.length += 5;
10337 this.output.ensureLengthFromBack(this.length);
10338 var offset = this.output.array.length - this.length;
10339 this.output.array[offset] = 254;
10340 this.output.array[offset + 1] = (varNumber >> 24) & 0xff;
10341 this.output.array[offset + 2] = (varNumber >> 16) & 0xff;
10342 this.output.array[offset + 3] = (varNumber >> 8) & 0xff;
10343 this.output.array[offset + 4] = varNumber & 0xff;
10344 }
10345 else {
10346 this.length += 9;
10347 this.output.ensureLengthFromBack(this.length);
10348 var offset = this.output.array.length - this.length;
10349 this.output.array[offset] = 255;
10350 var highBytes = Tlv.getHighBytes(varNumber);
10351 this.output.array[offset + 1] = (highBytes >> 24) & 0xff;
10352 this.output.array[offset + 2] = (highBytes >> 16) & 0xff;
10353 this.output.array[offset + 3] = (highBytes >> 8) & 0xff;
10354 this.output.array[offset + 4] = (highBytes) & 0xff;
10355 this.output.array[offset + 5] = (varNumber >> 24) & 0xff;
10356 this.output.array[offset + 6] = (varNumber >> 16) & 0xff;
10357 this.output.array[offset + 7] = (varNumber >> 8) & 0xff;
10358 this.output.array[offset + 8] = varNumber & 0xff;
10359 }
10360};
10361
10362/**
10363 * Encode the type and length as VAR-NUMBER and write to this.output just before
10364 * this.length from the back. Advance this.length.
10365 * @param {number} type The type of the TLV.
10366 * @param {number} length The non-negative length of the TLV.
10367 */
10368TlvEncoder.prototype.writeTypeAndLength = function(type, length)
10369{
10370 // Write backwards.
10371 this.writeVarNumber(length);
10372 this.writeVarNumber(type);
10373};
10374
10375/**
10376 * Write value as a non-negative integer and write it to this.output just before
10377 * this.length from the back. Advance this.length.
10378 * @param {number} value The non-negative integer to encode.
10379 */
10380TlvEncoder.prototype.writeNonNegativeInteger = function(value)
10381{
10382 if (value < 0)
10383 throw new Error("TLV integer value may not be negative");
10384
10385 // JavaScript doesn't distinguish int from float, so round.
10386 value = Math.round(value);
10387
10388 if (value <= 0xff) {
10389 this.length += 1;
10390 this.output.ensureLengthFromBack(this.length);
10391 this.output.array[this.output.array.length - this.length] = value & 0xff;
10392 }
10393 else if (value <= 0xffff) {
10394 this.length += 2;
10395 this.output.ensureLengthFromBack(this.length);
10396 var offset = this.output.array.length - this.length;
10397 this.output.array[offset] = (value >> 8) & 0xff;
10398 this.output.array[offset + 1] = value & 0xff;
10399 }
10400 else if (value <= 0xffffffff) {
10401 this.length += 4;
10402 this.output.ensureLengthFromBack(this.length);
10403 var offset = this.output.array.length - this.length;
10404 this.output.array[offset] = (value >> 24) & 0xff;
10405 this.output.array[offset + 1] = (value >> 16) & 0xff;
10406 this.output.array[offset + 2] = (value >> 8) & 0xff;
10407 this.output.array[offset + 3] = value & 0xff;
10408 }
10409 else {
10410 this.length += 8;
10411 this.output.ensureLengthFromBack(this.length);
10412 var offset = this.output.array.length - this.length;
10413 var highBytes = Tlv.getHighBytes(value);
10414 this.output.array[offset] = (highBytes >> 24) & 0xff;
10415 this.output.array[offset + 1] = (highBytes >> 16) & 0xff;
10416 this.output.array[offset + 2] = (highBytes >> 8) & 0xff;
10417 this.output.array[offset + 3] = (highBytes) & 0xff;
10418 this.output.array[offset + 4] = (value >> 24) & 0xff;
10419 this.output.array[offset + 5] = (value >> 16) & 0xff;
10420 this.output.array[offset + 6] = (value >> 8) & 0xff;
10421 this.output.array[offset + 7] = value & 0xff;
10422 }
10423};
10424
10425/**
10426 * Write the type, then the length of the encoded value then encode value as a
10427 * non-negative integer and write it to this.output just before this.length from
10428 * the back. Advance this.length.
10429 * @param {number} type The type of the TLV.
10430 * @param {number} value The non-negative integer to encode.
10431 */
10432TlvEncoder.prototype.writeNonNegativeIntegerTlv = function(type, value)
10433{
10434 // Write backwards.
10435 var saveNBytes = this.length;
10436 this.writeNonNegativeInteger(value);
10437 this.writeTypeAndLength(type, this.length - saveNBytes);
10438};
10439
10440/**
10441 * If value is negative or null then do nothing, otherwise call
10442 * writeNonNegativeIntegerTlv.
10443 * @param {number} type The type of the TLV.
10444 * @param {number} value If negative or null do nothing, otherwise the integer
10445 * to encode.
10446 */
10447TlvEncoder.prototype.writeOptionalNonNegativeIntegerTlv = function(type, value)
10448{
10449 if (value != null && value >= 0)
10450 this.writeNonNegativeIntegerTlv(type, value);
10451};
10452
10453/**
10454 * Write the buffer value to this.output just before this.length from the back.
10455 * Advance this.length.
10456 * @param {Buffer} buffer The byte array with the bytes to write. If value is
10457 * null, then do nothing.
10458 */
10459TlvEncoder.prototype.writeBuffer = function(buffer)
10460{
10461 if (buffer == null)
10462 return;
10463
10464 this.length += buffer.length;
10465 this.output.copyFromBack(buffer, this.length);
10466};
10467
10468/**
10469 * Write the type, then the length of the buffer then the buffer value to
10470 * this.output just before this.length from the back. Advance this.length.
10471 * @param {number} type The type of the TLV.
10472 * @param {Buffer} value The byte array with the bytes of the blob. If value is
10473 null, then just write the type and length 0.
10474 */
10475TlvEncoder.prototype.writeBlobTlv = function(type, value)
10476{
10477 if (value == null) {
10478 this.writeTypeAndLength(type, 0);
10479 return;
10480 }
10481
10482 // Write backwards, starting with the blob array.
10483 this.writeBuffer(value);
10484 this.writeTypeAndLength(type, value.length);
10485};
10486
10487/**
10488 * If the byte array is null or zero length then do nothing, otherwise call
10489 * writeBlobTlv.
10490 * @param {number} type The type of the TLV.
10491 * @param {Buffer} value If null or zero length do nothing, otherwise the byte
10492 * array with the bytes of the blob.
10493 */
10494TlvEncoder.prototype.writeOptionalBlobTlv = function(type, value)
10495{
10496 if (value != null && value.length > 0)
10497 this.writeBlobTlv(type, value);
10498};
10499
10500/**
10501 * Get a slice of the encoded bytes.
10502 * @return {Buffer} A slice backed by the encoding Buffer.
10503 */
10504TlvEncoder.prototype.getOutput = function()
10505{
10506 return this.output.array.slice(this.output.array.length - this.length);
10507};
10508/**
10509 * Copyright (C) 2014-2016 Regents of the University of California.
10510 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
10511 *
10512 * This program is free software: you can redistribute it and/or modify
10513 * it under the terms of the GNU Lesser General Public License as published by
10514 * the Free Software Foundation, either version 3 of the License, or
10515 * (at your option) any later version.
10516 *
10517 * This program is distributed in the hope that it will be useful,
10518 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10519 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10520 * GNU Lesser General Public License for more details.
10521 *
10522 * You should have received a copy of the GNU Lesser General Public License
10523 * along with this program. If not, see <http://www.gnu.org/licenses/>.
10524 * A copy of the GNU Lesser General Public License is in the file COPYING.
10525 */
10526
10527/** @ignore */
10528var DecodingException = require('../decoding-exception.js').DecodingException;
10529
10530/**
10531 * Create a new TlvDecoder for decoding the input in the NDN-TLV wire format.
10532 * @constructor
10533 * @param {Buffer} input The buffer with the bytes to decode.
10534 */
10535var TlvDecoder = function TlvDecoder(input)
10536{
10537 this.input = input;
10538 this.offset = 0;
10539};
10540
10541exports.TlvDecoder = TlvDecoder;
10542
10543/**
10544 * Decode VAR-NUMBER in NDN-TLV and return it. Update offset.
10545 * @return {number} The decoded VAR-NUMBER.
10546 */
10547TlvDecoder.prototype.readVarNumber = function()
10548{
10549 // Assume array values are in the range 0 to 255.
10550 var firstOctet = this.input[this.offset];
10551 this.offset += 1;
10552 if (firstOctet < 253)
10553 return firstOctet;
10554 else
10555 return this.readExtendedVarNumber(firstOctet);
10556};
10557
10558/**
10559 * A private function to do the work of readVarNumber, given the firstOctet
10560 * which is >= 253.
10561 * @param {number} firstOctet The first octet which is >= 253, used to decode
10562 * the remaining bytes.
10563 * @return {number} The decoded VAR-NUMBER.
10564 */
10565TlvDecoder.prototype.readExtendedVarNumber = function(firstOctet)
10566{
10567 var result;
10568 // This is a private function so we know firstOctet >= 253.
10569 if (firstOctet == 253) {
10570 result = ((this.input[this.offset] << 8) +
10571 this.input[this.offset + 1]);
10572 this.offset += 2;
10573 }
10574 else if (firstOctet == 254) {
10575 // Use abs because << 24 can set the high bit of the 32-bit int making it negative.
10576 result = (Math.abs(this.input[this.offset] << 24) +
10577 (this.input[this.offset + 1] << 16) +
10578 (this.input[this.offset + 2] << 8) +
10579 this.input[this.offset + 3]);
10580 this.offset += 4;
10581 }
10582 else {
10583 // Get the high byte first because JavaScript << is restricted to 32 bits.
10584 // Use abs because << 24 can set the high bit of the 32-bit int making it negative.
10585 var highByte = Math.abs(this.input[this.offset] << 24) +
10586 (this.input[this.offset + 1] << 16) +
10587 (this.input[this.offset + 2] << 8) +
10588 this.input[this.offset + 3];
10589 result = (highByte * 0x100000000 +
10590 (this.input[this.offset + 4] << 24) +
10591 (this.input[this.offset + 5] << 16) +
10592 (this.input[this.offset + 6] << 8) +
10593 this.input[this.offset + 7]);
10594 this.offset += 8;
10595 }
10596
10597 return result;
10598};
10599
10600/**
10601 * Decode the type and length from this's input starting at offset, expecting
10602 * the type to be expectedType and return the length. Update offset. Also make
10603 * sure the decoded length does not exceed the number of bytes remaining in the
10604 * input.
10605 * @param {number} expectedType The expected type.
10606 * @return {number} The length of the TLV.
10607 * @throws DecodingException if (did not get the expected TLV type or the TLV length
10608 * exceeds the buffer length.
10609 */
10610TlvDecoder.prototype.readTypeAndLength = function(expectedType)
10611{
10612 var type = this.readVarNumber();
10613 if (type != expectedType)
10614 throw new DecodingException(new Error("Did not get the expected TLV type"));
10615
10616 var length = this.readVarNumber();
10617 if (this.offset + length > this.input.length)
10618 throw new DecodingException(new Error("TLV length exceeds the buffer length"));
10619
10620 return length;
10621};
10622
10623/**
10624 * Decode the type and length from the input starting at offset, expecting the
10625 * type to be expectedType. Update offset. Also make sure the decoded length
10626 * does not exceed the number of bytes remaining in the input. Return the offset
10627 * of the end of this parent TLV, which is used in decoding optional nested
10628 * TLVs. After reading all nested TLVs, call finishNestedTlvs.
10629 * @param {number} expectedType The expected type.
10630 * @return {number} The offset of the end of the parent TLV.
10631 * @throws DecodingException if did not get the expected TLV type or the TLV
10632 * length exceeds the buffer length.
10633 */
10634TlvDecoder.prototype.readNestedTlvsStart = function(expectedType)
10635{
10636 return this.readTypeAndLength(expectedType) + this.offset;
10637};
10638
10639/**
10640 * Call this after reading all nested TLVs to skip any remaining unrecognized
10641 * TLVs and to check if the offset after the final nested TLV matches the
10642 * endOffset returned by readNestedTlvsStart.
10643 * @param {number} endOffset The offset of the end of the parent TLV, returned
10644 * by readNestedTlvsStart.
10645 * @throws DecodingException if the TLV length does not equal the total length
10646 * of the nested TLVs.
10647 */
10648TlvDecoder.prototype.finishNestedTlvs = function(endOffset)
10649{
10650 // We expect offset to be endOffset, so check this first.
10651 if (this.offset == endOffset)
10652 return;
10653
10654 // Skip remaining TLVs.
10655 while (this.offset < endOffset) {
10656 // Skip the type VAR-NUMBER.
10657 this.readVarNumber();
10658 // Read the length and update offset.
10659 var length = this.readVarNumber();
10660 this.offset += length;
10661
10662 if (this.offset > this.input.length)
10663 throw new DecodingException(new Error("TLV length exceeds the buffer length"));
10664 }
10665
10666 if (this.offset != endOffset)
10667 throw new DecodingException(new Error
10668 ("TLV length does not equal the total length of the nested TLVs"));
10669};
10670
10671/**
10672 * Decode the type from this's input starting at offset, and if it is the
10673 * expectedType, then return true, else false. However, if this's offset is
10674 * greater than or equal to endOffset, then return false and don't try to read
10675 * the type. Do not update offset.
10676 * @param {number} expectedType The expected type.
10677 * @param {number} endOffset The offset of the end of the parent TLV, returned
10678 * by readNestedTlvsStart.
10679 * @return {boolean} true if the type of the next TLV is the expectedType,
10680 * otherwise false.
10681 */
10682TlvDecoder.prototype.peekType = function(expectedType, endOffset)
10683{
10684 if (this.offset >= endOffset)
10685 // No more sub TLVs to look at.
10686 return false;
10687 else {
10688 var saveOffset = this.offset;
10689 var type = this.readVarNumber();
10690 // Restore offset.
10691 this.offset = saveOffset;
10692
10693 return type == expectedType;
10694 }
10695};
10696
10697/**
10698 * Decode a non-negative integer in NDN-TLV and return it. Update offset by
10699 * length.
10700 * @param {number} length The number of bytes in the encoded integer.
10701 * @return {number} The integer.
10702 * @throws DecodingException if length is an invalid length for a TLV
10703 * non-negative integer.
10704 */
10705TlvDecoder.prototype.readNonNegativeInteger = function(length)
10706{
10707 var result;
10708 if (length == 1)
10709 result = this.input[this.offset];
10710 else if (length == 2)
10711 result = ((this.input[this.offset] << 8) +
10712 this.input[this.offset + 1]);
10713 else if (length == 4)
10714 // Use abs because << 24 can set the high bit of the 32-bit int making it negative.
10715 result = (Math.abs(this.input[this.offset] << 24) +
10716 (this.input[this.offset + 1] << 16) +
10717 (this.input[this.offset + 2] << 8) +
10718 this.input[this.offset + 3]);
10719 else if (length == 8) {
10720 // Use abs because << 24 can set the high bit of the 32-bit int making it negative.
10721 var highByte = Math.abs(this.input[this.offset] << 24) +
10722 (this.input[this.offset + 1] << 16) +
10723 (this.input[this.offset + 2] << 8) +
10724 this.input[this.offset + 3];
10725 result = (highByte * 0x100000000 +
10726 Math.abs(this.input[this.offset + 4] << 24) +
10727 (this.input[this.offset + 5] << 16) +
10728 (this.input[this.offset + 6] << 8) +
10729 this.input[this.offset + 7]);
10730 }
10731 else
10732 throw new DecodingException(new Error("Invalid length for a TLV nonNegativeInteger"));
10733
10734 this.offset += length;
10735 return result;
10736};
10737
10738/**
10739 * Decode the type and length from this's input starting at offset, expecting
10740 * the type to be expectedType. Then decode a non-negative integer in NDN-TLV
10741 * and return it. Update offset.
10742 * @param {number} expectedType The expected type.
10743 * @return {number} The integer.
10744 * @throws DecodingException if did not get the expected TLV type or can't
10745 * decode the value.
10746 */
10747TlvDecoder.prototype.readNonNegativeIntegerTlv = function(expectedType)
10748{
10749 var length = this.readTypeAndLength(expectedType);
10750 return this.readNonNegativeInteger(length);
10751};
10752
10753/**
10754 * Peek at the next TLV, and if it has the expectedType then call
10755 * readNonNegativeIntegerTlv and return the integer. Otherwise, return null.
10756 * However, if this's offset is greater than or equal to endOffset, then return
10757 * null and don't try to read the type.
10758 * @param {number} expectedType The expected type.
10759 * @param {number} endOffset The offset of the end of the parent TLV, returned
10760 * by readNestedTlvsStart.
10761 * @return {number} The integer or null if the next TLV doesn't have the
10762 * expected type.
10763 */
10764TlvDecoder.prototype.readOptionalNonNegativeIntegerTlv = function
10765 (expectedType, endOffset)
10766{
10767 if (this.peekType(expectedType, endOffset))
10768 return this.readNonNegativeIntegerTlv(expectedType);
10769 else
10770 return null;
10771};
10772
10773/**
10774 * Decode the type and length from this's input starting at offset, expecting
10775 * the type to be expectedType. Then return an array of the bytes in the value.
10776 * Update offset.
10777 * @param {number} expectedType The expected type.
10778 * @return {Buffer} The bytes in the value as a slice on the buffer. This is
10779 * not a copy of the bytes in the input buffer. If you need a copy, then you
10780 * must make a copy of the return value.
10781 * @throws DecodingException if did not get the expected TLV type.
10782 */
10783TlvDecoder.prototype.readBlobTlv = function(expectedType)
10784{
10785 var length = this.readTypeAndLength(expectedType);
10786 var result = this.input.slice(this.offset, this.offset + length);
10787
10788 // readTypeAndLength already checked if length exceeds the input buffer.
10789 this.offset += length;
10790 return result;
10791};
10792
10793/**
10794 * Peek at the next TLV, and if it has the expectedType then call readBlobTlv
10795 * and return the value. Otherwise, return null. However, if this's offset is
10796 * greater than or equal to endOffset, then return null and don't try to read
10797 * the type.
10798 * @param {number} expectedType The expected type.
10799 * @param {number} endOffset The offset of the end of the parent TLV, returned
10800 * by readNestedTlvsStart.
10801 * @return {Buffer} The bytes in the value as a slice on the buffer or null if
10802 * the next TLV doesn't have the expected type. This is not a copy of the bytes
10803 * in the input buffer. If you need a copy, then you must make a copy of the
10804 * return value.
10805 */
10806TlvDecoder.prototype.readOptionalBlobTlv = function(expectedType, endOffset)
10807{
10808 if (this.peekType(expectedType, endOffset))
10809 return this.readBlobTlv(expectedType);
10810 else
10811 return null;
10812};
10813
10814/**
10815 * Peek at the next TLV, and if it has the expectedType then read a type and
10816 * value, ignoring the value, and return true. Otherwise, return false.
10817 * However, if this's offset is greater than or equal to endOffset, then return
10818 * false and don't try to read the type.
10819 * @param {number} expectedType The expected type.
10820 * @param {number} endOffset The offset of the end of the parent TLV, returned
10821 * by readNestedTlvsStart.
10822 * @return {boolean} true, or else false if the next TLV doesn't have the
10823 * expected type.
10824 */
10825TlvDecoder.prototype.readBooleanTlv = function(expectedType, endOffset)
10826{
10827 if (this.peekType(expectedType, endOffset)) {
10828 var length = this.readTypeAndLength(expectedType);
10829 // We expect the length to be 0, but update offset anyway.
10830 this.offset += length;
10831 return true;
10832 }
10833 else
10834 return false;
10835};
10836
10837/**
10838 * Get the offset into the input, used for the next read.
10839 * @return {number} The offset.
10840 */
10841TlvDecoder.prototype.getOffset = function()
10842{
10843 return this.offset;
10844};
10845
10846/**
10847 * Set the offset into the input, used for the next read.
10848 * @param {number} offset The new offset.
10849 */
10850TlvDecoder.prototype.seek = function(offset)
10851{
10852 this.offset = offset;
10853};
10854
10855/**
10856 * Return an array of a slice of the input for the given offset range.
10857 * @param {number} beginOffset The offset in the input of the beginning of the
10858 * slice.
10859 * @param {number} endOffset The offset in the input of the end of the slice.
10860 * @return {Buffer} The bytes in the value as a slice on the buffer. This is
10861 * not a copy of the bytes in the input buffer. If you need a copy, then you
10862 * must make a copy of the return value.
10863 */
10864TlvDecoder.prototype.getSlice = function(beginOffset, endOffset)
10865{
10866 return this.input.slice(beginOffset, endOffset);
10867};
10868/**
10869 * Copyright (C) 2014-2016 Regents of the University of California.
10870 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
10871 *
10872 * This program is free software: you can redistribute it and/or modify
10873 * it under the terms of the GNU Lesser General Public License as published by
10874 * the Free Software Foundation, either version 3 of the License, or
10875 * (at your option) any later version.
10876 *
10877 * This program is distributed in the hope that it will be useful,
10878 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10879 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10880 * GNU Lesser General Public License for more details.
10881 *
10882 * You should have received a copy of the GNU Lesser General Public License
10883 * along with this program. If not, see <http://www.gnu.org/licenses/>.
10884 * A copy of the GNU Lesser General Public License is in the file COPYING.
10885 */
10886
10887/** @ignore */
10888var TlvDecoder = require('./tlv-decoder.js').TlvDecoder;
10889
10890/**
10891 * A TlvStructureDecoder finds the end of an NDN-TLV element, even if the
10892 * element is supplied in parts.
10893 * Create and initialize a TlvStructureDecoder.
10894 * @constructor
10895 */
10896var TlvStructureDecoder = function TlvStructureDecoder()
10897{
10898 this.gotElementEnd_ = false;
10899 this.offset_ = 0;
10900 this.state_ = TlvStructureDecoder.READ_TYPE;
10901 this.headerLength_ = 0;
10902 this.useHeaderBuffer_ = false;
10903 // 8 bytes is enough to hold the extended bytes in the length encoding
10904 // where it is an 8-byte number.
10905 this.headerBuffer_ = new Buffer(8);
10906 this.nBytesToRead_ = 0;
10907};
10908
10909exports.TlvStructureDecoder = TlvStructureDecoder;
10910
10911TlvStructureDecoder.READ_TYPE = 0;
10912TlvStructureDecoder.READ_TYPE_BYTES = 1;
10913TlvStructureDecoder.READ_LENGTH = 2;
10914TlvStructureDecoder.READ_LENGTH_BYTES = 3;
10915TlvStructureDecoder.READ_VALUE_BYTES = 4;
10916
10917/**
10918 * Continue scanning input starting from this.offset_ to find the element end.
10919 * If the end of the element which started at offset 0 is found, this returns
10920 * true and getOffset() is the length of the element. Otherwise, this returns
10921 * false which means you should read more into input and call again.
10922 * @param {Buffer} input The input buffer. You have to pass in input each time
10923 * because the buffer could be reallocated.
10924 * @return {boolean} true if found the element end, false if not.
10925 */
10926TlvStructureDecoder.prototype.findElementEnd = function(input)
10927{
10928 if (this.gotElementEnd_)
10929 // Someone is calling when we already got the end.
10930 return true;
10931
10932 var decoder = new TlvDecoder(input);
10933
10934 while (true) {
10935 if (this.offset_ >= input.length)
10936 // All the cases assume we have some input. Return and wait for more.
10937 return false;
10938
10939 if (this.state_ == TlvStructureDecoder.READ_TYPE) {
10940 var firstOctet = input[this.offset_];
10941 this.offset_ += 1;
10942 if (firstOctet < 253)
10943 // The value is simple, so we can skip straight to reading the length.
10944 this.state_ = TlvStructureDecoder.READ_LENGTH;
10945 else {
10946 // Set up to skip the type bytes.
10947 if (firstOctet == 253)
10948 this.nBytesToRead_ = 2;
10949 else if (firstOctet == 254)
10950 this.nBytesToRead_ = 4;
10951 else
10952 // value == 255.
10953 this.nBytesToRead_ = 8;
10954
10955 this.state_ = TlvStructureDecoder.READ_TYPE_BYTES;
10956 }
10957 }
10958 else if (this.state_ == TlvStructureDecoder.READ_TYPE_BYTES) {
10959 var nRemainingBytes = input.length - this.offset_;
10960 if (nRemainingBytes < this.nBytesToRead_) {
10961 // Need more.
10962 this.offset_ += nRemainingBytes;
10963 this.nBytesToRead_ -= nRemainingBytes;
10964 return false;
10965 }
10966
10967 // Got the type bytes. Move on to read the length.
10968 this.offset_ += this.nBytesToRead_;
10969 this.state_ = TlvStructureDecoder.READ_LENGTH;
10970 }
10971 else if (this.state_ == TlvStructureDecoder.READ_LENGTH) {
10972 var firstOctet = input[this.offset_];
10973 this.offset_ += 1;
10974 if (firstOctet < 253) {
10975 // The value is simple, so we can skip straight to reading
10976 // the value bytes.
10977 this.nBytesToRead_ = firstOctet;
10978 if (this.nBytesToRead_ == 0) {
10979 // No value bytes to read. We're finished.
10980 this.gotElementEnd_ = true;
10981 return true;
10982 }
10983
10984 this.state_ = TlvStructureDecoder.READ_VALUE_BYTES;
10985 }
10986 else {
10987 // We need to read the bytes in the extended encoding of
10988 // the length.
10989 if (firstOctet == 253)
10990 this.nBytesToRead_ = 2;
10991 else if (firstOctet == 254)
10992 this.nBytesToRead_ = 4;
10993 else
10994 // value == 255.
10995 this.nBytesToRead_ = 8;
10996
10997 // We need to use firstOctet in the next state.
10998 this.firstOctet_ = firstOctet;
10999 this.state_ = TlvStructureDecoder.READ_LENGTH_BYTES;
11000 }
11001 }
11002 else if (this.state_ == TlvStructureDecoder.READ_LENGTH_BYTES) {
11003 var nRemainingBytes = input.length - this.offset_;
11004 if (!this.useHeaderBuffer_ && nRemainingBytes >= this.nBytesToRead_) {
11005 // We don't have to use the headerBuffer. Set nBytesToRead.
11006 decoder.seek(this.offset_);
11007
11008 this.nBytesToRead_ = decoder.readExtendedVarNumber(this.firstOctet_);
11009 // Update this.offset_ to the decoder's offset after reading.
11010 this.offset_ = decoder.getOffset();
11011 }
11012 else {
11013 this.useHeaderBuffer_ = true;
11014
11015 var nNeededBytes = this.nBytesToRead_ - this.headerLength_;
11016 if (nNeededBytes > nRemainingBytes) {
11017 // We can't get all of the header bytes from this input.
11018 // Save in headerBuffer.
11019 if (this.headerLength_ + nRemainingBytes > this.headerBuffer_.length)
11020 // We don't expect this to happen.
11021 throw new Error
11022 ("Cannot store more header bytes than the size of headerBuffer");
11023 input.slice(this.offset_, this.offset_ + nRemainingBytes).copy
11024 (this.headerBuffer_, this.headerLength_);
11025 this.offset_ += nRemainingBytes;
11026 this.headerLength_ += nRemainingBytes;
11027
11028 return false;
11029 }
11030
11031 // Copy the remaining bytes into headerBuffer, read the
11032 // length and set nBytesToRead.
11033 if (this.headerLength_ + nNeededBytes > this.headerBuffer_.length)
11034 // We don't expect this to happen.
11035 throw new Error
11036 ("Cannot store more header bytes than the size of headerBuffer");
11037 input.slice(this.offset_, this.offset_ + nNeededBytes).copy
11038 (this.headerBuffer_, this.headerLength_);
11039 this.offset_ += nNeededBytes;
11040
11041 // Use a local decoder just for the headerBuffer.
11042 var bufferDecoder = new TlvDecoder(this.headerBuffer_);
11043 // Replace nBytesToRead with the length of the value.
11044 this.nBytesToRead_ = bufferDecoder.readExtendedVarNumber(this.firstOctet_);
11045 }
11046
11047 if (this.nBytesToRead_ == 0) {
11048 // No value bytes to read. We're finished.
11049 this.gotElementEnd_ = true;
11050 return true;
11051 }
11052
11053 // Get ready to read the value bytes.
11054 this.state_ = TlvStructureDecoder.READ_VALUE_BYTES;
11055 }
11056 else if (this.state_ == TlvStructureDecoder.READ_VALUE_BYTES) {
11057 var nRemainingBytes = input.length - this.offset_;
11058 if (nRemainingBytes < this.nBytesToRead_) {
11059 // Need more.
11060 this.offset_ += nRemainingBytes;
11061 this.nBytesToRead_ -= nRemainingBytes;
11062 return false;
11063 }
11064
11065 // Got the bytes. We're finished.
11066 this.offset_ += this.nBytesToRead_;
11067 this.gotElementEnd_ = true;
11068 return true;
11069 }
11070 else
11071 // We don't expect this to happen.
11072 throw new Error("findElementEnd: unrecognized state");
11073 }
11074};
11075
11076/**
11077 * Get the current offset into the input buffer.
11078 * @return {number} The offset.
11079 */
11080TlvStructureDecoder.prototype.getOffset = function()
11081{
11082 return this.offset_;
11083};
11084
11085/**
11086 * Set the offset into the input, used for the next read.
11087 * @param {number} offset The new offset.
11088 */
11089TlvStructureDecoder.prototype.seek = function(offset)
11090{
11091 this.offset_ = offset;
11092};
11093/**
11094 * Copyright (C) 2014-2016 Regents of the University of California.
11095 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
11096 *
11097 * This program is free software: you can redistribute it and/or modify
11098 * it under the terms of the GNU Lesser General Public License as published by
11099 * the Free Software Foundation, either version 3 of the License, or
11100 * (at your option) any later version.
11101 *
11102 * This program is distributed in the hope that it will be useful,
11103 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11104 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11105 * GNU Lesser General Public License for more details.
11106 *
11107 * You should have received a copy of the GNU Lesser General Public License
11108 * along with this program. If not, see <http://www.gnu.org/licenses/>.
11109 * A copy of the GNU Lesser General Public License is in the file COPYING.
11110 */
11111
11112/** @ignore */
11113var TlvEncoder = require('./tlv/tlv-encoder.js').TlvEncoder; /** @ignore */
11114var TlvDecoder = require('./tlv/tlv-decoder.js').TlvDecoder; /** @ignore */
11115var Blob = require('../util/blob.js').Blob; /** @ignore */
11116var Name = require('../name.js').Name; /** @ignore */
11117
11118/**
11119 * ProtobufTlv has static methods to encode and decode an Protobuf Message
11120 * object as NDN-TLV. The Protobuf tag value is used as the TLV type code. A
11121 * Protobuf message is encoded/decoded as a nested TLV encoding. Protobuf types
11122 * uint32, uint64 and enum are encoded/decoded as TLV nonNegativeInteger. (It is
11123 * an error if an enum value is negative.) Protobuf types bytes and string are
11124 * encoded/decoded as TLV bytes. The Protobuf type bool is encoded/decoded as a
11125 * TLV boolean (a zero length value for True, omitted for False). The Protobuf
11126 * type double is encoded/decoded as an 8-byte little-endian IEEE 754 double.
11127 * Other Protobuf types are an error.
11128 *
11129 * Protobuf has no "outer" message type, so you need to put your TLV message
11130 * inside an outer "typeless" message.
11131 * @constructor
11132 */
11133var ProtobufTlv = function ProtobufTlv()
11134{
11135};
11136
11137exports.ProtobufTlv = ProtobufTlv;
11138
11139// Load ProtoBuf.Reflect.Message.Field dynamically so that protobufjs is optional.
11140ProtobufTlv._Field = null;
11141ProtobufTlv.establishField = function()
11142{
11143 if (ProtobufTlv._Field === null) {
Alexander Afanasyev1663a412013-03-02 13:52:00 -080011144 try {
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080011145 // Using protobuf.min.js in the browser.
11146 ProtobufTlv._Field = dcodeIO.ProtoBuf.Reflect.Message.Field;
11147 }
11148 catch (ex) {
11149 // Using protobufjs in node.
11150 ProtobufTlv._Field = require("protobufjs").Reflect.Message.Field;
11151 }
11152 }
11153}
11154
11155/**
11156 * Encode the Protobuf message object as NDN-TLV. This calls
11157 * message.encodeAB() to ensure that all required fields are present and
11158 * raises an exception if not. (This does not use the result of toArrayBuffer().)
11159 * @param {ProtoBuf.Builder.Message} message The Protobuf message object.
11160 * @param {ProtoBuf.Reflect.T} descriptor The reflection descriptor for the
11161 * message. For example, if the message is of type "MyNamespace.MyMessage" then
11162 * the descriptor is builder.lookup("MyNamespace.MyMessage").
11163 * @return {Blob} The encoded buffer in a Blob object.
11164 */
11165ProtobufTlv.encode = function(message, descriptor)
11166{
11167 ProtobufTlv.establishField();
11168
11169 message.encodeAB();
11170 var encoder = new TlvEncoder();
11171 ProtobufTlv._encodeMessageValue(message, descriptor, encoder);
11172 return new Blob(encoder.getOutput(), false);
11173};
11174
11175/**
11176 * Decode the input as NDN-TLV and update the fields of the Protobuf message
11177 * object.
11178 * @param {ProtoBuf.Builder.Message} message The Protobuf message object. This
11179 * does not first clear the object.
11180 * @param {ProtoBuf.Reflect.T} descriptor The reflection descriptor for the
11181 * message. For example, if the message is of type "MyNamespace.MyMessage" then
11182 * the descriptor is builder.lookup("MyNamespace.MyMessage").
11183 * @param {Blob|Buffer} input The buffer with the bytes to decode.
11184 */
11185ProtobufTlv.decode = function(message, descriptor, input)
11186{
11187 ProtobufTlv.establishField();
11188
11189 // If input is a blob, get its buf().
11190 var decodeBuffer = typeof input === 'object' && input instanceof Blob ?
11191 input.buf() : input;
11192
11193 var decoder = new TlvDecoder(decodeBuffer);
11194 ProtobufTlv._decodeMessageValue
11195 (message, descriptor, decoder, decodeBuffer.length);
11196};
11197
11198ProtobufTlv._encodeMessageValue = function(message, descriptor, encoder)
11199{
11200 var fields = descriptor.getChildren(ProtobufTlv._Field);
11201 // Encode the fields backwards.
11202 for (var iField = fields.length - 1; iField >= 0; --iField) {
11203 var field = fields[iField];
11204 var tlvType = field.id;
11205
11206 var values;
11207 if (field.repeated)
11208 values = message[field.name];
11209 else {
11210 if (message[field.name] != null)
11211 // Make a singleton list.
11212 values = [message[field.name]];
11213 else
11214 continue;
11215 }
11216
11217 // Encode the values backwards.
11218 for (var iValue = values.length - 1; iValue >= 0; --iValue) {
11219 var value = values[iValue];
11220
11221 if (field.type.name == "message") {
11222 var saveLength = encoder.getLength();
11223
11224 // Encode backwards.
11225 ProtobufTlv._encodeMessageValue(value, field.resolvedType, encoder);
11226 encoder.writeTypeAndLength(tlvType, encoder.getLength() - saveLength);
11227 }
11228 else if (field.type.name == "uint32" ||
11229 field.type.name == "uint64")
11230 encoder.writeNonNegativeIntegerTlv(tlvType, value);
11231 else if (field.type.name == "enum") {
11232 if (value < 0)
11233 throw new Error("ProtobufTlv::encode: ENUM value may not be negative");
11234 encoder.writeNonNegativeIntegerTlv(tlvType, value);
11235 }
11236 else if (field.type.name == "bytes") {
11237 var buffer = value.toBuffer();
11238 if (buffer.length == undefined)
11239 // We are not running in Node.js, so assume we are using the dcodeIO
11240 // browser implementation based on ArrayBuffer.
11241 buffer = new Uint8Array(value.toArrayBuffer());
11242 encoder.writeBlobTlv(tlvType, buffer);
11243 }
11244 else if (field.type.name == "string")
11245 // Use Blob to convert.
11246 encoder.writeBlobTlv(tlvType, new Blob(value, false).buf());
11247 else if (field.type.name == "bool") {
11248 if (value)
11249 encoder.writeTypeAndLength(tlvType, 0);
11250 }
11251 else if (field.type.name == "double") {
11252 var encoding = new Buffer(8);
11253 encoding.writeDoubleLE(value, 0);
11254 encoder.writeBlobTlv(tlvType, encoding);
11255 }
11256 else
11257 throw new Error("ProtobufTlv::encode: Unknown field type");
11258 }
11259 }
11260};
11261
11262ProtobufTlv._decodeMessageValue = function(message, descriptor, decoder, endOffset)
11263{
11264 var fields = descriptor.getChildren(ProtobufTlv._Field);
11265 for (var iField = 0; iField < fields.length; ++iField) {
11266 var field = fields[iField];
11267 var tlvType = field.id;
11268
11269 if (!field.required && !decoder.peekType(tlvType, endOffset))
11270 continue;
11271
11272 if (field.repeated) {
11273 while (decoder.peekType(tlvType, endOffset)) {
11274 if (field.type.name == "message") {
11275 var innerEndOffset = decoder.readNestedTlvsStart(tlvType);
11276 var value = new (field.resolvedType.build())();
11277 message.add(field.name, value);
11278 ProtobufTlv._decodeMessageValue
11279 (value, field.resolvedType, decoder, innerEndOffset);
11280 decoder.finishNestedTlvs(innerEndOffset);
11281 }
11282 else
11283 message.add
11284 (field.name,
11285 ProtobufTlv._decodeFieldValue(field, tlvType, decoder, endOffset));
11286 }
11287 }
11288 else {
11289 if (field.type.name == "message") {
11290 var innerEndOffset = decoder.readNestedTlvsStart(tlvType);
11291 var value = new (field.resolvedType.build())();
11292 message.set(field.name, value);
11293 ProtobufTlv._decodeMessageValue
11294 (value, field.resolvedType, decoder, innerEndOffset);
11295 decoder.finishNestedTlvs(innerEndOffset);
11296 }
11297 else
11298 message.set
11299 (field.name,
11300 ProtobufTlv._decodeFieldValue(field, tlvType, decoder, endOffset));
11301 }
11302 }
11303};
11304
11305/**
11306 * This is a helper for _decodeMessageValue. Decode a single field and return
11307 * the value. Assume the field.type.name is not "message".
11308 */
11309ProtobufTlv._decodeFieldValue = function(field, tlvType, decoder, endOffset)
11310{
11311 if (field.type.name == "uint32" ||
11312 field.type.name == "uint64" ||
11313 field.type.name == "enum")
11314 return decoder.readNonNegativeIntegerTlv(tlvType);
11315 else if (field.type.name == "bytes")
11316 return decoder.readBlobTlv(tlvType);
11317 else if (field.type.name == "string")
11318 return decoder.readBlobTlv(tlvType).toString();
11319 else if (field.type.name == "bool")
11320 return decoder.readBooleanTlv(tlvType, endOffset);
11321 else if (field.type.name == "double")
11322 return decoder.readBlobTlv(tlvType).readDoubleLE(0);
11323 else
11324 throw new Error("ProtobufTlv.decode: Unknown field type");
11325};
11326
11327/**
11328 * Return a Name made from the component array in a Protobuf message object,
11329 * assuming that it was defined with "repeated bytes". For example:
11330 * message Name {
11331 * repeated bytes component = 8;
11332 * }
11333 * @param {Array} componentArray The array from the Protobuf message object
11334 * representing the "repeated bytes" component array.
11335 * @return A new Name.
11336 */
11337ProtobufTlv.toName = function(componentArray)
11338{
11339 var name = new Name();
11340 for (var i = 0; i < componentArray.length; ++i)
11341 name.append
11342 (new Blob(new Buffer(componentArray[i].toBinary(), "binary")), false);
11343
11344 return name;
11345};
11346/**
11347 * Copyright (C) 2014-2016 Regents of the University of California.
11348 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
11349 * @author: From code in ndn-cxx by Yingdi Yu <yingdi@cs.ucla.edu>
11350 *
11351 * This program is free software: you can redistribute it and/or modify
11352 * it under the terms of the GNU Lesser General Public License as published by
11353 * the Free Software Foundation, either version 3 of the License, or
11354 * (at your option) any later version.
11355 *
11356 * This program is distributed in the hope that it will be useful,
11357 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11358 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11359 * GNU Lesser General Public License for more details.
11360 *
11361 * You should have received a copy of the GNU Lesser General Public License
11362 * along with this program. If not, see <http://www.gnu.org/licenses/>.
11363 * A copy of the GNU Lesser General Public License is in the file COPYING.
11364 */
11365
11366/**
11367 * @constructor
11368 */
11369var OID = function OID(oid)
11370{
11371 if (typeof oid === 'string') {
11372 var splitString = oid.split(".");
11373 this.oid = [];
11374 for (var i = 0; i < splitString.length; ++i)
11375 this.oid.push(parseInt(splitString[i]));
11376 }
11377 else
11378 // Assume oid is an array of int. Make a copy.
11379 this.oid = oid.slice(0, oid.length);
11380};
11381
11382exports.OID = OID;
11383
11384OID.prototype.getIntegerList = function()
11385{
11386 return this.oid;
11387};
11388
11389OID.prototype.setIntegerList = function(oid)
11390{
11391 // Make a copy.
11392 this.oid = oid.slice(0, oid.length);
11393};
11394
11395OID.prototype.toString = function()
11396{
11397 var result = "";
11398 for (var i = 0; i < this.oid.length; ++i) {
11399 if (i !== 0)
11400 result += ".";
11401 result += this.oid[i];
11402 }
11403
11404 return result;
11405};
11406
11407OID.prototype.equals = function(other)
11408{
11409 if (!(other instanceof OID))
11410 return false;
11411 if (this.oid.length !== other.oid.length)
11412 return false;
11413
11414 for (var i = 0; i < this.oid.length; ++i) {
11415 if (this.oid[i] != other.oid[i])
11416 return false;
11417 }
11418 return true;
11419};
11420/**
11421 * Copyright (C) 2013-2016 Regents of the University of California.
11422 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
11423 *
11424 * This program is free software: you can redistribute it and/or modify
11425 * it under the terms of the GNU Lesser General Public License as published by
11426 * the Free Software Foundation, either version 3 of the License, or
11427 * (at your option) any later version.
11428 *
11429 * This program is distributed in the hope that it will be useful,
11430 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11431 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11432 * GNU Lesser General Public License for more details.
11433 *
11434 * You should have received a copy of the GNU Lesser General Public License
11435 * along with this program. If not, see <http://www.gnu.org/licenses/>.
11436 * A copy of the GNU Lesser General Public License is in the file COPYING.
11437 */
11438
11439/**
11440 * Create a WireFormat base class where the encode and decode methods throw an error. You should use a derived class like TlvWireFormat.
11441 * @constructor
11442 */
11443var WireFormat = function WireFormat() {
11444};
11445
11446exports.WireFormat = WireFormat;
11447
11448/**
11449 * Encode name and return the encoding. Your derived class should override.
11450 * @param {Name} name The Name to encode.
11451 * @return {Blob} A Blob containing the encoding.
11452 * @throws Error This always throws an "unimplemented" error. The derived class should override.
11453 */
11454WireFormat.prototype.encodeName = function(name)
11455{
11456 throw new Error("encodeName is unimplemented in the base WireFormat class. You should use a derived class.");
11457};
11458
11459/**
11460 * Decode input as a name and set the fields of the Name object.
11461 * Your derived class should override.
11462 * @param {Name} name The Name object whose fields are updated.
11463 * @param {Buffer} input The buffer with the bytes to decode.
11464 * @param {boolean} copy (optional) If true, copy from the input when making new
11465 * Blob values. If false, then Blob values share memory with the input, which
11466 * must remain unchanged while the Blob values are used. If omitted, use true.
11467 * @throws Error This always throws an "unimplemented" error. The derived class should override.
11468 */
11469WireFormat.prototype.decodeName = function(name, input, copy)
11470{
11471 throw new Error("decodeName is unimplemented in the base WireFormat class. You should use a derived class.");
11472};
11473
11474/**
11475 * Encode interest and return the encoding. Your derived class should override.
11476 * @param {Interest} interest The Interest to encode.
11477 * @return {object} An associative array with fields
11478 * (encoding, signedPortionBeginOffset, signedPortionEndOffset) where encoding
11479 * is a Blob containing the encoding, signedPortionBeginOffset is the offset in
11480 * the encoding of the beginning of the signed portion, and
11481 * signedPortionEndOffset is the offset in the encoding of the end of the signed
11482 * portion. The signed portion starts from the first name component and ends
11483 * just before the final name component (which is assumed to be a signature for
11484 * a signed interest).
11485 * @throws Error This always throws an "unimplemented" error. The derived class should override.
11486 */
11487WireFormat.prototype.encodeInterest = function(interest)
11488{
11489 throw new Error("encodeInterest is unimplemented in the base WireFormat class. You should use a derived class.");
11490};
11491
11492/**
11493 * Decode input as an interest and set the fields of the interest object.
11494 * Your derived class should override.
11495 * @param {Interest} interest The Interest object whose fields are updated.
11496 * @param {Buffer} input The buffer with the bytes to decode.
11497 * @param {boolean} copy (optional) If true, copy from the input when making new
11498 * Blob values. If false, then Blob values share memory with the input, which
11499 * must remain unchanged while the Blob values are used. If omitted, use true.
11500 * @return {object} An associative array with fields
11501 * (signedPortionBeginOffset, signedPortionEndOffset) where
11502 * signedPortionBeginOffset is the offset in the encoding of the beginning of
11503 * the signed portion, and signedPortionEndOffset is the offset in the encoding
11504 * of the end of the signed portion. The signed portion starts from the first
11505 * name component and ends just before the final name component (which is
11506 * assumed to be a signature for a signed interest).
11507 * @throws Error This always throws an "unimplemented" error. The derived class should override.
11508 */
11509WireFormat.prototype.decodeInterest = function(interest, input, copy)
11510{
11511 throw new Error("decodeInterest is unimplemented in the base WireFormat class. You should use a derived class.");
11512};
11513
11514/**
11515 * Encode data and return the encoding and signed offsets. Your derived class
11516 * should override.
11517 * @param {Data} data The Data object to encode.
11518 * @return {object} An associative array with fields
11519 * (encoding, signedPortionBeginOffset, signedPortionEndOffset) where encoding
11520 * is a Blob containing the encoding, signedPortionBeginOffset is the offset in
11521 * the encoding of the beginning of the signed portion, and
11522 * signedPortionEndOffset is the offset in the encoding of the end of the
11523 * signed portion.
11524 * @throws Error This always throws an "unimplemented" error. The derived class should override.
11525 */
11526WireFormat.prototype.encodeData = function(data)
11527{
11528 throw new Error("encodeData is unimplemented in the base WireFormat class. You should use a derived class.");
11529};
11530
11531/**
11532 * Decode input as a data packet, set the fields in the data object, and return
11533 * the signed offsets. Your derived class should override.
11534 * @param {Data} data The Data object whose fields are updated.
11535 * @param {Buffer} input The buffer with the bytes to decode.
11536 * @param {boolean} copy (optional) If true, copy from the input when making new
11537 * Blob values. If false, then Blob values share memory with the input, which
11538 * must remain unchanged while the Blob values are used. If omitted, use true.
11539 * @return {object} An associative array with fields
11540 * (signedPortionBeginOffset, signedPortionEndOffset) where
11541 * signedPortionBeginOffset is the offset in the encoding of the beginning of
11542 * the signed portion, and signedPortionEndOffset is the offset in the encoding
11543 * of the end of the signed portion.
11544 * @throws Error This always throws an "unimplemented" error. The derived class should override.
11545 */
11546WireFormat.prototype.decodeData = function(data, input, copy)
11547{
11548 throw new Error("decodeData is unimplemented in the base WireFormat class. You should use a derived class.");
11549};
11550
11551/**
11552 * Encode controlParameters and return the encoding. Your derived class should
11553 * override.
11554 * @param {ControlParameters} controlParameters The ControlParameters object to
11555 * encode.
11556 * @return {Blob} A Blob containing the encoding.
11557 * @throws Error This always throws an "unimplemented" error. The derived class should override.
11558 */
11559WireFormat.prototype.encodeControlParameters = function(controlParameters)
11560{
11561 throw new Error("encodeControlParameters is unimplemented in the base WireFormat class. You should use a derived class.");
11562};
11563
11564/**
11565 * Decode input as a controlParameters and set the fields of the
11566 * controlParameters object. Your derived class should override.
11567 * @param {ControlParameters} controlParameters The ControlParameters object
11568 * whose fields are updated.
11569 * @param {Buffer} input The buffer with the bytes to decode.
11570 * @param {boolean} copy (optional) If true, copy from the input when making new
11571 * Blob values. If false, then Blob values share memory with the input, which
11572 * must remain unchanged while the Blob values are used. If omitted, use true.
11573 * @throws Error This always throws an "unimplemented" error. The derived class should override.
11574 */
11575WireFormat.prototype.decodeControlParameters = function
11576 (controlParameters, input, copy)
11577{
11578 throw new Error("decodeControlParameters is unimplemented in the base WireFormat class. You should use a derived class.");
11579};
11580
11581/**
11582 * Encode controlResponse and return the encoding. Your derived class should
11583 * override.
11584 * @param {ControlResponse} controlResponse The ControlResponse object to
11585 * encode.
11586 * @return {Blob} A Blob containing the encoding.
11587 * @throws Error This always throws an "unimplemented" error. The derived class should override.
11588 */
11589WireFormat.prototype.encodeControlResponse = function(controlResponse)
11590{
11591 throw new Error("encodeControlResponse is unimplemented in the base WireFormat class. You should use a derived class.");
11592};
11593
11594/**
11595 * Decode input as a controlResponse and set the fields of the
11596 * controlResponse object. Your derived class should override.
11597 * @param {ControlResponse} controlResponse The ControlResponse object
11598 * whose fields are updated.
11599 * @param {Buffer} input The buffer with the bytes to decode.
11600 * @param {boolean} copy (optional) If true, copy from the input when making new
11601 * Blob values. If false, then Blob values share memory with the input, which
11602 * must remain unchanged while the Blob values are used. If omitted, use true.
11603 * @throws Error This always throws an "unimplemented" error. The derived class should override.
11604 */
11605WireFormat.prototype.decodeControlResponse = function
11606 (controlResponse, input, copy)
11607{
11608 throw new Error("decodeControlResponse is unimplemented in the base WireFormat class. You should use a derived class.");
11609};
11610
11611/**
11612 * Encode signature as a SignatureInfo and return the encoding. Your derived
11613 * class should override.
11614 * @param {Signature} signature An object of a subclass of Signature to encode.
11615 * @return {Blob} A Blob containing the encoding.
11616 * @throws Error This always throws an "unimplemented" error. The derived class should override.
11617 */
11618WireFormat.prototype.encodeSignatureInfo = function(signature)
11619{
11620 throw new Error("encodeSignatureInfo is unimplemented in the base WireFormat class. You should use a derived class.");
11621};
11622
11623/**
11624 * Decode signatureInfo as a signature info and signatureValue as the related
11625 * SignatureValue, and return a new object which is a subclass of Signature.
11626 * Your derived class should override.
11627 * @param {Buffer} signatureInfo The buffer with the signature info bytes to
11628 * decode.
11629 * @param {Buffer} signatureValue The buffer with the signature value to decode.
11630 * @param {boolean} copy (optional) If true, copy from the input when making new
11631 * Blob values. If false, then Blob values share memory with the input, which
11632 * must remain unchanged while the Blob values are used. If omitted, use true.
11633 * @return {Signature} A new object which is a subclass of Signature.
11634 * @throws Error This always throws an "unimplemented" error. The derived class should override.
11635 */
11636WireFormat.prototype.decodeSignatureInfoAndValue = function
11637 (signatureInfo, signatureValue, copy)
11638{
11639 throw new Error("decodeSignatureInfoAndValue is unimplemented in the base WireFormat class. You should use a derived class.");
11640};
11641
11642/**
11643 * Encode the signatureValue in the Signature object as a SignatureValue (the
11644 * signature bits) and return the encoding. Your derived class should override.
11645 * @param {Signature} signature An object of a subclass of Signature with the
11646 * signature value to encode.
11647 * @return {Blob} A Blob containing the encoding.
11648 * @throws Error This always throws an "unimplemented" error. The derived class should override.
11649 */
11650WireFormat.prototype.encodeSignatureValue = function(signature)
11651{
11652 throw new Error("encodeSignatureValue is unimplemented in the base WireFormat class. You should use a derived class.");
11653};
11654
11655/**
11656 * Decode input as an NDN-TLV LpPacket and set the fields of the lpPacket object.
11657 * Your derived class should override.
11658 * @param {LpPacket} lpPacket The LpPacket object whose fields are updated.
11659 * @param {Buffer} input The buffer with the bytes to decode.
11660 * @param {boolean} copy (optional) If true, copy from the input when making new
11661 * Blob values. If false, then Blob values share memory with the input, which
11662 * must remain unchanged while the Blob values are used. If omitted, use true.
11663 * @throws Error This always throws an "unimplemented" error. The derived class
11664 * should override.
11665 */
11666WireFormat.prototype.decodeLpPacket = function(lpPacket, input, copy)
11667{
11668 throw new Error
11669 ("decodeLpPacket is unimplemented in the base WireFormat class. You should use a derived class.");
11670};
11671
11672/**
11673 * Encode the DelegationSet and return the encoding. Your derived class
11674 * should override.
11675 * @param {DelegationSet} delegationSet The DelegationSet object to
11676 * encode.
11677 * @return {Blob} A Blob containing the encoding.
11678 * @throws Error This always throws an "unimplemented" error. The derived class
11679 * should override.
11680 */
11681WireFormat.prototype.encodeDelegationSet = function(delegationSet)
11682{
11683 throw new Error
11684 ("encodeDelegationSet is unimplemented in the base WireFormat class. You should use a derived class.");
11685};
11686
11687/**
11688 * Decode input as an DelegationSet and set the fields of the
11689 * delegationSet object. Your derived class should override.
11690 * @param {DelegationSet} delegationSet The DelegationSet object
11691 * whose fields are updated.
11692 * @param {Buffer} input The buffer with the bytes to decode.
11693 * @param {boolean} copy (optional) If true, copy from the input when making new
11694 * Blob values. If false, then Blob values share memory with the input, which
11695 * must remain unchanged while the Blob values are used. If omitted, use true.
11696 * @throws Error This always throws an "unimplemented" error. The derived class
11697 * should override.
11698 */
11699WireFormat.prototype.decodeDelegationSet = function(delegationSet, input, copy)
11700{
11701 throw new Error
11702 ("decodeDelegationSet is unimplemented in the base WireFormat class. You should use a derived class.");
11703};
11704
11705/**
11706 * Encode the EncryptedContent and return the encoding. Your derived class
11707 * should override.
11708 * @param {EncryptedContent} encryptedContent The EncryptedContent object to
11709 * encode.
11710 * @return {Blob} A Blob containing the encoding.
11711 * @throws Error This always throws an "unimplemented" error. The derived class
11712 * should override.
11713 */
11714WireFormat.prototype.encodeEncryptedContent = function(encryptedContent)
11715{
11716 throw new Error
11717 ("encodeEncryptedContent is unimplemented in the base WireFormat class. You should use a derived class.");
11718};
11719
11720/**
11721 * Decode input as an EncryptedContent and set the fields of the
11722 * encryptedContent object. Your derived class should override.
11723 * @param {EncryptedContent} encryptedContent The EncryptedContent object
11724 * whose fields are updated.
11725 * @param {Buffer} input The buffer with the bytes to decode.
11726 * @param {boolean} copy (optional) If true, copy from the input when making new
11727 * Blob values. If false, then Blob values share memory with the input, which
11728 * must remain unchanged while the Blob values are used. If omitted, use true.
11729 * @throws Error This always throws an "unimplemented" error. The derived class
11730 * should override.
11731 */
11732WireFormat.prototype.decodeEncryptedContent = function
11733 (encryptedContent, input, copy)
11734{
11735 throw new Error
11736 ("decodeEncryptedContent is unimplemented in the base WireFormat class. You should use a derived class.");
11737};
11738
11739/**
11740 * Set the static default WireFormat used by default encoding and decoding
11741 * methods.
11742 * @param {WireFormat} wireFormat An object of a subclass of WireFormat.
11743 */
11744WireFormat.setDefaultWireFormat = function(wireFormat)
11745{
11746 WireFormat.defaultWireFormat = wireFormat;
11747};
11748
11749/**
11750 * Return the default WireFormat used by default encoding and decoding methods
11751 * which was set with setDefaultWireFormat.
11752 * @return {WireFormat} An object of a subclass of WireFormat.
11753 */
11754WireFormat.getDefaultWireFormat = function()
11755{
11756 return WireFormat.defaultWireFormat;
11757};
11758
11759// Invoke TlvWireFormat to set the default format.
11760// Since tlv-wire-format.js includes this file, put this at the bottom
11761// to avoid problems with cycles of require.
11762var TlvWireFormat = require('./tlv-wire-format.js').TlvWireFormat;
11763/**
11764 * Copyright (C) 2013-2016 Regents of the University of California.
11765 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
11766 *
11767 * This program is free software: you can redistribute it and/or modify
11768 * it under the terms of the GNU Lesser General Public License as published by
11769 * the Free Software Foundation, either version 3 of the License, or
11770 * (at your option) any later version.
11771 *
11772 * This program is distributed in the hope that it will be useful,
11773 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11774 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11775 * GNU Lesser General Public License for more details.
11776 *
11777 * You should have received a copy of the GNU Lesser General Public License
11778 * along with this program. If not, see <http://www.gnu.org/licenses/>.
11779 * A copy of the GNU Lesser General Public License is in the file COPYING.
11780 */
11781
11782/** @ignore */
11783var DataUtils = require('./data-utils.js').DataUtils; /** @ignore */
11784var Tlv = require('./tlv/tlv.js').Tlv; /** @ignore */
11785var TlvStructureDecoder = require('./tlv/tlv-structure-decoder.js').TlvStructureDecoder; /** @ignore */
11786var DecodingException = require('./decoding-exception.js').DecodingException; /** @ignore */
11787var NdnCommon = require('../util/ndn-common.js').NdnCommon; /** @ignore */
11788var LOG = require('../log.js').Log.LOG;
11789
11790/**
11791 * A ElementReader lets you call onReceivedData multiple times which uses a
11792 * TlvStructureDecoder to detect the end of a TLV element and calls
11793 * elementListener.onReceivedElement(element) with the element. This handles
11794 * the case where a single call to onReceivedData may contain multiple elements.
11795 * @constructor
11796 * @param {object} elementListener An object with an onReceivedElement method.
11797 */
11798var ElementReader = function ElementReader(elementListener)
11799{
11800 this.elementListener_ = elementListener;
11801 this.dataParts_ = [];
11802 this.tlvStructureDecoder_ = new TlvStructureDecoder();
11803};
11804
11805exports.ElementReader = ElementReader;
11806
11807/**
11808 * Continue to read data until the end of an element, then call
11809 * this.elementListener_.onReceivedElement(element). The buffer passed to
11810 * onReceivedElement is only valid during this call. If you need the data
11811 * later, you must copy.
11812 * @param {Buffer} data The Buffer with the incoming element's bytes.
11813 */
11814ElementReader.prototype.onReceivedData = function(data)
11815{
11816 // Process multiple elements in the data.
11817 while (true) {
11818 var gotElementEnd;
11819 var offset;
11820
11821 try {
11822 if (this.dataParts_.length === 0) {
11823 // This is the beginning of an element.
11824 if (data.length <= 0)
11825 // Wait for more data.
11826 return;
11827 }
11828
11829 // Scan the input to check if a whole TLV element has been read.
11830 this.tlvStructureDecoder_.seek(0);
11831 gotElementEnd = this.tlvStructureDecoder_.findElementEnd(data);
11832 offset = this.tlvStructureDecoder_.getOffset();
Alexander Afanasyev1663a412013-03-02 13:52:00 -080011833 } catch (ex) {
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080011834 // Reset to read a new element on the next call.
11835 this.dataParts_ = [];
11836 this.tlvStructureDecoder_ = new TlvStructureDecoder();
11837
11838 throw ex;
11839 }
11840
11841 if (gotElementEnd) {
11842 // Got the remainder of an element. Report to the caller.
11843 var element;
11844 if (this.dataParts_.length === 0)
11845 element = data.slice(0, offset);
11846 else {
11847 this.dataParts_.push(data.slice(0, offset));
11848 element = DataUtils.concatArrays(this.dataParts_);
11849 this.dataParts_ = [];
11850 }
11851
11852 // Reset to read a new element. Do this before calling onReceivedElement
11853 // in case it throws an exception.
11854 data = data.slice(offset, data.length);
11855 this.tlvStructureDecoder_ = new TlvStructureDecoder();
11856
11857 this.elementListener_.onReceivedElement(element);
11858 if (data.length == 0)
11859 // No more data in the packet.
11860 return;
11861
11862 // else loop back to decode.
11863 }
11864 else {
11865 // Save a copy. We will call concatArrays later.
11866 var totalLength = data.length;
11867 for (var i = 0; i < this.dataParts_.length; ++i)
11868 totalLength += this.dataParts_[i].length;
11869 if (totalLength > NdnCommon.MAX_NDN_PACKET_SIZE) {
11870 // Reset to read a new element on the next call.
11871 this.dataParts_ = [];
11872 this.tlvStructureDecoder_ = new TlvStructureDecoder();
11873
11874 throw new DecodingException(new Error
11875 ("The incoming packet exceeds the maximum limit Face.getMaxNdnPacketSize()"));
11876 }
11877
11878 this.dataParts_.push(new Buffer(data));
11879 if (LOG > 3) console.log('Incomplete packet received. Length ' + data.length + '. Wait for more input.');
11880 return;
11881 }
11882 }
11883};
11884/**
11885 * Copyright (C) 2014-2016 Regents of the University of California.
11886 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
11887 *
11888 * This program is free software: you can redistribute it and/or modify
11889 * it under the terms of the GNU Lesser General Public License as published by
11890 * the Free Software Foundation, either version 3 of the License, or
11891 * (at your option) any later version.
11892 *
11893 * This program is distributed in the hope that it will be useful,
11894 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11895 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11896 * GNU Lesser General Public License for more details.
11897 *
11898 * You should have received a copy of the GNU Lesser General Public License
11899 * along with this program. If not, see <http://www.gnu.org/licenses/>.
11900 * A copy of the GNU Lesser General Public License is in the file COPYING.
11901 */
11902
11903/**
11904 * Create a new DerDecodingException wrapping the given error object.
11905 * Call with: throw new DerDecodingException(new Error("message")).
11906 * @constructor
11907 * @param {Error} error The exception created with new Error.
11908 */
11909function DerDecodingException(error)
11910{
11911 if (error) {
11912 error.__proto__ = DerDecodingException.prototype;
11913 return error;
11914 }
11915}
11916DerDecodingException.prototype = new Error();
11917DerDecodingException.prototype.name = "DerDecodingException";
11918
11919exports.DerDecodingException = DerDecodingException;
11920/**
11921 * Copyright (C) 2014-2016 Regents of the University of California.
11922 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
11923 *
11924 * This program is free software: you can redistribute it and/or modify
11925 * it under the terms of the GNU Lesser General Public License as published by
11926 * the Free Software Foundation, either version 3 of the License, or
11927 * (at your option) any later version.
11928 *
11929 * This program is distributed in the hope that it will be useful,
11930 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11931 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11932 * GNU Lesser General Public License for more details.
11933 *
11934 * You should have received a copy of the GNU Lesser General Public License
11935 * along with this program. If not, see <http://www.gnu.org/licenses/>.
11936 * A copy of the GNU Lesser General Public License is in the file COPYING.
11937 */
11938
11939/**
11940 * Create a new DerEncodingException wrapping the given error object.
11941 * Call with: throw new DerEncodingException(new Error("message")).
11942 * @constructor
11943 * @param {Error} error The exception created with new Error.
11944 */
11945function DerEncodingException(error)
11946{
11947 if (error) {
11948 error.__proto__ = DerEncodingException.prototype;
11949 return error;
11950 }
11951}
11952DerEncodingException.prototype = new Error();
11953DerEncodingException.prototype.name = "DerEncodingException";
11954
11955exports.DerEncodingException = DerEncodingException;
11956/**
11957 * Copyright (C) 2014-2016 Regents of the University of California.
11958 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
11959 * @author: From PyNDN der.py by Adeola Bannis <thecodemaiden@gmail.com>.
11960 * @author: Originally from code in ndn-cxx by Yingdi Yu <yingdi@cs.ucla.edu>
11961 *
11962 * This program is free software: you can redistribute it and/or modify
11963 * it under the terms of the GNU Lesser General Public License as published by
11964 * the Free Software Foundation, either version 3 of the License, or
11965 * (at your option) any later version.
11966 *
11967 * This program is distributed in the hope that it will be useful,
11968 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11969 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11970 * GNU Lesser General Public License for more details.
11971 *
11972 * You should have received a copy of the GNU Lesser General Public License
11973 * along with this program. If not, see <http://www.gnu.org/licenses/>.
11974 * A copy of the GNU Lesser General Public License is in the file COPYING.
11975 */
11976
11977/**
11978 * The DerNodeType enum defines the known DER node types.
11979 */
11980var DerNodeType = function DerNodeType()
11981{
11982}
11983
11984exports.DerNodeType = DerNodeType;
11985
11986DerNodeType.Eoc = 0;
11987DerNodeType.Boolean = 1;
11988DerNodeType.Integer = 2;
11989DerNodeType.BitString = 3;
11990DerNodeType.OctetString = 4;
11991DerNodeType.Null = 5;
11992DerNodeType.ObjectIdentifier = 6;
11993DerNodeType.ObjectDescriptor = 7;
11994DerNodeType.External = 40;
11995DerNodeType.Real = 9;
11996DerNodeType.Enumerated = 10;
11997DerNodeType.EmbeddedPdv = 43;
11998DerNodeType.Utf8String = 12;
11999DerNodeType.RelativeOid = 13;
12000DerNodeType.Sequence = 48;
12001DerNodeType.Set = 49;
12002DerNodeType.NumericString = 18;
12003DerNodeType.PrintableString = 19;
12004DerNodeType.T61String = 20;
12005DerNodeType.VideoTexString = 21;
12006DerNodeType.Ia5String = 22;
12007DerNodeType.UtcTime = 23;
12008DerNodeType.GeneralizedTime = 24;
12009DerNodeType.GraphicString = 25;
12010DerNodeType.VisibleString = 26;
12011DerNodeType.GeneralString = 27;
12012DerNodeType.UniversalString = 28;
12013DerNodeType.CharacterString = 29;
12014DerNodeType.BmpString = 30;
12015/**
12016 * Copyright (C) 2014-2016 Regents of the University of California.
12017 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
12018 * @author: From PyNDN der_node.py by Adeola Bannis <thecodemaiden@gmail.com>.
12019 * @author: Originally from code in ndn-cxx by Yingdi Yu <yingdi@cs.ucla.edu>
12020 *
12021 * This program is free software: you can redistribute it and/or modify
12022 * it under the terms of the GNU Lesser General Public License as published by
12023 * the Free Software Foundation, either version 3 of the License, or
12024 * (at your option) any later version.
12025 *
12026 * This program is distributed in the hope that it will be useful,
12027 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12028 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12029 * GNU Lesser General Public License for more details.
12030 *
12031 * You should have received a copy of the GNU Lesser General Public License
12032 * along with this program. If not, see <http://www.gnu.org/licenses/>.
12033 * A copy of the GNU Lesser General Public License is in the file COPYING.
12034 */
12035
12036/** @ignore */
12037var DynamicBuffer = require('../../util/dynamic-buffer.js').DynamicBuffer; /** @ignore */
12038var Blob = require('../../util/blob.js').Blob; /** @ignore */
12039var DerDecodingException = require('./der-decoding-exception.js').DerDecodingException; /** @ignore */
12040var DerEncodingException = require('./der-encoding-exception.js').DerEncodingException; /** @ignore */
12041var DerNodeType = require('./der-node-type.js').DerNodeType;
12042
12043/**
12044 * DerNode implements the DER node types used in encoding/decoding DER-formatted
12045 * data.
12046 *
12047 * Create a generic DER node with the given nodeType. This is a private
12048 * constructor used by one of the public DerNode subclasses defined below.
12049 * @param {number} nodeType One of the defined DER DerNodeType constants.
12050 * @constructor
12051 */
12052var DerNode = function DerNode(nodeType)
12053{
12054 this.nodeType_ = nodeType;
12055 this.parent_ = null;
12056 this.header_ = new Buffer(0);
12057 this.payload_ = new DynamicBuffer(0);
12058 this.payloadPosition_ = 0;
12059};
12060
12061exports.DerNode = DerNode;
12062
12063/**
12064 * Return the number of bytes in DER
12065 * @return {number}
12066 */
12067DerNode.prototype.getSize = function()
12068{
12069 return this.header_.length + this.payloadPosition_;
12070};
12071
12072/**
12073 * Encode the given size and update the header.
12074 * @param {number} size
12075 */
12076DerNode.prototype.encodeHeader = function(size)
12077{
12078 var buffer = new DynamicBuffer(10);
12079 var bufferPosition = 0;
12080 buffer.array[bufferPosition++] = this.nodeType_;
12081 if (size < 0)
12082 // We don't expect this to happen since this is an internal method and
12083 // always called with the non-negative size() of some buffer.
12084 throw new Error("encodeHeader: DER object has negative length");
12085 else if (size <= 127)
12086 buffer.array[bufferPosition++] = size & 0xff;
12087 else {
12088 var tempBuf = new DynamicBuffer(10);
12089 // We encode backwards from the back.
12090
12091 var val = size;
12092 var n = 0;
12093 while (val != 0) {
12094 ++n;
12095 tempBuf.ensureLengthFromBack(n);
12096 tempBuf.array[tempBuf.array.length - n] = val & 0xff;
12097 val >>= 8;
12098 }
12099 var nTempBufBytes = n + 1;
12100 tempBuf.ensureLengthFromBack(nTempBufBytes);
12101 tempBuf.array[tempBuf.array.length - nTempBufBytes] = ((1<<7) | n) & 0xff;
12102
12103 buffer.copy(tempBuf.slice(tempBuf.array.length - nTempBufBytes), bufferPosition);
12104 bufferPosition += nTempBufBytes;
12105 }
12106
12107 this.header_ = buffer.slice(0, bufferPosition);
12108};
12109
12110/**
12111 * Extract the header from an input buffer and return the size.
12112 * @param {Buffer} inputBuf The input buffer to read from.
12113 * @param {number} startIdx The offset into the buffer.
12114 * @return {number} The parsed size in the header.
12115 */
12116DerNode.prototype.decodeHeader = function(inputBuf, startIdx)
12117{
12118 var idx = startIdx;
12119
12120 var nodeType = inputBuf[idx] & 0xff;
12121 idx += 1;
12122
12123 this.nodeType_ = nodeType;
12124
12125 var sizeLen = inputBuf[idx] & 0xff;
12126 idx += 1;
12127
12128 var header = new DynamicBuffer(10);
12129 var headerPosition = 0;
12130 header.array[headerPosition++] = nodeType;
12131 header.array[headerPosition++] = sizeLen;
12132
12133 var size = sizeLen;
12134 var isLongFormat = (sizeLen & (1 << 7)) != 0;
12135 if (isLongFormat) {
12136 var lenCount = sizeLen & ((1<<7) - 1);
12137 size = 0;
12138 while (lenCount > 0) {
12139 var b = inputBuf[idx];
12140 idx += 1;
12141 header.ensureLength(headerPosition + 1);
12142 header.array[headerPosition++] = b;
12143 size = 256 * size + (b & 0xff);
12144 lenCount -= 1;
12145 }
12146 }
12147
12148 this.header_ = header.slice(0, headerPosition);
12149 return size;
12150};
12151
12152/**
12153 * Get the raw data encoding for this node.
12154 * @return {Blob} The raw data encoding.
12155 */
12156DerNode.prototype.encode = function()
12157{
12158 var buffer = new Buffer(this.getSize());
12159
12160 this.header_.copy(buffer);
12161 this.payload_.slice(0, this.payloadPosition_).copy(buffer, this.header_.length);
12162
12163 return new Blob(buffer, false);
12164};
12165
12166/**
12167 * Decode and store the data from an input buffer.
12168 * @param {Buffer} inputBuf The input buffer to read from. This reads from
12169 * startIdx (regardless of the buffer's position) and does not change the
12170 * position.
12171 * @param {number} startIdx The offset into the buffer.
12172 */
12173DerNode.prototype.decode = function(inputBuf, startIdx)
12174{
12175 var idx = startIdx;
12176 var payloadSize = this.decodeHeader(inputBuf, idx);
12177 var skipBytes = this.header_.length;
12178 if (payloadSize > 0) {
12179 idx += skipBytes;
12180 this.payloadAppend(inputBuf.slice(idx, idx + payloadSize));
12181 }
12182};
12183
12184/**
12185 * Copy buffer to this.payload_ at this.payloadPosition_ and update
12186 * this.payloadPosition_.
12187 * @param {Buffer} buffer The buffer to copy.
12188 */
12189DerNode.prototype.payloadAppend = function(buffer)
12190{
12191 this.payloadPosition_ = this.payload_.copy(buffer, this.payloadPosition_);
12192}
12193
12194/**
12195 * Parse the data from the input buffer recursively and return the root as an
12196 * object of a subclass of DerNode.
12197 * @param {Buffer} inputBuf The input buffer to read from.
12198 * @param {number} startIdx (optional) The offset into the buffer. If omitted,
12199 * use 0.
12200 * @return {DerNode} An object of a subclass of DerNode.
12201 */
12202DerNode.parse = function(inputBuf, startIdx)
12203{
12204 if (startIdx == undefined)
12205 startIdx = 0;
12206
12207 var nodeType = inputBuf[startIdx] & 0xff;
12208 // Don't increment idx. We're just peeking.
12209
12210 var newNode;
12211 if (nodeType === DerNodeType.Boolean)
12212 newNode = new DerNode.DerBoolean();
12213 else if (nodeType === DerNodeType.Integer)
12214 newNode = new DerNode.DerInteger();
12215 else if (nodeType === DerNodeType.BitString)
12216 newNode = new DerNode.DerBitString();
12217 else if (nodeType === DerNodeType.OctetString)
12218 newNode = new DerNode.DerOctetString();
12219 else if (nodeType === DerNodeType.Null)
12220 newNode = new DerNode.DerNull();
12221 else if (nodeType === DerNodeType.ObjectIdentifier)
12222 newNode = new DerNode.DerOid();
12223 else if (nodeType === DerNodeType.Sequence)
12224 newNode = new DerNode.DerSequence();
12225 else if (nodeType === DerNodeType.PrintableString)
12226 newNode = new DerNode.DerPrintableString();
12227 else if (nodeType === DerNodeType.GeneralizedTime)
12228 newNode = new DerNode.DerGeneralizedTime();
12229 else
12230 throw new DerDecodingException(new Error("Unimplemented DER type " + nodeType));
12231
12232 newNode.decode(inputBuf, startIdx);
12233 return newNode;
12234};
12235
12236/**
12237 * Convert the encoded data to a standard representation. Overridden by some
12238 * subclasses (e.g. DerBoolean).
12239 * @return {Blob} The encoded data as a Blob.
12240 */
12241DerNode.prototype.toVal = function()
12242{
12243 return this.encode();
12244};
12245
12246/**
12247 * Get a copy of the payload bytes.
12248 * @return {Blob} A copy of the payload.
12249 */
12250DerNode.prototype.getPayload = function()
12251{
12252 return new Blob(this.payload_.slice(0, this.payloadPosition_), true);
12253};
12254
12255/**
12256 * If this object is a DerNode.DerSequence, get the children of this node.
12257 * Otherwise, throw an exception. (DerSequence overrides to implement this
12258 * method.)
12259 * @return {Array<DerNode>} The children as an array of DerNode.
12260 * @throws DerDecodingException if this object is not a DerSequence.
12261 */
12262DerNode.prototype.getChildren = function()
12263{
12264 throw new DerDecodingException(new Error
12265 ("getChildren: This DerNode is not DerSequence"));
12266};
12267
12268/**
12269 * Check that index is in bounds for the children list, return children[index].
12270 * @param {Array<DerNode>} children The list of DerNode, usually returned by
12271 * another call to getChildren.
12272 * @param {number} index The index of the children.
12273 * @return {DerNode.DerSequence} children[index].
12274 * @throws DerDecodingException if index is out of bounds or if children[index]
12275 * is not a DerSequence.
12276 */
12277DerNode.getSequence = function(children, index)
12278{
12279 if (index < 0 || index >= children.length)
12280 throw new DerDecodingException(new Error
12281 ("getSequence: Child index is out of bounds"));
12282
12283 if (!(children[index] instanceof DerNode.DerSequence))
12284 throw new DerDecodingException(new Error
12285 ("getSequence: Child DerNode is not a DerSequence"));
12286
12287 return children[index];
12288};
12289
12290/**
12291 * A DerStructure extends DerNode to hold other DerNodes.
12292 * Create a DerStructure with the given nodeType. This is a private
12293 * constructor. To create an object, use DerSequence.
12294 * @param {number} nodeType One of the defined DER DerNodeType constants.
12295 */
12296DerNode.DerStructure = function DerStructure(nodeType)
12297{
12298 // Call the base constructor.
12299 DerNode.call(this, nodeType);
12300
12301 this.childChanged_ = false;
12302 this.nodeList_ = []; // Of DerNode.
12303 this.size_ = 0;
12304};
12305DerNode.DerStructure.prototype = new DerNode();
12306DerNode.DerStructure.prototype.name = "DerStructure";
12307
12308/**
12309 * Get the total length of the encoding, including children.
12310 * @return {number} The total (header + payload) length.
12311 */
12312DerNode.DerStructure.prototype.getSize = function()
12313{
12314 if (this.childChanged_) {
12315 this.updateSize();
12316 this.childChanged_ = false;
12317 }
12318
12319 this.encodeHeader(this.size_);
12320 return this.size_ + this.header_.length;
12321};
12322
12323/**
12324 * Get the children of this node.
12325 * @return {Array<DerNode>} The children as an array of DerNode.
12326 */
12327DerNode.DerStructure.prototype.getChildren = function()
12328{
12329 return this.nodeList_;
12330};
12331
12332DerNode.DerStructure.prototype.updateSize = function()
12333{
12334 var newSize = 0;
12335
12336 for (var i = 0; i < this.nodeList_.length; ++i) {
12337 var n = this.nodeList_[i];
12338 newSize += n.getSize();
12339 }
12340
12341 this.size_ = newSize;
12342 this.childChanged_ = false;
12343};
12344
12345/**
12346 * Add a child to this node.
12347 * @param {DerNode} node The child node to add.
12348 * @param {boolean} (optional) notifyParent Set to true to cause any containing
12349 * nodes to update their size. If omitted, use false.
12350 */
12351DerNode.DerStructure.prototype.addChild = function(node, notifyParent)
12352{
12353 node.parent_ = this;
12354 this.nodeList_.push(node);
12355
12356 if (notifyParent) {
12357 if (this.parent_ != null)
12358 this.parent_.setChildChanged();
12359 }
12360
12361 this.childChanged_ = true;
12362};
12363
12364/**
12365 * Mark the child list as dirty, so that we update size when necessary.
12366 */
12367DerNode.DerStructure.prototype.setChildChanged = function()
12368{
12369 if (this.parent_ != null)
12370 this.parent_.setChildChanged();
12371 this.childChanged_ = true;
12372};
12373
12374/**
12375 * Override the base encode to return raw data encoding for this node and its
12376 * children.
12377 * @return {Blob} The raw data encoding.
12378 */
12379DerNode.DerStructure.prototype.encode = function()
12380{
12381 var buffer = new DynamicBuffer(10);
12382 var bufferPosition = 0;
12383 this.updateSize();
12384 this.encodeHeader(this.size_);
12385 bufferPosition = buffer.copy(this.header_, bufferPosition);
12386
12387 for (var i = 0; i < this.nodeList_.length; ++i) {
12388 var n = this.nodeList_[i];
12389 var encodedChild = n.encode();
12390 bufferPosition = buffer.copy(encodedChild.buf(), bufferPosition);
12391 }
12392
12393 return new Blob(buffer.slice(0, bufferPosition), false);
12394};
12395
12396/**
12397 * Override the base decode to decode and store the data from an input
12398 * buffer. Recursively populates child nodes.
12399 * @param {Buffer} inputBuf The input buffer to read from.
12400 * @param {number} startIdx The offset into the buffer.
12401 */
12402DerNode.DerStructure.prototype.decode = function(inputBuf, startIdx)
12403{
12404 var idx = startIdx;
12405 this.size_ = this.decodeHeader(inputBuf, idx);
12406 idx += this.header_.length;
12407
12408 var accSize = 0;
12409 while (accSize < this.size_) {
12410 var node = DerNode.parse(inputBuf, idx);
12411 var size = node.getSize();
12412 idx += size;
12413 accSize += size;
12414 this.addChild(node, false);
12415 }
12416};
12417
12418////////
12419// Now for all the node types...
12420////////
12421
12422/**
12423 * A DerByteString extends DerNode to handle byte strings.
12424 * Create a DerByteString with the given inputData and nodeType. This is a
12425 * private constructor used by one of the public subclasses such as
12426 * DerOctetString or DerPrintableString.
12427 * @param {Buffer} inputData An input buffer containing the string to encode.
12428 * @param {number} nodeType One of the defined DER DerNodeType constants.
12429 */
12430DerNode.DerByteString = function DerByteString(inputData, nodeType)
12431{
12432 // Call the base constructor.
12433 DerNode.call(this, nodeType);
12434
12435 if (inputData != null) {
12436 this.payloadAppend(inputData);
12437 this.encodeHeader(inputData.length);
12438 }
12439};
12440DerNode.DerByteString.prototype = new DerNode();
12441DerNode.DerByteString.prototype.name = "DerByteString";
12442
12443/**
12444 * Override to return just the byte string.
12445 * @return {Blob} The byte string as a copy of the payload buffer.
12446 */
12447DerNode.DerByteString.prototype.toVal = function()
12448{
12449 return this.getPayload();
12450};
12451
12452/**
12453 * DerBoolean extends DerNode to encode a boolean value.
12454 * Create a new DerBoolean for the value.
12455 * @param {boolean} value The value to encode.
12456 */
12457DerNode.DerBoolean = function DerBoolean(value)
12458{
12459 // Call the base constructor.
12460 DerNode.call(this, DerNodeType.Boolean);
12461
12462 if (value != undefined) {
12463 var val = value ? 0xff : 0x00;
12464 this.payload_.ensureLength(this.payloadPosition_ + 1);
12465 this.payload_.array[this.payloadPosition_++] = val;
12466 this.encodeHeader(1);
12467 }
12468};
12469DerNode.DerBoolean.prototype = new DerNode();
12470DerNode.DerBoolean.prototype.name = "DerBoolean";
12471
12472DerNode.DerBoolean.prototype.toVal = function()
12473{
12474 var val = this.payload_.array[0];
12475 return val != 0x00;
12476};
12477
12478/**
12479 * DerInteger extends DerNode to encode an integer value.
12480 * Create a new DerInteger for the value.
12481 * @param {number|Buffer} integer The value to encode. If integer is a Buffer
12482 * byte array of a positive integer, you must ensure that the first byte is less
12483 * than 0x80.
12484 */
12485DerNode.DerInteger = function DerInteger(integer)
12486{
12487 // Call the base constructor.
12488 DerNode.call(this, DerNodeType.Integer);
12489
12490 if (integer != undefined) {
12491 if (Buffer.isBuffer(integer)) {
12492 if (integer.length > 0 && integer[0] >= 0x80)
12493 throw new DerEncodingException(new Error
12494 ("DerInteger: Negative integers are not currently supported"));
12495
12496 if (integer.length == 0)
12497 this.payloadAppend(new Buffer([0]));
12498 else
12499 this.payloadAppend(integer);
12500 }
12501 else {
12502 // JavaScript doesn't distinguish int from float, so round.
12503 integer = Math.round(integer);
12504
12505 if (integer < 0)
12506 throw new DerEncodingException(new Error
12507 ("DerInteger: Negative integers are not currently supported"));
12508
12509 // Convert the integer to bytes the easy/slow way.
12510 var temp = new DynamicBuffer(10);
12511 // We encode backwards from the back.
12512 var length = 0;
12513 while (true) {
12514 ++length;
12515 temp.ensureLengthFromBack(length);
12516 temp.array[temp.array.length - length] = integer & 0xff;
12517 integer >>= 8;
12518
12519 if (integer <= 0)
12520 // We check for 0 at the end so we encode one byte if it is 0.
12521 break;
12522 }
12523
12524 if (temp.array[temp.array.length - length] >= 0x80) {
12525 // Make it a non-negative integer.
12526 ++length;
12527 temp.ensureLengthFromBack(length);
12528 temp.array[temp.array.length - length] = 0;
12529 }
12530
12531 this.payloadAppend(temp.slice(temp.array.length - length));
12532 }
12533
12534 this.encodeHeader(this.payloadPosition_);
12535 }
12536};
12537DerNode.DerInteger.prototype = new DerNode();
12538DerNode.DerInteger.prototype.name = "DerInteger";
12539
12540DerNode.DerInteger.prototype.toVal = function()
12541{
12542 if (this.payloadPosition_ > 0 && this.payload_.array[0] >= 0x80)
12543 throw new DerDecodingException(new Error
12544 ("DerInteger: Negative integers are not currently supported"));
12545
12546 var result = 0;
12547 for (var i = 0; i < this.payloadPosition_; ++i) {
12548 result <<= 8;
12549 result += this.payload_.array[i];
12550 }
12551
12552 return result;
12553};
12554
12555/**
12556 * A DerBitString extends DerNode to handle a bit string.
12557 * Create a DerBitString with the given padding and inputBuf.
12558 * @param {Buffer} inputBuf An input buffer containing the bit octets to encode.
12559 * @param {number} paddingLen The number of bits of padding at the end of the bit
12560 * string. Should be less than 8.
12561 */
12562DerNode.DerBitString = function DerBitString(inputBuf, paddingLen)
12563{
12564 // Call the base constructor.
12565 DerNode.call(this, DerNodeType.BitString);
12566
12567 if (inputBuf != undefined) {
12568 this.payload_.ensureLength(this.payloadPosition_ + 1);
12569 this.payload_.array[this.payloadPosition_++] = paddingLen & 0xff;
12570 this.payloadAppend(inputBuf);
12571 this.encodeHeader(this.payloadPosition_);
12572 }
12573};
12574DerNode.DerBitString.prototype = new DerNode();
12575DerNode.DerBitString.prototype.name = "DerBitString";
12576
12577/**
12578 * DerOctetString extends DerByteString to encode a string of bytes.
12579 * Create a new DerOctetString for the inputData.
12580 * @param {Buffer} inputData An input buffer containing the string to encode.
12581 */
12582DerNode.DerOctetString = function DerOctetString(inputData)
12583{
12584 // Call the base constructor.
12585 DerNode.DerByteString.call(this, inputData, DerNodeType.OctetString);
12586};
12587DerNode.DerOctetString.prototype = new DerNode.DerByteString();
12588DerNode.DerOctetString.prototype.name = "DerOctetString";
12589
12590/**
12591 * A DerNull extends DerNode to encode a null value.
12592 * Create a DerNull.
12593 */
12594DerNode.DerNull = function DerNull()
12595{
12596 // Call the base constructor.
12597 DerNode.call(this, DerNodeType.Null);
12598 this.encodeHeader(0);
12599};
12600DerNode.DerNull.prototype = new DerNode();
12601DerNode.DerNull.prototype.name = "DerNull";
12602
12603/**
12604 * A DerOid extends DerNode to represent an object identifier.
12605 * Create a DerOid with the given object identifier. The object identifier
12606 * string must begin with 0,1, or 2 and must contain at least 2 digits.
12607 * @param {string|OID} oid The OID string or OID object to encode.
12608 */
12609DerNode.DerOid = function DerOid(oid)
12610{
12611 // Call the base constructor.
12612 DerNode.call(this, DerNodeType.ObjectIdentifier);
12613
12614 if (oid != undefined) {
12615 if (typeof oid === 'string') {
12616 var splitString = oid.split(".");
12617 var parts = [];
12618 for (var i = 0; i < splitString.length; ++i)
12619 parts.push(parseInt(splitString[i]));
12620
12621 this.prepareEncoding(parts);
12622 }
12623 else
12624 // Assume oid is of type OID.
12625 this.prepareEncoding(oid.getIntegerList());
12626 }
12627};
12628DerNode.DerOid.prototype = new DerNode();
12629DerNode.DerOid.prototype.name = "DerOid";
12630
12631/**
12632 * Encode a sequence of integers into an OID object and set the payload.
12633 * @param {Array<number>} value The array of integers.
12634 */
12635DerNode.DerOid.prototype.prepareEncoding = function(value)
12636{
12637 var firstNumber;
12638 if (value.length == 0)
12639 throw new DerEncodingException(new Error("No integer in OID"));
12640 else {
12641 if (value[0] >= 0 && value[0] <= 2)
12642 firstNumber = value[0] * 40;
12643 else
12644 throw new DerEncodingException(new Error("First integer in OID is out of range"));
12645 }
12646
12647 if (value.length >= 2) {
12648 if (value[1] >= 0 && value[1] <= 39)
12649 firstNumber += value[1];
12650 else
12651 throw new DerEncodingException(new Error("Second integer in OID is out of range"));
12652 }
12653
12654 var encodedBuffer = new DynamicBuffer(10);
12655 var encodedBufferPosition = 0;
12656 encodedBufferPosition = encodedBuffer.copy
12657 (DerNode.DerOid.encode128(firstNumber), encodedBufferPosition);
12658
12659 if (value.length > 2) {
12660 for (var i = 2; i < value.length; ++i)
12661 encodedBufferPosition = encodedBuffer.copy
12662 (DerNode.DerOid.encode128(value[i]), encodedBufferPosition);
12663 }
12664
12665 this.encodeHeader(encodedBufferPosition);
12666 this.payloadAppend(encodedBuffer.slice(0, encodedBufferPosition));
12667};
12668
12669/**
12670 * Compute the encoding for one part of an OID, where values greater than 128
12671 * must be encoded as multiple bytes.
12672 * @param {number} value A component of an OID.
12673 * @return {Buffer} The encoded buffer.
12674 */
12675DerNode.DerOid.encode128 = function(value)
12676{
12677 var mask = (1 << 7) - 1;
12678 var outBytes = new DynamicBuffer(10);
12679 var outBytesLength = 0;
12680 // We encode backwards from the back.
12681
12682 if (value < 128) {
12683 ++outBytesLength;
12684 outBytes.array[outBytes.array.length - outBytesLength] = value & mask;
12685 }
12686 else {
12687 ++outBytesLength;
12688 outBytes.array[outBytes.array.length - outBytesLength] = value & mask;
12689 value >>= 7;
12690
12691 while (value != 0) {
12692 ++outBytesLength;
12693 outBytes.ensureLengthFromBack(outBytesLength);
12694 outBytes.array[outBytes.array.length - outBytesLength] =
12695 (value & mask) | (1 << 7);
12696 value >>= 7;
12697 }
12698 }
12699
12700 return outBytes.slice(outBytes.array.length - outBytesLength);
12701};
12702
12703/**
12704 * Convert an encoded component of the encoded OID to the original integer.
12705 * @param {number} offset The offset into this node's payload.
12706 * @param {Array<number>} skip Set skip[0] to the number of payload bytes to skip.
12707 * @return {number} The original integer.
12708 */
12709DerNode.DerOid.prototype.decode128 = function(offset, skip)
12710{
12711 var flagMask = 0x80;
12712 var result = 0;
12713 var oldOffset = offset;
12714
12715 while ((this.payload_.array[offset] & flagMask) != 0) {
12716 result = 128 * result + (this.payload_.array[offset] & 0xff) - 128;
12717 offset += 1;
12718 }
12719
12720 result = result * 128 + (this.payload_.array[offset] & 0xff);
12721
12722 skip[0] = offset - oldOffset + 1;
12723 return result;
12724};
12725
12726/**
12727 * Override to return the string representation of the OID.
12728 * @return {string} The string representation of the OID.
12729 */
12730DerNode.DerOid.prototype.toVal = function()
12731{
12732 var offset = 0;
12733 var components = []; // of number.
12734
12735 while (offset < this.payloadPosition_) {
12736 var skip = [0];
12737 var nextVal = this.decode128(offset, skip);
12738 offset += skip[0];
12739 components.push(nextVal);
12740 }
12741
12742 // For some odd reason, the first digits are represented in one byte.
12743 var firstByte = components[0];
12744 var firstDigit = Math.floor(firstByte / 40);
12745 var secondDigit = firstByte % 40;
12746
12747 var result = firstDigit + "." + secondDigit;
12748 for (var i = 1; i < components.length; ++i)
12749 result += "." + components[i];
12750
12751 return result;
12752};
12753
12754/**
12755 * A DerSequence extends DerStructure to contains an ordered sequence of other
12756 * nodes.
12757 * Create a DerSequence.
12758 */
12759DerNode.DerSequence = function DerSequence()
12760{
12761 // Call the base constructor.
12762 DerNode.DerStructure.call(this, DerNodeType.Sequence);
12763};
12764DerNode.DerSequence.prototype = new DerNode.DerStructure();
12765DerNode.DerSequence.prototype.name = "DerSequence";
12766
12767/**
12768 * A DerPrintableString extends DerByteString to handle a a printable string. No
12769 * escaping or other modification is done to the string.
12770 * Create a DerPrintableString with the given inputData.
12771 * @param {Buffer} inputData An input buffer containing the string to encode.
12772 */
12773DerNode.DerPrintableString = function DerPrintableString(inputData)
12774{
12775 // Call the base constructor.
12776 DerNode.DerByteString.call(this, inputData, DerNodeType.PrintableString);
12777};
12778DerNode.DerPrintableString.prototype = new DerNode.DerByteString();
12779DerNode.DerPrintableString.prototype.name = "DerPrintableString";
12780
12781/**
12782 * A DerGeneralizedTime extends DerNode to represent a date and time, with
12783 * millisecond accuracy.
12784 * Create a DerGeneralizedTime with the given milliseconds since 1970.
12785 * @param {number} msSince1970 The timestamp as milliseconds since Jan 1, 1970.
12786 */
12787DerNode.DerGeneralizedTime = function DerGeneralizedTime(msSince1970)
12788{
12789 // Call the base constructor.
12790 DerNode.call(this, DerNodeType.GeneralizedTime);
12791
12792 if (msSince1970 != undefined) {
12793 var derTime = DerNode.DerGeneralizedTime.toDerTimeString(msSince1970);
12794 // Use Blob to convert to a Buffer.
12795 this.payloadAppend(new Blob(derTime).buf());
12796 this.encodeHeader(this.payloadPosition_);
12797 }
12798};
12799DerNode.DerGeneralizedTime.prototype = new DerNode();
12800DerNode.DerGeneralizedTime.prototype.name = "DerGeneralizedTime";
12801
12802/**
12803 * Convert a UNIX timestamp to the internal string representation.
12804 * @param {type} msSince1970 Timestamp as milliseconds since Jan 1, 1970.
12805 * @return {string} The string representation.
12806 */
12807DerNode.DerGeneralizedTime.toDerTimeString = function(msSince1970)
12808{
12809 var utcTime = new Date(Math.round(msSince1970));
12810 return utcTime.getUTCFullYear() +
12811 DerNode.DerGeneralizedTime.to2DigitString(utcTime.getUTCMonth() + 1) +
12812 DerNode.DerGeneralizedTime.to2DigitString(utcTime.getUTCDate()) +
12813 DerNode.DerGeneralizedTime.to2DigitString(utcTime.getUTCHours()) +
12814 DerNode.DerGeneralizedTime.to2DigitString(utcTime.getUTCMinutes()) +
12815 DerNode.DerGeneralizedTime.to2DigitString(utcTime.getUTCSeconds()) +
12816 "Z";
12817};
12818
12819/**
12820 * A private method to zero pad an integer to 2 digits.
12821 * @param {number} x The number to pad. Assume it is a non-negative integer.
12822 * @return {string} The padded string.
12823 */
12824DerNode.DerGeneralizedTime.to2DigitString = function(x)
12825{
12826 var result = x.toString();
12827 return result.length === 1 ? "0" + result : result;
12828};
12829
12830/**
12831 * Override to return the milliseconds since 1970.
12832 * @return {number} The timestamp value as milliseconds since 1970.
12833 */
12834DerNode.DerGeneralizedTime.prototype.toVal = function()
12835{
12836 var timeStr = this.payload_.slice(0, this.payloadPosition_).toString();
12837 return Date.UTC
12838 (parseInt(timeStr.substr(0, 4)),
12839 parseInt(timeStr.substr(4, 2) - 1),
12840 parseInt(timeStr.substr(6, 2)),
12841 parseInt(timeStr.substr(8, 2)),
12842 parseInt(timeStr.substr(10, 2)),
12843 parseInt(timeStr.substr(12, 2)));
12844};
12845/**
12846 * Copyright (C) 2014-2016 Regents of the University of California.
12847 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
12848 * From PyNDN boost_info_parser by Adeola Bannis.
12849 *
12850 * This program is free software: you can redistribute it and/or modify
12851 * it under the terms of the GNU Lesser General Public License as published by
12852 * the Free Software Foundation, either version 3 of the License, or
12853 * (at your option) any later version.
12854 *
12855 * This program is distributed in the hope that it will be useful,
12856 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12857 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12858 * GNU Lesser General Public License for more details.
12859 *
12860 * You should have received a copy of the GNU Lesser General Public License
12861 * along with this program. If not, see <http://www.gnu.org/licenses/>.
12862 * A copy of the GNU Lesser General Public License is in the file COPYING.
12863 */
12864
12865/** @ignore */
12866var fs = require('fs');
12867
12868/**
12869 * BoostInfoTree is provided for compatibility with the Boost INFO property list
12870 * format used in ndn-cxx.
12871 *
12872 * Each node in the tree may have a name and a value as well as associated
12873 * sub-trees. The sub-tree names are not unique, and so sub-trees are stored as
12874 * dictionaries where the key is a sub-tree name and the values are the
12875 * sub-trees sharing the same name.
12876 *
12877 * Nodes can be accessed with a path syntax, as long as nodes in the path do not
12878 * contain the path separator '/' in their names.
12879 * @constructor
12880 */
12881var BoostInfoTree = function BoostInfoTree(value, parent)
12882{
12883 // subtrees is an array of {key: treeName, value: subtreeList} where
12884 // treeName is a string and subtreeList is an array of BoostInfoTree.
12885 // We can't use a dictionary because we want the keys to be in order.
12886 this.subtrees = [];
12887 this.value = value;
12888 this.parent = parent;
12889
12890 this.lastChild = null;
12891};
12892
12893/**
12894 * Insert a BoostInfoTree as a sub-tree with the given name.
12895 * @param {string} treeName The name of the new sub-tree.
12896 * @param {BoostInfoTree} newTree The sub-tree to add.
12897 */
12898BoostInfoTree.prototype.addSubtree = function(treeName, newTree)
12899{
12900 var subtreeList = this.find(treeName);
12901 if (subtreeList !== null)
12902 subtreeList.push(newTree);
12903 else
12904 this.subtrees.push({key: treeName, value: [newTree]});
12905
12906 newTree.parent = this;
12907 this.lastChild = newTree;
12908};
12909
12910/**
12911 * Create a new BoostInfo and insert it as a sub-tree with the given name.
12912 * @param {string} treeName The name of the new sub-tree.
12913 * @param {string} value The value associated with the new sub-tree.
12914 * @return {BoostInfoTree} The created sub-tree.
12915 */
12916BoostInfoTree.prototype.createSubtree = function(treeName, value)
12917{
12918 var newTree = new BoostInfoTree(value, this);
12919 this.addSubtree(treeName, newTree);
12920 return newTree;
12921};
12922
12923/**
12924 * Look up using the key and return a list of the subtrees.
12925 * @param {string} key The key which may be a path separated with '/'.
12926 * @return {Array<BoostInfoTree>} A new array with pointers to the subtrees.
12927 */
12928BoostInfoTree.prototype.get = function(key)
12929{
12930 // Strip beginning '/'.
12931 key = key.replace(/^\/+/, "");
12932 if (key.length === 0)
12933 return [this];
12934 var path = key.split('/');
12935
12936 var subtrees = this.find(path[0]);
12937 if (subtrees === null)
12938 return [];
12939 if (path.length == 1)
12940 return subtrees.slice(0);
12941
12942 var newPath = path.slice(1).join('/');
12943 var foundVals = [];
12944 for (var i = 0; i < subtrees.length; ++i) {
12945 var t = subtrees[i];
12946 var partial = t.get(newPath);
12947 foundVals = foundVals.concat(partial);
12948 }
12949 return foundVals;
12950};
12951
12952/**
12953 * Look up using the key and return string value of the first subtree.
12954 * @param {string} key The key which may be a path separated with '/'.
12955 * @return {string} The string value or null if not found.
12956 */
12957BoostInfoTree.prototype.getFirstValue = function(key)
12958{
12959 var list = this.get(key);
12960 if (list.length >= 1)
12961 return list[0].value;
12962 else
12963 return null;
12964};
12965
12966BoostInfoTree.prototype.getValue = function() { return this.value; };
12967
12968BoostInfoTree.prototype.getParent = function() { return this.parent; };
12969
12970BoostInfoTree.prototype.getLastChild = function() { return this.lastChild; };
12971
12972BoostInfoTree.prototype.prettyPrint = function(indentLevel)
12973{
12974 indentLevel = indentLevel || 1;
12975
12976 var prefix = Array(indentLevel + 1).join(' ');
12977 var s = "";
12978
12979 if (this.parent != null) {
12980 if (this.value && this.value.length > 0)
12981 s += "\"" + this.value + "\"";
12982 s += "\n";
12983 }
12984
12985 if (this.subtrees.length > 0) {
12986 if (this.parent)
12987 s += prefix + "{\n";
12988 var nextLevel = Array(indentLevel + 2 + 1).join(' ');
12989 for (var i = 0; i < this.subtrees.length; ++i) {
12990 for (var iSubTree = 0; iSubTree < this.subtrees[i].value.length; ++iSubTree)
12991 s += nextLevel + this.subtrees[i].key + " " +
12992 this.subtrees[i].value[iSubTree].prettyPrint(indentLevel + 2);
12993 }
12994
12995 if (this.parent)
12996 s += prefix + "}\n";
12997 }
12998
12999 return s;
13000};
13001
13002BoostInfoTree.prototype.toString = function()
13003{
13004 return this.prettyPrint();
13005};
13006
13007/**
13008 * Use treeName to find the array of BoostInfoTree in this.subtrees.
13009 * @param {string} treeName The key in this.subtrees to search for. This does a
13010 * flat search in subtrees_. It does not split by '/' into a path.
13011 * @return {Array<BoostInfoTree>} A array of BoostInfoTree, or null if not found.
13012 */
13013BoostInfoTree.prototype.find = function(treeName)
13014{
13015 for (var i = 0; i < this.subtrees.length; ++i) {
13016 if (this.subtrees[i].key == treeName)
13017 return this.subtrees[i].value;
13018 }
13019
13020 return null;
13021};
13022
13023/**
13024 * A BoostInfoParser reads files in Boost's INFO format and constructs a
13025 * BoostInfoTree.
13026 * @constructor
13027 */
13028var BoostInfoParser = function BoostInfoParser()
13029{
13030 this.root = new BoostInfoTree();
13031};
13032
13033exports.BoostInfoParser = BoostInfoParser;
13034exports.BoostInfoTree = BoostInfoTree; // debug
13035
13036/**
13037 * Add the contents of the file or input string to the root BoostInfoTree. There
13038 * are two forms:
13039 * read(fileName) reads fileName from the file system.
13040 * read(input, inputName) reads from the input, in which case inputName is used
13041 * only for log messages, etc.
13042 * @param {string} fileName The path to the INFO file.
13043 * @param {string} input The contents of the INFO file, with lines separated by
13044 * "\n" or "\r\n".
13045 * @param {string} inputName Use with input for log messages, etc.
13046 */
13047BoostInfoParser.prototype.read = function(fileNameOrInput, inputName)
13048{
13049 var input;
13050 if (typeof inputName == 'string')
13051 input = fileNameOrInput;
13052 else {
13053 // No inputName, so assume the first arg is the file name.
13054 var fileName = fileNameOrInput;
13055 inputName = fileName;
13056 input = fs.readFileSync(fileName).toString();
13057 }
13058
13059 var ctx = this.root;
13060 var thisParser = this;
13061 input.split(/\r?\n/).forEach(function(line) {
13062 ctx = thisParser.parseLine(line.trim(), ctx);
13063 });
13064};
13065
13066/**
13067 * Write the root tree of this BoostInfoParser as file in Boost's INFO format.
13068 * @param {string} fileName The output path.
13069 */
13070BoostInfoParser.prototype.write = function(fileName)
13071{
13072 fs.writeFileSync(fileName, "" + this.root);
13073};
13074
13075/**
13076 * Get the root tree of this parser.
13077 * @return {BoostInfoTree} The root BoostInfoTree.
13078 */
13079BoostInfoParser.prototype.getRoot = function() { return this.root; };
13080
13081/**
13082 * Similar to Python's shlex.split, split s into an array of strings which are
13083 * separated by whitespace, treating a string within quotes as a single entity
13084 * regardless of whitespace between the quotes. Also allow a backslash to escape
13085 * the next character.
13086 * @param {string} s The input string to split.
13087 * @return {Array<string>} An array of strings.
13088 */
13089BoostInfoParser.shlex_split = function(s)
13090{
13091 var result = [];
13092 if (s == "")
13093 return result;
13094 var whiteSpace = " \t\n\r";
13095 var iStart = 0;
13096
13097 while (true) {
13098 // Move iStart past whitespace.
13099 while (whiteSpace.indexOf(s[iStart]) >= 0) {
13100 iStart += 1;
13101 if (iStart >= s.length)
13102 // Done.
13103 return result;
13104 }
13105
13106 // Move iEnd to the end of the token.
13107 var iEnd = iStart;
13108 var inQuotation = false;
13109 var token = "";
13110 while (true) {
13111 if (s[iEnd] == '\\') {
13112 // Append characters up to the backslash, skip the backslash and
13113 // move iEnd past the escaped character.
13114 token += s.substring(iStart, iEnd);
13115 iStart = iEnd + 1;
13116 iEnd = iStart;
13117 if (iEnd >= s.length)
13118 // An unusual case: A backslash at the end of the string.
13119 break;
13120 }
13121 else {
13122 if (inQuotation) {
13123 if (s[iEnd] == '\"') {
13124 // Append characters up to the end quote and skip.
13125 token += s.substring(iStart, iEnd);
13126 iStart = iEnd + 1;
13127 inQuotation = false;
13128 }
13129 }
13130 else {
13131 if (s[iEnd] == '\"') {
13132 // Append characters up to the start quote and skip.
13133 token += s.substring(iStart, iEnd);
13134 iStart = iEnd + 1;
13135 inQuotation = true;
13136 }
13137 else
13138 if (whiteSpace.indexOf(s[iEnd]) >= 0)
13139 break;
13140 }
13141 }
13142
13143 iEnd += 1;
13144 if (iEnd >= s.length)
13145 break;
13146 }
13147
13148 token += s.substring(iStart, iEnd);
13149 result.push(token);
13150 if (iEnd >= s.length)
13151 // Done.
13152 return result;
13153
13154 iStart = iEnd;
13155 }
13156};
13157
13158BoostInfoParser.prototype.parseLine = function(line, context)
13159{
13160 // Skip blank lines and comments.
13161 var commentStart = line.indexOf(';');
13162 if (commentStart >= 0)
13163 line = line.substring(0, commentStart).trim();
13164 if (line.length == 0)
13165 return context;
13166
13167 // Usually we are expecting key and optional value.
13168 var strings = BoostInfoParser.shlex_split(line);
13169 var isSectionStart = false;
13170 var isSectionEnd = false;
13171 for (var i = 0; i < strings.length; ++i) {
13172 isSectionStart = (isSectionStart || strings[i] == "{");
13173 isSectionEnd = (isSectionEnd || strings[i] == "}");
13174 }
13175
13176 if (!isSectionStart && !isSectionEnd) {
13177 var key = strings[0];
13178 var val;
13179 if (strings.length > 1)
13180 val = strings[1];
13181 context.createSubtree(key, val);
13182
13183 return context;
13184 }
13185
13186 // OK, who is the joker who put a { on the same line as the key name?!
13187 var sectionStart = line.indexOf('{');
13188 if (sectionStart > 0) {
13189 var firstPart = line.substring(0, sectionStart);
13190 var secondPart = line.substring(sectionStart);
13191
13192 var ctx = this.parseLine(firstPart, context);
13193 return this.parseLine(secondPart, ctx);
13194 }
13195
13196 // If we encounter a {, we are beginning a new context.
13197 // TODO: Error if there was already a subcontext here.
13198 if (line[0] == '{') {
13199 context = context.getLastChild();
13200 return context;
13201 }
13202
13203 // If we encounter a }, we are ending a list context.
13204 if (line[0] == '}') {
13205 context = context.getParent();
13206 return context;
13207 }
13208
13209 throw runtime_error("BoostInfoParser: input line is malformed");
13210};
13211/**
13212 * Copyright (C) 2014-2016 Regents of the University of California.
13213 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
13214 *
13215 * This program is free software: you can redistribute it and/or modify
13216 * it under the terms of the GNU Lesser General Public License as published by
13217 * the Free Software Foundation, either version 3 of the License, or
13218 * (at your option) any later version.
13219 *
13220 * This program is distributed in the hope that it will be useful,
13221 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13222 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13223 * GNU Lesser General Public License for more details.
13224 *
13225 * You should have received a copy of the GNU Lesser General Public License
13226 * along with this program. If not, see <http://www.gnu.org/licenses/>.
13227 * A copy of the GNU Lesser General Public License is in the file COPYING.
13228 */
13229
13230/** @ignore */
13231var Name = require('../name.js').Name; /** @ignore */
13232var InterestFilter = require('../interest-filter.js').InterestFilter; /** @ignore */
13233var ForwardingFlags = require('../forwarding-flags.js').ForwardingFlags; /** @ignore */
13234var WireFormat = require('../encoding/wire-format.js').WireFormat; /** @ignore */
13235var LOG = require('../log.js').Log.LOG;
13236
13237/**
13238 * A MemoryContentCache holds a set of Data packets and answers an Interest to
13239 * return the correct Data packet. The cache is periodically cleaned up to
13240 * remove each stale Data packet based on its FreshnessPeriod (if it has one).
13241 * @note This class is an experimental feature. See the API docs for more detail at
13242 * http://named-data.net/doc/ndn-ccl-api/memory-content-cache.html .
13243 *
13244 * Create a new MemoryContentCache to use the given Face.
13245 *
13246 * @param {Face} face The Face to use to call registerPrefix and
13247 * setInterestFilter, and which will call this object's OnInterest callback.
13248 * @param {number} cleanupIntervalMilliseconds (optional) The interval
13249 * in milliseconds between each check to clean up stale content in the cache. If
13250 * omitted, use a default of 1000 milliseconds. If this is a large number, then
13251 * effectively the stale content will not be removed from the cache.
13252 * @constructor
13253 */
13254var MemoryContentCache = function MemoryContentCache
13255 (face, cleanupIntervalMilliseconds)
13256{
13257 cleanupIntervalMilliseconds = (cleanupIntervalMilliseconds || 1000.0);
13258
13259 this.face = face;
13260 this.cleanupIntervalMilliseconds = cleanupIntervalMilliseconds;
13261 this.nextCleanupTime = new Date().getTime() + cleanupIntervalMilliseconds;
13262
13263 this.onDataNotFoundForPrefix = {}; /**< The map key is the prefix.toUri().
13264 The value is an OnInterest function. */
13265 this.interestFilterIdList = []; /**< elements are number */
13266 this.registeredPrefixIdList = []; /**< elements are number */
13267 this.noStaleTimeCache = []; /**< elements are MemoryContentCache.Content */
13268 this.staleTimeCache = []; /**< elements are MemoryContentCache.StaleTimeContent */
13269 //StaleTimeContent::Compare contentCompare_;
13270 this.emptyComponent = new Name.Component();
13271 this.pendingInterestTable = [];
13272
13273 var thisMemoryContentCache = this;
13274 this.storePendingInterestCallback = function
13275 (localPrefix, localInterest, localFace, localInterestFilterId, localFilter) {
13276 thisMemoryContentCache.storePendingInterest(localInterest, localFace);
13277 };
13278};
13279
13280exports.MemoryContentCache = MemoryContentCache;
13281
13282/**
13283 * Call registerPrefix on the Face given to the constructor so that this
13284 * MemoryContentCache will answer interests whose name has the prefix.
13285 * Alternatively, if the Face's registerPrefix has already been called,
13286 * then you can call this object's setInterestFilter.
13287 * @param {Name} prefix The Name for the prefix to register. This copies the Name.
13288 * @param {function} onRegisterFailed If this fails to register the prefix for
13289 * any reason, this calls onRegisterFailed(prefix) where prefix is the prefix
13290 * given to registerPrefix.
13291 * NOTE: The library will log any exceptions thrown by this callback, but for
13292 * better error handling the callback should catch and properly handle any
13293 * exceptions.
13294 * @param {function} onRegisterSuccess (optional) When this receives a success
13295 * message, this calls onRegisterSuccess[0](prefix, registeredPrefixId). If
13296 * onRegisterSuccess is [null] or omitted, this does not use it. (As a special
13297 * case, this optional parameter is supplied as an array of one function,
13298 * instead of just a function, in order to detect when it is used instead of the
13299 * following optional onDataNotFound function.)
13300 * NOTE: The library will log any exceptions thrown by this callback, but for
13301 * better error handling the callback should catch and properly handle any
13302 * exceptions.
13303 * @param {function} onDataNotFound (optional) If a data packet for an interest
13304 * is not found in the cache, this forwards the interest by calling
13305 * onDataNotFound(prefix, interest, face, interestFilterId, filter). Your
13306 * callback can find the Data packet for the interest and call
13307 * face.putData(data). If your callback cannot find the Data packet, it can
13308 * optionally call storePendingInterest(interest, face) to store the pending
13309 * interest in this object to be satisfied by a later call to add(data). If you
13310 * want to automatically store all pending interests, you can simply use
13311 * getStorePendingInterest() for onDataNotFound. If onDataNotFound is omitted or
13312 * null, this does not use it.
13313 * NOTE: The library will log any exceptions thrown by this callback, but for
13314 * better error handling the callback should catch and properly handle any
13315 * exceptions.
13316 * @param {ForwardingFlags} flags (optional) See Face.registerPrefix.
13317 * @param {WireFormat} wireFormat (optional) See Face.registerPrefix.
13318 */
13319MemoryContentCache.prototype.registerPrefix = function
13320 (prefix, onRegisterFailed, onRegisterSuccess, onDataNotFound, flags, wireFormat)
13321{
13322 var arg3 = onRegisterSuccess;
13323 var arg4 = onDataNotFound;
13324 var arg5 = flags;
13325 var arg6 = wireFormat;
13326 // arg3, arg4, arg5, arg6 may be:
13327 // [OnRegisterSuccess], OnDataNotFound, ForwardingFlags, WireFormat
13328 // [OnRegisterSuccess], OnDataNotFound, ForwardingFlags, null
13329 // [OnRegisterSuccess], OnDataNotFound, WireFormat, null
13330 // [OnRegisterSuccess], OnDataNotFound, null, null
13331 // [OnRegisterSuccess], ForwardingFlags, WireFormat, null
13332 // [OnRegisterSuccess], ForwardingFlags, null, null
13333 // [OnRegisterSuccess], WireFormat, null, null
13334 // [OnRegisterSuccess], null, null, null
13335 // OnDataNotFound, ForwardingFlags, WireFormat, null
13336 // OnDataNotFound, ForwardingFlags, null, null
13337 // OnDataNotFound, WireFormat, null, null
13338 // OnDataNotFound, null, null, null
13339 // ForwardingFlags, WireFormat, null, null
13340 // ForwardingFlags, null, null, null
13341 // WireFormat, null, null, null
13342 // null, null, null, null
13343 if (typeof arg3 === "object" && arg3.length === 1 &&
13344 typeof arg3[0] === "function")
13345 onRegisterSuccess = arg3[0];
13346 else
13347 onRegisterSuccess = null;
13348
13349 if (typeof arg3 === "function")
13350 onDataNotFound = arg3;
13351 else if (typeof arg4 === "function")
13352 onDataNotFound = arg4;
13353 else
13354 onDataNotFound = null;
13355
13356 if (arg3 instanceof ForwardingFlags)
13357 flags = arg3;
13358 else if (arg4 instanceof ForwardingFlags)
13359 flags = arg4;
13360 else if (arg5 instanceof ForwardingFlags)
13361 flags = arg5;
13362 else
13363 flags = new ForwardingFlags();
13364
13365 if (arg3 instanceof WireFormat)
13366 wireFormat = arg3;
13367 else if (arg4 instanceof WireFormat)
13368 wireFormat = arg4;
13369 else if (arg5 instanceof WireFormat)
13370 wireFormat = arg5;
13371 else if (arg6 instanceof WireFormat)
13372 wireFormat = arg6;
13373 else
13374 wireFormat = WireFormat.getDefaultWireFormat();
13375
13376 if (onDataNotFound)
13377 this.onDataNotFoundForPrefix[prefix.toUri()] = onDataNotFound;
13378 var registeredPrefixId = this.face.registerPrefix
13379 (prefix, this.onInterest.bind(this), onRegisterFailed, onRegisterSuccess,
13380 flags, wireFormat);
13381 this.registeredPrefixIdList.push(registeredPrefixId);
13382};
13383
13384/**
13385 * Call setInterestFilter on the Face given to the constructor so that this
13386 * MemoryContentCache will answer interests whose name matches the filter.
13387 * There are two forms of setInterestFilter.
13388 * The first form uses the exact given InterestFilter:
13389 * setInterestFilter(filter, [onDataNotFound]).
13390 * The second form creates an InterestFilter from the given prefix Name:
13391 * setInterestFilter(prefix, [onDataNotFound]).
13392 * @param {InterestFilter} filter The InterestFilter with a prefix and optional
13393 * regex filter used to match the name of an incoming Interest. This makes a
13394 * copy of filter.
13395 * @param {Name} prefix The Name prefix used to match the name of an incoming
13396 * Interest.
13397 * @param {function} onDataNotFound (optional) If a data packet for an interest
13398 * is not found in the cache, this forwards the interest by calling
13399 * onDataNotFound(prefix, interest, face, interestFilterId, filter). Your
13400 * callback can find the Data packet for the interest and call
13401 * face.putData(data). If your callback cannot find the Data packet, it can
13402 * optionally call storePendingInterest(interest, face) to store the pending
13403 * interest in this object to be satisfied by a later call to add(data). If you
13404 * want to automatically store all pending interests, you can simply use
13405 * getStorePendingInterest() for onDataNotFound. If onDataNotFound is omitted or
13406 * null, this does not use it.
13407 * NOTE: The library will log any exceptions thrown by this callback, but for
13408 * better error handling the callback should catch and properly handle any
13409 * exceptions.
13410 */
13411MemoryContentCache.prototype.setInterestFilter = function
13412 (filterOrPrefix, onDataNotFound)
13413{
13414 if (onDataNotFound) {
13415 var prefix;
13416 if (typeof filterOrPrefix === 'object' && filterOrPrefix instanceof InterestFilter)
13417 prefix = filterOrPrefix.getPrefix();
13418 else
13419 prefix = filterOrPrefix;
13420 this.onDataNotFoundForPrefix[prefix.toUri()] = onDataNotFound;
13421 }
13422 var interestFilterId = this.face.setInterestFilter
13423 (filterOrPrefix, this.onInterest.bind(this));
13424 this.interestFilterIdList.push(interestFilterId);
13425};
13426
13427/**
13428 * Call Face.unsetInterestFilter and Face.removeRegisteredPrefix for all the
13429 * prefixes given to the setInterestFilter and registerPrefix method on this
13430 * MemoryContentCache object so that it will not receive interests any more. You
13431 * can call this if you want to "shut down" this MemoryContentCache while your
13432 * application is still running.
13433 */
13434MemoryContentCache.prototype.unregisterAll = function()
13435{
13436 for (var i = 0; i < this.interestFilterIdList.length; ++i)
13437 this.face.unsetInterestFilter(this.interestFilterIdList[i]);
13438 this.interestFilterIdList = [];
13439
13440 for (var i = 0; i < this.registeredPrefixIdList.length; ++i)
13441 this.face.removeRegisteredPrefix(this.registeredPrefixIdList[i]);
13442 this.registeredPrefixIdList = [];
13443
13444 // Also clear each onDataNotFoundForPrefix given to registerPrefix.
13445 this.onDataNotFoundForPrefix = {};
13446};
13447
13448/**
13449 * Add the Data packet to the cache so that it is available to use to answer
13450 * interests. If data.getMetaInfo().getFreshnessPeriod() is not null, set the
13451 * staleness time to now plus data.getMetaInfo().getFreshnessPeriod(), which is
13452 * checked during cleanup to remove stale content. This also checks if
13453 * cleanupIntervalMilliseconds milliseconds have passed and removes stale
13454 * content from the cache. After removing stale content, remove timed-out
13455 * pending interests from storePendingInterest(), then if the added Data packet
13456 * satisfies any interest, send it through the face and remove the interest
13457 * from the pending interest table.
13458 * @param {Data} data The Data packet object to put in the cache. This copies
13459 * the fields from the object.
13460 */
13461MemoryContentCache.prototype.add = function(data)
13462{
13463 this.doCleanup();
13464
13465 if (data.getMetaInfo().getFreshnessPeriod() != null &&
13466 data.getMetaInfo().getFreshnessPeriod() >= 0.0) {
13467 // The content will go stale, so use staleTimeCache.
13468 var content = new MemoryContentCache.StaleTimeContent(data);
13469 // Insert into staleTimeCache, sorted on content.staleTimeMilliseconds.
13470 // Search from the back since we expect it to go there.
13471 var i = this.staleTimeCache.length - 1;
13472 while (i >= 0) {
13473 if (this.staleTimeCache[i].staleTimeMilliseconds <= content.staleTimeMilliseconds)
13474 break;
13475 --i;
13476 }
13477 // Element i is the greatest less than or equal to
13478 // content.staleTimeMilliseconds, so insert after it.
13479 this.staleTimeCache.splice(i + 1, 0, content);
13480 }
13481 else
13482 // The data does not go stale, so use noStaleTimeCache.
13483 this.noStaleTimeCache.push(new MemoryContentCache.Content(data));
13484
13485 // Remove timed-out interests and check if the data packet matches any pending
13486 // interest.
13487 // Go backwards through the list so we can erase entries.
13488 var nowMilliseconds = new Date().getTime();
13489 for (var i = this.pendingInterestTable.length - 1; i >= 0; --i) {
13490 if (this.pendingInterestTable[i].isTimedOut(nowMilliseconds)) {
13491 this.pendingInterestTable.splice(i, 1);
13492 continue;
13493 }
13494 if (this.pendingInterestTable[i].getInterest().matchesName(data.getName())) {
13495 try {
13496 // Send to the same face from the original call to onInterest.
13497 // wireEncode returns the cached encoding if available.
13498 this.pendingInterestTable[i].getFace().send(data.wireEncode().buf());
13499 }
13500 catch (ex) {
13501 if (LOG > 0)
13502 console.log("" + ex);
13503 return;
13504 }
13505
13506 // The pending interest is satisfied, so remove it.
13507 this.pendingInterestTable.splice(i, 1);
13508 }
13509 }
13510};
13511
13512/**
13513 * Store an interest from an OnInterest callback in the internal pending
13514 * interest table (normally because there is no Data packet available yet to
13515 * satisfy the interest). add(data) will check if the added Data packet
13516 * satisfies any pending interest and send it through the face.
13517 * @param {Interest} interest The Interest for which we don't have a Data packet
13518 * yet. You should not modify the interest after calling this.
13519 * @param {Face} face The Face with the connection which received
13520 * the interest. This comes from the OnInterest callback.
13521 */
13522MemoryContentCache.prototype.storePendingInterest = function(interest, face)
13523{
13524 this.pendingInterestTable.push
13525 (new MemoryContentCache.PendingInterest(interest, face));
13526};
13527
13528/**
13529 * Return a callback to use for onDataNotFound in registerPrefix which simply
13530 * calls storePendingInterest() to store the interest that doesn't match a
13531 * Data packet. add(data) will check if the added Data packet satisfies any
13532 * pending interest and send it.
13533 * @return {function} A callback to use for onDataNotFound in registerPrefix().
13534 */
13535MemoryContentCache.prototype.getStorePendingInterest = function()
13536{
13537 return this.storePendingInterestCallback;
13538};
13539
13540/**
13541 * This is the OnInterest callback which is called when the library receives
13542 * an interest whose name has the prefix given to registerPrefix. First check
13543 * if cleanupIntervalMilliseconds milliseconds have passed and remove stale
13544 * content from the cache. Then search the cache for the Data packet, matching
13545 * any interest selectors including ChildSelector, and send the Data packet
13546 * to the face. If no matching Data packet is in the cache, call
13547 * the callback in onDataNotFoundForPrefix (if defined).
13548 */
13549MemoryContentCache.prototype.onInterest = function
13550 (prefix, interest, face, interestFilterId, filter)
13551{
13552 this.doCleanup();
13553
13554 var selectedComponent = 0;
13555 var selectedEncoding = null;
13556 // We need to iterate over both arrays.
13557 var totalSize = this.staleTimeCache.length + this.noStaleTimeCache.length;
13558 for (var i = 0; i < totalSize; ++i) {
13559 var content;
13560 if (i < this.staleTimeCache.length)
13561 content = this.staleTimeCache[i];
13562 else
13563 // We have iterated over the first array. Get from the second.
13564 content = this.noStaleTimeCache[i - this.staleTimeCache.length];
13565
13566 if (interest.matchesName(content.getName())) {
13567 if (interest.getChildSelector() < 0) {
13568 // No child selector, so send the first match that we have found.
13569 face.send(content.getDataEncoding());
13570 return;
13571 }
13572 else {
13573 // Update selectedEncoding based on the child selector.
13574 var component;
13575 if (content.getName().size() > interest.getName().size())
13576 component = content.getName().get(interest.getName().size());
13577 else
13578 component = this.emptyComponent;
13579
13580 var gotBetterMatch = false;
13581 if (selectedEncoding === null)
13582 // Save the first match.
13583 gotBetterMatch = true;
13584 else {
13585 if (interest.getChildSelector() == 0) {
13586 // Leftmost child.
13587 if (component.compare(selectedComponent) < 0)
13588 gotBetterMatch = true;
13589 }
13590 else {
13591 // Rightmost child.
13592 if (component.compare(selectedComponent) > 0)
13593 gotBetterMatch = true;
13594 }
13595 }
13596
13597 if (gotBetterMatch) {
13598 selectedComponent = component;
13599 selectedEncoding = content.getDataEncoding();
13600 }
13601 }
13602 }
13603 }
13604
13605 if (selectedEncoding !== null)
13606 // We found the leftmost or rightmost child.
13607 face.send(selectedEncoding);
13608 else {
13609 // Call the onDataNotFound callback (if defined).
13610 var onDataNotFound = this.onDataNotFoundForPrefix[prefix.toUri()];
13611 if (onDataNotFound)
13612 onDataNotFound(prefix, interest, face, interestFilterId, filter);
13613 }
13614};
13615
13616/**
13617 * Check if now is greater than nextCleanupTime and, if so, remove stale
13618 * content from staleTimeCache and reset nextCleanupTime based on
13619 * cleanupIntervalMilliseconds. Since add(Data) does a sorted insert into
13620 * staleTimeCache, the check for stale data is quick and does not require
13621 * searching the entire staleTimeCache.
13622 */
13623MemoryContentCache.prototype.doCleanup = function()
13624{
13625 var now = new Date().getTime();
13626 if (now >= this.nextCleanupTime) {
13627 // staleTimeCache is sorted on staleTimeMilliseconds, so we only need to
13628 // erase the stale entries at the front, then quit.
13629 while (this.staleTimeCache.length > 0 && this.staleTimeCache[0].isStale(now))
13630 this.staleTimeCache.shift();
13631
13632 this.nextCleanupTime = now + this.cleanupIntervalMilliseconds;
13633 }
13634};
13635
13636/**
13637 * Content is a private class to hold the name and encoding for each entry
13638 * in the cache. This base class is for a Data packet without a FreshnessPeriod.
13639 *
13640 * Create a new Content entry to hold data's name and wire encoding.
13641 * @param {Data} data The Data packet whose name and wire encoding are copied.
13642 */
13643MemoryContentCache.Content = function MemoryContentCacheContent(data)
13644{
13645 // Allow an undefined data so that StaleTimeContent can set the prototype.
13646 if (data) {
13647 // Copy the name.
13648 this.name = new Name(data.getName());
13649 // wireEncode returns the cached encoding if available.
13650 this.dataEncoding = data.wireEncode().buf();
13651 }
13652};
13653
13654MemoryContentCache.Content.prototype.getName = function() { return this.name; };
13655
13656MemoryContentCache.Content.prototype.getDataEncoding = function() { return this.dataEncoding; };
13657
13658/**
13659 * StaleTimeContent extends Content to include the staleTimeMilliseconds for
13660 * when this entry should be cleaned up from the cache.
13661 *
13662 * Create a new StaleTimeContent to hold data's name and wire encoding as well
13663 * as the staleTimeMilliseconds which is now plus
13664 * data.getMetaInfo().getFreshnessPeriod().
13665 * @param {Data} data The Data packet whose name and wire encoding are copied.
13666 */
13667MemoryContentCache.StaleTimeContent = function MemoryContentCacheStaleTimeContent
13668 (data)
13669{
13670 // Call the base constructor.
13671 MemoryContentCache.Content.call(this, data);
13672
13673 // Set up staleTimeMilliseconds which is The time when the content becomse
13674 // stale in milliseconds according to new Date().getTime().
13675 this.staleTimeMilliseconds = new Date().getTime() +
13676 data.getMetaInfo().getFreshnessPeriod();
13677};
13678
13679MemoryContentCache.StaleTimeContent.prototype = new MemoryContentCache.Content();
13680MemoryContentCache.StaleTimeContent.prototype.name = "StaleTimeContent";
13681
13682/**
13683 * Check if this content is stale.
13684 * @param {number} nowMilliseconds The current time in milliseconds from
13685 * new Date().getTime().
13686 * @return {boolean} True if this content is stale, otherwise false.
13687 */
13688MemoryContentCache.StaleTimeContent.prototype.isStale = function(nowMilliseconds)
13689{
13690 return this.staleTimeMilliseconds <= nowMilliseconds;
13691};
13692
13693/**
13694 * A PendingInterest holds an interest which onInterest received but could
13695 * not satisfy. When we add a new data packet to the cache, we will also check
13696 * if it satisfies a pending interest.
13697 */
13698MemoryContentCache.PendingInterest = function MemoryContentCachePendingInterest
13699 (interest, face)
13700{
13701 this.interest = interest;
13702 this.face = face;
13703
13704 if (this.interest.getInterestLifetimeMilliseconds() >= 0.0)
13705 this.timeoutMilliseconds = (new Date()).getTime() +
13706 this.interest.getInterestLifetimeMilliseconds();
13707 else
13708 this.timeoutMilliseconds = -1.0;
13709};
13710
13711/**
13712 * Return the interest given to the constructor.
13713 */
13714MemoryContentCache.PendingInterest.prototype.getInterest = function()
13715{
13716 return this.interest;
13717};
13718
13719/**
13720 * Return the face given to the constructor.
13721 */
13722MemoryContentCache.PendingInterest.prototype.getFace = function()
13723{
13724 return this.face;
13725};
13726
13727/**
13728 * Check if this interest is timed out.
13729 * @param {number} nowMilliseconds The current time in milliseconds from
13730 * new Date().getTime().
13731 * @return {boolean} True if this interest timed out, otherwise false.
13732 */
13733MemoryContentCache.PendingInterest.prototype.isTimedOut = function(nowMilliseconds)
13734{
13735 return this.timeoutTimeMilliseconds >= 0.0 &&
13736 nowMilliseconds >= this.timeoutTimeMilliseconds;
13737};
13738/**
13739 * Copyright (C) 2014-2016 Regents of the University of California.
13740 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
13741 * From PyNDN ndn_regex.py by Adeola Bannis.
13742 * Originally from Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>.
13743 *
13744 * This program is free software: you can redistribute it and/or modify
13745 * it under the terms of the GNU Lesser General Public License as published by
13746 * the Free Software Foundation, either version 3 of the License, or
13747 * (at your option) any later version.
13748 *
13749 * This program is distributed in the hope that it will be useful,
13750 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13751 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13752 * GNU Lesser General Public License for more details.
13753 *
13754 * You should have received a copy of the GNU Lesser General Public License
13755 * along with this program. If not, see <http://www.gnu.org/licenses/>.
13756 * A copy of the GNU Lesser General Public License is in the file COPYING.
13757 */
13758
13759/** @ignore */
13760var Name = require('../name.js').Name;
13761
13762/**
13763 * An NdnRegexMatcher has static methods to convert an NDN regex
13764 * (http://redmine.named-data.net/projects/ndn-cxx/wiki/Regex) to a JavaScript
13765 * RegExp that can match against URIs.
13766 * @constructor
13767 */
13768var NdnRegexMatcher = function NdnRegexMatcher()
13769{
13770};
13771
13772exports.NdnRegexMatcher = NdnRegexMatcher;
13773
13774/**
13775 * Determine if the provided NDN regex matches the given Name.
13776 * @param {string} pattern The NDN regex.
13777 * @param {Name} name The Name to match against the regex.
13778 * @return {Object} The match object from String.match, or null if the pattern
13779 * does not match.
13780 */
13781NdnRegexMatcher.match = function(pattern, name)
13782{
13783 var nameUri = name.toUri();
13784
13785 pattern = NdnRegexMatcher.sanitizeSets(pattern);
13786
13787 pattern = pattern.replace(/<>/g, "(?:<.+?>)");
13788 pattern = pattern.replace(/>/g, "");
13789 pattern = pattern.replace(/<(?!!)/g, "/");
13790
13791 return nameUri.match(new RegExp(pattern));
13792};
13793
13794NdnRegexMatcher.sanitizeSets = function(pattern)
13795{
13796 var newPattern = pattern;
13797
13798 // Positive sets can be changed to (comp1|comp2).
13799 // Negative sets must be changed to negative lookahead assertions.
13800
13801 var regex1 = /\[(\^?)(.*?)\]/g;
13802 var match;
13803 while ((match = regex1.exec(pattern)) !== null) {
13804 // Insert | between components.
13805 // Match 2 is the last match, so we use the hack of working backwards from
13806 // lastIndex. If possible, this should be changed to a more direct solution.
13807 var start = regex1.lastIndex - "]".length - match[2].length;
13808 var end = start + match[2].length;
13809 if (start - end === 0)
13810 continue;
13811 var oldStr = match[2];
13812 var newStr = oldStr.replace(/></g, ">|<");
13813 newPattern = newPattern.substr(0, start) + newStr + newPattern.substr(end);
13814 }
13815
13816 // Replace [] with (), or (?! ) for negative lookahead.
13817 // If we use negative lookahead, we also have to consume one component.
13818 var isNegative = newPattern.indexOf("[^") >= 0;
13819 if (isNegative) {
13820 newPattern = newPattern.replace(/\[\^/g, "(?:(?!");
13821 newPattern = newPattern.replace(/\]/g, ")(?:/.*)*)");
13822 }
13823 else {
13824 newPattern = newPattern.replace(/\[/g, "(");
13825 newPattern = newPattern.replace(/\]/g, ")");
13826 }
13827
13828 return newPattern;
13829};
13830/**
13831 * Copyright (C) 2015-2016 Regents of the University of California.
13832 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
13833 * @author: From ndn-cxx util/segment-fetcher https://github.com/named-data/ndn-cxx
13834 *
13835 * This program is free software: you can redistribute it and/or modify
13836 * it under the terms of the GNU Lesser General Public License as published by
13837 * the Free Software Foundation, either version 3 of the License, or
13838 * (at your option) any later version.
13839 *
13840 * This program is distributed in the hope that it will be useful,
13841 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13842 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13843 * GNU Lesser General Public License for more details.
13844 *
13845 * You should have received a copy of the GNU Lesser General Public License
13846 * along with this program. If not, see <http://www.gnu.org/licenses/>.
13847 * A copy of the GNU Lesser General Public License is in the file COPYING.
13848 */
13849
13850/** @ignore */
13851var Interest = require('../interest.js').Interest; /** @ignore */
13852var Blob = require('./blob.js').Blob; /** @ignore */
13853var KeyChain = require('../security/key-chain.js').KeyChain; /** @ignore */
13854var NdnCommon = require('./ndn-common.js').NdnCommon;
13855
13856/**
13857 * SegmentFetcher is a utility class to fetch the latest version of segmented data.
13858 *
13859 * SegmentFetcher assumes that the data is named /<prefix>/<version>/<segment>,
13860 * where:
13861 * - <prefix> is the specified name prefix,
13862 * - <version> is an unknown version that needs to be discovered, and
13863 * - <segment> is a segment number. (The number of segments is unknown and is
13864 * controlled by the `FinalBlockId` field in at least the last Data packet.
13865 *
13866 * The following logic is implemented in SegmentFetcher:
13867 *
13868 * 1. Express the first Interest to discover the version:
13869 *
13870 * >> Interest: /<prefix>?ChildSelector=1&MustBeFresh=true
13871 *
13872 * 2. Infer the latest version of the Data: <version> = Data.getName().get(-2)
13873 *
13874 * 3. If the segment number in the retrieved packet == 0, go to step 5.
13875 *
13876 * 4. Send an Interest for segment 0:
13877 *
13878 * >> Interest: /<prefix>/<version>/<segment=0>
13879 *
13880 * 5. Keep sending Interests for the next segment while the retrieved Data does
13881 * not have a FinalBlockId or the FinalBlockId != Data.getName().get(-1).
13882 *
13883 * >> Interest: /<prefix>/<version>/<segment=(N+1))>
13884 *
13885 * 6. Call the onComplete callback with a Blob that concatenates the content
13886 * from all the segmented objects.
13887 *
13888 * If an error occurs during the fetching process, the onError callback is called
13889 * with a proper error code. The following errors are possible:
13890 *
13891 * - `INTEREST_TIMEOUT`: if any of the Interests times out
13892 * - `DATA_HAS_NO_SEGMENT`: if any of the retrieved Data packets don't have a segment
13893 * as the last component of the name (not counting the implicit digest)
13894 * - `SEGMENT_VERIFICATION_FAILED`: if any retrieved segment fails
13895 * the user-provided VerifySegment callback or KeyChain verifyData.
13896 * - `IO_ERROR`: for I/O errors when sending an Interest.
13897 *
13898 * In order to validate individual segments, a KeyChain needs to be supplied.
13899 * If verifyData fails, the fetching process is aborted with
13900 * SEGMENT_VERIFICATION_FAILED. If data validation is not required, pass null.
13901 *
13902 * Example:
13903 * var onComplete = function(content) { ... }
13904 *
13905 * var onError = function(errorCode, message) { ... }
13906 *
13907 * var interest = new Interest(new Name("/data/prefix"));
13908 * interest.setInterestLifetimeMilliseconds(1000);
13909 *
13910 * SegmentFetcher.fetch(face, interest, null, onComplete, onError);
13911 *
13912 * This is a private constructor to create a new SegmentFetcher to use the Face.
13913 * An application should use SegmentFetcher.fetch. If validatorKeyChain is not
13914 * null, use it and ignore verifySegment. After creating the SegmentFetcher,
13915 * call fetchFirstSegment.
13916 * @param {Face} face This calls face.expressInterest to fetch more segments.
13917 * @param validatorKeyChain {KeyChain} If this is not null, use its verifyData
13918 * instead of the verifySegment callback.
13919 * @param {function} verifySegment When a Data packet is received this calls
13920 * verifySegment(data) where data is a Data object. If it returns False then
13921 * abort fetching and call onError with
13922 * SegmentFetcher.ErrorCode.SEGMENT_VERIFICATION_FAILED.
13923 * NOTE: The library will log any exceptions thrown by this callback, but for
13924 * better error handling the callback should catch and properly handle any
13925 * exceptions.
13926 * @param {function} onComplete When all segments are received, call
13927 * onComplete(content) where content is a Blob which has the concatenation of
13928 * the content of all the segments.
13929 * NOTE: The library will log any exceptions thrown by this callback, but for
13930 * better error handling the callback should catch and properly handle any
13931 * exceptions.
13932 * @param {function} onError Call onError.onError(errorCode, message) for
13933 * timeout or an error processing segments. errorCode is a value from
13934 * SegmentFetcher.ErrorCode and message is a related string.
13935 * NOTE: The library will log any exceptions thrown by this callback, but for
13936 * better error handling the callback should catch and properly handle any
13937 * exceptions.
13938 * @constructor
13939 */
13940var SegmentFetcher = function SegmentFetcher
13941 (face, validatorKeyChain, verifySegment, onComplete, onError)
13942{
13943 this.face = face;
13944 this.validatorKeyChain = validatorKeyChain;
13945 this.verifySegment = verifySegment;
13946 this.onComplete = onComplete;
13947 this.onError = onError;
13948
13949 this.contentParts = []; // of Buffer
13950};
13951
13952exports.SegmentFetcher = SegmentFetcher;
13953
13954/**
13955 * An ErrorCode value is passed in the onError callback.
13956 */
13957SegmentFetcher.ErrorCode = {
13958 INTEREST_TIMEOUT: 1,
13959 DATA_HAS_NO_SEGMENT: 2,
13960 SEGMENT_VERIFICATION_FAILED: 3
13961};
13962
13963/**
13964 * DontVerifySegment may be used in fetch to skip validation of Data packets.
13965 */
13966SegmentFetcher.DontVerifySegment = function(data)
13967{
13968 return true;
13969};
13970
13971/**
13972 * Initiate segment fetching. For more details, see the documentation for the
13973 * class. There are two forms of fetch:
13974 * fetch(face, baseInterest, validatorKeyChain, onComplete, onError)
13975 * and
13976 * fetch(face, baseInterest, verifySegment, onComplete, onError)
13977 * @param {Face} face This calls face.expressInterest to fetch more segments.
13978 * @param {Interest} baseInterest An Interest for the initial segment of the
13979 * requested data, where baseInterest.getName() has the name prefix. This
13980 * interest may include a custom InterestLifetime and selectors that will
13981 * propagate to all subsequent Interests. The only exception is that the initial
13982 * Interest will be forced to include selectors "ChildSelector=1" and
13983 * "MustBeFresh=true" which will be turned off in subsequent Interests.
13984 * @param validatorKeyChain {KeyChain} When a Data packet is received this calls
13985 * validatorKeyChain.verifyData(data). If validation fails then abortfetching
13986 * and call onError with SEGMENT_VERIFICATION_FAILED. This does not make a copy
13987 * of the KeyChain; the object must remain valid while fetching.
13988 * If validatorKeyChain is null, this does not validate the data packet.
13989 * @param {function} verifySegment When a Data packet is received this calls
13990 * verifySegment(data) where data is a Data object. If it returns False then
13991 * abort fetching and call onError with
13992 * SegmentFetcher.ErrorCode.SEGMENT_VERIFICATION_FAILED. If data validation is
13993 * not required, use SegmentFetcher.DontVerifySegment.
13994 * NOTE: The library will log any exceptions thrown by this callback, but for
13995 * better error handling the callback should catch and properly handle any
13996 * exceptions.
13997 * @param {function} onComplete When all segments are received, call
13998 * onComplete(content) where content is a Blob which has the concatenation of
13999 * the content of all the segments.
14000 * NOTE: The library will log any exceptions thrown by this callback, but for
14001 * better error handling the callback should catch and properly handle any
14002 * exceptions.
14003 * @param {function} onError Call onError.onError(errorCode, message) for
14004 * timeout or an error processing segments. errorCode is a value from
14005 * SegmentFetcher.ErrorCode and message is a related string.
14006 * NOTE: The library will log any exceptions thrown by this callback, but for
14007 * better error handling the callback should catch and properly handle any
14008 * exceptions.
14009 */
14010SegmentFetcher.fetch = function
14011 (face, baseInterest, validatorKeyChainOrVerifySegment, onComplete, onError)
14012{
14013 if (validatorKeyChainOrVerifySegment == null ||
14014 validatorKeyChainOrVerifySegment instanceof KeyChain)
14015 new SegmentFetcher
14016 (face, validatorKeyChainOrVerifySegment, SegmentFetcher.DontVerifySegment,
14017 onComplete, onError)
14018 .fetchFirstSegment(baseInterest);
14019 else
14020 new SegmentFetcher
14021 (face, null, validatorKeyChainOrVerifySegment, onComplete, onError)
14022 .fetchFirstSegment(baseInterest);
14023};
14024
14025SegmentFetcher.prototype.fetchFirstSegment = function(baseInterest)
14026{
14027 var interest = new Interest(baseInterest);
14028 interest.setChildSelector(1);
14029 interest.setMustBeFresh(true);
14030 var thisSegmentFetcher = this;
14031 this.face.expressInterest
14032 (interest,
14033 function(originalInterest, data)
14034 { thisSegmentFetcher.onData(originalInterest, data); },
14035 function(interest) { thisSegmentFetcher.onTimeout(interest); });
14036};
14037
14038SegmentFetcher.prototype.fetchNextSegment = function
14039 (originalInterest, dataName, segment)
14040{
14041 // Start with the original Interest to preserve any special selectors.
14042 var interest = new Interest(originalInterest);
14043 // Changing a field clears the nonce so that the library will generate a new
14044 // one.
14045 interest.setChildSelector(0);
14046 interest.setMustBeFresh(false);
14047 interest.setName(dataName.getPrefix(-1).appendSegment(segment));
14048 var thisSegmentFetcher = this;
14049 this.face.expressInterest
14050 (interest, function(originalInterest, data)
14051 { thisSegmentFetcher.onData(originalInterest, data); },
14052 function(interest) { thisSegmentFetcher.onTimeout(interest); });
14053};
14054
14055SegmentFetcher.prototype.onData = function(originalInterest, data)
14056{
14057 if (this.validatorKeyChain != null) {
14058 try {
14059 var thisSegmentFetcher = this;
14060 this.validatorKeyChain.verifyData
14061 (data,
14062 function(localData) {
14063 thisSegmentFetcher.onVerified(localData, originalInterest);
14064 },
14065 this.onValidationFailed.bind(this));
14066 } catch (ex) {
14067 console.log("Error in KeyChain.verifyData: " + ex);
14068 }
14069 }
14070 else {
14071 if (!this.verifySegment(data)) {
14072 try {
14073 this.onError
14074 (SegmentFetcher.ErrorCode.SEGMENT_VERIFICATION_FAILED,
14075 "Segment verification failed");
14076 } catch (ex) {
14077 console.log("Error in onError: " + NdnCommon.getErrorWithStackTrace(ex));
14078 }
14079 return;
14080 }
14081
14082 this.onVerified(data, originalInterest);
14083 }
14084};
14085
14086SegmentFetcher.prototype.onVerified = function(data, originalInterest)
14087{
14088 if (!SegmentFetcher.endsWithSegmentNumber(data.getName())) {
14089 // We don't expect a name without a segment number. Treat it as a bad packet.
14090 try {
14091 this.onError
14092 (SegmentFetcher.ErrorCode.DATA_HAS_NO_SEGMENT,
14093 "Got an unexpected packet without a segment number: " +
14094 data.getName().toUri());
14095 } catch (ex) {
14096 console.log("Error in onError: " + NdnCommon.getErrorWithStackTrace(ex));
14097 }
14098 }
14099 else {
14100 var currentSegment = 0;
14101 try {
14102 currentSegment = data.getName().get(-1).toSegment();
14103 }
14104 catch (ex) {
14105 try {
14106 this.onError
14107 (SegmentFetcher.ErrorCode.DATA_HAS_NO_SEGMENT,
14108 "Error decoding the name segment number " +
14109 data.getName().get(-1).toEscapedString() + ": " + ex);
14110 } catch (ex) {
14111 console.log("Error in onError: " + NdnCommon.getErrorWithStackTrace(ex));
14112 }
14113 return;
14114 }
14115
14116 var expectedSegmentNumber = this.contentParts.length;
14117 if (currentSegment != expectedSegmentNumber)
14118 // Try again to get the expected segment. This also includes the case
14119 // where the first segment is not segment 0.
14120 this.fetchNextSegment
14121 (originalInterest, data.getName(), expectedSegmentNumber);
14122 else {
14123 // Save the content and check if we are finished.
14124 this.contentParts.push(data.getContent().buf());
14125
14126 if (data.getMetaInfo().getFinalBlockId().getValue().size() > 0) {
14127 var finalSegmentNumber = 0;
14128 try {
14129 finalSegmentNumber = (data.getMetaInfo().getFinalBlockId().toSegment());
14130 }
14131 catch (ex) {
14132 try {
14133 this.onError
14134 (SegmentFetcher.ErrorCode.DATA_HAS_NO_SEGMENT,
14135 "Error decoding the FinalBlockId segment number " +
14136 data.getMetaInfo().getFinalBlockId().toEscapedString() +
14137 ": " + ex);
14138 } catch (ex) {
14139 console.log("Error in onError: " + NdnCommon.getErrorWithStackTrace(ex));
14140 }
14141 return;
14142 }
14143
14144 if (currentSegment == finalSegmentNumber) {
14145 // We are finished.
14146
14147 // Concatenate to get content.
14148 var content = Buffer.concat(this.contentParts);
14149 try {
14150 this.onComplete(new Blob(content, false));
14151 } catch (ex) {
14152 console.log("Error in onComplete: " + NdnCommon.getErrorWithStackTrace(ex));
14153 }
14154 return;
14155 }
14156 }
14157
14158 // Fetch the next segment.
14159 this.fetchNextSegment
14160 (originalInterest, data.getName(), expectedSegmentNumber + 1);
14161 }
14162 }
14163}
14164
14165SegmentFetcher.prototype.onValidationFailed = function(data, reason)
14166{
14167 try {
14168 this.onError
14169 (SegmentFetcher.ErrorCode.SEGMENT_VERIFICATION_FAILED,
14170 "Segment verification failed for " + data.getName().toUri() +
14171 " . Reason: " + reason);
14172 } catch (ex) {
14173 console.log("Error in onError: " + NdnCommon.getErrorWithStackTrace(ex));
14174 }
14175};
14176
14177SegmentFetcher.prototype.onTimeout = function(interest)
14178{
14179 try {
14180 this.onError
14181 (SegmentFetcher.ErrorCode.INTEREST_TIMEOUT,
14182 "Time out for interest " + interest.getName().toUri());
14183 } catch (ex) {
14184 console.log("Error in onError: " + NdnCommon.getErrorWithStackTrace(ex));
14185 }
14186};
14187
14188/**
14189 * Check if the last component in the name is a segment number.
14190 * @param {Name} name The name to check.
14191 * @return {boolean} True if the name ends with a segment number, otherwise false.
14192 */
14193SegmentFetcher.endsWithSegmentNumber = function(name)
14194{
14195 return name.size() >= 1 && name.get(-1).isSegment();
14196};
14197/**
14198 * Copyright (C) 2014-2016 Regents of the University of California.
14199 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
14200 *
14201 * This program is free software: you can redistribute it and/or modify
14202 * it under the terms of the GNU Lesser General Public License as published by
14203 * the Free Software Foundation, either version 3 of the License, or
14204 * (at your option) any later version.
14205 *
14206 * This program is distributed in the hope that it will be useful,
14207 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14208 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14209 * GNU Lesser General Public License for more details.
14210 *
14211 * You should have received a copy of the GNU Lesser General Public License
14212 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14213 * A copy of the GNU Lesser General Public License is in the file COPYING.
14214 */
14215
14216/**
14217 * Transport is a base class for specific transport classes such as TcpTransport.
14218 * @constructor
14219 */
14220var Transport = function Transport()
14221{
14222};
14223
14224exports.Transport = Transport;
14225
14226/**
14227 * Transport.ConnectionInfo is a base class for connection information used by
14228 * subclasses of Transport.
14229 */
14230Transport.ConnectionInfo = function TransportConnectionInfo()
14231{
14232};
14233
14234/**
14235 * Determine whether this transport connecting according to connectionInfo is to
14236 * a node on the current machine. This affects the processing of
14237 * Face.registerPrefix(): if the NFD is local, registration occurs with the
14238 * '/localhost/nfd...' prefix; if non-local, the library will attempt to use
14239 * remote prefix registration using '/localhop/nfd...'
14240 * @param {Transport.ConnectionInfo} connectionInfo A ConnectionInfo with the
14241 * host to check.
14242 * @param {function} onResult On success, this calls onResult(isLocal) where
14243 * isLocal is true if the host is local, false if not. We use callbacks because
14244 * this may need to do an asynchronous DNS lookup.
14245 * @param {function} onError On failure for DNS lookup or other error, this
14246 * calls onError(message) where message is an error string.
14247 */
14248Transport.prototype.isLocal = function(connectionInfo, onResult, onError)
14249{
14250 onError("Transport.isLocal is not implemented");
14251};
14252/**
14253 * Copyright (C) 2016 Regents of the University of California.
14254 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
14255 * @author: Wentao Shang
14256 *
14257 * This program is free software: you can redistribute it and/or modify
14258 * it under the terms of the GNU Lesser General Public License as published by
14259 * the Free Software Foundation, either version 3 of the License, or
14260 * (at your option) any later version.
14261 *
14262 * This program is distributed in the hope that it will be useful,
14263 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14264 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14265 * GNU Lesser General Public License for more details.
14266 *
14267 * You should have received a copy of the GNU Lesser General Public License
14268 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14269 * A copy of the GNU Lesser General Public License is in the file COPYING.
14270 */
14271
14272/**
14273 * A MicroForwarderTransport extends Transport to connect to the browser's
14274 * micro forwarder service. This assumes that the MicroForwarder extensions has
14275 * been installed.
14276 * @constructor
14277 */
14278var MicroForwarderTransport = function MicroForwarderTransport()
14279{
14280 // Call the base constructor.
14281 Transport.call(this);
14282
14283 this.elementReader = null;
14284 this.connectionInfo = null; // Read by Face.
14285 this.onReceivedObject = null;
14286
14287 var thisTransport = this;
14288 window.addEventListener("message", function(event) {
14289 // We only accept messages from ourselves
14290 if (event.source != window)
14291 return;
14292
14293 if (event.data.type && (event.data.type == "FromMicroForwarderStub")) {
14294 var obj = event.data.object;
14295 if (obj.type && obj.type == "Buffer") {
14296 if (thisTransport.elementReader != null)
14297 thisTransport.elementReader.onReceivedData(new Buffer(obj.data));
14298 }
14299 else {
14300 if (thisTransport.onReceivedObject)
14301 thisTransport.onReceivedObject(obj);
14302 }
14303 }
14304 }, false);
14305};
14306
14307MicroForwarderTransport.prototype = new Transport();
14308MicroForwarderTransport.prototype.name = "MicroForwarderTransport";
14309
14310/**
14311 * Create a new MicroForwarderTransport.ConnectionInfo which extends
14312 * Transport.ConnectionInfo to hold info for the micro forwarer connection.
14313 */
14314MicroForwarderTransport.ConnectionInfo = function MicroForwarderTransportConnectionInfo()
14315{
14316 // Call the base constructor.
14317 Transport.ConnectionInfo .call(this);
14318};
14319
14320MicroForwarderTransport.ConnectionInfo.prototype = new Transport.ConnectionInfo();
14321MicroForwarderTransport.ConnectionInfo.prototype.name = "MicroForwarderTransport.ConnectionInfo";
14322
14323/**
14324 * Check if the fields of this MicroForwarderTransport.ConnectionInfo equal the other
14325 * MicroForwarderTransport.ConnectionInfo.
14326 * @param {MicroForwarderTransport.ConnectionInfo} The other object to check.
14327 * @return {boolean} True if the objects have equal fields, false if not.
14328 */
14329MicroForwarderTransport.ConnectionInfo.prototype.equals = function(other)
14330{
14331 if (other == null)
14332 return false;
14333 return true;
14334};
14335
14336MicroForwarderTransport.ConnectionInfo.prototype.toString = function()
14337{
14338 return "{}";
14339};
14340
14341/**
14342 * Set the onReceivedObject callback, replacing any previous callback.
14343 * @param {function} onReceivedObject (optional) If supplied and the received
14344 * object type field is not "Buffer" then just call this.onReceivedObject(obj).
14345 * If this is null, then don't call it.
14346 */
14347MicroForwarderTransport.prototype.setOnReceivedObject = function(onReceivedObject)
14348{
14349 this.onReceivedObject = onReceivedObject;
14350}
14351
14352/**
14353 * Determine whether this transport connecting according to connectionInfo is to
14354 * a node on the current machine. Unix transports are always local.
14355 * @param {MicroForwarderTransport.ConnectionInfo} connectionInfo This is ignored.
14356 * @param {function} onResult This calls onResult(true) because micro forwarder
14357 * transports are always local.
14358 * @param {function} onError This is ignored.
14359 */
14360MicroForwarderTransport.prototype.isLocal = function(connectionInfo, onResult, onError)
14361{
14362 onResult(true);
14363};
14364
14365/**
14366 * Connect to the micro forwarder according to the info in connectionInfo.
14367 * Listen on the connection to read an entire packet element and call
14368 * elementListener.onReceivedElement(element). However, if the received object
14369 * type field is not "Buffer" then just call this.onReceivedObject(obj).
14370 * @param {MicroForwarderTransport.ConnectionInfo} connectionInfo
14371 * @param {object} elementListener The elementListener with function
14372 * onReceivedElement which must remain valid during the life of this object.
14373 * @param {function} onopenCallback Once connected, call onopenCallback().
14374 * @param {function} onclosedCallback (optional) If the connection is closed by
14375 * the remote host, call onclosedCallback(). If omitted or null, don't call it.
14376 */
14377MicroForwarderTransport.prototype.connect = function
14378 (connectionInfo, elementListener, onopenCallback, onclosedCallback)
14379{
14380 // The window listener is already set up.
14381 this.elementReader = new ElementReader(elementListener);
14382 this.connectionInfo = connectionInfo;
14383 onopenCallback();
14384};
14385
14386/**
14387 * Send the JavaScript over the connection created by connect.
14388 * @param {object} obj The object to send. It should have a field "type". If
14389 * "type" is "Buffer" then it is processed like an NDN packet.
14390 */
14391MicroForwarderTransport.prototype.sendObject = function(obj)
14392{
14393 window.postMessage({
14394 type: "FromMicroForwarderTransport",
14395 object: obj
14396 }, "*");
14397};
14398
14399/**
14400 * Send the buffer over the connection created by connect.
14401 * @param {Buffer} buffer The bytes to send.
14402 */
14403MicroForwarderTransport.prototype.send = function(buffer)
14404{
14405 if (this.connectionInfo == null) {
14406 console.log("MicroForwarderTransport connection is not established.");
14407 return;
14408 }
14409
14410 this.sendObject(buffer.toJSON());
14411};
14412/**
14413 * Copyright (C) 2016 Regents of the University of California.
14414 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
14415 * @author: Wentao Shang
14416 *
14417 * This program is free software: you can redistribute it and/or modify
14418 * it under the terms of the GNU Lesser General Public License as published by
14419 * the Free Software Foundation, either version 3 of the License, or
14420 * (at your option) any later version.
14421 *
14422 * This program is distributed in the hope that it will be useful,
14423 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14424 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14425 * GNU Lesser General Public License for more details.
14426 *
14427 * You should have received a copy of the GNU Lesser General Public License
14428 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14429 * A copy of the GNU Lesser General Public License is in the file COPYING.
14430 */
14431
14432/**
14433 * A RuntimePortTransport extends Transport to connect to a WebExtensions
14434 * runtime.port.
14435 * @param {function} onReceivedObject (optional) If supplied and the received
14436 * object type field is not "Buffer" then just call this.onReceivedObject(obj).
14437 * If this is null, then don't call it.
14438 * @constructor
14439 */
14440var RuntimePortTransport = function RuntimePortTransport(onReceivedObject)
14441{
14442 // Call the base constructor.
14443 Transport.call(this);
14444
14445 this.elementReader = null;
14446 this.connectionInfo = null; // Read by Face.
14447 this.onReceivedObject = onReceivedObject;
14448 this.port = null;
14449};
14450
14451RuntimePortTransport.prototype = new Transport();
14452RuntimePortTransport.prototype.name = "RuntimePortTransport";
14453
14454/**
14455 * Create a new RuntimePortTransport.ConnectionInfo which extends
14456 * Transport.ConnectionInfo to hold the runtime.port used to connect.
14457 * @param {runtime.port} port The runtime.port object.
14458 */
14459RuntimePortTransport.ConnectionInfo = function RuntimePortTransportConnectionInfo
14460 (port)
14461{
14462 // Call the base constructor.
14463 Transport.ConnectionInfo .call(this);
14464
14465 this.port = port;
14466};
14467
14468RuntimePortTransport.ConnectionInfo.prototype = new Transport.ConnectionInfo();
14469RuntimePortTransport.ConnectionInfo.prototype.name = "RuntimePortTransport.ConnectionInfo";
14470
14471/**
14472 * Check if the fields of this RuntimePortTransport.ConnectionInfo equal the other
14473 * RuntimePortTransport.ConnectionInfo.
14474 * @param {RuntimePortTransport.ConnectionInfo} The other object to check.
14475 * @return {boolean} True if the objects have equal fields, false if not.
14476 */
14477RuntimePortTransport.ConnectionInfo.prototype.equals = function(other)
14478{
14479 if (other == null || other.port == undefined)
14480 return false;
14481 return this.port == other.port;
14482};
14483
14484RuntimePortTransport.ConnectionInfo.prototype.toString = function()
14485{
14486 return "{}";
14487};
14488
14489/**
14490 * Set the onReceivedObject callback, replacing any previous callback.
14491 * @param {function} onReceivedObject (optional) If supplied and the received
14492 * object type field is not "Buffer" then just call this.onReceivedObject(obj).
14493 * If this is null, then don't call it.
14494 */
14495RuntimePortTransport.prototype.setOnReceivedObject = function(onReceivedObject)
14496{
14497 this.onReceivedObject = onReceivedObject;
14498}
14499
14500/**
14501 * Determine whether this transport connecting according to connectionInfo is to
14502 * a node on the current machine. RuntimePortTransport is always local.
14503 * @param {RuntimePortTransport.ConnectionInfo} connectionInfo This is ignored.
14504 * @param {function} onResult This calls onResult(true) because a runtime.port
14505 * is always local.
14506 * @param {function} onError This is ignored.
14507 */
14508RuntimePortTransport.prototype.isLocal = function(connectionInfo, onResult, onError)
14509{
14510 onResult(true);
14511};
14512
14513/**
14514 * Connect to the runtime.port in connectionInfo. For a received object obj, if
14515 * obj.type is "Buffer", read an entire packet element from obj.data and call
14516 * elementListener.onReceivedElement(element). Otherwise just call
14517 * onReceivedObject(obj) using the callback given to the constructor.
14518 * @param {RuntimePortTransport.ConnectionInfo} connectionInfo The
14519 * ConnectionInfo with the runtime.port.
14520 * @param {object} elementListener The elementListener with function
14521 * onReceivedElement which must remain valid during the life of this object.
14522 * @param {function} onOpenCallback Once connected, call onOpenCallback().
14523 * @param {function} onClosedCallback (optional) If the connection is closed by
14524 * the remote host, call onClosedCallback(). If omitted or null, don't call it.
14525 */
14526RuntimePortTransport.prototype.connect = function
14527 (connectionInfo, elementListener, onOpenCallback, onClosedCallback)
14528{
14529 // The window listener is already set up.
14530 this.elementReader = new ElementReader(elementListener);
14531 this.connectionInfo = connectionInfo;
14532 this.port = this.connectionInfo.port;
14533
14534 // Add a listener to wait for a message object from the tab
14535 var thisTransport = this;
14536 this.port.onMessage.addListener(function(obj) {
14537 if (obj.type == "Buffer")
14538 thisTransport.elementReader.onReceivedData
14539 (Buffer.isBuffer(obj.data) ? obj.data : new Buffer(obj.data));
14540 else {
14541 if (thisTransport.onReceivedObject != null)
14542 thisTransport.onReceivedObject(obj);
14543 }
14544 });
14545
14546 this.port.onDisconnect.addListener(function() {
14547 thisTransport.port = null;
14548 if (onClosedCallback != null)
14549 onClosedCallback();
14550 });
14551
14552 onOpenCallback();
14553};
14554
14555/**
14556 * Send the JavaScript object over the connection created by connect.
14557 * @param {object} obj The object to send. If it is a JSON Buffer then it is
14558 * processed like an NDN packet.
14559 */
14560RuntimePortTransport.prototype.sendObject = function(obj)
14561{
14562 if (this.port == null) {
14563 console.log("RuntimePortTransport connection is not established.");
14564 return;
14565 }
14566
14567 this.port.postMessage(obj);
14568};
14569
14570/**
14571 * Send the buffer over the connection created by connect.
14572 * @param {Buffer} buffer The bytes to send.
14573 */
14574RuntimePortTransport.prototype.send = function(buffer)
14575{
14576 this.sendObject(buffer.toJSON());
14577};
14578/**
14579 * Copyright (C) 2013-2016 Regents of the University of California.
14580 * @author: Wentao Shang
14581 *
14582 * This program is free software: you can redistribute it and/or modify
14583 * it under the terms of the GNU Lesser General Public License as published by
14584 * the Free Software Foundation, either version 3 of the License, or
14585 * (at your option) any later version.
14586 *
14587 * This program is distributed in the hope that it will be useful,
14588 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14589 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14590 * GNU Lesser General Public License for more details.
14591 *
14592 * You should have received a copy of the GNU Lesser General Public License
14593 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14594 * A copy of the GNU Lesser General Public License is in the file COPYING.
14595 */
14596
14597/** @ignore */
14598var ElementReader = require('../encoding/element-reader.js').ElementReader; /** @ignore */
14599var LOG = require('../log.js').Log.LOG; /** @ignore */
14600var Transport = require('./transport.js').Transport; /** @ignore */
14601var Face;
14602
14603/**
14604 * @constructor
14605 */
14606var WebSocketTransport = function WebSocketTransport()
14607{
14608 // Call the base constructor.
14609 Transport.call(this);
14610
14611 if (!WebSocket)
14612 throw new Error("WebSocket support is not available on this platform.");
14613
14614 this.ws = null;
14615 this.connectionInfo = null; // Read by Face.
14616 this.elementReader = null;
14617 this.defaultGetConnectionInfo = Face.makeShuffledHostGetConnectionInfo
14618 (["A.ws.ndn.ucla.edu", "B.ws.ndn.ucla.edu", "C.ws.ndn.ucla.edu", "D.ws.ndn.ucla.edu",
14619 "E.ws.ndn.ucla.edu", "F.ws.ndn.ucla.edu", "G.ws.ndn.ucla.edu", "H.ws.ndn.ucla.edu",
14620 "I.ws.ndn.ucla.edu", "J.ws.ndn.ucla.edu", "K.ws.ndn.ucla.edu", "L.ws.ndn.ucla.edu",
14621 "M.ws.ndn.ucla.edu", "N.ws.ndn.ucla.edu"],
14622 9696,
14623 function(host, port) { return new WebSocketTransport.ConnectionInfo(host, port); });
14624};
14625
14626WebSocketTransport.prototype = new Transport();
14627WebSocketTransport.prototype.name = "WebSocketTransport";
14628
14629WebSocketTransport.importFace = function(face){
14630 Face = face;
14631};
14632
14633exports.WebSocketTransport = WebSocketTransport;
14634
14635/**
14636 * Create a new WebSocketTransport.ConnectionInfo which extends
14637 * Transport.ConnectionInfo to hold the host and port info for the WebSocket
14638 * connection.
14639 * @param {string} host The host for the connection. However, if the host string
14640 * begins with "ws:" or "wss:", then ignore port and use the string as the full
14641 * endpoint URI.
14642 * @param {number} port (optional) The port number for the connection. If
14643 * omitted, use 9696.
14644 */
14645WebSocketTransport.ConnectionInfo = function WebSocketTransportConnectionInfo
14646 (host, port)
14647{
14648 // Call the base constructor.
14649 Transport.ConnectionInfo .call(this);
14650
14651 port = (port !== undefined ? port : 9696);
14652
14653 this.host = host;
14654 this.port = port;
14655};
14656
14657WebSocketTransport.ConnectionInfo.prototype = new Transport.ConnectionInfo();
14658WebSocketTransport.ConnectionInfo.prototype.name = "WebSocketTransport.ConnectionInfo";
14659
14660/**
14661 * Check if the fields of this WebSocketTransport.ConnectionInfo equal the other
14662 * WebSocketTransport.ConnectionInfo.
14663 * @param {WebSocketTransport.ConnectionInfo} The other object to check.
14664 * @return {boolean} True if the objects have equal fields, false if not.
14665 */
14666WebSocketTransport.ConnectionInfo.prototype.equals = function(other)
14667{
14668 if (other == null || other.host == undefined || other.port == undefined)
14669 return false;
14670 return this.host == other.host && this.port == other.port;
14671};
14672
14673WebSocketTransport.ConnectionInfo.prototype.toString = function()
14674{
14675 if (this.hostIsUri())
14676 return "{ uri: " + this.host + " }";
14677 else
14678 return "{ host: " + this.host + ", port: " + this.port + " }";
14679};
14680
14681WebSocketTransport.ConnectionInfo.prototype.hostIsUri = function()
14682{
14683 return this.host.substr(0, 3) == "ws:" ||
14684 this.host.substr(0, 4) == "wss:";
14685}
14686
14687/**
14688 * Determine whether this transport connecting according to connectionInfo is to
14689 * a node on the current machine. WebSocket transports are always non-local.
14690 * @param {WebSocketTransport.ConnectionInfo} connectionInfo This is ignored.
14691 * @param {function} onResult This calls onResult(false) because WebSocket
14692 * transports are always non-local.
14693 * @param {function} onError This is ignored.
14694 */
14695WebSocketTransport.prototype.isLocal = function(connectionInfo, onResult, onError)
14696{
14697 onResult(false);
14698};
14699
14700/**
14701 * Connect to a WebSocket according to the info in connectionInfo. Listen on
14702 * the port to read an entire packet element and call
14703 * elementListener.onReceivedElement(element). Note: this connect method
14704 * previously took a Face object which is deprecated and renamed as the method
14705 * connectByFace.
14706 * @param {WebSocketTransport.ConnectionInfo} connectionInfo A
14707 * WebSocketTransport.ConnectionInfo.
14708 * @param {object} elementListener The elementListener with function
14709 * onReceivedElement which must remain valid during the life of this object.
14710 * @param {function} onopenCallback Once connected, call onopenCallback().
14711 * @param {function} onclosedCallback (optional) If the connection is closed by
14712 * the remote host, call onclosedCallback(). If omitted or null, don't call it.
14713 */
14714WebSocketTransport.prototype.connect = function
14715 (connectionInfo, elementListener, onopenCallback, onclosedCallback)
14716{
14717 this.close();
14718
14719 var uri = connectionInfo.hostIsUri() ?
14720 connectionInfo.host : 'ws://' + connectionInfo.host + ':' + connectionInfo.port;
14721 this.ws = new WebSocket(uri);
14722 if (LOG > 0) console.log('ws connection created.');
14723 this.connectionInfo = connectionInfo;
14724
14725 this.ws.binaryType = "arraybuffer";
14726
14727 this.elementReader = new ElementReader(elementListener);
14728 var self = this;
14729 this.ws.onmessage = function(ev) {
14730 var result = ev.data;
14731 //console.log('RecvHandle called.');
14732
14733 if (result == null || result == undefined || result == "") {
14734 console.log('INVALID ANSWER');
14735 }
14736 else if (result instanceof ArrayBuffer) {
14737 // The Buffer constructor expects an instantiated array.
14738 var bytearray = new Buffer(new Uint8Array(result));
14739
14740 if (LOG > 3) console.log('BINARY RESPONSE IS ' + bytearray.toString('hex'));
14741
14742 try {
14743 // Find the end of the element and call onReceivedElement.
14744 self.elementReader.onReceivedData(bytearray);
14745 } catch (ex) {
14746 console.log("NDN.ws.onmessage exception: " + ex);
14747 return;
14748 }
14749 }
14750 }
14751
14752 this.ws.onopen = function(ev) {
14753 if (LOG > 3) console.log(ev);
14754 if (LOG > 3) console.log('ws.onopen: WebSocket connection opened.');
14755 if (LOG > 3) console.log('ws.onopen: ReadyState: ' + this.readyState);
14756 // Face.registerPrefix will fetch the ndndid when needed.
14757
14758 onopenCallback();
14759 }
14760
14761 this.ws.onerror = function(ev) {
14762 console.log('ws.onerror: ReadyState: ' + this.readyState);
14763 console.log(ev);
14764 console.log('ws.onerror: WebSocket error: ' + ev.data);
14765 }
14766
14767 this.ws.onclose = function(ev) {
14768 console.log('ws.onclose: WebSocket connection closed.');
14769 self.ws = null;
14770
14771 if (onclosedCallback != null)
14772 onclosedCallback();
14773 }
14774};
14775
14776/**
14777 * @deprecated This is deprecated. You should not call Transport.connect
14778 * directly, since it is called by Face methods.
14779 */
14780WebSocketTransport.prototype.connectByFace = function(face, onopenCallback)
14781{
14782 this.connect
14783 (face.connectionInfo, face, onopenCallback,
14784 function() { face.closeByTransport(); });
14785};
14786
14787/**
14788 * Send the Uint8Array data.
14789 */
14790WebSocketTransport.prototype.send = function(data)
14791{
14792 if (this.ws != null) {
14793 // If we directly use data.buffer to feed ws.send(),
14794 // WebSocket may end up sending a packet with 10000 bytes of data.
14795 // That is, WebSocket will flush the entire buffer
14796 // regardless of the offset of the Uint8Array. So we have to create
14797 // a new Uint8Array buffer with just the right size and copy the
14798 // content from binaryInterest to the new buffer.
14799 // ---Wentao
14800 var bytearray = new Uint8Array(data.length);
14801 bytearray.set(data);
14802 this.ws.send(bytearray.buffer);
14803 if (LOG > 3) console.log('ws.send() returned.');
14804 }
14805 else
14806 console.log('WebSocket connection is not established.');
14807};
14808
14809/**
14810 * Close the connection.
14811 */
14812WebSocketTransport.prototype.close = function()
14813{
14814 if (this.ws != null)
14815 delete this.ws;
14816}
14817
14818/**
14819 * Copyright (C) 2013-2016 Regents of the University of California.
14820 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
14821 *
14822 * This program is free software: you can redistribute it and/or modify
14823 * it under the terms of the GNU Lesser General Public License as published by
14824 * the Free Software Foundation, either version 3 of the License, or
14825 * (at your option) any later version.
14826 *
14827 * This program is distributed in the hope that it will be useful,
14828 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14829 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14830 * GNU Lesser General Public License for more details.
14831 *
14832 * You should have received a copy of the GNU Lesser General Public License
14833 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14834 * A copy of the GNU Lesser General Public License is in the file COPYING.
14835 */
14836
14837// The Face constructor uses TcpTransport by default which is not available in the browser, so override to WebSocketTransport.
14838exports.TcpTransport = require("./transport/web-socket-transport").WebSocketTransport;
14839/**
14840 * This class represents a Name as an array of components where each is a byte array.
14841 * Copyright (C) 2013-2016 Regents of the University of California.
14842 * @author: Meki Cheraoui, Jeff Thompson <jefft0@remap.ucla.edu>
14843 *
14844 * This program is free software: you can redistribute it and/or modify
14845 * it under the terms of the GNU Lesser General Public License as published by
14846 * the Free Software Foundation, either version 3 of the License, or
14847 * (at your option) any later version.
14848 *
14849 * This program is distributed in the hope that it will be useful,
14850 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14851 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14852 * GNU Lesser General Public License for more details.
14853 *
14854 * You should have received a copy of the GNU Lesser General Public License
14855 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14856 * A copy of the GNU Lesser General Public License is in the file COPYING.
14857 */
14858
14859/** @ignore */
14860var Blob = require('./util/blob.js').Blob; /** @ignore */
14861var DataUtils = require('./encoding/data-utils.js').DataUtils; /** @ignore */
14862var LOG = require('./log.js').Log.LOG;
14863var DecodingException = require('./encoding/decoding-exception.js').DecodingException;
14864
14865/**
14866 * Create a new Name from components.
14867 *
14868 * @constructor
14869 * @param {string|Name|Array<string|Array<number>|ArrayBuffer|Buffer|Name>} components if a string, parse it as a URI. If a Name, add a deep copy of its components.
14870 * Otherwise it is an array of components which are appended according to Name.append, so
14871 * convert each and store it as an array of Buffer. If a component is a string, encode as utf8.
14872 */
14873var Name = function Name(components)
14874{
14875 if (typeof components == 'string') {
14876 if (LOG > 3) console.log('Content Name String ' + components);
14877 this.components = Name.createNameArray(components);
14878 }
14879 else if (typeof components === 'object') {
14880 this.components = [];
14881 if (components instanceof Name)
14882 this.append(components);
14883 else {
14884 for (var i = 0; i < components.length; ++i)
14885 this.append(components[i]);
14886 }
14887 }
14888 else if (components == null)
14889 this.components = [];
14890 else
14891 if (LOG > 1) console.log("NO CONTENT NAME GIVEN");
14892
14893 this.changeCount = 0;
14894};
14895
14896exports.Name = Name;
14897
14898/**
14899 * Create a new GENERIC Name.Component with a copy of the given value.
14900 * (To create an ImplicitSha256Digest component, use fromImplicitSha256Digest.)
14901 * @param {Name.Component|String|Array<number>|ArrayBuffer|Buffer} value If the value is a string, encode it as utf8 (but don't unescape).
14902 * @constructor
14903 */
14904Name.Component = function NameComponent(value)
14905{
14906 if (typeof value === 'object' && value instanceof Name.Component) {
14907 // The copy constructor.
14908 this.value_ = value.value_;
14909 this.type_ = value.type_;
14910 return;
14911 }
14912
14913 if (!value)
14914 this.value_ = new Blob([]);
14915 else if (typeof value === 'object' && typeof ArrayBuffer !== 'undefined' &&
14916 value instanceof ArrayBuffer)
14917 // Make a copy. Turn the value into a Uint8Array since the Buffer
14918 // constructor doesn't take an ArrayBuffer.
14919 this.value_ = new Blob(new Buffer(new Uint8Array(value)), false);
14920 else if (typeof value === 'object' && value instanceof Blob)
14921 this.value_ = value;
14922 else
14923 // Blob will make a copy if needed.
14924 this.value_ = new Blob(value);
14925
14926 this.type_ = Name.Component.ComponentType.GENERIC;
14927};
14928
14929/**
14930 * A Name.Component.ComponentType specifies the recognized types of a name
14931 * component.
14932 */
14933Name.Component.ComponentType = {
14934 IMPLICIT_SHA256_DIGEST: 1,
14935 GENERIC: 8
14936};
14937
14938/**
14939 * Get the component value.
14940 * @return {Blob} The component value.
14941 */
14942Name.Component.prototype.getValue = function()
14943{
14944 return this.value_;
14945};
14946
14947/**
14948 * @deprecated Use getValue. This method returns a Buffer which is the former
14949 * behavior of getValue, and should only be used while updating your code.
14950 */
14951Name.Component.prototype.getValueAsBuffer = function()
14952{
14953 // Assume the caller won't modify it.
14954 return this.value_.buf();
14955};
14956
14957/**
14958 * @deprecated Use getValue which returns a Blob.
14959 */
14960Object.defineProperty(Name.Component.prototype, "value",
14961 { get: function() { return this.getValueAsBuffer(); } });
14962
14963/**
14964 * Convert this component value to a string by escaping characters according to the NDN URI Scheme.
14965 * This also adds "..." to a value with zero or more ".".
14966 * This adds a type code prefix as needed, such as "sha256digest=".
14967 * @return {string} The escaped string.
14968 */
14969Name.Component.prototype.toEscapedString = function()
14970{
14971 if (this.type_ === Name.Component.ComponentType.IMPLICIT_SHA256_DIGEST)
14972 return "sha256digest=" + this.value_.toHex();
14973 else
14974 return Name.toEscapedString(this.value_.buf());
14975};
14976
14977/**
14978 * Check if this component is a segment number according to NDN naming
14979 * conventions for "Segment number" (marker 0x00).
14980 * http://named-data.net/doc/tech-memos/naming-conventions.pdf
14981 * @return {number} True if this is a segment number.
14982 */
14983Name.Component.prototype.isSegment = function()
14984{
14985 return this.value_.size() >= 1 && this.value_.buf()[0] == 0x00 &&
14986 this.isGeneric();
14987};
14988
14989/**
14990 * Check if this component is a segment byte offset according to NDN
14991 * naming conventions for segment "Byte offset" (marker 0xFB).
14992 * http://named-data.net/doc/tech-memos/naming-conventions.pdf
14993 * @return True if this is a segment byte offset.
14994 */
14995Name.Component.prototype.isSegmentOffset = function()
14996{
14997 return this.value_.size() >= 1 && this.value_.buf()[0] == 0xFB &&
14998 this.isGeneric();
14999};
15000
15001/**
15002 * Check if this component is a version number according to NDN naming
15003 * conventions for "Versioning" (marker 0xFD).
15004 * http://named-data.net/doc/tech-memos/naming-conventions.pdf
15005 * @return {number} True if this is a version number.
15006 */
15007Name.Component.prototype.isVersion = function()
15008{
15009 return this.value_.size() >= 1 && this.value_.buf()[0] == 0xFD &&
15010 this.isGeneric();
15011};
15012
15013/**
15014 * Check if this component is a timestamp according to NDN naming
15015 * conventions for "Timestamp" (marker 0xFC).
15016 * http://named-data.net/doc/tech-memos/naming-conventions.pdf
15017 * @return True if this is a timestamp.
15018 */
15019Name.Component.prototype.isTimestamp = function()
15020{
15021 return this.value_.size() >= 1 && this.value_.buf()[0] == 0xFC &&
15022 this.isGeneric();
15023};
15024
15025/**
15026 * Check if this component is a sequence number according to NDN naming
15027 * conventions for "Sequencing" (marker 0xFE).
15028 * http://named-data.net/doc/tech-memos/naming-conventions.pdf
15029 * @return True if this is a sequence number.
15030 */
15031Name.Component.prototype.isSequenceNumber = function()
15032{
15033 return this.value_.size() >= 1 && this.value_.buf()[0] == 0xFE &&
15034 this.isGeneric();
15035};
15036
15037/**
15038 * Check if this component is a generic component.
15039 * @return {boolean} True if this is an generic component.
15040 */
15041Name.Component.prototype.isGeneric = function()
15042{
15043 return this.type_ === Name.Component.ComponentType.GENERIC;
15044};
15045
15046/**
15047 * Check if this component is an ImplicitSha256Digest component.
15048 * @return {boolean} True if this is an ImplicitSha256Digest component.
15049 */
15050Name.Component.prototype.isImplicitSha256Digest = function()
15051{
15052 return this.type_ === Name.Component.ComponentType.IMPLICIT_SHA256_DIGEST;
15053};
15054
15055/**
15056 * Interpret this name component as a network-ordered number and return an integer.
15057 * @return {number} The integer number.
15058 */
15059Name.Component.prototype.toNumber = function()
15060{
15061 return DataUtils.bigEndianToUnsignedInt(this.value_.buf());
15062};
15063
15064/**
15065 * Interpret this name component as a network-ordered number with a marker and
15066 * return an integer.
15067 * @param {number} marker The required first byte of the component.
15068 * @return {number} The integer number.
15069 * @throws Error If the first byte of the component does not equal the marker.
15070 */
15071Name.Component.prototype.toNumberWithMarker = function(marker)
15072{
15073 if (this.value_.size() == 0 || this.value_.buf()[0] != marker)
15074 throw new Error("Name component does not begin with the expected marker");
15075
15076 return DataUtils.bigEndianToUnsignedInt(this.value_.buf().slice(1));
15077};
15078
15079/**
15080 * Interpret this name component as a segment number according to NDN naming
15081 * conventions for "Segment number" (marker 0x00).
15082 * http://named-data.net/doc/tech-memos/naming-conventions.pdf
15083 * @return {number} The integer segment number.
15084 * @throws Error If the first byte of the component is not the expected marker.
15085 */
15086Name.Component.prototype.toSegment = function()
15087{
15088 return this.toNumberWithMarker(0x00);
15089};
15090
15091/**
15092 * Interpret this name component as a segment byte offset according to NDN
15093 * naming conventions for segment "Byte offset" (marker 0xFB).
15094 * http://named-data.net/doc/tech-memos/naming-conventions.pdf
15095 * @return The integer segment byte offset.
15096 * @throws Error If the first byte of the component is not the expected marker.
15097 */
15098Name.Component.prototype.toSegmentOffset = function()
15099{
15100 return this.toNumberWithMarker(0xFB);
15101};
15102
15103/**
15104 * Interpret this name component as a version number according to NDN naming
15105 * conventions for "Versioning" (marker 0xFD). Note that this returns
15106 * the exact number from the component without converting it to a time
15107 * representation.
15108 * @return {number} The integer version number.
15109 * @throws Error If the first byte of the component is not the expected marker.
15110 */
15111Name.Component.prototype.toVersion = function()
15112{
15113 return this.toNumberWithMarker(0xFD);
15114};
15115
15116/**
15117 * Interpret this name component as a timestamp according to NDN naming
15118 * conventions for "Timestamp" (marker 0xFC).
15119 * http://named-data.net/doc/tech-memos/naming-conventions.pdf
15120 * @return The number of microseconds since the UNIX epoch (Thursday,
15121 * 1 January 1970) not counting leap seconds.
15122 * @throws Error If the first byte of the component is not the expected marker.
15123 */
15124Name.Component.prototype.toTimestamp = function()
15125{
15126 return this.toNumberWithMarker(0xFC);
15127};
15128
15129/**
15130 * Interpret this name component as a sequence number according to NDN naming
15131 * conventions for "Sequencing" (marker 0xFE).
15132 * http://named-data.net/doc/tech-memos/naming-conventions.pdf
15133 * @return The integer sequence number.
15134 * @throws Error If the first byte of the component is not the expected marker.
15135 */
15136Name.Component.prototype.toSequenceNumber = function()
15137{
15138 return this.toNumberWithMarker(0xFE);
15139};
15140
15141/**
15142 * Create a component whose value is the nonNegativeInteger encoding of the
15143 * number.
15144 * @param {number} number
15145 * @return {Name.Component}
15146 */
15147Name.Component.fromNumber = function(number)
15148{
15149 var encoder = new TlvEncoder(8);
15150 encoder.writeNonNegativeInteger(number);
15151 return new Name.Component(new Blob(encoder.getOutput(), false));
15152};
15153
15154/**
15155 * Create a component whose value is the marker appended with the
15156 * nonNegativeInteger encoding of the number.
15157 * @param {number} number
15158 * @param {number} marker
15159 * @return {Name.Component}
15160 */
15161Name.Component.fromNumberWithMarker = function(number, marker)
15162{
15163 var encoder = new TlvEncoder(9);
15164 // Encode backwards.
15165 encoder.writeNonNegativeInteger(number);
15166 encoder.writeNonNegativeInteger(marker);
15167 return new Name.Component(new Blob(encoder.getOutput(), false));
15168};
15169
15170/**
15171 * Create a component with the encoded segment number according to NDN
15172 * naming conventions for "Segment number" (marker 0x00).
15173 * http://named-data.net/doc/tech-memos/naming-conventions.pdf
15174 * param {number} segment The segment number.
15175 * returns {Name.Component} The new Component.
15176 */
15177Name.Component.fromSegment = function(segment)
15178{
15179 return Name.Component.fromNumberWithMarker(segment, 0x00);
15180};
15181
15182/**
15183 * Create a component with the encoded segment byte offset according to NDN
15184 * naming conventions for segment "Byte offset" (marker 0xFB).
15185 * http://named-data.net/doc/tech-memos/naming-conventions.pdf
15186 * param {number} segmentOffset The segment byte offset.
15187 * returns {Name.Component} The new Component.
15188 */
15189Name.Component.fromSegmentOffset = function(segmentOffset)
15190{
15191 return Name.Component.fromNumberWithMarker(segmentOffset, 0xFB);
15192};
15193
15194/**
15195 * Create a component with the encoded version number according to NDN
15196 * naming conventions for "Versioning" (marker 0xFD).
15197 * http://named-data.net/doc/tech-memos/naming-conventions.pdf
15198 * Note that this encodes the exact value of version without converting from a
15199 * time representation.
15200 * param {number} version The version number.
15201 * returns {Name.Component} The new Component.
15202 */
15203Name.Component.fromVersion = function(version)
15204{
15205 return Name.Component.fromNumberWithMarker(version, 0xFD);
15206};
15207
15208/**
15209 * Create a component with the encoded timestamp according to NDN naming
15210 * conventions for "Timestamp" (marker 0xFC).
15211 * http://named-data.net/doc/tech-memos/naming-conventions.pdf
15212 * param {number} timestamp The number of microseconds since the UNIX epoch (Thursday,
15213 * 1 January 1970) not counting leap seconds.
15214 * returns {Name.Component} The new Component.
15215 */
15216Name.Component.fromTimestamp = function(timestamp)
15217{
15218 return Name.Component.fromNumberWithMarker(timestamp, 0xFC);
15219};
15220
15221/**
15222 * Create a component with the encoded sequence number according to NDN naming
15223 * conventions for "Sequencing" (marker 0xFE).
15224 * http://named-data.net/doc/tech-memos/naming-conventions.pdf
15225 * param {number} sequenceNumber The sequence number.
15226 * returns {Name.Component} The new Component.
15227 */
15228Name.Component.fromSequenceNumber = function(sequenceNumber)
15229{
15230 return Name.Component.fromNumberWithMarker(sequenceNumber, 0xFE);
15231};
15232
15233/**
15234 * Create a component of type ImplicitSha256DigestComponent, so that
15235 * isImplicitSha256Digest() is true.
15236 * @param {Blob|Buffer} digest The SHA-256 digest value.
15237 * @return {Name.Component} The new Component.
15238 * @throws DecodingException If the digest length is not 32 bytes.
15239 */
15240Name.Component.fromImplicitSha256Digest = function(digest)
15241{
15242 digestBlob = typeof digest === 'object' && digest instanceof Blob ?
15243 digest : new Blob(digest, true);
15244 if (digestBlob.size() !== 32)
15245 throw new DecodingException
15246 ("Name.Component.fromImplicitSha256Digest: The digest length must be 32 bytes");
15247
15248 var result = new Name.Component(digestBlob);
15249 result.type_ = Name.Component.ComponentType.IMPLICIT_SHA256_DIGEST;
15250 return result;
15251};
15252
15253/**
15254 * Get the successor of this component, as described in Name.getSuccessor.
15255 * @return {Name.Component} A new Name.Component which is the successor of this.
15256 */
15257Name.Component.prototype.getSuccessor = function()
15258{
15259 // Allocate an extra byte in case the result is larger.
15260 var result = new Buffer(this.value_.size() + 1);
15261
15262 var carry = true;
15263 for (var i = this.value_.size() - 1; i >= 0; --i) {
15264 if (carry) {
15265 result[i] = (this.value_.buf()[i] + 1) & 0xff;
15266 carry = (result[i] === 0);
15267 }
15268 else
15269 result[i] = this.value_.buf()[i];
15270 }
15271
15272 if (carry)
15273 // Assume all the bytes were set to zero (or the component was empty). In
15274 // NDN ordering, carry does not mean to prepend a 1, but to make a component
15275 // one byte longer of all zeros.
15276 result[result.length - 1] = 0;
15277 else
15278 // We didn't need the extra byte.
15279 result = result.slice(0, this.value_.size());
15280
15281 return new Name.Component(new Blob(result, false));
15282};
15283
15284/**
15285 * Check if this is the same component as other.
15286 * @param {Name.Component} other The other Component to compare with.
15287 * @return {Boolean} true if the components are equal, otherwise false.
15288 */
15289Name.Component.prototype.equals = function(other)
15290{
15291 return typeof other === 'object' && other instanceof Name.Component &&
15292 this.value_.equals(other.value_) && this.type_ === other.type_;
15293};
15294
15295/**
15296 * Compare this to the other Component using NDN canonical ordering.
15297 * @param {Name.Component} other The other Component to compare with.
15298 * @return {number} 0 if they compare equal, -1 if this comes before other in
15299 * the canonical ordering, or 1 if this comes after other in the canonical
15300 * ordering.
15301 *
15302 * @see http://named-data.net/doc/0.2/technical/CanonicalOrder.html
15303 */
15304Name.Component.prototype.compare = function(other)
15305{
15306 if (this.type_ < other.type_)
15307 return -1;
15308 if (this.type_ > other.type_)
15309 return 1;
15310
15311 return Name.Component.compareBuffers(this.value_.buf(), other.value_.buf());
15312};
15313
15314/**
15315 * Do the work of Name.Component.compare to compare the component buffers.
15316 * @param {Buffer} component1
15317 * @param {Buffer} component2
15318 * @return {number} 0 if they compare equal, -1 if component1 comes before
15319 * component2 in the canonical ordering, or 1 if component1 comes after
15320 * component2 in the canonical ordering.
15321 */
15322Name.Component.compareBuffers = function(component1, component2)
15323{
15324 if (component1.length < component2.length)
15325 return -1;
15326 if (component1.length > component2.length)
15327 return 1;
15328
15329 for (var i = 0; i < component1.length; ++i) {
15330 if (component1[i] < component2[i])
15331 return -1;
15332 if (component1[i] > component2[i])
15333 return 1;
15334 }
15335
15336 return 0;
15337};
15338
15339/**
15340 * @deprecated Use toUri.
15341 */
15342Name.prototype.getName = function()
15343{
15344 return this.toUri();
15345};
15346
15347/** Parse uri as a URI and return an array of Buffer components.
15348 */
15349Name.createNameArray = function(uri)
15350{
15351 uri = uri.trim();
15352 if (uri.length <= 0)
15353 return [];
15354
15355 var iColon = uri.indexOf(':');
15356 if (iColon >= 0) {
15357 // Make sure the colon came before a '/'.
15358 var iFirstSlash = uri.indexOf('/');
15359 if (iFirstSlash < 0 || iColon < iFirstSlash)
15360 // Omit the leading protocol such as ndn:
15361 uri = uri.substr(iColon + 1, uri.length - iColon - 1).trim();
15362 }
15363
15364 if (uri[0] == '/') {
15365 if (uri.length >= 2 && uri[1] == '/') {
15366 // Strip the authority following "//".
15367 var iAfterAuthority = uri.indexOf('/', 2);
15368 if (iAfterAuthority < 0)
15369 // Unusual case: there was only an authority.
15370 return [];
15371 else
15372 uri = uri.substr(iAfterAuthority + 1, uri.length - iAfterAuthority - 1).trim();
15373 }
15374 else
15375 uri = uri.substr(1, uri.length - 1).trim();
15376 }
15377
15378 var array = uri.split('/');
15379
15380 // Unescape the components.
15381 var sha256digestPrefix = "sha256digest=";
15382 for (var i = 0; i < array.length; ++i) {
15383 var component;
15384 if (array[i].substr(0, sha256digestPrefix.length) == sha256digestPrefix) {
15385 var hexString = array[i].substr(sha256digestPrefix.length).trim();
15386 component = Name.Component.fromImplicitSha256Digest
15387 (new Blob(new Buffer(hexString, 'hex')), false);
15388 }
15389 else
15390 component = new Name.Component(Name.fromEscapedString(array[i]));
15391
15392 if (component.getValue().isNull()) {
15393 // Ignore the illegal componenent. This also gets rid of a trailing '/'.
15394 array.splice(i, 1);
15395 --i;
15396 continue;
15397 }
15398 else
15399 array[i] = component;
15400 }
15401
15402 return array;
15403};
15404
15405/**
15406 * Parse the uri according to the NDN URI Scheme and set the name with the
15407 * components.
15408 * @param {string} uri The URI string.
15409 */
15410Name.prototype.set = function(uri)
15411{
15412 this.components = Name.createNameArray(uri);
15413 ++this.changeCount;
15414};
15415
15416/**
15417 * Convert the component to a Buffer and append a GENERIC component to this Name.
15418 * Return this Name object to allow chaining calls to add.
15419 * @param {Name.Component|String|Array<number>|ArrayBuffer|Buffer|Name} component If a component is a string, encode as utf8 (but don't unescape).
15420 * @return {Name}
15421 */
15422Name.prototype.append = function(component)
15423{
15424 if (typeof component == 'object' && component instanceof Name) {
15425 var components;
15426 if (component == this)
15427 // special case, when we need to create a copy
15428 components = this.components.slice(0, this.components.length);
15429 else
15430 components = component.components;
15431
15432 for (var i = 0; i < components.length; ++i)
15433 this.components.push(new Name.Component(components[i]));
15434 }
15435 else if (typeof component === 'object' && component instanceof Name.Component)
15436 // The Component is immutable, so use it as is.
15437 this.components.push(component);
15438 else
15439 // Just use the Name.Component constructor.
15440 this.components.push(new Name.Component(component));
15441
15442 ++this.changeCount;
15443 return this;
15444};
15445
15446/**
15447 * @deprecated Use append.
15448 */
15449Name.prototype.add = function(component)
15450{
15451 return this.append(component);
15452};
15453
15454/**
15455 * Clear all the components.
15456 */
15457Name.prototype.clear = function()
15458{
15459 this.components = [];
15460 ++this.changeCount;
15461};
15462
15463/**
15464 * Return the escaped name string according to NDN URI Scheme.
15465 * @param {boolean} includeScheme (optional) If true, include the "ndn:" scheme
15466 * in the URI, e.g. "ndn:/example/name". If false, just return the path, e.g.
15467 * "/example/name". If ommitted, then just return the path which is the default
15468 * case where toUri() is used for display.
15469 * @return {String}
15470 */
15471Name.prototype.toUri = function(includeScheme)
15472{
15473 if (this.size() == 0)
15474 return includeScheme ? "ndn:/" : "/";
15475
15476 var result = includeScheme ? "ndn:" : "";
15477
15478 for (var i = 0; i < this.size(); ++i)
15479 result += "/"+ this.components[i].toEscapedString();
15480
15481 return result;
15482};
15483
15484/**
15485 * @deprecated Use toUri.
15486 */
15487Name.prototype.to_uri = function()
15488{
15489 return this.toUri();
15490};
15491
15492Name.prototype.toString = function() { return this.toUri(); }
15493
15494/**
15495 * Append a component with the encoded segment number according to NDN
15496 * naming conventions for "Segment number" (marker 0x00).
15497 * http://named-data.net/doc/tech-memos/naming-conventions.pdf
15498 * @param {number} segment The segment number.
15499 * @return {Name} This name so that you can chain calls to append.
15500 */
15501Name.prototype.appendSegment = function(segment)
15502{
15503 return this.append(Name.Component.fromSegment(segment));
15504};
15505
15506/**
15507 * Append a component with the encoded segment byte offset according to NDN
15508 * naming conventions for segment "Byte offset" (marker 0xFB).
15509 * http://named-data.net/doc/tech-memos/naming-conventions.pdf
15510 * @param {number} segmentOffset The segment byte offset.
15511 * @return {Name} This name so that you can chain calls to append.
15512 */
15513Name.prototype.appendSegmentOffset = function(segmentOffset)
15514{
15515 return this.append(Name.Component.fromSegmentOffset(segmentOffset));
15516};
15517
15518/**
15519 * Append a component with the encoded version number according to NDN
15520 * naming conventions for "Versioning" (marker 0xFD).
15521 * http://named-data.net/doc/tech-memos/naming-conventions.pdf
15522 * Note that this encodes the exact value of version without converting from a time representation.
15523 * @param {number} version The version number.
15524 * @return {Name} This name so that you can chain calls to append.
15525 */
15526Name.prototype.appendVersion = function(version)
15527{
15528 return this.append(Name.Component.fromVersion(version));
15529};
15530
15531/**
15532 * Append a component with the encoded timestamp according to NDN naming
15533 * conventions for "Timestamp" (marker 0xFC).
15534 * http://named-data.net/doc/tech-memos/naming-conventions.pdf
15535 * @param {number} timestamp The number of microseconds since the UNIX epoch (Thursday,
15536 * 1 January 1970) not counting leap seconds.
15537 * @return This name so that you can chain calls to append.
15538 */
15539Name.prototype.appendTimestamp = function(timestamp)
15540{
15541 return this.append(Name.Component.fromTimestamp(timestamp));
15542};
15543
15544/**
15545 * Append a component with the encoded sequence number according to NDN naming
15546 * conventions for "Sequencing" (marker 0xFE).
15547 * http://named-data.net/doc/tech-memos/naming-conventions.pdf
15548 * @param {number} sequenceNumber The sequence number.
15549 * @return This name so that you can chain calls to append.
15550 */
15551Name.prototype.appendSequenceNumber = function(sequenceNumber)
15552{
15553 return this.append(Name.Component.fromSequenceNumber(sequenceNumber));
15554};
15555
15556/**
15557 * Append a component of type ImplicitSha256DigestComponent, so that
15558 * isImplicitSha256Digest() is true.
15559 * @param {Blob|Buffer} digest The SHA-256 digest value.
15560 * @return This name so that you can chain calls to append.
15561 * @throws DecodingException If the digest length is not 32 bytes.
15562 */
15563Name.prototype.appendImplicitSha256Digest = function(digest)
15564{
15565 return this.append(Name.Component.fromImplicitSha256Digest(digest));
15566};
15567
15568/**
15569 * @deprecated Use appendSegment.
15570 */
15571Name.prototype.addSegment = function(number)
15572{
15573 return this.appendSegment(number);
15574};
15575
15576/**
15577 * Get a new name, constructed as a subset of components.
15578 * @param {number} iStartComponent The index if the first component to get. If
15579 * iStartComponent is -N then return return components starting from
15580 * name.size() - N.
15581 * @param {number} (optional) nComponents The number of components starting at
15582 * iStartComponent. If omitted or greater than the size of this name, get until
15583 * the end of the name.
15584 * @return {Name} A new name.
15585 */
15586Name.prototype.getSubName = function(iStartComponent, nComponents)
15587{
15588 if (iStartComponent < 0)
15589 iStartComponent = this.components.length - (-iStartComponent);
15590
15591 if (nComponents == undefined)
15592 nComponents = this.components.length - iStartComponent;
15593
15594 var result = new Name();
15595
15596 var iEnd = iStartComponent + nComponents;
15597 for (var i = iStartComponent; i < iEnd && i < this.components.length; ++i)
15598 result.components.push(this.components[i]);
15599
15600 return result;
15601};
15602
15603/**
15604 * Return a new Name with the first nComponents components of this Name.
15605 * @param {number} nComponents The number of prefix components. If nComponents is -N then return the prefix up
15606 * to name.size() - N. For example getPrefix(-1) returns the name without the final component.
15607 * @return {Name} A new name.
15608 */
15609Name.prototype.getPrefix = function(nComponents)
15610{
15611 if (nComponents < 0)
15612 return this.getSubName(0, this.components.length + nComponents);
15613 else
15614 return this.getSubName(0, nComponents);
15615};
15616
15617/**
15618 * @deprecated Use getPrefix(-nComponents).
15619 */
15620Name.prototype.cut = function(nComponents)
15621{
15622 return new Name(this.components.slice(0, this.components.length - nComponents));
15623};
15624
15625/**
15626 * Return the number of name components.
15627 * @return {number}
15628 */
15629Name.prototype.size = function()
15630{
15631 return this.components.length;
15632};
15633
15634/**
15635 * Get a Name Component by index number.
15636 * @param {Number} i The index of the component, starting from 0. However, if i is negative, return the component
15637 * at size() - (-i).
15638 * @return {Name.Component} The name component at the index. You must not
15639 * change the returned Name.Component object.
15640 */
15641Name.prototype.get = function(i)
15642{
15643 if (i >= 0) {
15644 if (i >= this.components.length)
15645 throw new Error("Name.get: Index is out of bounds");
15646
15647 return this.components[i];
15648 }
15649 else {
15650 // Negative index.
15651 if (i < -this.components.length)
15652 throw new Error("Name.get: Index is out of bounds");
15653
15654 return this.components[this.components.length - (-i)];
15655 }
15656};
15657
15658/**
15659 * @deprecated Use size().
15660 */
15661Name.prototype.getComponentCount = function()
15662{
15663 return this.components.length;
15664};
15665
15666/**
15667 * @deprecated To get just the component value array, use get(i).getValue().buf().
15668 */
15669Name.prototype.getComponent = function(i)
15670{
15671 return new Buffer(this.components[i].getValue().buf());
15672};
15673
15674/**
15675 * The "file name" in a name is the last component that isn't blank and doesn't start with one of the
15676 * special marker octets (for version, etc.). Return the index in this.components of
15677 * the file name, or -1 if not found.
15678 */
15679Name.prototype.indexOfFileName = function()
15680{
15681 for (var i = this.size() - 1; i >= 0; --i) {
15682 var component = this.components[i].getValue().buf();
15683 if (component.length <= 0)
15684 continue;
15685
15686 if (component[0] == 0 || component[0] == 0xC0 || component[0] == 0xC1 ||
15687 (component[0] >= 0xF5 && component[0] <= 0xFF))
15688 continue;
15689
15690 return i;
15691 }
15692
15693 return -1;
15694};
15695
15696/**
15697 * Encode this Name for a particular wire format.
15698 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
15699 * this object. If omitted, use WireFormat.getDefaultWireFormat().
15700 * @return {Blob} The encoded buffer in a Blob object.
15701 */
15702Name.prototype.wireEncode = function(wireFormat)
15703{
15704 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
15705 return wireFormat.encodeName(this);
15706};
15707
15708/**
15709 * Decode the input using a particular wire format and update this Name.
15710 * @param {Blob|Buffer} input The buffer with the bytes to decode.
15711 * @param {WireFormat} wireFormat (optional) A WireFormat object used to decode
15712 * this object. If omitted, use WireFormat.getDefaultWireFormat().
15713 */
15714Name.prototype.wireDecode = function(input, wireFormat)
15715{
15716 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
15717 if (typeof input === 'object' && input instanceof Blob)
15718 // Input is a blob, so get its buf() and set copy false.
15719 wireFormat.decodeName(this, input.buf(), false);
15720 else
15721 wireFormat.decodeName(this, input, true);
15722};
15723
15724/**
15725 * Compare this to the other Name using NDN canonical ordering. If the first
15726 * components of each name are not equal, this returns -1 if the first comes
15727 * before the second using the NDN canonical ordering for name components, or 1
15728 * if it comes after. If they are equal, this compares the second components of
15729 * each name, etc. If both names are the same up to the size of the shorter
15730 * name, this returns -1 if the first name is shorter than the second or 1 if it
15731 * is longer. For example, std::sort gives: /a/b/d /a/b/cc /c /c/a /bb . This
15732 * is intuitive because all names with the prefix /a are next to each other.
15733 * But it may be also be counter-intuitive because /c comes before /bb according
15734 * to NDN canonical ordering since it is shorter.
15735 * The first form of compare is simply compare(other). The second form is
15736 * compare(iStartComponent, nComponents, other [, iOtherStartComponent] [, nOtherComponents])
15737 * which is equivalent to
15738 * self.getSubName(iStartComponent, nComponents).compare
15739 * (other.getSubName(iOtherStartComponent, nOtherComponents)) .
15740 * @param {number} iStartComponent The index if the first component of this name
15741 * to get. If iStartComponent is -N then compare components starting from
15742 * name.size() - N.
15743 * @param {number} nComponents The number of components starting at
15744 * iStartComponent. If greater than the size of this name, compare until the end
15745 * of the name.
15746 * @param {Name} other The other Name to compare with.
15747 * @param {number} iOtherStartComponent (optional) The index if the first
15748 * component of the other name to compare. If iOtherStartComponent is -N then
15749 * compare components starting from other.size() - N. If omitted, compare
15750 * starting from index 0.
15751 * @param {number} nOtherComponents (optional) The number of components
15752 * starting at iOtherStartComponent. If omitted or greater than the size of this
15753 * name, compare until the end of the name.
15754 * @return {number} 0 If they compare equal, -1 if self comes before other in
15755 * the canonical ordering, or 1 if self comes after other in the canonical
15756 * ordering.
15757 * @see http://named-data.net/doc/0.2/technical/CanonicalOrder.html
15758 */
15759Name.prototype.compare = function
15760 (iStartComponent, nComponents, other, iOtherStartComponent, nOtherComponents)
15761{
15762 if (iStartComponent instanceof Name) {
15763 // compare(other)
15764 other = iStartComponent;
15765 iStartComponent = 0;
15766 nComponents = this.size();
15767 }
15768
15769 if (iOtherStartComponent == undefined)
15770 iOtherStartComponent = 0;
15771 if (nOtherComponents == undefined)
15772 nOtherComponents = other.size();
15773
15774 if (iStartComponent < 0)
15775 iStartComponent = this.size() - (-iStartComponent);
15776 if (iOtherStartComponent < 0)
15777 iOtherStartComponent = other.size() - (-iOtherStartComponent);
15778
15779 nComponents = Math.min(nComponents, this.size() - iStartComponent);
15780 nOtherComponents = Math.min(nOtherComponents, other.size() - iOtherStartComponent);
15781
15782 var count = Math.min(nComponents, nOtherComponents);
15783 for (var i = 0; i < count; ++i) {
15784 var comparison = this.components[iStartComponent + i].compare
15785 (other.components[iOtherStartComponent + i]);
15786 if (comparison == 0)
15787 // The components at this index are equal, so check the next components.
15788 continue;
15789
15790 // Otherwise, the result is based on the components at this index.
15791 return comparison;
15792 }
15793
15794 // The components up to min(this.size(), other.size()) are equal, so the
15795 // shorter name is less.
15796 if (nComponents < nOtherComponents)
15797 return -1;
15798 else if (nComponents > nOtherComponents)
15799 return 1;
15800 else
15801 return 0;
15802};
15803
15804/**
15805 * Return true if this Name has the same components as name.
15806 */
15807Name.prototype.equals = function(name)
15808{
15809 if (this.components.length != name.components.length)
15810 return false;
15811
15812 // Start from the last component because they are more likely to differ.
15813 for (var i = this.components.length - 1; i >= 0; --i) {
15814 if (!this.components[i].equals(name.components[i]))
15815 return false;
15816 }
15817
15818 return true;
15819};
15820
15821/**
15822 * @deprecated Use equals.
15823 */
15824Name.prototype.equalsName = function(name)
15825{
15826 return this.equals(name);
15827};
15828
15829/**
15830 * Find the last component in name that has a ContentDigest and return the digest value as Buffer,
15831 * or null if not found. See Name.getComponentContentDigestValue.
15832 */
15833Name.prototype.getContentDigestValue = function()
15834{
15835 for (var i = this.size() - 1; i >= 0; --i) {
15836 var digestValue = Name.getComponentContentDigestValue(this.components[i]);
15837 if (digestValue != null)
15838 return digestValue;
15839 }
15840
15841 return null;
15842};
15843
15844/**
15845 * If component is a ContentDigest, return the digest value as a Buffer slice (don't modify!).
15846 * If not a ContentDigest, return null.
15847 * A ContentDigest component is Name.ContentDigestPrefix + 32 bytes + Name.ContentDigestSuffix.
15848 */
15849Name.getComponentContentDigestValue = function(component)
15850{
15851 if (typeof component == 'object' && component instanceof Name.Component)
15852 component = component.getValue().buf();
15853
15854 var digestComponentLength = Name.ContentDigestPrefix.length + 32 + Name.ContentDigestSuffix.length;
15855 // Check for the correct length and equal ContentDigestPrefix and ContentDigestSuffix.
15856 if (component.length == digestComponentLength &&
15857 DataUtils.arraysEqual(component.slice(0, Name.ContentDigestPrefix.length),
15858 Name.ContentDigestPrefix) &&
15859 DataUtils.arraysEqual(component.slice
15860 (component.length - Name.ContentDigestSuffix.length, component.length),
15861 Name.ContentDigestSuffix))
15862 return component.slice(Name.ContentDigestPrefix.length, Name.ContentDigestPrefix.length + 32);
15863 else
15864 return null;
15865};
15866
15867// Meta GUID "%C1.M.G%C1" + ContentDigest with a 32 byte BLOB.
15868Name.ContentDigestPrefix = new Buffer([0xc1, 0x2e, 0x4d, 0x2e, 0x47, 0xc1, 0x01, 0xaa, 0x02, 0x85]);
15869Name.ContentDigestSuffix = new Buffer([0x00]);
15870
15871
15872/**
15873 * Return value as an escaped string according to NDN URI Scheme.
15874 * We can't use encodeURIComponent because that doesn't encode all the
15875 * characters we want to.
15876 * This does not add a type code prefix such as "sha256digest=".
15877 * @param {Buffer|Name.Component} value The value or Name.Component to escape.
15878 * @return {string} The escaped string.
15879 */
15880Name.toEscapedString = function(value)
15881{
15882 if (typeof value == 'object' && value instanceof Name.Component)
15883 value = value.getValue().buf();
15884 else if (typeof value === 'object' && value instanceof Blob)
15885 value = value.buf();
15886
15887 var result = "";
15888 var gotNonDot = false;
15889 for (var i = 0; i < value.length; ++i) {
15890 if (value[i] != 0x2e) {
15891 gotNonDot = true;
15892 break;
15893 }
15894 }
15895 if (!gotNonDot) {
15896 // Special case for component of zero or more periods. Add 3 periods.
15897 result = "...";
15898 for (var i = 0; i < value.length; ++i)
15899 result += ".";
15900 }
15901 else {
15902 for (var i = 0; i < value.length; ++i) {
15903 var x = value[i];
15904 // Check for 0-9, A-Z, a-z, (+), (-), (.), (_)
15905 if (x >= 0x30 && x <= 0x39 || x >= 0x41 && x <= 0x5a ||
15906 x >= 0x61 && x <= 0x7a || x == 0x2b || x == 0x2d ||
15907 x == 0x2e || x == 0x5f)
15908 result += String.fromCharCode(x);
15909 else
15910 result += "%" + (x < 16 ? "0" : "") + x.toString(16).toUpperCase();
15911 }
15912 }
15913 return result;
15914};
15915
15916/**
15917 * Make a blob value by decoding the escapedString according to NDN URI Scheme.
15918 * If escapedString is "", "." or ".." then return null, which means to skip the
15919 * component in the name.
15920 * This does not check for a type code prefix such as "sha256digest=".
15921 * @param {string} escapedString The escaped string to decode.
15922 * @return {Blob} The unescaped Blob value. If the escapedString is not a valid
15923 * escaped component, then the Blob isNull().
15924 */
15925Name.fromEscapedString = function(escapedString)
15926{
15927 var value = unescape(escapedString.trim());
15928
15929 if (value.match(/[^.]/) == null) {
15930 // Special case for value of only periods.
15931 if (value.length <= 2)
15932 // Zero, one or two periods is illegal. Ignore this componenent to be
15933 // consistent with the C implementation.
15934 return new Blob();
15935 else
15936 // Remove 3 periods.
15937 return new Blob
15938 (DataUtils.toNumbersFromString(value.substr(3, value.length - 3)), false);
15939 }
15940 else
15941 return new Blob(DataUtils.toNumbersFromString(value), false);
15942};
15943
15944/**
15945 * @deprecated Use fromEscapedString. This method returns a Buffer which is the former
15946 * behavior of fromEscapedString, and should only be used while updating your code.
15947 */
15948Name.fromEscapedStringAsBuffer = function(escapedString)
15949{
15950 return Name.fromEscapedString(escapedString).buf();
15951};
15952
15953/**
15954 * Get the successor of this name which is defined as follows.
15955 *
15956 * N represents the set of NDN Names, and X,Y ∈ N.
15957 * Operator < is defined by the NDN canonical order on N.
15958 * Y is the successor of X, if (a) X < Y, and (b) ∄ Z ∈ N s.t. X < Z < Y.
15959 *
15960 * In plain words, the successor of a name is the same name, but with its last
15961 * component advanced to a next possible value.
15962 *
15963 * Examples:
15964 *
15965 * - The successor of / is /%00
15966 * - The successor of /%00%01/%01%02 is /%00%01/%01%03
15967 * - The successor of /%00%01/%01%FF is /%00%01/%02%00
15968 * - The successor of /%00%01/%FF%FF is /%00%01/%00%00%00
15969 *
15970 * @return {Name} A new name which is the successor of this.
15971 */
15972Name.prototype.getSuccessor = function()
15973{
15974 if (this.size() == 0) {
15975 // Return "/%00".
15976 var result = new Name();
15977 result.append(new Blob(new Buffer([0]), false));
15978 return result;
15979 }
15980 else
15981 return this.getPrefix(-1).append(this.get(-1).getSuccessor());
15982};
15983
15984/**
15985 * Return true if the N components of this name are the same as the first N
15986 * components of the given name.
15987 * @param {Name} name The name to check.
15988 * @return {Boolean} true if this matches the given name. This always returns
15989 * true if this name is empty.
15990 */
15991Name.prototype.match = function(name)
15992{
15993 var i_name = this.components;
15994 var o_name = name.components;
15995
15996 // This name is longer than the name we are checking it against.
15997 if (i_name.length > o_name.length)
15998 return false;
15999
16000 // Check if at least one of given components doesn't match. Check from last to
16001 // first since the last components are more likely to differ.
16002 for (var i = i_name.length - 1; i >= 0; --i) {
16003 if (!i_name[i].equals(o_name[i]))
16004 return false;
16005 }
16006
16007 return true;
16008};
16009
16010/**
16011 * Return true if the N components of this name are the same as the first N
16012 * components of the given name.
16013 * @param {Name} name The name to check.
16014 * @return {Boolean} true if this matches the given name. This always returns
16015 * true if this name is empty.
16016 */
16017Name.prototype.isPrefixOf = function(name) { return this.match(name); }
16018
16019/**
16020 * Get the change count, which is incremented each time this object is changed.
16021 * @return {number} The change count.
16022 */
16023Name.prototype.getChangeCount = function()
16024{
16025 return this.changeCount;
16026};
16027
16028// Put these requires at the bottom to avoid circular references.
16029var TlvEncoder = require('./encoding/tlv/tlv-encoder.js').TlvEncoder;
16030var WireFormat = require('./encoding/wire-format.js').WireFormat;
16031/**
16032 * This class represents an NDN KeyLocator object.
16033 * Copyright (C) 2014-2016 Regents of the University of California.
16034 * @author: Meki Cheraoui
16035 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
16036 *
16037 * This program is free software: you can redistribute it and/or modify
16038 * it under the terms of the GNU Lesser General Public License as published by
16039 * the Free Software Foundation, either version 3 of the License, or
16040 * (at your option) any later version.
16041 *
16042 * This program is distributed in the hope that it will be useful,
16043 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16044 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16045 * GNU Lesser General Public License for more details.
16046 *
16047 * You should have received a copy of the GNU Lesser General Public License
16048 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16049 * A copy of the GNU Lesser General Public License is in the file COPYING.
16050 */
16051
16052/** @ignore */
16053var Blob = require('./util/blob.js').Blob; /** @ignore */
16054var ChangeCounter = require('./util/change-counter.js').ChangeCounter; /** @ignore */
16055var Name = require('./name.js').Name;
16056
16057/**
16058 * KeyLocator
16059 */
16060var KeyLocatorType = {
16061 KEYNAME: 1,
16062 KEY_LOCATOR_DIGEST: 2
16063};
16064
16065exports.KeyLocatorType = KeyLocatorType;
16066
16067/**
16068 * @constructor
16069 */
16070var KeyLocator = function KeyLocator(input, type)
16071{
16072 if (typeof input === 'object' && input instanceof KeyLocator) {
16073 // Copy from the input KeyLocator.
16074 this.type_ = input.type_;
16075 this.keyName_ = new ChangeCounter(new Name(input.getKeyName()));
16076 this.keyData_ = input.keyData_;
16077 }
16078 else {
16079 this.type_ = type;
16080 this.keyName_ = new ChangeCounter(new Name());
16081 this.keyData_ = new Blob();
16082
16083 if (type == KeyLocatorType.KEYNAME)
16084 this.keyName_.set(typeof input === 'object' && input instanceof Name ?
16085 new Name(input) : new Name());
16086 else if (type == KeyLocatorType.KEY_LOCATOR_DIGEST)
16087 this.keyData_ = new Blob(input);
16088 }
16089
16090 this.changeCount_ = 0;
16091};
16092
16093exports.KeyLocator = KeyLocator;
16094
16095/**
16096 * Get the key locator type. If KeyLocatorType.KEYNAME, you may also
16097 * getKeyName(). If KeyLocatorType.KEY_LOCATOR_DIGEST, you may also
16098 * getKeyData() to get the digest.
16099 * @return {number} The key locator type as a KeyLocatorType enum value,
16100 * or null if not specified.
16101 */
16102KeyLocator.prototype.getType = function() { return this.type_; };
16103
16104/**
16105 * Get the key name. This is meaningful if getType() is KeyLocatorType.KEYNAME.
16106 * @return {Name} The key name. If not specified, the Name is empty.
16107 */
16108KeyLocator.prototype.getKeyName = function()
16109{
16110 return this.keyName_.get();
16111};
16112
16113/**
16114 * Get the key data. If getType() is KeyLocatorType.KEY_LOCATOR_DIGEST, this is
16115 * the digest bytes.
16116 * @return {Blob} The key data, or an isNull Blob if not specified.
16117 */
16118KeyLocator.prototype.getKeyData = function()
16119{
16120 return this.keyData_;
16121};
16122
16123/**
16124 * @deprecated Use getKeyData. This method returns a Buffer which is the former
16125 * behavior of getKeyData, and should only be used while updating your code.
16126 */
16127KeyLocator.prototype.getKeyDataAsBuffer = function()
16128{
16129 return this.getKeyData().buf();
16130};
16131
16132/**
16133 * Set the key locator type. If KeyLocatorType.KEYNAME, you must also
16134 * setKeyName(). If KeyLocatorType.KEY_LOCATOR_DIGEST, you must also
16135 * setKeyData() to the digest.
16136 * @param {number} type The key locator type as a KeyLocatorType enum value. If
16137 * null, the type is unspecified.
16138 */
16139KeyLocator.prototype.setType = function(type)
16140{
16141 this.type_ = type;
16142 ++this.changeCount_;
16143};
16144
16145/**
16146 * Set key name to a copy of the given Name. This is the name if getType()
16147 * is KeyLocatorType.KEYNAME.
16148 * @param {Name} name The key name which is copied.
16149 */
16150KeyLocator.prototype.setKeyName = function(name)
16151{
16152 this.keyName_.set(typeof name === 'object' && name instanceof Name ?
16153 new Name(name) : new Name());
16154 ++this.changeCount_;
16155};
16156
16157/**
16158 * Set the key data to the given value. This is the digest bytes if getType() is
16159 * KeyLocatorType.KEY_LOCATOR_DIGEST.
16160 * @param {Blob} keyData A Blob with the key data bytes.
16161 */
16162KeyLocator.prototype.setKeyData = function(keyData)
16163{
16164 this.keyData_ = typeof keyData === 'object' && keyData instanceof Blob ?
16165 keyData : new Blob(keyData);
16166 ++this.changeCount_;
16167};
16168
16169/**
16170 * Clear the keyData and set the type to not specified.
16171 */
16172KeyLocator.prototype.clear = function()
16173{
16174 this.type_ = null;
16175 this.keyName_.set(new Name());
16176 this.keyData_ = new Blob();
16177 ++this.changeCount_;
16178};
16179
16180/**
16181 * Check if this key locator has the same values as the given key locator.
16182 * @param {KeyLocator} other The other key locator to check.
16183 * @return {boolean} true if the key locators are equal, otherwise false.
16184 */
16185KeyLocator.prototype.equals = function(other)
16186{
16187 if (this.type_ != other.type_)
16188 return false;
16189
16190 if (this.type_ == KeyLocatorType.KEYNAME) {
16191 if (!this.getKeyName().equals(other.getKeyName()))
16192 return false;
16193 }
16194 else if (this.type_ == KeyLocatorType.KEY_LOCATOR_DIGEST) {
16195 if (!this.getKeyData().equals(other.getKeyData()))
Alexander Afanasyev1663a412013-03-02 13:52:00 -080016196 return false;
16197 }
16198
16199 return true;
16200};
16201
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080016202/**
16203 * If the signature is a type that has a KeyLocator (so that,
16204 * getFromSignature will succeed), return true.
16205 * Note: This is a static method of KeyLocator instead of a method of
16206 * Signature so that the Signature base class does not need to be overloaded
16207 * with all the different kinds of information that various signature
16208 * algorithms may use.
16209 * @param {Signature} signature An object of a subclass of Signature.
16210 * @return {boolean} True if the signature is a type that has a KeyLocator,
16211 * otherwise false.
Alexander Afanasyev1663a412013-03-02 13:52:00 -080016212 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080016213KeyLocator.canGetFromSignature = function(signature)
16214{
16215 return signature instanceof Sha256WithRsaSignature ||
16216 signature instanceof Sha256WithEcdsaSignature ||
16217 signature instanceof HmacWithSha256Signature;
Alexander Afanasyev1663a412013-03-02 13:52:00 -080016218}
16219
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080016220/**
16221 * If the signature is a type that has a KeyLocator, then return it. Otherwise
16222 * throw an error.
16223 * @param {Signature} signature An object of a subclass of Signature.
16224 * @return {KeyLocator} The signature's KeyLocator. It is an error if signature
16225 * doesn't have a KeyLocator.
Alexander Afanasyev1663a412013-03-02 13:52:00 -080016226 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080016227KeyLocator.getFromSignature = function(signature)
16228{
16229 if (signature instanceof Sha256WithRsaSignature ||
16230 signature instanceof Sha256WithEcdsaSignature ||
16231 signature instanceof HmacWithSha256Signature)
16232 return signature.getKeyLocator();
16233 else
16234 throw new Error
16235 ("KeyLocator.getFromSignature: Signature type does not have a KeyLocator");
16236}
Alexander Afanasyev1663a412013-03-02 13:52:00 -080016237
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080016238/**
16239 * Get the change count, which is incremented each time this object (or a child
16240 * object) is changed.
16241 * @return {number} The change count.
16242 */
16243KeyLocator.prototype.getChangeCount = function()
16244{
16245 // Make sure each of the checkChanged is called.
16246 var changed = this.keyName_.checkChanged();
16247 if (changed)
16248 // A child object has changed, so update the change count.
16249 ++this.changeCount_;
Alexander Afanasyev1663a412013-03-02 13:52:00 -080016250
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080016251 return this.changeCount_;
Alexander Afanasyev1663a412013-03-02 13:52:00 -080016252};
16253
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080016254// Define properties so we can change member variable types and implement changeCount_.
16255Object.defineProperty(KeyLocator.prototype, "type",
16256 { get: function() { return this.getType(); },
16257 set: function(val) { this.setType(val); } });
16258/**
16259 * @@deprecated Use getKeyData and setKeyData.
Alexander Afanasyev1663a412013-03-02 13:52:00 -080016260 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080016261Object.defineProperty(KeyLocator.prototype, "keyData",
16262 { get: function() { return this.getKeyDataAsBuffer(); },
16263 set: function(val) { this.setKeyData(val); } });
16264
16265// Put this last to avoid a require loop.
16266var Sha256WithRsaSignature = require('./sha256-with-rsa-signature.js').Sha256WithRsaSignature;
16267var Sha256WithEcdsaSignature = require('./sha256-with-ecdsa-signature.js').Sha256WithEcdsaSignature;
16268var HmacWithSha256Signature = require('./hmac-with-sha256-signature.js').HmacWithSha256Signature;
16269/**
16270 * This class represents an NDN Data MetaInfo object.
16271 * Copyright (C) 2014-2016 Regents of the University of California.
16272 * @author: Meki Cheraoui
16273 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
16274 *
16275 * This program is free software: you can redistribute it and/or modify
16276 * it under the terms of the GNU Lesser General Public License as published by
16277 * the Free Software Foundation, either version 3 of the License, or
16278 * (at your option) any later version.
16279 *
16280 * This program is distributed in the hope that it will be useful,
16281 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16282 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16283 * GNU Lesser General Public License for more details.
16284 *
16285 * You should have received a copy of the GNU Lesser General Public License
16286 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16287 * A copy of the GNU Lesser General Public License is in the file COPYING.
16288 */
16289
16290/** @ignore */
16291var Name = require('./name.js').Name;
16292
16293/**
16294 * A ContentType specifies the content type in a MetaInfo object. If the
16295 * content type in the packet is not a recognized enum value, then we use
16296 * ContentType.OTHER_CODE and you can call MetaInfo.getOtherTypeCode(). We do
16297 * this to keep the recognized content type values independent of packet
16298 * encoding formats.
16299 */
16300var ContentType = {
16301 BLOB:0,
16302 LINK:1,
16303 KEY: 2,
16304 NACK:3,
16305 OTHER_CODE: 0x7fff
16306};
16307
16308exports.ContentType = ContentType;
16309
16310/**
16311 * Create a new MetaInfo with the optional values.
16312 * @constructor
16313 */
16314var MetaInfo = function MetaInfo(publisherOrMetaInfo, timestamp, type, locator, freshnessSeconds, finalBlockId)
16315{
16316 if (timestamp)
16317 throw new Error
16318 ("MetaInfo constructor: timestamp support has been removed.");
16319 if (locator)
16320 throw new Error
16321 ("MetaInfo constructor: locator support has been removed.");
16322
16323 if (typeof publisherOrMetaInfo === 'object' &&
16324 publisherOrMetaInfo instanceof MetaInfo) {
16325 // Copy values.
16326 var metaInfo = publisherOrMetaInfo;
16327 this.publisher_ = metaInfo.publisher_;
16328 this.type_ = metaInfo.type_;
16329 this.otherTypeCode_ = metaInfo.otherTypeCode_;
16330 this.freshnessPeriod_ = metaInfo.freshnessPeriod_;
16331 this.finalBlockId_ = metaInfo.finalBlockId_;
16332 }
16333 else {
16334 if (publisherOrMetaInfo)
16335 throw new Error
16336 ("MetaInfo constructor: publisher support has been removed.");
16337
16338 this.type = type == null || type < 0 ? ContentType.BLOB : type;
16339 this.otherTypeCode_ = -1;
16340 this.freshnessSeconds = freshnessSeconds; // deprecated
16341 this.finalBlockID = finalBlockId; // byte array // deprecated
16342 }
16343
16344 this.changeCount_ = 0;
16345};
16346
16347exports.MetaInfo = MetaInfo;
16348
16349/**
16350 * Get the content type.
16351 * @return {number} The content type as an int from ContentType. If this is
16352 * ContentType.OTHER_CODE, then call getOtherTypeCode() to get the unrecognized
16353 * content type code.
16354 */
16355MetaInfo.prototype.getType = function()
16356{
16357 return this.type_;
16358};
16359
16360/**
16361 * Get the content type code from the packet which is other than a recognized
16362 * ContentType enum value. This is only meaningful if getType() is
16363 * ContentType.OTHER_CODE.
16364 * @return {number} The type code.
16365 */
16366MetaInfo.prototype.getOtherTypeCode = function()
16367{
16368 return this.otherTypeCode_;
16369};
16370
16371/**
16372 * Get the freshness period.
16373 * @return {number} The freshness period in milliseconds, or null if not
16374 * specified.
16375 */
16376MetaInfo.prototype.getFreshnessPeriod = function()
16377{
16378 return this.freshnessPeriod_;
16379};
16380
16381/**
16382 * Get the final block ID.
16383 * @return {Name.Component} The final block ID as a Name.Component. If the
16384 * Name.Component getValue().size() is 0, then the final block ID is not specified.
16385 */
16386MetaInfo.prototype.getFinalBlockId = function()
16387{
16388 return this.finalBlockId_;
16389};
16390
16391/**
16392 * @deprecated Use getFinalBlockId.
16393 */
16394MetaInfo.prototype.getFinalBlockID = function()
16395{
16396 return this.getFinalBlockId();
16397};
16398
16399/**
16400 * @deprecated Use getFinalBlockId. This method returns a Buffer which is the former
16401 * behavior of getFinalBlockId, and should only be used while updating your code.
16402 */
16403MetaInfo.prototype.getFinalBlockIDAsBuffer = function()
16404{
16405 return this.finalBlockId_.getValue().buf();
16406};
16407
16408/**
16409 * Set the content type.
16410 * @param {number} type The content type as an int from ContentType. If null,
16411 * this uses ContentType.BLOB. If the packet's content type is not a recognized
16412 * ContentType enum value, use ContentType.OTHER_CODE and call setOtherTypeCode().
16413 */
16414MetaInfo.prototype.setType = function(type)
16415{
16416 this.type_ = type == null || type < 0 ? ContentType.BLOB : type;
16417 ++this.changeCount_;
16418};
16419
16420/**
16421 * Set the packet’s content type code to use when the content type enum is
16422 * ContentType.OTHER_CODE. If the packet’s content type code is a recognized
16423 * enum value, just call setType().
16424 * @param {number} otherTypeCode The packet’s unrecognized content type code,
16425 * which must be non-negative.
16426 */
16427MetaInfo.prototype.setOtherTypeCode = function(otherTypeCode)
16428{
16429 if (otherTypeCode < 0)
16430 throw new Error("MetaInfo other type code must be non-negative");
16431
16432 this.otherTypeCode_ = otherTypeCode;
16433 ++this.changeCount_;
16434};
16435
16436/**
16437 * Set the freshness period.
16438 * @param {number} freshnessPeriod The freshness period in milliseconds, or null
16439 * for not specified.
16440 */
16441MetaInfo.prototype.setFreshnessPeriod = function(freshnessPeriod)
16442{
16443 if (freshnessPeriod == null || freshnessPeriod < 0)
16444 this.freshnessPeriod_ = null;
16445 else
16446 this.freshnessPeriod_ = freshnessPeriod;
16447 ++this.changeCount_;
16448};
16449
16450/**
16451 * Set the final block ID.
16452 * @param {Name.Component} finalBlockId The final block ID as a Name.Component.
16453 * If not specified, set to a new default Name.Component(), or to a
16454 * Name.Component where getValue().size() is 0.
16455 */
16456MetaInfo.prototype.setFinalBlockId = function(finalBlockId)
16457{
16458 this.finalBlockId_ = typeof finalBlockId === 'object' &&
16459 finalBlockId instanceof Name.Component ?
16460 finalBlockId : new Name.Component(finalBlockId);
16461 ++this.changeCount_;
16462};
16463
16464/**
16465 * @deprecated Use setFinalBlockId.
16466 */
16467MetaInfo.prototype.setFinalBlockID = function(finalBlockId)
16468{
16469 this.setFinalBlockId(finalBlockId);
16470};
16471
16472/**
16473 * Get the change count, which is incremented each time this object is changed.
16474 * @return {number} The change count.
16475 */
16476MetaInfo.prototype.getChangeCount = function()
16477{
16478 return this.changeCount_;
16479};
16480
16481// Define properties so we can change member variable types and implement changeCount_.
16482Object.defineProperty(MetaInfo.prototype, "type",
16483 { get: function() { return this.getType(); },
16484 set: function(val) { this.setType(val); } });
16485/**
16486 * @deprecated Use getFreshnessPeriod and setFreshnessPeriod.
16487 */
16488Object.defineProperty(MetaInfo.prototype, "freshnessSeconds",
16489 { get: function() {
16490 if (this.freshnessPeriod_ == null || this.freshnessPeriod_ < 0)
16491 return null;
16492 else
16493 // Convert from milliseconds.
16494 return this.freshnessPeriod_ / 1000.0;
16495 },
16496 set: function(val) {
16497 if (val == null || val < 0)
16498 this.freshnessPeriod_ = null;
16499 else
16500 // Convert to milliseconds.
16501 this.freshnessPeriod_ = val * 1000.0;
16502 ++this.changeCount_;
16503 } });
16504/**
16505 * @deprecated Use getFinalBlockId and setFinalBlockId.
16506 */
16507Object.defineProperty(MetaInfo.prototype, "finalBlockID",
16508 { get: function() { return this.getFinalBlockIDAsBuffer(); },
16509 set: function(val) { this.setFinalBlockId(val); } });
16510/**
16511 * This class represents an NDN Data Signature object.
16512 * Copyright (C) 2016 Regents of the University of California.
16513 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
16514 *
16515 * This program is free software: you can redistribute it and/or modify
16516 * it under the terms of the GNU Lesser General Public License as published by
16517 * the Free Software Foundation, either version 3 of the License, or
16518 * (at your option) any later version.
16519 *
16520 * This program is distributed in the hope that it will be useful,
16521 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16522 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16523 * GNU Lesser General Public License for more details.
16524 *
16525 * You should have received a copy of the GNU Lesser General Public License
16526 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16527 * A copy of the GNU Lesser General Public License is in the file COPYING.
16528 */
16529
16530/** @ignore */
16531var Blob = require('./util/blob.js').Blob; /** @ignore */
16532var ChangeCounter = require('./util/change-counter.js').ChangeCounter; /** @ignore */
16533var KeyLocator = require('./key-locator.js').KeyLocator;
16534
16535/**
16536 * Create a new Sha256WithEcdsaSignature object, possibly copying values from
16537 * another object.
16538 *
16539 * @param {Sha256WithEcdsaSignature} value (optional) If value is a
16540 * Sha256WithEcdsaSignature, copy its values. If value is omitted, the
16541 * keyLocator is the default with unspecified values and the signature is
16542 * unspecified.
16543 * @constructor
16544 */
16545var Sha256WithEcdsaSignature = function Sha256WithEcdsaSignature(value)
16546{
16547 if (typeof value === 'object' && value instanceof Sha256WithEcdsaSignature) {
16548 // Copy the values.
16549 this.keyLocator_ = new ChangeCounter(new KeyLocator(value.getKeyLocator()));
16550 this.signature_ = value.signature_;
16551 }
16552 else {
16553 this.keyLocator_ = new ChangeCounter(new KeyLocator());
16554 this.signature_ = new Blob();
16555 }
16556
16557 this.changeCount_ = 0;
16558};
16559
16560exports.Sha256WithEcdsaSignature = Sha256WithEcdsaSignature;
16561
16562/**
16563 * Create a new Sha256WithEcdsaSignature which is a copy of this object.
16564 * @return {Sha256WithEcdsaSignature} A new object which is a copy of this
16565 * object.
16566 */
16567Sha256WithEcdsaSignature.prototype.clone = function()
16568{
16569 return new Sha256WithEcdsaSignature(this);
16570};
16571
16572/**
16573 * Get the key locator.
16574 * @return {KeyLocator} The key locator.
16575 */
16576Sha256WithEcdsaSignature.prototype.getKeyLocator = function()
16577{
16578 return this.keyLocator_.get();
16579};
16580
16581/**
16582 * Get the data packet's signature bytes.
16583 * @return {Blob} The signature bytes. If not specified, the value isNull().
16584 */
16585Sha256WithEcdsaSignature.prototype.getSignature = function()
16586{
16587 return this.signature_;
16588};
16589
16590/**
16591 * Set the key locator to a copy of the given keyLocator.
16592 * @param {KeyLocator} keyLocator The KeyLocator to copy.
16593 */
16594Sha256WithEcdsaSignature.prototype.setKeyLocator = function(keyLocator)
16595{
16596 this.keyLocator_.set(typeof keyLocator === 'object' &&
16597 keyLocator instanceof KeyLocator ?
16598 new KeyLocator(keyLocator) : new KeyLocator());
16599 ++this.changeCount_;
16600};
16601
16602/**
16603 * Set the data packet's signature bytes.
16604 * @param {Blob} signature
16605 */
16606Sha256WithEcdsaSignature.prototype.setSignature = function(signature)
16607{
16608 this.signature_ = typeof signature === 'object' && signature instanceof Blob ?
16609 signature : new Blob(signature);
16610 ++this.changeCount_;
16611};
16612
16613/**
16614 * Get the change count, which is incremented each time this object (or a child
16615 * object) is changed.
16616 * @return {number} The change count.
16617 */
16618Sha256WithEcdsaSignature.prototype.getChangeCount = function()
16619{
16620 // Make sure each of the checkChanged is called.
16621 var changed = this.keyLocator_.checkChanged();
16622 if (changed)
16623 // A child object has changed, so update the change count.
16624 ++this.changeCount_;
16625
16626 return this.changeCount_;
16627};
16628/**
16629 * This class represents an NDN Data Signature object.
16630 * Copyright (C) 2014-2016 Regents of the University of California.
16631 * @author: Meki Cheraoui
16632 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
16633 *
16634 * This program is free software: you can redistribute it and/or modify
16635 * it under the terms of the GNU Lesser General Public License as published by
16636 * the Free Software Foundation, either version 3 of the License, or
16637 * (at your option) any later version.
16638 *
16639 * This program is distributed in the hope that it will be useful,
16640 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16641 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16642 * GNU Lesser General Public License for more details.
16643 *
16644 * You should have received a copy of the GNU Lesser General Public License
16645 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16646 * A copy of the GNU Lesser General Public License is in the file COPYING.
16647 */
16648
16649/** @ignore */
16650var Blob = require('./util/blob.js').Blob; /** @ignore */
16651var ChangeCounter = require('./util/change-counter.js').ChangeCounter; /** @ignore */
16652var KeyLocator = require('./key-locator.js').KeyLocator;
16653
16654/**
16655 * Create a new Sha256WithRsaSignature object, possibly copying values from
16656 * another object.
16657 *
16658 * @param {Sha256WithRsaSignature} value (optional) If value is a
16659 * Sha256WithRsaSignature, copy its values. If value is omitted, the keyLocator
16660 * is the default with unspecified values and the signature is unspecified.
16661 * @constructor
16662 */
16663var Sha256WithRsaSignature = function Sha256WithRsaSignature(value)
16664{
16665 if (typeof value === 'object' && value instanceof Sha256WithRsaSignature) {
16666 // Copy the values.
16667 this.keyLocator_ = new ChangeCounter(new KeyLocator(value.getKeyLocator()));
16668 this.signature_ = value.signature_;
16669 }
16670 else {
16671 this.keyLocator_ = new ChangeCounter(new KeyLocator());
16672 this.signature_ = new Blob();
16673 }
16674
16675 this.changeCount_ = 0;
16676};
16677
16678exports.Sha256WithRsaSignature = Sha256WithRsaSignature;
16679
16680/**
16681 * Create a new Sha256WithRsaSignature which is a copy of this object.
16682 * @return {Sha256WithRsaSignature} A new object which is a copy of this object.
16683 */
16684Sha256WithRsaSignature.prototype.clone = function()
16685{
16686 return new Sha256WithRsaSignature(this);
16687};
16688
16689/**
16690 * Get the key locator.
16691 * @return {KeyLocator} The key locator.
16692 */
16693Sha256WithRsaSignature.prototype.getKeyLocator = function()
16694{
16695 return this.keyLocator_.get();
16696};
16697
16698/**
16699 * Get the data packet's signature bytes.
16700 * @return {Blob} The signature bytes. If not specified, the value isNull().
16701 */
16702Sha256WithRsaSignature.prototype.getSignature = function()
16703{
16704 return this.signature_;
16705};
16706
16707/**
16708 * @deprecated Use getSignature. This method returns a Buffer which is the former
16709 * behavior of getSignature, and should only be used while updating your code.
16710 */
16711Sha256WithRsaSignature.prototype.getSignatureAsBuffer = function()
16712{
16713 return this.signature_.buf();
16714};
16715
16716/**
16717 * Set the key locator to a copy of the given keyLocator.
16718 * @param {KeyLocator} keyLocator The KeyLocator to copy.
16719 */
16720Sha256WithRsaSignature.prototype.setKeyLocator = function(keyLocator)
16721{
16722 this.keyLocator_.set(typeof keyLocator === 'object' &&
16723 keyLocator instanceof KeyLocator ?
16724 new KeyLocator(keyLocator) : new KeyLocator());
16725 ++this.changeCount_;
16726};
16727
16728/**
16729 * Set the data packet's signature bytes.
16730 * @param {Blob} signature
16731 */
16732Sha256WithRsaSignature.prototype.setSignature = function(signature)
16733{
16734 this.signature_ = typeof signature === 'object' && signature instanceof Blob ?
16735 signature : new Blob(signature);
16736 ++this.changeCount_;
16737};
16738
16739/**
16740 * Get the change count, which is incremented each time this object (or a child
16741 * object) is changed.
16742 * @return {number} The change count.
16743 */
16744Sha256WithRsaSignature.prototype.getChangeCount = function()
16745{
16746 // Make sure each of the checkChanged is called.
16747 var changed = this.keyLocator_.checkChanged();
16748 if (changed)
16749 // A child object has changed, so update the change count.
16750 ++this.changeCount_;
16751
16752 return this.changeCount_;
16753};
16754
16755// Define properties so we can change member variable types and implement changeCount_.
16756Object.defineProperty(Sha256WithRsaSignature.prototype, "keyLocator",
16757 { get: function() { return this.getKeyLocator(); },
16758 set: function(val) { this.setKeyLocator(val); } });
16759/**
16760 * @@deprecated Use getSignature and setSignature.
16761 */
16762Object.defineProperty(Sha256WithRsaSignature.prototype, "signature",
16763 { get: function() { return this.getSignatureAsBuffer(); },
16764 set: function(val) { this.setSignature(val); } });
16765/**
16766 * This class represents an NDN Data Signature object.
16767 * Copyright (C) 2016 Regents of the University of California.
16768 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
16769 *
16770 * This program is free software: you can redistribute it and/or modify
16771 * it under the terms of the GNU Lesser General Public License as published by
16772 * the Free Software Foundation, either version 3 of the License, or
16773 * (at your option) any later version.
16774 *
16775 * This program is distributed in the hope that it will be useful,
16776 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16777 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16778 * GNU Lesser General Public License for more details.
16779 *
16780 * You should have received a copy of the GNU Lesser General Public License
16781 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16782 * A copy of the GNU Lesser General Public License is in the file COPYING.
16783 */
16784
16785/** @ignore */
16786var Blob = require('./util/blob.js').Blob;
16787
16788/**
16789 * A GenericSignature extends Signature and holds the encoding bytes of the
16790 * SignatureInfo so that the application can process experimental signature
16791 * types. When decoding a packet, if the type of SignatureInfo is not
16792 * recognized, the library creates a GenericSignature.
16793 * Create a new GenericSignature object, possibly copying values from another
16794 * object.
16795 *
16796 * @param {GenericSignature} value (optional) If value is a GenericSignature,
16797 * copy its values.
16798 * @constructor
16799 */
16800var GenericSignature = function GenericSignature(value)
16801{
16802 if (typeof value === 'object' && value instanceof GenericSignature) {
16803 // Copy the values.
16804 this.signature_ = value.signature_;
16805 this.signatureInfoEncoding_ = value.signatureInfoEncoding_;
16806 this.typeCode_ = value.typeCode_;
16807 }
16808 else {
16809 this.signature_ = new Blob();
16810 this.signatureInfoEncoding_ = new Blob();
16811 this.typeCode_ = null;
16812 }
16813
16814 this.changeCount_ = 0;
16815};
16816
16817exports.GenericSignature = GenericSignature;
16818
16819/**
16820 * Create a new GenericSignature which is a copy of this object.
16821 * @return {GenericSignature} A new object which is a copy of this object.
16822 */
16823GenericSignature.prototype.clone = function()
16824{
16825 return new GenericSignature(this);
16826};
16827
16828/**
16829 * Get the data packet's signature bytes.
16830 * @return {Blob} The signature bytes. If not specified, the value isNull().
16831 */
16832GenericSignature.prototype.getSignature = function()
16833{
16834 return this.signature_;
16835};
16836
16837/**
16838 * @deprecated Use getSignature. This method returns a Buffer which is the former
16839 * behavior of getSignature, and should only be used while updating your code.
16840 */
16841GenericSignature.prototype.getSignatureAsBuffer = function()
16842{
16843 return this.signature_.buf();
16844};
16845
16846/**
16847 * Get the bytes of the entire signature info encoding (including the type
16848 * code).
16849 * @return {Blob} The encoding bytes. If not specified, the value isNull().
16850 */
16851GenericSignature.prototype.getSignatureInfoEncoding = function()
16852{
16853 return this.signatureInfoEncoding_;
16854};
16855
16856/**
16857 * Get the type code of the signature type. When wire decode calls
16858 * setSignatureInfoEncoding, it sets the type code. Note that the type code
16859 * is ignored during wire encode, which simply uses getSignatureInfoEncoding()
16860 * where the encoding already has the type code.
16861 * @return {number} The type code, or null if not known.
16862 */
16863GenericSignature.prototype.getTypeCode = function() { return this.typeCode_; };
16864
16865/**
16866 * Set the data packet's signature bytes.
16867 * @param {Blob} signature
16868 */
16869GenericSignature.prototype.setSignature = function(signature)
16870{
16871 this.signature_ = typeof signature === 'object' && signature instanceof Blob ?
16872 signature : new Blob(signature);
16873 ++this.changeCount_;
16874};
16875
16876/**
16877 * Set the bytes of the entire signature info encoding (including the type
16878 * code).
16879 * @param {Blob} signatureInfoEncoding A Blob with the encoding bytes.
16880 * @param {number} (optional) The type code of the signature type, or null if
16881 * not known. (When a GenericSignature is created by wire decoding, it sets
16882 * the typeCode.)
16883 */
16884GenericSignature.prototype.setSignatureInfoEncoding = function
16885 (signatureInfoEncoding, typeCode)
16886{
16887 this.signatureInfoEncoding_ =
16888 typeof signatureInfoEncoding === 'object' && signatureInfoEncoding instanceof Blob ?
16889 signatureInfoEncoding : new Blob(signatureInfoEncoding);
16890 this.typeCode_ = typeCode;
16891 ++this.changeCount_;
16892};
16893
16894/**
16895 * Get the change count, which is incremented each time this object (or a child
16896 * object) is changed.
16897 * @return {number} The change count.
16898 */
16899GenericSignature.prototype.getChangeCount = function()
16900{
16901 return this.changeCount_;
16902};
16903
16904/**
16905 * @@deprecated Use getSignature and setSignature.
16906 */
16907Object.defineProperty(GenericSignature.prototype, "signature",
16908 { get: function() { return this.getSignatureAsBuffer(); },
16909 set: function(val) { this.setSignature(val); } });
16910/**
16911 * This class represents an NDN Data Signature object.
16912 * Copyright (C) 2016 Regents of the University of California.
16913 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
16914 *
16915 * This program is free software: you can redistribute it and/or modify
16916 * it under the terms of the GNU Lesser General Public License as published by
16917 * the Free Software Foundation, either version 3 of the License, or
16918 * (at your option) any later version.
16919 *
16920 * This program is distributed in the hope that it will be useful,
16921 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16922 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16923 * GNU Lesser General Public License for more details.
16924 *
16925 * You should have received a copy of the GNU Lesser General Public License
16926 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16927 * A copy of the GNU Lesser General Public License is in the file COPYING.
16928 */
16929
16930/** @ignore */
16931var Blob = require('./util/blob.js').Blob; /** @ignore */
16932var ChangeCounter = require('./util/change-counter.js').ChangeCounter; /** @ignore */
16933var KeyLocator = require('./key-locator.js').KeyLocator;
16934
16935/**
16936 * An HmacWithSha256Signature holds the signature bits and other info
16937 * representing an HmacWithSha256 signature in a packet.
16938 * Create a new HmacWithSha256Signature object, possibly copying values from
16939 * another object.
16940 *
16941 * @param {HmacWithSha256Signature} value (optional) If value is a
16942 * HmacWithSha256Signature, copy its values. If value is omitted, the keyLocator
16943 * is the default with unspecified values and the signature is unspecified.
16944 * @constructor
16945 */
16946var HmacWithSha256Signature = function HmacWithSha256Signature(value)
16947{
16948 if (typeof value === 'object' && value instanceof HmacWithSha256Signature) {
16949 // Copy the values.
16950 this.keyLocator_ = new ChangeCounter(new KeyLocator(value.getKeyLocator()));
16951 this.signature_ = value.signature_;
16952 }
16953 else {
16954 this.keyLocator_ = new ChangeCounter(new KeyLocator());
16955 this.signature_ = new Blob();
16956 }
16957
16958 this.changeCount_ = 0;
16959};
16960
16961exports.HmacWithSha256Signature = HmacWithSha256Signature;
16962
16963/**
16964 * Create a new HmacWithSha256Signature which is a copy of this object.
16965 * @return {HmacWithSha256Signature} A new object which is a copy of this object.
16966 */
16967HmacWithSha256Signature.prototype.clone = function()
16968{
16969 return new HmacWithSha256Signature(this);
16970};
16971
16972/**
16973 * Get the key locator.
16974 * @return {KeyLocator} The key locator.
16975 */
16976HmacWithSha256Signature.prototype.getKeyLocator = function()
16977{
16978 return this.keyLocator_.get();
16979};
16980
16981/**
16982 * Get the data packet's signature bytes.
16983 * @return {Blob} The signature bytes. If not specified, the value isNull().
16984 */
16985HmacWithSha256Signature.prototype.getSignature = function()
16986{
16987 return this.signature_;
16988};
16989
16990/**
16991 * @deprecated Use getSignature. This method returns a Buffer which is the former
16992 * behavior of getSignature, and should only be used while updating your code.
16993 */
16994HmacWithSha256Signature.prototype.getSignatureAsBuffer = function()
16995{
16996 return this.signature_.buf();
16997};
16998
16999/**
17000 * Set the key locator to a copy of the given keyLocator.
17001 * @param {KeyLocator} keyLocator The KeyLocator to copy.
17002 */
17003HmacWithSha256Signature.prototype.setKeyLocator = function(keyLocator)
17004{
17005 this.keyLocator_.set(typeof keyLocator === 'object' &&
17006 keyLocator instanceof KeyLocator ?
17007 new KeyLocator(keyLocator) : new KeyLocator());
17008 ++this.changeCount_;
17009};
17010
17011/**
17012 * Set the data packet's signature bytes.
17013 * @param {Blob} signature
17014 */
17015HmacWithSha256Signature.prototype.setSignature = function(signature)
17016{
17017 this.signature_ = typeof signature === 'object' && signature instanceof Blob ?
17018 signature : new Blob(signature);
17019 ++this.changeCount_;
17020};
17021
17022/**
17023 * Get the change count, which is incremented each time this object (or a child
17024 * object) is changed.
17025 * @return {number} The change count.
17026 */
17027HmacWithSha256Signature.prototype.getChangeCount = function()
17028{
17029 // Make sure each of the checkChanged is called.
17030 var changed = this.keyLocator_.checkChanged();
17031 if (changed)
17032 // A child object has changed, so update the change count.
17033 ++this.changeCount_;
17034
17035 return this.changeCount_;
17036};
17037
17038// Define properties so we can change member variable types and implement changeCount_.
17039Object.defineProperty(HmacWithSha256Signature.prototype, "keyLocator",
17040 { get: function() { return this.getKeyLocator(); },
17041 set: function(val) { this.setKeyLocator(val); } });
17042/**
17043 * @@deprecated Use getSignature and setSignature.
17044 */
17045Object.defineProperty(HmacWithSha256Signature.prototype, "signature",
17046 { get: function() { return this.getSignatureAsBuffer(); },
17047 set: function(val) { this.setSignature(val); } });
17048/**
17049 * This class represents an NDN Data Signature object.
17050 * Copyright (C) 2014-2016 Regents of the University of California.
17051 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
17052 *
17053 * This program is free software: you can redistribute it and/or modify
17054 * it under the terms of the GNU Lesser General Public License as published by
17055 * the Free Software Foundation, either version 3 of the License, or
17056 * (at your option) any later version.
17057 *
17058 * This program is distributed in the hope that it will be useful,
17059 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17060 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17061 * GNU Lesser General Public License for more details.
17062 *
17063 * You should have received a copy of the GNU Lesser General Public License
17064 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17065 * A copy of the GNU Lesser General Public License is in the file COPYING.
17066 */
17067
17068/** @ignore */
17069var Blob = require('./util/blob.js').Blob;
17070
17071/**
17072 * A DigestSha256Signature extends Signature and holds the signature bits (which
17073 * are only the SHA256 digest) and an empty SignatureInfo for a data packet or
17074 * signed interest.
17075 *
17076 * Create a new DigestSha256Signature object, possibly copying values from
17077 * another object.
17078 *
17079 * @param {DigestSha256Signature} value (optional) If value is a
17080 * DigestSha256Signature, copy its values. If value is omitted, the signature
17081 * is unspecified.
17082 * @constructor
17083 */
17084var DigestSha256Signature = function DigestSha256Signature(value)
17085{
17086 if (typeof value === 'object' && value instanceof DigestSha256Signature)
17087 // Copy the values.
17088 this.signature_ = value.signature_;
17089 else
17090 this.signature_ = new Blob();
17091
17092 this.changeCount_ = 0;
17093};
17094
17095exports.DigestSha256Signature = DigestSha256Signature;
17096
17097/**
17098 * Create a new DigestSha256Signature which is a copy of this object.
17099 * @return {DigestSha256Signature} A new object which is a copy of this object.
17100 */
17101DigestSha256Signature.prototype.clone = function()
17102{
17103 return new DigestSha256Signature(this);
17104};
17105
17106/**
17107 * Get the signature bytes (which are only the digest).
17108 * @return {Blob} The signature bytes. If not specified, the value isNull().
17109 */
17110DigestSha256Signature.prototype.getSignature = function()
17111{
17112 return this.signature_;
17113};
17114
17115/**
17116 * Set the signature bytes to the given value.
17117 * @param {Blob} signature
17118 */
17119DigestSha256Signature.prototype.setSignature = function(signature)
17120{
17121 this.signature_ = typeof signature === 'object' && signature instanceof Blob ?
17122 signature : new Blob(signature);
17123 ++this.changeCount_;
17124};
17125
17126/**
17127 * Get the change count, which is incremented each time this object is changed.
17128 * @return {number} The change count.
17129 */
17130DigestSha256Signature.prototype.getChangeCount = function()
17131{
17132 return this.changeCount_;
17133};
17134
17135// Define properties so we can change member variable types and implement changeCount_.
17136/**
17137 * @@deprecated Use getSignature and setSignature.
17138 */
17139Object.defineProperty(DigestSha256Signature.prototype, "signature",
17140 { get: function() { return this.getSignature(); },
17141 set: function(val) { this.setSignature(val); } });
17142/**
17143 * This class represents an NDN Data object.
17144 * Copyright (C) 2013-2016 Regents of the University of California.
17145 * @author: Meki Cheraoui
17146 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
17147 *
17148 * This program is free software: you can redistribute it and/or modify
17149 * it under the terms of the GNU Lesser General Public License as published by
17150 * the Free Software Foundation, either version 3 of the License, or
17151 * (at your option) any later version.
17152 *
17153 * This program is distributed in the hope that it will be useful,
17154 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17155 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17156 * GNU Lesser General Public License for more details.
17157 *
17158 * You should have received a copy of the GNU Lesser General Public License
17159 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17160 * A copy of the GNU Lesser General Public License is in the file COPYING.
17161 */
17162
17163/** @ignore */
17164var Blob = require('./util/blob.js').Blob; /** @ignore */
17165var SignedBlob = require('./util/signed-blob.js').SignedBlob; /** @ignore */
17166var ChangeCounter = require('./util/change-counter.js').ChangeCounter; /** @ignore */
17167var Name = require('./name.js').Name; /** @ignore */
17168var Sha256WithRsaSignature = require('./sha256-with-rsa-signature.js').Sha256WithRsaSignature; /** @ignore */
17169var MetaInfo = require('./meta-info.js').MetaInfo; /** @ignore */
17170var IncomingFaceId = require('./lp/incoming-face-id.js').IncomingFaceId; /** @ignore */
17171var WireFormat = require('./encoding/wire-format.js').WireFormat; /** @ignore */
17172var Crypto = require('./crypto.js');
17173
17174/**
17175 * Create a new Data with the optional values. There are 2 forms of constructor:
17176 * new Data([name] [, content]);
17177 * new Data(name, metaInfo [, content]);
17178 *
17179 * @constructor
17180 * @param {Name} name
17181 * @param {MetaInfo} metaInfo
17182 * @param {Buffer} content
17183 */
17184var Data = function Data(nameOrData, metaInfoOrContent, arg3)
17185{
17186 if (nameOrData instanceof Data) {
17187 // The copy constructor.
17188 var data = nameOrData;
17189
17190 // Copy the Data object.
17191 this.name_ = new ChangeCounter(new Name(data.getName()));
17192 this.metaInfo_ = new ChangeCounter(new MetaInfo(data.getMetaInfo()));
17193 this.signature_ = new ChangeCounter(data.getSignature().clone());
17194 this.content_ = data.content_;
17195 this.defaultWireEncoding_ = data.getDefaultWireEncoding();
17196 this.defaultFullName_ = data.defaultFullName_;
17197 this.defaultWireEncodingFormat_ = data.defaultWireEncodingFormat_;
17198 }
17199 else {
17200 var name = nameOrData;
17201 if (typeof name === 'string')
17202 this.name_ = new ChangeCounter(new Name(name));
17203 else
17204 this.name_ = new ChangeCounter(typeof name === 'object' && name instanceof Name ?
17205 new Name(name) : new Name());
17206
17207 var metaInfo;
17208 var content;
17209 if (typeof metaInfoOrContent === 'object' &&
17210 metaInfoOrContent instanceof MetaInfo) {
17211 metaInfo = metaInfoOrContent;
17212 content = arg3;
17213 }
17214 else {
17215 metaInfo = null;
17216 content = metaInfoOrContent;
17217 }
17218
17219 this.metaInfo_ = new ChangeCounter(typeof metaInfo === 'object' && metaInfo instanceof MetaInfo ?
17220 new MetaInfo(metaInfo) : new MetaInfo());
17221
17222 this.content_ = typeof content === 'object' && content instanceof Blob ?
17223 content : new Blob(content, true);
17224
17225 this.signature_ = new ChangeCounter(new Sha256WithRsaSignature());
17226 this.defaultWireEncoding_ = new SignedBlob();
17227 this.defaultFullName_ = new Name();
17228 this.defaultWireEncodingFormat_ = null;
17229 }
17230
17231 this.getDefaultWireEncodingChangeCount_ = 0;
17232 this.changeCount_ = 0;
17233 this.lpPacket_ = null;
17234};
17235
17236exports.Data = Data;
17237
17238/**
17239 * Get the data packet's name.
17240 * @return {Name} The name. If not specified, the name size() is 0.
17241 */
17242Data.prototype.getName = function()
17243{
17244 return this.name_.get();
17245};
17246
17247/**
17248 * Get the data packet's meta info.
17249 * @return {MetaInfo} The meta info.
17250 */
17251Data.prototype.getMetaInfo = function()
17252{
17253 return this.metaInfo_.get();
17254};
17255
17256/**
17257 * Get the data packet's signature object.
17258 * @return {Signature} The signature object.
17259 */
17260Data.prototype.getSignature = function()
17261{
17262 return this.signature_.get();
17263};
17264
17265/**
17266 * Get the data packet's content.
17267 * @return {Blob} The content as a Blob, which isNull() if unspecified.
17268 */
17269Data.prototype.getContent = function()
17270{
17271 return this.content_;
17272};
17273
17274/**
17275 * @deprecated Use getContent. This method returns a Buffer which is the former
17276 * behavior of getContent, and should only be used while updating your code.
17277 */
17278Data.prototype.getContentAsBuffer = function()
17279{
17280 return this.content_.buf();
17281};
17282
17283/**
17284 * Return the default wire encoding, which was encoded with
17285 * getDefaultWireEncodingFormat().
17286 * @return {SignedBlob} The default wire encoding, whose isNull() may be true
17287 * if there is no default wire encoding.
17288 */
17289Data.prototype.getDefaultWireEncoding = function()
17290{
17291 if (this.getDefaultWireEncodingChangeCount_ != this.getChangeCount()) {
17292 // The values have changed, so the default wire encoding is invalidated.
17293 this.defaultWireEncoding_ = new SignedBlob();
17294 this.defaultWireEncodingFormat_ = null;
17295 this.getDefaultWireEncodingChangeCount_ = this.getChangeCount();
17296 }
17297
17298 return this.defaultWireEncoding_;
17299};
17300
17301/**
17302 * Get the WireFormat which is used by getDefaultWireEncoding().
17303 * @return {WireFormat} The WireFormat, which is only meaningful if the
17304 * getDefaultWireEncoding() is not isNull().
17305 */
17306Data.prototype.getDefaultWireEncodingFormat = function()
17307{
17308 return this.defaultWireEncodingFormat_;
17309};
17310
17311/**
17312 * Get the incoming face ID according to the incoming packet header.
17313 * @return {number} The incoming face ID. If not specified, return null.
17314 */
17315Data.prototype.getIncomingFaceId = function()
17316{
17317 var field =
17318 this.lpPacket_ === null ? null : IncomingFaceId.getFirstHeader(this.lpPacket_);
17319 return field === null ? null : field.getFaceId();
17320};
17321
17322/**
17323 * Get the Data packet's full name, which includes the final
17324 * ImplicitSha256Digest component based on the wire encoding for a particular
17325 * wire format.
17326 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
17327 * this object. If omitted, use WireFormat.getDefaultWireFormat().
17328 * @return {Name} The full name. You must not change the Name object - if you
17329 * need to change it then make a copy.
17330 */
17331Data.prototype.getFullName = function(wireFormat)
17332{
17333 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
17334
17335 // The default full name depends on the default wire encoding.
17336 if (!this.getDefaultWireEncoding().isNull() &&
17337 this.defaultFullName_.size() > 0 &&
17338 this.getDefaultWireEncodingFormat() == wireFormat)
17339 // We already have a full name. A non-null default wire encoding means
17340 // that the Data packet fields have not changed.
17341 return this.defaultFullName_;
17342
17343 var fullName = new Name(this.getName());
17344 var hash = Crypto.createHash('sha256');
17345 // wireEncode will use the cached encoding if possible.
17346 hash.update(this.wireEncode(wireFormat).buf());
17347 fullName.appendImplicitSha256Digest(new Blob(hash.digest(), false));
17348
17349 if (wireFormat == WireFormat.getDefaultWireFormat())
17350 // wireEncode has already set defaultWireEncodingFormat_.
17351 this.defaultFullName_ = fullName;
17352
17353 return fullName;
17354};
17355
17356/**
17357 * Set name to a copy of the given Name.
17358 * @param {Name} name The Name which is copied.
17359 * @return {Data} This Data so that you can chain calls to update values.
17360 */
17361Data.prototype.setName = function(name)
17362{
17363 this.name_.set(typeof name === 'object' && name instanceof Name ?
17364 new Name(name) : new Name());
17365 ++this.changeCount_;
17366 return this;
17367};
17368
17369/**
17370 * Set metaInfo to a copy of the given MetaInfo.
17371 * @param {MetaInfo} metaInfo The MetaInfo which is copied.
17372 * @return {Data} This Data so that you can chain calls to update values.
17373 */
17374Data.prototype.setMetaInfo = function(metaInfo)
17375{
17376 this.metaInfo_.set(typeof metaInfo === 'object' && metaInfo instanceof MetaInfo ?
17377 new MetaInfo(metaInfo) : new MetaInfo());
17378 ++this.changeCount_;
17379 return this;
17380};
17381
17382/**
17383 * Set the signature to a copy of the given signature.
17384 * @param {Signature} signature The signature object which is cloned.
17385 * @return {Data} This Data so that you can chain calls to update values.
17386 */
17387Data.prototype.setSignature = function(signature)
17388{
17389 this.signature_.set(signature == null ?
17390 new Sha256WithRsaSignature() : signature.clone());
17391 ++this.changeCount_;
17392 return this;
17393};
17394
17395/**
17396 * Set the content to the given value.
17397 * @param {Blob|Buffer} content The content bytes. If content is not a Blob,
17398 * then create a new Blob to copy the bytes (otherwise take another pointer to
17399 * the same Blob).
17400 * @return {Data} This Data so that you can chain calls to update values.
17401 */
17402Data.prototype.setContent = function(content)
17403{
17404 this.content_ = typeof content === 'object' && content instanceof Blob ?
17405 content : new Blob(content, true);
17406 ++this.changeCount_;
17407 return this;
17408};
17409
17410/**
17411 * Encode this Data for a particular wire format. If wireFormat is the default
17412 * wire format, also set the defaultWireEncoding field to the encoded result.
17413 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
17414 * this object. If omitted, use WireFormat.getDefaultWireFormat().
17415 * @return {SignedBlob} The encoded buffer in a SignedBlob object.
17416 */
17417Data.prototype.wireEncode = function(wireFormat)
17418{
17419 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
17420
17421 if (!this.getDefaultWireEncoding().isNull() &&
17422 this.getDefaultWireEncodingFormat() == wireFormat)
17423 // We already have an encoding in the desired format.
17424 return this.getDefaultWireEncoding();
17425
17426 var result = wireFormat.encodeData(this);
17427 var wireEncoding = new SignedBlob
17428 (result.encoding, result.signedPortionBeginOffset,
17429 result.signedPortionEndOffset);
17430
17431 if (wireFormat == WireFormat.getDefaultWireFormat())
17432 // This is the default wire encoding.
17433 this.setDefaultWireEncoding
17434 (wireEncoding, WireFormat.getDefaultWireFormat());
17435 return wireEncoding;
17436};
17437
17438/**
17439 * Decode the input using a particular wire format and update this Data. If
17440 * wireFormat is the default wire format, also set the defaultWireEncoding to
17441 * another pointer to the input.
17442 * @param {Blob|Buffer} input The buffer with the bytes to decode.
17443 * @param {WireFormat} wireFormat (optional) A WireFormat object used to decode
17444 * this object. If omitted, use WireFormat.getDefaultWireFormat().
17445 */
17446Data.prototype.wireDecode = function(input, wireFormat)
17447{
17448 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
17449
17450 var result;
17451 if (typeof input === 'object' && input instanceof Blob)
17452 // Input is a blob, so get its buf() and set copy false.
17453 result = wireFormat.decodeData(this, input.buf(), false);
17454 else
17455 result = wireFormat.decodeData(this, input, true);
17456
17457 if (wireFormat == WireFormat.getDefaultWireFormat())
17458 // This is the default wire encoding. In the Blob constructor, set copy
17459 // true, but if input is already a Blob, it won't copy.
17460 this.setDefaultWireEncoding(new SignedBlob
17461 (new Blob(input, true), result.signedPortionBeginOffset,
17462 result.signedPortionEndOffset),
17463 WireFormat.getDefaultWireFormat());
17464 else
17465 this.setDefaultWireEncoding(new SignedBlob(), null);
17466};
17467
17468/**
17469 * An internal library method to set the LpPacket for an incoming packet. The
17470 * application should not call this.
17471 * @param {LpPacket} lpPacket The LpPacket. This does not make a copy.
17472 * @return {Data} This Data so that you can chain calls to update values.
17473 * @note This is an experimental feature. This API may change in the future.
17474 */
17475Data.prototype.setLpPacket = function(lpPacket)
17476{
17477 this.lpPacket_ = lpPacket;
17478 // Don't update changeCount_ since this doesn't affect the wire encoding.
17479 return this;
17480}
17481
17482/**
17483 * Get the change count, which is incremented each time this object (or a child
17484 * object) is changed.
17485 * @return {number} The change count.
17486 */
17487Data.prototype.getChangeCount = function()
17488{
17489 // Make sure each of the checkChanged is called.
17490 var changed = this.name_.checkChanged();
17491 changed = this.metaInfo_.checkChanged() || changed;
17492 changed = this.signature_.checkChanged() || changed;
17493 if (changed)
17494 // A child object has changed, so update the change count.
17495 ++this.changeCount_;
17496
17497 return this.changeCount_;
17498};
17499
17500Data.prototype.setDefaultWireEncoding = function
17501 (defaultWireEncoding, defaultWireEncodingFormat)
17502{
17503 this.defaultWireEncoding_ = defaultWireEncoding;
17504 this.defaultWireEncodingFormat_ = defaultWireEncodingFormat;
17505 // Set getDefaultWireEncodingChangeCount_ so that the next call to
17506 // getDefaultWireEncoding() won't clear _defaultWireEncoding.
17507 this.getDefaultWireEncodingChangeCount_ = this.getChangeCount();
17508};
17509
17510// Define properties so we can change member variable types and implement changeCount_.
17511Object.defineProperty(Data.prototype, "name",
17512 { get: function() { return this.getName(); },
17513 set: function(val) { this.setName(val); } });
17514Object.defineProperty(Data.prototype, "metaInfo",
17515 { get: function() { return this.getMetaInfo(); },
17516 set: function(val) { this.setMetaInfo(val); } });
17517Object.defineProperty(Data.prototype, "signature",
17518 { get: function() { return this.getSignature(); },
17519 set: function(val) { this.setSignature(val); } });
17520/**
17521 * @deprecated Use getContent and setContent.
17522 */
17523Object.defineProperty(Data.prototype, "content",
17524 { get: function() { return this.getContentAsBuffer(); },
17525 set: function(val) { this.setContent(val); } });
17526/**
17527 * Copyright (C) 2014-2016 Regents of the University of California.
17528 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
17529 *
17530 * This program is free software: you can redistribute it and/or modify
17531 * it under the terms of the GNU Lesser General Public License as published by
17532 * the Free Software Foundation, either version 3 of the License, or
17533 * (at your option) any later version.
17534 *
17535 * This program is distributed in the hope that it will be useful,
17536 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17537 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17538 * GNU Lesser General Public License for more details.
17539 *
17540 * You should have received a copy of the GNU Lesser General Public License
17541 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17542 * A copy of the GNU Lesser General Public License is in the file COPYING.
17543 */
17544
17545/**
17546 * Create a new SecurityException to report an exception from the security
17547 * library, wrapping the given error object.
17548 * Call with: throw new SecurityException(new Error("message")).
17549 * @constructor
17550 * @param {Error} error The exception created with new Error.
17551 */
17552function SecurityException(error)
17553{
17554 if (error) {
17555 error.__proto__ = SecurityException.prototype;
17556 return error;
17557 }
17558}
17559
17560SecurityException.prototype = new Error();
17561SecurityException.prototype.name = "SecurityException";
17562
17563exports.SecurityException = SecurityException;
17564
17565function UnrecognizedKeyFormatException(error)
17566{
17567 // Call the base constructor.
17568 SecurityException.call(this, error);
17569}
17570UnrecognizedKeyFormatException.prototype = new SecurityException();
17571UnrecognizedKeyFormatException.prototype.name = "UnrecognizedKeyFormatException";
17572
17573exports.UnrecognizedKeyFormatException = UnrecognizedKeyFormatException;
17574
17575function UnrecognizedDigestAlgorithmException(error)
17576{
17577 // Call the base constructor.
17578 SecurityException.call(this, error);
17579}
17580UnrecognizedDigestAlgorithmException.prototype = new SecurityException();
17581UnrecognizedDigestAlgorithmException.prototype.name = "UnrecognizedDigestAlgorithmException";
17582
17583exports.UnrecognizedDigestAlgorithmException = UnrecognizedDigestAlgorithmException;
17584/**
17585 * Copyright (C) 2014-2016 Regents of the University of California.
17586 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
17587 * From ndn-cxx security by Yingdi Yu <yingdi@cs.ucla.edu>.
17588 *
17589 * This program is free software: you can redistribute it and/or modify
17590 * it under the terms of the GNU Lesser General Public License as published by
17591 * the Free Software Foundation, either version 3 of the License, or
17592 * (at your option) any later version.
17593 *
17594 * This program is distributed in the hope that it will be useful,
17595 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17596 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17597 * GNU Lesser General Public License for more details.
17598 *
17599 * You should have received a copy of the GNU Lesser General Public License
17600 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17601 * A copy of the GNU Lesser General Public License is in the file COPYING.
17602 */
17603
17604/**
17605 * This module defines constants used by the security library.
17606 */
17607
17608/**
17609 * The KeyType integer is used by the Sqlite key storage, so don't change them.
17610 * Make these the same as ndn-cxx in case the storage file is shared.
17611 * @constructor
17612 */
17613var KeyType = function KeyType()
17614{
17615}
17616
17617exports.KeyType = KeyType;
17618
17619KeyType.RSA = 0;
17620KeyType.ECDSA = 1;
17621KeyType.AES = 128;
17622
17623var KeyClass = function KeyClass()
17624{
17625};
17626
17627exports.KeyClass = KeyClass;
17628
17629KeyClass.PUBLIC = 1;
17630KeyClass.PRIVATE = 2;
17631KeyClass.SYMMETRIC = 3;
17632
17633var DigestAlgorithm = function DigestAlgorithm()
17634{
17635};
17636
17637exports.DigestAlgorithm = DigestAlgorithm;
17638
17639DigestAlgorithm.SHA256 = 1;
17640/**
17641 * Copyright (C) 2014-2016 Regents of the University of California.
17642 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
17643 * From ndn-cxx security by Yingdi Yu <yingdi@cs.ucla.edu>.
17644 *
17645 * This program is free software: you can redistribute it and/or modify
17646 * it under the terms of the GNU Lesser General Public License as published by
17647 * the Free Software Foundation, either version 3 of the License, or
17648 * (at your option) any later version.
17649 *
17650 * This program is distributed in the hope that it will be useful,
17651 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17652 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17653 * GNU Lesser General Public License for more details.
17654 *
17655 * You should have received a copy of the GNU Lesser General Public License
17656 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17657 * A copy of the GNU Lesser General Public License is in the file COPYING.
17658 */
17659
17660/** @ignore */
17661var KeyType = require('./security-types.js').KeyType;
17662
17663/**
17664 * KeyParams is a base class for key parameters. Its subclasses are used to
17665 * store parameters for key generation. You should create one of the subclasses,
17666 * for example RsaKeyParams.
17667 * @constructor
17668 */
17669var KeyParams = function KeyParams(keyType)
17670{
17671 this.keyType = keyType;
17672};
17673
17674exports.KeyParams = KeyParams;
17675
17676KeyParams.prototype.getKeyType = function()
17677{
17678 return this.keyType;
17679};
17680
17681var RsaKeyParams = function RsaKeyParams(size)
17682{
17683 // Call the base constructor.
17684 KeyParams.call(this, RsaKeyParams.getType());
17685
17686 if (size == null)
17687 size = RsaKeyParams.getDefaultSize();
17688 this.size = size;
17689};
17690
17691RsaKeyParams.prototype = new KeyParams();
17692RsaKeyParams.prototype.name = "RsaKeyParams";
17693
17694exports.RsaKeyParams = RsaKeyParams;
17695
17696RsaKeyParams.prototype.getKeySize = function()
17697{
17698 return this.size;
17699};
17700
17701RsaKeyParams.getDefaultSize = function() { return 2048; };
17702
17703RsaKeyParams.getType = function() { return KeyType.RSA; };
17704
17705var EcdsaKeyParams = function EcdsaKeyParams(size)
17706{
17707 // Call the base constructor.
17708 KeyParams.call(this, EcdsaKeyParams.getType());
17709
17710 if (size == null)
17711 size = EcdsaKeyParams.getDefaultSize();
17712 this.size = size;
17713};
17714
17715EcdsaKeyParams.prototype = new KeyParams();
17716EcdsaKeyParams.prototype.name = "EcdsaKeyParams";
17717
17718exports.EcdsaKeyParams = EcdsaKeyParams;
17719
17720EcdsaKeyParams.prototype.getKeySize = function()
17721{
17722 return this.size;
17723};
17724
17725EcdsaKeyParams.getDefaultSize = function() { return 256; };
17726
17727EcdsaKeyParams.getType = function() { return KeyType.ECDSA; };
17728
17729var AesKeyParams = function AesKeyParams(size)
17730{
17731 // Call the base constructor.
17732 KeyParams.call(this, AesKeyParams.getType());
17733
17734 if (size == null)
17735 size = AesKeyParams.getDefaultSize();
17736 this.size = size;
17737};
17738
17739AesKeyParams.prototype = new KeyParams();
17740AesKeyParams.prototype.name = "AesKeyParams";
17741
17742exports.AesKeyParams = AesKeyParams;
17743
17744AesKeyParams.prototype.getKeySize = function()
17745{
17746 return this.size;
17747};
17748
17749AesKeyParams.getDefaultSize = function() { return 64; };
17750
17751AesKeyParams.getType = function() { return KeyType.AES; };
17752/**
17753 * Copyright (C) 2014-2016 Regents of the University of California.
17754 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
17755 * From ndn-cxx security by Yingdi Yu <yingdi@cs.ucla.edu>.
17756 *
17757 * This program is free software: you can redistribute it and/or modify
17758 * it under the terms of the GNU Lesser General Public License as published by
17759 * the Free Software Foundation, either version 3 of the License, or
17760 * (at your option) any later version.
17761 *
17762 * This program is distributed in the hope that it will be useful,
17763 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17764 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17765 * GNU Lesser General Public License for more details.
17766 *
17767 * You should have received a copy of the GNU Lesser General Public License
17768 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17769 * A copy of the GNU Lesser General Public License is in the file COPYING.
17770 */
17771
17772// Use capitalized Crypto to not clash with the browser's crypto.subtle.
17773/** @ignore */
17774var Crypto = require('../../crypto.js'); /** @ignore */
17775var Blob = require('../../util/blob.js').Blob; /** @ignore */
17776var DerDecodingException = require('../../encoding/der/der-decoding-exception.js').DerDecodingException; /** @ignore */
17777var DerNode = require('../../encoding/der/der-node.js').DerNode; /** @ignore */
17778var SecurityException = require('../security-exception.js').SecurityException; /** @ignore */
17779var UnrecognizedKeyFormatException = require('../security-exception.js').UnrecognizedKeyFormatException; /** @ignore */
17780var KeyType = require('../security-types.js').KeyType; /** @ignore */
17781var DigestAlgorithm = require('../security-types.js').DigestAlgorithm;
17782
17783/**
17784 * Create a new PublicKey by decoding the keyDer. Set the key type from the
17785 * decoding.
17786 * @param {Blob} keyDer The blob of the SubjectPublicKeyInfo DER.
17787 * @throws UnrecognizedKeyFormatException if can't decode the key DER.
17788 * @constructor
17789 */
17790var PublicKey = function PublicKey(keyDer)
17791{
17792 if (!keyDer) {
17793 this.keyDer = new Blob();
17794 this.keyType = null;
17795 return;
17796 }
17797
17798 this.keyDer = keyDer;
17799
17800 // Get the public key OID.
17801 var oidString = null;
17802 try {
17803 var parsedNode = DerNode.parse(keyDer.buf(), 0);
17804 var rootChildren = parsedNode.getChildren();
17805 var algorithmIdChildren = DerNode.getSequence(rootChildren, 0).getChildren();
17806 oidString = algorithmIdChildren[0].toVal();
17807 }
17808 catch (ex) {
17809 throw new UnrecognizedKeyFormatException(new Error
17810 ("PublicKey.decodeKeyType: Error decoding the public key: " + ex.message));
17811 }
17812
17813 // Verify that the we can decode.
17814 if (oidString == PublicKey.RSA_ENCRYPTION_OID) {
17815 this.keyType = KeyType.RSA;
17816 // TODO: Check RSA decoding.
17817 }
17818 else if (oidString == PublicKey.EC_ENCRYPTION_OID) {
17819 this.keyType = KeyType.ECDSA;
17820 // TODO: Check EC decoding.
17821 }
17822};
17823
17824exports.PublicKey = PublicKey;
17825
17826/**
17827 * Encode the public key into DER.
17828 * @return {DerNode} The encoded DER syntax tree.
17829 */
17830PublicKey.prototype.toDer = function()
17831{
17832 return DerNode.parse(this.keyDer.buf());
17833};
17834
17835/**
17836 * Get the key type.
17837 * @return {number} The key type as an int from KeyType.
17838 */
17839PublicKey.prototype.getKeyType = function()
17840{
17841 return this.keyType;
17842};
17843
17844/**
17845 * Get the digest of the public key.
17846 * @param {number} digestAlgorithm (optional) The integer from DigestAlgorithm,
17847 * such as DigestAlgorithm.SHA256. If omitted, use DigestAlgorithm.SHA256 .
17848 * @return {Blob} The digest value.
17849 */
17850PublicKey.prototype.getDigest = function(digestAlgorithm)
17851{
17852 if (digestAlgorithm == undefined)
17853 digestAlgorithm = DigestAlgorithm.SHA256;
17854
17855 if (digestAlgorithm == DigestAlgorithm.SHA256) {
17856 var hash = Crypto.createHash('sha256');
17857 hash.update(this.keyDer.buf());
17858 return new Blob(hash.digest(), false);
17859 }
17860 else
17861 throw new SecurityException(new Error("Wrong format!"));
17862};
17863
17864/**
17865 * Get the raw bytes of the public key in DER format.
17866 * @return {Blob} The public key DER.
17867 */
17868PublicKey.prototype.getKeyDer = function()
17869{
17870 return this.keyDer;
17871};
17872
17873PublicKey.RSA_ENCRYPTION_OID = "1.2.840.113549.1.1.1";
17874PublicKey.EC_ENCRYPTION_OID = "1.2.840.10045.2.1";
17875/**
17876 * Copyright (C) 2014-2016 Regents of the University of California.
17877 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
17878 * From ndn-cxx security by Yingdi Yu <yingdi@cs.ucla.edu>.
17879 *
17880 * This program is free software: you can redistribute it and/or modify
17881 * it under the terms of the GNU Lesser General Public License as published by
17882 * the Free Software Foundation, either version 3 of the License, or
17883 * (at your option) any later version.
17884 *
17885 * This program is distributed in the hope that it will be useful,
17886 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17887 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17888 * GNU Lesser General Public License for more details.
17889 *
17890 * You should have received a copy of the GNU Lesser General Public License
17891 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17892 * A copy of the GNU Lesser General Public License is in the file COPYING.
17893 */
17894
17895/** @ignore */
17896var DerNode = require('../../encoding/der/der-node.js').DerNode; /** @ignore */
17897var OID = require('../../encoding/oid.js').OID;
17898
17899/**
17900 * A CertificateExtension represents the Extension entry in a certificate.
17901 * Create a new CertificateExtension.
17902 * @param {string|OID} oid The oid of subject description entry.
17903 * @param {boolean} isCritical If true, the extension must be handled.
17904 * @param {Blob} value The extension value.
17905 * @constructor
17906 */
17907var CertificateExtension = function CertificateExtension(oid, isCritical, value)
17908{
17909 if (typeof oid === 'string')
17910 this.extensionId = new OID(oid);
17911 else
17912 // Assume oid is already an OID.
17913 this.extensionId = oid;
17914
17915 this.isCritical = isCritical;
17916 this.extensionValue = value;
17917};
17918
17919exports.CertificateExtension = CertificateExtension;
17920
17921/**
17922 * Encode the object into a DER syntax tree.
17923 * @return {DerNode} The encoded DER syntax tree.
17924 */
17925CertificateExtension.prototype.toDer = function()
17926{
17927 var root = new DerNode.DerSequence();
17928
17929 var extensionId = new DerNode.DerOid(this.extensionId);
17930 var isCritical = new DerNode.DerBoolean(this.isCritical);
17931 var extensionValue = new DerNode.DerOctetString(this.extensionValue.buf());
17932
17933 root.addChild(extensionId);
17934 root.addChild(isCritical);
17935 root.addChild(extensionValue);
17936
17937 root.getSize();
17938
17939 return root;
17940};
17941
17942CertificateExtension.prototype.toDerBlob = function()
17943{
17944 return this.toDer().encode();
17945};
17946
17947CertificateExtension.prototype.getOid = function()
17948{
17949 return this.extensionId;
17950};
17951
17952CertificateExtension.prototype.getIsCritical = function()
17953{
17954 return this.isCritical;
17955};
17956
17957CertificateExtension.prototype.getValue = function()
17958{
17959 return this.extensionValue;
17960};
17961/**
17962 * Copyright (C) 2014-2016 Regents of the University of California.
17963 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
17964 * From ndn-cxx security by Yingdi Yu <yingdi@cs.ucla.edu>.
17965 *
17966 * This program is free software: you can redistribute it and/or modify
17967 * it under the terms of the GNU Lesser General Public License as published by
17968 * the Free Software Foundation, either version 3 of the License, or
17969 * (at your option) any later version.
17970 *
17971 * This program is distributed in the hope that it will be useful,
17972 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17973 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17974 * GNU Lesser General Public License for more details.
17975 *
17976 * You should have received a copy of the GNU Lesser General Public License
17977 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17978 * A copy of the GNU Lesser General Public License is in the file COPYING.
17979 */
17980
17981/** @ignore */
17982var Blob = require('../../util/blob.js').Blob; /** @ignore */
17983var OID = require('../../encoding/oid.js').OID; /** @ignore */
17984var DerNode = require('../../encoding/der/der-node.js').DerNode;
17985
17986/**
17987 * A CertificateSubjectDescription represents the SubjectDescription entry in a
17988 * Certificate.
17989 * Create a new CertificateSubjectDescription.
17990 * @param {string|OID} oid The oid of the subject description entry.
17991 * @param {string} value The value of the subject description entry.
17992 * @constructor
17993 */
17994var CertificateSubjectDescription = function CertificateSubjectDescription
17995 (oid, value)
17996{
17997 if (typeof oid === 'string')
17998 this.oid = new OID(oid);
17999 else
18000 // Assume oid is already an OID.
18001 this.oid = oid;
18002
18003 this.value = value;
18004};
18005
18006exports.CertificateSubjectDescription = CertificateSubjectDescription;
18007
18008/**
18009 * Encode the object into a DER syntax tree.
18010 * @return {DerNode} The encoded DER syntax tree.
18011 */
18012CertificateSubjectDescription.prototype.toDer = function()
18013{
18014 var root = new DerNode.DerSequence();
18015
18016 var oid = new DerNode.DerOid(this.oid);
18017 // Use Blob to convert the String to a ByteBuffer.
18018 var value = new DerNode.DerPrintableString(new Blob(this.value).buf());
18019
18020 root.addChild(oid);
18021 root.addChild(value);
18022
18023 return root;
18024};
18025
18026CertificateSubjectDescription.prototype.getOidString = function()
18027{
18028 return this.oid.toString();
18029};
18030
18031CertificateSubjectDescription.prototype.getValue = function()
18032{
18033 return this.value;
18034};
18035/**
18036 * Copyright (C) 2014-2016 Regents of the University of California.
18037 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
18038 * From ndn-cxx security by Yingdi Yu <yingdi@cs.ucla.edu>.
18039 *
18040 * This program is free software: you can redistribute it and/or modify
18041 * it under the terms of the GNU Lesser General Public License as published by
18042 * the Free Software Foundation, either version 3 of the License, or
18043 * (at your option) any later version.
18044 *
18045 * This program is distributed in the hope that it will be useful,
18046 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18047 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18048 * GNU Lesser General Public License for more details.
18049 *
18050 * You should have received a copy of the GNU Lesser General Public License
18051 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18052 * A copy of the GNU Lesser General Public License is in the file COPYING.
18053 */
18054
18055/** @ignore */
18056var Data = require('../../data.js').Data; /** @ignore */
18057var ContentType = require('../../meta-info.js').ContentType; /** @ignore */
18058var WireFormat = require('../../encoding/wire-format.js').WireFormat; /** @ignore */
18059var DerNode = require('../../encoding/der/der-node.js').DerNode; /** @ignore */
18060var KeyType = require('../../security/security-types.js').KeyType; /** @ignore */
18061var PublicKey = require('./public-key.js').PublicKey; /** @ignore */
18062var CertificateSubjectDescription = require('./certificate-subject-description.js').CertificateSubjectDescription; /** @ignore */
18063var CertificateExtension = require('./certificate-extension.js').CertificateExtension;
18064
18065/**
18066 * Create a Certificate from the content in the data packet (if not omitted).
18067 * @param {Data} data (optional) The data packet with the content to decode.
18068 * If omitted, create a Certificate with default values and the Data content
18069 * is empty.
18070 * @constructor
18071 */
18072var Certificate = function Certificate(data)
18073{
18074 // Call the base constructor.
18075 if (data != undefined)
18076 Data.call(this, data);
18077 else
18078 Data.call(this);
18079
18080 this.subjectDescriptionList = []; // of CertificateSubjectDescription
18081 this.extensionList = []; // of CertificateExtension
18082 this.notBefore = Number.MAX_VALUE; // MillisecondsSince1970
18083 this.notAfter = -Number.MAX_VALUE; // MillisecondsSince1970
18084 this.key = new PublicKey();
18085
18086 if (data != undefined)
18087 this.decode();
18088};
18089Certificate.prototype = new Data();
18090Certificate.prototype.name = "Certificate";
18091
18092exports.Certificate = Certificate;
18093
18094/**
18095 * Encode the contents of the certificate in DER format and set the Content
18096 * and MetaInfo fields.
18097 */
18098Certificate.prototype.encode = function()
18099{
18100 var root = this.toDer();
18101 this.setContent(root.encode());
18102 this.getMetaInfo().setType(ContentType.KEY);
18103};
18104
18105/**
18106 * Add a subject description.
18107 * @param {CertificateSubjectDescription} description The description to be added.
18108 */
18109Certificate.prototype.addSubjectDescription = function(description)
18110{
18111 this.subjectDescriptionList.push(description);
18112};
18113
18114/**
18115 * Get the subject description list.
18116 * @return {Array<CertificateSubjectDescription>} The subject description list.
18117 */
18118Certificate.prototype.getSubjectDescriptionList = function()
18119{
18120 return this.subjectDescriptionList;
18121};
18122
18123/**
18124 * Add a certificate extension.
18125 * @param {CertificateSubjectDescription} extension The extension to be added.
18126 */
18127Certificate.prototype.addExtension = function(extension)
18128{
18129 this.extensionList.push(extension);
18130};
18131
18132/**
18133 * Get the certificate extension list.
18134 * @return {Array<CertificateExtension>} The extension list.
18135 */
18136Certificate.prototype.getExtensionList = function()
18137{
18138 return this.extensionList;
18139};
18140
18141Certificate.prototype.setNotBefore = function(notBefore)
18142{
18143 this.notBefore = notBefore;
18144};
18145
18146Certificate.prototype.getNotBefore = function()
18147{
18148 return this.notBefore;
18149};
18150
18151Certificate.prototype.setNotAfter = function(notAfter)
18152{
18153 this.notAfter = notAfter;
18154};
18155
18156Certificate.prototype.getNotAfter = function()
18157{
18158 return this.notAfter;
18159};
18160
18161Certificate.prototype.setPublicKeyInfo = function(key)
18162{
18163 this.key = key;
18164};
18165
18166Certificate.prototype.getPublicKeyInfo = function()
18167{
18168 return this.key;
18169};
18170
18171/**
18172 * Check if the certificate is valid.
18173 * @return {Boolean} True if the current time is earlier than notBefore.
18174 */
18175Certificate.prototype.isTooEarly = function()
18176{
18177 var now = new Date().getTime();
18178 return now < this.notBefore;
18179};
18180
18181/**
18182 * Check if the certificate is valid.
18183 * @return {Boolean} True if the current time is later than notAfter.
18184 */
18185Certificate.prototype.isTooLate = function()
18186{
18187 var now = new Date().getTime();
18188 return now > this.notAfter;
18189};
18190
18191/**
18192 * Encode the certificate fields in DER format.
18193 * @return {DerSequence} The DER encoded contents of the certificate.
18194 */
18195Certificate.prototype.toDer = function()
18196{
18197 var root = new DerNode.DerSequence();
18198 var validity = new DerNode.DerSequence();
18199 var notBefore = new DerNode.DerGeneralizedTime(this.notBefore);
18200 var notAfter = new DerNode.DerGeneralizedTime(this.notAfter);
18201
18202 validity.addChild(notBefore);
18203 validity.addChild(notAfter);
18204
18205 root.addChild(validity);
18206
18207 var subjectList = new DerNode.DerSequence();
18208 for (var i = 0; i < this.subjectDescriptionList.length; ++i)
18209 subjectList.addChild(this.subjectDescriptionList[i].toDer());
18210
18211 root.addChild(subjectList);
18212 root.addChild(this.key.toDer());
18213
18214 if (this.extensionList.length > 0) {
18215 var extensionList = new DerNode.DerSequence();
18216 for (var i = 0; i < this.extensionList.length; ++i)
18217 extensionList.addChild(this.extensionList[i].toDer());
18218 root.addChild(extensionList);
18219 }
18220
18221 return root;
18222};
18223
18224/**
18225 * Populate the fields by the decoding DER data from the Content.
18226 */
18227Certificate.prototype.decode = function()
18228{
18229 var root = DerNode.parse(this.getContent().buf());
18230
18231 // We need to ensure that there are:
18232 // validity (notBefore, notAfter)
18233 // subject list
18234 // public key
18235 // (optional) extension list
18236
18237 var rootChildren = root.getChildren();
18238 // 1st: validity info
18239 var validityChildren = DerNode.getSequence(rootChildren, 0).getChildren();
18240 this.notBefore = validityChildren[0].toVal();
18241 this.notAfter = validityChildren[1].toVal();
18242
18243 // 2nd: subjectList
18244 var subjectChildren = DerNode.getSequence(rootChildren, 1).getChildren();
18245 for (var i = 0; i < subjectChildren.length; ++i) {
18246 var sd = DerNode.getSequence(subjectChildren, i);
18247 var descriptionChildren = sd.getChildren();
18248 var oidStr = descriptionChildren[0].toVal();
18249 var value = descriptionChildren[1].toVal().buf().toString('binary');
18250
18251 this.addSubjectDescription(new CertificateSubjectDescription(oidStr, value));
18252 }
18253
18254 // 3rd: public key
18255 var publicKeyInfo = rootChildren[2].encode();
18256 this.key = new PublicKey(publicKeyInfo);
18257
18258 if (rootChildren.length > 3) {
18259 var extensionChildren = DerNode.getSequence(rootChildren, 3).getChildren();
18260 for (var i = 0; i < extensionChildren.length; ++i) {
18261 var extInfo = DerNode.getSequence(extensionChildren, i);
18262
18263 var children = extInfo.getChildren();
18264 var oidStr = children[0].toVal();
18265 var isCritical = children[1].toVal();
18266 var value = children[2].toVal();
18267 this.addExtension(new CertificateExtension(oidStr, isCritical, value));
18268 }
18269 }
18270};
18271
18272/**
18273 * Override to call the base class wireDecode then populate the certificate
18274 * fields.
18275 * @param {Blob|Buffer} input The buffer with the bytes to decode.
18276 * @param {WireFormat} wireFormat (optional) A WireFormat object used to decode
18277 * this object. If omitted, use WireFormat.getDefaultWireFormat().
18278 */
18279Certificate.prototype.wireDecode = function(input, wireFormat)
18280{
18281 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
18282
18283 Data.prototype.wireDecode.call(this, input, wireFormat);
18284 this.decode();
18285};
18286
18287Certificate.prototype.toString = function()
18288{
18289 var s = "Certificate name:\n";
18290 s += " " + this.getName().toUri() + "\n";
18291 s += "Validity:\n";
18292
18293 var notBeforeStr = Certificate.toIsoString(Math.round(this.notBefore));
18294 var notAfterStr = Certificate.toIsoString(Math.round(this.notAfter));
18295
18296 s += " NotBefore: " + notBeforeStr + "\n";
18297 s += " NotAfter: " + notAfterStr + "\n";
18298 for (var i = 0; i < this.subjectDescriptionList.length; ++i) {
18299 var sd = this.subjectDescriptionList[i];
18300 s += "Subject Description:\n";
18301 s += " " + sd.getOidString() + ": " + sd.getValue() + "\n";
18302 }
18303
18304 s += "Public key bits:\n";
18305 var keyDer = this.key.getKeyDer();
18306 var encodedKey = keyDer.buf().toString('base64');
18307 for (var i = 0; i < encodedKey.length; i += 64)
18308 s += encodedKey.substring(i, Math.min(i + 64, encodedKey.length)) + "\n";
18309
18310 if (this.extensionList.length > 0) {
18311 s += "Extensions:\n";
18312 for (var i = 0; i < this.extensionList.length; ++i) {
18313 var ext = this.extensionList[i];
18314 s += " OID: " + ext.getOid() + "\n";
18315 s += " Is critical: " + (ext.getIsCritical() ? 'Y' : 'N') + "\n";
18316
18317 s += " Value: " + ext.getValue().toHex() + "\n" ;
18318 }
18319 }
18320
18321 return s;
18322};
18323
18324/**
18325 * Convert a UNIX timestamp to ISO time representation with the "T" in the middle.
18326 * @param {type} msSince1970 Timestamp as milliseconds since Jan 1, 1970.
18327 * @return {string} The string representation.
18328 */
18329Certificate.toIsoString = function(msSince1970)
18330{
18331 var utcTime = new Date(Math.round(msSince1970));
18332 return utcTime.getUTCFullYear() +
18333 Certificate.to2DigitString(utcTime.getUTCMonth() + 1) +
18334 Certificate.to2DigitString(utcTime.getUTCDate()) +
18335 "T" +
18336 Certificate.to2DigitString(utcTime.getUTCHours()) +
18337 Certificate.to2DigitString(utcTime.getUTCMinutes()) +
18338 Certificate.to2DigitString(utcTime.getUTCSeconds());
18339};
18340
18341/**
18342 * A private method to zero pad an integer to 2 digits.
18343 * @param {number} x The number to pad. Assume it is a non-negative integer.
18344 * @return {string} The padded string.
18345 */
18346Certificate.to2DigitString = function(x)
18347{
18348 var result = x.toString();
18349 return result.length === 1 ? "0" + result : result;
18350};
18351/**
18352 * Copyright (C) 2014-2016 Regents of the University of California.
18353 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
18354 * From ndn-cxx security by Yingdi Yu <yingdi@cs.ucla.edu>.
18355 *
18356 * This program is free software: you can redistribute it and/or modify
18357 * it under the terms of the GNU Lesser General Public License as published by
18358 * the Free Software Foundation, either version 3 of the License, or
18359 * (at your option) any later version.
18360 *
18361 * This program is distributed in the hope that it will be useful,
18362 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18363 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18364 * GNU Lesser General Public License for more details.
18365 *
18366 * You should have received a copy of the GNU Lesser General Public License
18367 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18368 * A copy of the GNU Lesser General Public License is in the file COPYING.
18369 */
18370
18371/** @ignore */
18372var Data = require('../../data.js').Data; /** @ignore */
18373var Name = require('../../name.js').Name; /** @ignore */
18374var SecurityException = require('../../security//security-exception.js').SecurityException; /** @ignore */
18375var Certificate = require('./certificate.js').Certificate; /** @ignore */
18376var WireFormat = require('../../encoding/wire-format.js').WireFormat;
18377
18378/**
18379 * @constructor
18380 */
18381var IdentityCertificate = function IdentityCertificate(data)
18382{
18383 // Call the base constructor.
18384 if (data != undefined)
18385 // This works if data is Data or IdentityCertificate.
18386 Certificate.call(this, data);
18387 else
18388 Certificate.call(this);
18389
18390 this.publicKeyName = new Name();
18391
18392 if (data instanceof IdentityCertificate) {
18393 // The copy constructor.
18394 this.publicKeyName = new Name(data.publicKeyName);
18395 }
18396 else if (data instanceof Data) {
18397 if (!IdentityCertificate.isCorrectName(data.getName()))
18398 throw new SecurityException(new Error("Wrong Identity Certificate Name!"));
18399
18400 this.setPublicKeyName();
18401 }
18402};
18403IdentityCertificate.prototype = new Certificate();
18404IdentityCertificate.prototype.name = "IdentityCertificate";
18405
18406exports.IdentityCertificate = IdentityCertificate;
18407
18408/**
18409 * Override the base class method to check that the name is a valid identity
18410 * certificate name.
18411 * @param {Name} name The identity certificate name which is copied.
18412 * @return {Data} This Data so that you can chain calls to update values.
18413 */
18414IdentityCertificate.prototype.setName = function(name)
18415{
18416 if (!IdentityCertificate.isCorrectName(name))
18417 throw new SecurityException(new Error("Wrong Identity Certificate Name!"));
18418
18419 // Call the super class method.
18420 Certificate.prototype.setName.call(this, name);
18421 this.setPublicKeyName();
18422 return this;
18423};
18424
18425/**
18426 * Override to call the base class wireDecode then update the public key name.
18427 * @param {Blob|Buffer} input The buffer with the bytes to decode.
18428 * @param {WireFormat} wireFormat (optional) A WireFormat object used to decode
18429 * this object. If omitted, use WireFormat.getDefaultWireFormat().
18430 */
18431IdentityCertificate.prototype.wireDecode = function(input, wireFormat)
18432{
18433 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
18434
18435 Certificate.prototype.wireDecode.call(this, input, wireFormat);
18436 this.setPublicKeyName();
18437};
18438
18439IdentityCertificate.prototype.getPublicKeyName = function()
18440{
18441 return this.publicKeyName;
18442};
18443
18444IdentityCertificate.isIdentityCertificate = function(certificate)
18445{
18446 return IdentityCertificate.isCorrectName(certificate.getName());
18447};
18448
18449/**
18450 * Get the public key name from the full certificate name.
18451 * @param {Name} certificateName The full certificate name.
18452 * @return {Name} The related public key name.
18453 */
18454IdentityCertificate.certificateNameToPublicKeyName = function(certificateName)
18455{
18456 var idString = "ID-CERT";
18457 var foundIdString = false;
18458 var idCertComponentIndex = certificateName.size() - 1;
18459 for (; idCertComponentIndex + 1 > 0; --idCertComponentIndex) {
18460 if (certificateName.get(idCertComponentIndex).toEscapedString() == idString) {
18461 foundIdString = true;
18462 break;
18463 }
18464 }
18465
18466 if (!foundIdString)
18467 throw new Error
18468 ("Incorrect identity certificate name " + certificateName.toUri());
18469
18470 var tempName = certificateName.getSubName(0, idCertComponentIndex);
18471 var keyString = "KEY";
18472 var foundKeyString = false;
18473 var keyComponentIndex = 0;
18474 for (; keyComponentIndex < tempName.size(); keyComponentIndex++) {
18475 if (tempName.get(keyComponentIndex).toEscapedString() == keyString) {
18476 foundKeyString = true;
18477 break;
18478 }
18479 }
18480
18481 if (!foundKeyString)
18482 throw new Error
18483 ("Incorrect identity certificate name " + certificateName.toUri());
18484
18485 return tempName
18486 .getSubName(0, keyComponentIndex)
18487 .append(tempName.getSubName
18488 (keyComponentIndex + 1, tempName.size() - keyComponentIndex - 1));
18489};
18490
18491IdentityCertificate.isCorrectName = function(name)
18492{
18493 var i = name.size() - 1;
18494
18495 var idString = "ID-CERT";
18496 for (; i >= 0; i--) {
18497 if (name.get(i).toEscapedString() == idString)
18498 break;
18499 }
18500
18501 if (i < 0)
18502 return false;
18503
18504 var keyIdx = 0;
18505 var keyString = "KEY";
18506 for (; keyIdx < name.size(); keyIdx++) {
18507 if(name.get(keyIdx).toEscapedString() == keyString)
18508 break;
18509 }
18510
18511 if (keyIdx >= name.size())
18512 return false;
18513
18514 return true;
18515};
18516
18517IdentityCertificate.prototype.setPublicKeyName = function()
18518{
18519 this.publicKeyName = IdentityCertificate.certificateNameToPublicKeyName
18520 (this.getName());
18521};
18522
18523/**
18524 * Copyright (C) 2014-2016 Regents of the University of California.
18525 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
18526 * From ndn-cxx security by Yingdi Yu <yingdi@cs.ucla.edu>.
18527 *
18528 * This program is free software: you can redistribute it and/or modify
18529 * it under the terms of the GNU Lesser General Public License as published by
18530 * the Free Software Foundation, either version 3 of the License, or
18531 * (at your option) any later version.
18532 *
18533 * This program is distributed in the hope that it will be useful,
18534 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18535 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18536 * GNU Lesser General Public License for more details.
18537 *
18538 * You should have received a copy of the GNU Lesser General Public License
18539 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18540 * A copy of the GNU Lesser General Public License is in the file COPYING.
18541 */
18542
18543/** @ignore */
18544var Name = require('../../name.js').Name; /** @ignore */
18545var SecurityException = require('../security-exception.js').SecurityException; /** @ignore */
18546var SyncPromise = require('../../util/sync-promise.js').SyncPromise;
18547
18548/**
18549 * IdentityStorage is a base class for the storage of identity, public keys and
18550 * certificates. Private keys are stored in PrivateKeyStorage.
18551 * This is an abstract base class. A subclass must implement the methods.
18552 * @constructor
18553 */
18554var IdentityStorage = function IdentityStorage()
18555{
18556};
18557
18558exports.IdentityStorage = IdentityStorage;
18559
18560/**
18561 * Check if the specified identity already exists.
18562 * @param {Name} identityName The identity name.
18563 * @param {boolean} useSync (optional) If true then return a SyncPromise which
18564 * is already fulfilled. If omitted or false, this may return a SyncPromise or
18565 * an async Promise.
18566 * @return {Promise|SyncPromise} A promise which returns true if the identity
18567 * exists.
18568 */
18569IdentityStorage.prototype.doesIdentityExistPromise = function
18570 (identityName, useSync)
18571{
18572 return SyncPromise.reject(new Error
18573 ("IdentityStorage.doesIdentityExistPromise is not implemented"));
18574};
18575
18576/**
18577 * Check if the specified identity already exists.
18578 * @param {Name} identityName The identity name.
18579 * @return {boolean} true if the identity exists, otherwise false.
18580 * @throws Error If doesIdentityExistPromise doesn't return a SyncPromise which
18581 * is already fulfilled.
18582 */
18583IdentityStorage.prototype.doesIdentityExist = function(identityName)
18584{
18585 return SyncPromise.getValue(this.doesIdentityExistPromise(identityName, true));
18586};
18587
18588/**
18589 * Add a new identity. Do nothing if the identity already exists.
18590 * @param {Name} identityName The identity name to be added.
18591 * @param {boolean} useSync (optional) If true then return a SyncPromise which
18592 * is already fulfilled. If omitted or false, this may return a SyncPromise or
18593 * an async Promise.
18594 * @return {Promise|SyncPromise} A promise which fulfills when the identity is
18595 * added.
18596 */
18597IdentityStorage.prototype.addIdentityPromise = function(identityName, useSync)
18598{
18599 return SyncPromise.reject(new Error
18600 ("IdentityStorage.addIdentityPromise is not implemented"));
18601};
18602
18603/**
18604 * Add a new identity. Do nothing if the identity already exists.
18605 * @param {Name} identityName The identity name to be added.
18606 * @throws Error If addIdentityPromise doesn't return a SyncPromise which
18607 * is already fulfilled.
18608 */
18609IdentityStorage.prototype.addIdentity = function(identityName)
18610{
18611 return SyncPromise.getValue(this.addIdentityPromise(identityName, true));
18612};
18613
18614/**
18615 * Revoke the identity.
18616 * @return {boolean} true if the identity was revoked, false if not.
18617 */
18618IdentityStorage.prototype.revokeIdentity = function()
18619{
18620 return SyncPromise.reject(new Error
18621 ("IdentityStorage.revokeIdentity is not implemented"));
18622};
18623
18624/**
18625 * Generate a name for a new key belonging to the identity.
18626 * @param {Name} identityName The identity name.
18627 * @param {boolean} useKsk If true, generate a KSK name, otherwise a DSK name.
18628 * @param {boolean} useSync (optional) If true then return a SyncPromise which
18629 * is already fulfilled. If omitted or false, this may return a SyncPromise or
18630 * an async Promise.
18631 * @return {Promise|SyncPromise} A promise that returns the generated key Name.
18632 */
18633IdentityStorage.prototype.getNewKeyNamePromise = function
18634 (identityName, useKsk, useSync)
18635{
18636 var timestamp = Math.floor(new Date().getTime() / 1000.0);
18637 while (timestamp <= IdentityStorage.lastTimestamp)
18638 // Make the timestamp unique.
18639 timestamp += 1;
18640 IdentityStorage.lastTimestamp = timestamp;
18641
18642 // Get the number of seconds as a string.
18643 var seconds = "" + timestamp;
18644
18645 var keyIdStr;
18646 if (useKsk)
18647 keyIdStr = "ksk-" + seconds;
18648 else
18649 keyIdStr = "dsk-" + seconds;
18650
18651 var keyName = new Name(identityName).append(keyIdStr);
18652
18653 return this.doesKeyExistPromise(keyName, useSync)
18654 .then(function(exists) {
18655 if (exists)
18656 throw new SecurityException(new Error("Key name already exists"));
18657
18658 return SyncPromise.resolve(keyName);
18659 });
18660};
18661
18662/**
18663 * Generate a name for a new key belonging to the identity.
18664 * @param {Name} identityName The identity name.
18665 * @param {boolean} useKsk If true, generate a KSK name, otherwise a DSK name.
18666 * @return {Name} The generated key name.
18667 * @throws Error If getNewKeyNamePromise doesn't return a SyncPromise which
18668 * is already fulfilled.
18669 */
18670IdentityStorage.prototype.getNewKeyName = function(identityName, useKsk)
18671{
18672 return SyncPromise.getValue
18673 (this.getNewKeyNamePromise(identityName, useKsk, true));
18674};
18675
18676/**
18677 * Check if the specified key already exists.
18678 * @param {Name} keyName The name of the key.
18679 * @param {boolean} useSync (optional) If true then return a SyncPromise which
18680 * is already fulfilled. If omitted or false, this may return a SyncPromise or
18681 * an async Promise.
18682 * @return {Promise|SyncPromise} A promise which returns true if the key exists.
18683 */
18684IdentityStorage.prototype.doesKeyExistPromise = function(keyName, useSync)
18685{
18686 return SyncPromise.reject(new Error
18687 ("IdentityStorage.doesKeyExistPromise is not implemented"));
18688};
18689
18690/**
18691 * Check if the specified key already exists.
18692 * @param {Name} keyName The name of the key.
18693 * @return {boolean} true if the key exists, otherwise false.
18694 * @throws Error If doesKeyExistPromise doesn't return a SyncPromise which
18695 * is already fulfilled.
18696 */
18697IdentityStorage.prototype.doesKeyExist = function(keyName)
18698{
18699 return SyncPromise.getValue(this.doesKeyExistPromise(keyName, true));
18700};
18701
18702/**
18703 * Add a public key to the identity storage. Also call addIdentity to ensure
18704 * that the identityName for the key exists. However, if the key already
18705 * exists, do nothing.
18706 * @param {Name} keyName The name of the public key to be added.
18707 * @param {number} keyType Type of the public key to be added from KeyType, such
18708 * as KeyType.RSA..
18709 * @param {Blob} publicKeyDer A blob of the public key DER to be added.
18710 * @param {boolean} useSync (optional) If true then return a SyncPromise which
18711 * is already fulfilled. If omitted or false, this may return a SyncPromise or
18712 * an async Promise.
18713 * @return {Promise|SyncPromise} A promise which fulfills when complete.
18714 */
18715IdentityStorage.prototype.addKeyPromise = function
18716 (keyName, keyType, publicKeyDer, useSync)
18717{
18718 return SyncPromise.reject(new Error
18719 ("IdentityStorage.addKeyPromise is not implemented"));
18720};
18721
18722/**
18723 * Add a public key to the identity storage. Also call addIdentity to ensure
18724 * that the identityName for the key exists.
18725 * @param {Name} keyName The name of the public key to be added.
18726 * @param {number} keyType Type of the public key to be added from KeyType, such
18727 * as KeyType.RSA..
18728 * @param {Blob} publicKeyDer A blob of the public key DER to be added.
18729 * @throws SecurityException if a key with the keyName already exists.
18730 * @throws Error If addKeyPromise doesn't return a SyncPromise which
18731 * is already fulfilled.
18732 */
18733IdentityStorage.prototype.addKey = function(keyName, keyType, publicKeyDer)
18734{
18735 return SyncPromise.getValue
18736 (this.addKeyPromise(keyName, keyType, publicKeyDer, true));
18737};
18738
18739/**
18740 * Get the public key DER blob from the identity storage.
18741 * @param {Name} keyName The name of the requested public key.
18742 * @param {boolean} useSync (optional) If true then return a SyncPromise which
18743 * is already fulfilled. If omitted or false, this may return a SyncPromise or
18744 * an async Promise.
18745 * @return {Promise|SyncPromise} A promise which returns the DER Blob, or a
18746 * promise rejected with SecurityException if the key doesn't exist.
18747 */
18748IdentityStorage.prototype.getKeyPromise = function(keyName, useSync)
18749{
18750 return SyncPromise.reject(new Error
18751 ("IdentityStorage.getKeyPromise is not implemented"));
18752};
18753
18754/**
18755 * Get the public key DER blob from the identity storage.
18756 * @param {Name} keyName The name of the requested public key.
18757 * @return {Blob} The DER Blob.
18758 * @throws SecurityException if the key doesn't exist.
18759 * @throws Error If getKeyPromise doesn't return a SyncPromise which
18760 * is already fulfilled.
18761 */
18762IdentityStorage.prototype.getKey = function(keyName)
18763{
18764 return SyncPromise.getValue(this.getKeyPromise(keyName, true));
18765};
18766
18767/**
18768 * Activate a key. If a key is marked as inactive, its private part will not be
18769 * used in packet signing.
18770 * @param {Name} keyName name of the key
18771 */
18772IdentityStorage.prototype.activateKey = function(keyName)
18773{
18774 throw new Error("IdentityStorage.activateKey is not implemented");
18775};
18776
18777/**
18778 * Deactivate a key. If a key is marked as inactive, its private part will not
18779 * be used in packet signing.
18780 * @param {Name} keyName name of the key
18781 */
18782IdentityStorage.prototype.deactivateKey = function(keyName)
18783{
18784 throw new Error("IdentityStorage.deactivateKey is not implemented");
18785};
18786
18787/**
18788 * Check if the specified certificate already exists.
18789 * @param {Name} certificateName The name of the certificate.
18790 * @param {boolean} useSync (optional) If true then return a SyncPromise which
18791 * is already fulfilled. If omitted or false, this may return a SyncPromise or
18792 * an async Promise.
18793 * @return {Promise|SyncPromise} A promise which returns true if the certificate
18794 * exists.
18795 */
18796IdentityStorage.prototype.doesCertificateExistPromise = function
18797 (certificateName, useSync)
18798{
18799 return SyncPromise.reject(new Error
18800 ("IdentityStorage.doesCertificateExistPromise is not implemented"));
18801};
18802
18803/**
18804 * Check if the specified certificate already exists.
18805 * @param {Name} certificateName The name of the certificate.
18806 * @return {boolean} true if the certificate exists, otherwise false.
18807 * @throws Error If doesCertificateExistPromise doesn't return a SyncPromise
18808 * which is already fulfilled.
18809 */
18810IdentityStorage.prototype.doesCertificateExist = function(certificateName)
18811{
18812 return SyncPromise.getValue
18813 (this.doesCertificateExistPromise(certificateName, true));
18814};
18815
18816/**
18817 * Add a certificate to the identity storage. Also call addKey to ensure that
18818 * the certificate key exists. If the certificate is already installed, don't
18819 * replace it.
18820 * @param {IdentityCertificate} certificate The certificate to be added. This
18821 * makes a copy of the certificate.
18822 * @param {boolean} useSync (optional) If true then return a SyncPromise which
18823 * is already fulfilled. If omitted or false, this may return a SyncPromise or
18824 * an async Promise.
18825 * @return {Promise|SyncPromise} A promise which fulfills when finished.
18826 */
18827IdentityStorage.prototype.addCertificatePromise = function(certificate, useSync)
18828{
18829 return SyncPromise.reject(new Error
18830 ("IdentityStorage.addCertificatePromise is not implemented"));
18831};
18832
18833/**
18834 * Add a certificate to the identity storage.
18835 * @param {IdentityCertificate} certificate The certificate to be added. This
18836 * makes a copy of the certificate.
18837 * @throws SecurityException if the certificate is already installed.
18838 * @throws Error If addCertificatePromise doesn't return a SyncPromise which
18839 * is already fulfilled.
18840 */
18841IdentityStorage.prototype.addCertificate = function(certificate)
18842{
18843 return SyncPromise.getValue(this.addCertificatePromise(certificate, true));
18844};
18845
18846/**
18847 * Get a certificate from the identity storage.
18848 * @param {Name} certificateName The name of the requested certificate.
18849 * @param {boolean} useSync (optional) If true then return a SyncPromise which
18850 * is already fulfilled. If omitted or false, this may return a SyncPromise or
18851 * an async Promise.
18852 * @return {Promise|SyncPromise} A promise which returns the requested
18853 * IdentityCertificate, or a promise rejected with SecurityException if the
18854 * certificate doesn't exist.
18855 */
18856IdentityStorage.prototype.getCertificatePromise = function
18857 (certificateName, useSync)
18858{
18859 return SyncPromise.reject(new Error
18860 ("IdentityStorage.getCertificatePromise is not implemented"));
18861};
18862
18863/**
18864 * Get a certificate from the identity storage.
18865 * @param {Name} certificateName The name of the requested certificate.
18866 * @return {IdentityCertificate} The requested certificate.
18867 * @throws SecurityException if the certificate doesn't exist.
18868 * @throws Error If getCertificatePromise doesn't return a SyncPromise which
18869 * is already fulfilled.
18870 */
18871IdentityStorage.prototype.getCertificate = function(certificateName)
18872{
18873 return SyncPromise.getValue(this.getValuePromise(certificateName, true));
18874};
18875
18876/**
18877 * Get the TPM locator associated with this storage.
18878 * @param {boolean} useSync (optional) If true then return a rejected promise
18879 * since this only supports async code.
18880 * @return {Promise|SyncPromise} A promise which returns the TPM locator, or a
18881 * promise rejected with SecurityException if the TPM locator doesn't exist.
18882 */
18883IdentityStorage.prototype.getTpmLocatorPromise = function(useSync)
18884{
18885 return SyncPromise.reject(new Error
18886 ("IdentityStorage.getTpmLocatorPromise is not implemented"));
18887};
18888
18889/**
18890 * Get the TPM locator associated with this storage.
18891 * @return {string} The TPM locator.
18892 * @throws SecurityException if the TPM locator doesn't exist.
18893 * @throws Error If getTpmLocatorPromise doesn't return a SyncPromise which is
18894 * already fulfilled.
18895 */
18896IdentityStorage.prototype.getTpmLocator = function()
18897{
18898 return SyncPromise.getValue(this.getTpmLocatorPromise(true));
18899};
18900
18901/*****************************************
18902 * Get/Set Default *
18903 *****************************************/
18904
18905/**
18906 * Get the default identity.
18907 * @param {boolean} useSync (optional) If true then return a SyncPromise which
18908 * is already fulfilled. If omitted or false, this may return a SyncPromise or
18909 * an async Promise.
18910 * @return {Promise|SyncPromise} A promise which returns the Name of default
18911 * identity, or a promise rejected with SecurityException if the default
18912 * identity is not set.
18913 */
18914IdentityStorage.prototype.getDefaultIdentityPromise = function(useSync)
18915{
18916 return SyncPromise.reject(new Error
18917 ("IdentityStorage.getDefaultIdentityPromise is not implemented"));
18918};
18919
18920/**
18921 * Get the default identity.
18922 * @return {Name} The name of default identity.
18923 * @throws SecurityException if the default identity is not set.
18924 * @throws Error If getDefaultIdentityPromise doesn't return a SyncPromise
18925 * which is already fulfilled.
18926 */
18927IdentityStorage.prototype.getDefaultIdentity = function()
18928{
18929 return SyncPromise.getValue
18930 (this.getDefaultIdentityPromise(true));
18931};
18932
18933/**
18934 * Get the default key name for the specified identity.
18935 * @param {Name} identityName The identity name.
18936 * @param {boolean} useSync (optional) If true then return a SyncPromise which
18937 * is already fulfilled. If omitted or false, this may return a SyncPromise or
18938 * an async Promise.
18939 * @return {Promise|SyncPromise} A promise which returns the default key Name,
18940 * or a promise rejected with SecurityException if the default key name for the
18941 * identity is not set.
18942 */
18943IdentityStorage.prototype.getDefaultKeyNameForIdentityPromise = function
18944 (identityName, useSync)
18945{
18946 return SyncPromise.reject(new Error
18947 ("IdentityStorage.getDefaultKeyNameForIdentityPromise is not implemented"));
18948};
18949
18950/**
18951 * Get the default key name for the specified identity.
18952 * @param {Name} identityName The identity name.
18953 * @return {Name} The default key name.
18954 * @throws SecurityException if the default key name for the identity is not set.
18955 * @throws Error If getDefaultKeyNameForIdentityPromise doesn't return a
18956 * SyncPromise which is already fulfilled.
18957 */
18958IdentityStorage.prototype.getDefaultKeyNameForIdentity = function(identityName)
18959{
18960 return SyncPromise.getValue
18961 (this.getDefaultKeyNameForIdentityPromise(identityName, true));
18962};
18963
18964/**
18965 * Get the default certificate name for the specified identity.
18966 * @param {Name} identityName The identity name.
18967 * @param {boolean} useSync (optional) If true then return a SyncPromise which
18968 * is already fulfilled. If omitted or false, this may return a SyncPromise or
18969 * an async Promise.
18970 * @return {Promise|SyncPromise} A promise which returns the default certificate
18971 * Name, or a promise rejected with SecurityException if the default key name
18972 * for the identity is not set or the default certificate name for the key name
18973 * is not set.
18974 */
18975IdentityStorage.prototype.getDefaultCertificateNameForIdentityPromise = function
18976 (identityName, useSync)
18977{
18978 var thisStorage = this;
18979 return this.getDefaultKeyNameForIdentityPromise(identityName)
18980 .then(function(keyName) {
18981 return thisStorage.getDefaultCertificateNameForKeyPromise(keyName);
18982 });
18983};
18984
18985/**
18986 * Get the default certificate name for the specified identity.
18987 * @param {Name} identityName The identity name.
18988 * @return {Name} The default certificate name.
18989 * @throws SecurityException if the default key name for the identity is not
18990 * set or the default certificate name for the key name is not set.
18991 * @throws Error If getDefaultCertificateNameForIdentityPromise doesn't return
18992 * a SyncPromise which is already fulfilled.
18993 */
18994IdentityStorage.prototype.getDefaultCertificateNameForIdentity = function
18995 (identityName)
18996{
18997 return SyncPromise.getValue
18998 (this.getDefaultCertificateNameForIdentityPromise(identityName, true));
18999};
19000
19001/**
19002 * Get the default certificate name for the specified key.
19003 * @param {Name} keyName The key name.
19004 * @param {boolean} useSync (optional) If true then return a SyncPromise which
19005 * is already fulfilled. If omitted or false, this may return a SyncPromise or
19006 * an async Promise.
19007 * @return {Promise|SyncPromise} A promise which returns the default certificate
19008 * Name, or a promise rejected with SecurityException if the default certificate
19009 * name for the key name is not set.
19010 */
19011IdentityStorage.prototype.getDefaultCertificateNameForKeyPromise = function
19012 (keyName, useSync)
19013{
19014 return SyncPromise.reject(new Error
19015 ("IdentityStorage.getDefaultCertificateNameForKeyPromise is not implemented"));
19016};
19017
19018/**
19019 * Get the default certificate name for the specified key.
19020 * @param {Name} keyName The key name.
19021 * @return {Name} The default certificate name.
19022 * @throws SecurityException if the default certificate name for the key name
19023 * is not set.
19024 * @throws Error If getDefaultCertificateNameForKeyPromise doesn't return a
19025 * SyncPromise which is already fulfilled.
19026 */
19027IdentityStorage.prototype.getDefaultCertificateNameForKey = function(keyName)
19028{
19029 return SyncPromise.getValue
19030 (this.getDefaultCertificateNameForKeyPromise(keyName, true));
19031};
19032
19033/**
19034 * Append all the identity names to the nameList.
19035 * @param {Array<Name>} nameList Append result names to nameList.
19036 * @param {boolean} isDefault If true, add only the default identity name. If
19037 * false, add only the non-default identity names.
19038 * @param {boolean} useSync (optional) If true then return a rejected promise
19039 * since this only supports async code.
19040 * @return {Promise} A promise which fulfills when the names are added to
19041 * nameList.
19042 */
19043IdentityStorage.prototype.getAllIdentitiesPromise = function
19044 (nameList, isDefault, useSync)
19045{
19046 return SyncPromise.reject(new Error
19047 ("IdentityStorage.getAllIdentitiesPromise is not implemented"));
19048};
19049
19050/**
19051 * Append all the key names of a particular identity to the nameList.
19052 * @param {Name} identityName The identity name to search for.
19053 * @param {Array<Name>} nameList Append result names to nameList.
19054 * @param {boolean} isDefault If true, add only the default key name. If false,
19055 * add only the non-default key names.
19056 * @param {boolean} useSync (optional) If true then return a SyncPromise which
19057 * is already fulfilled. If omitted or false, this may return a SyncPromise or
19058 * an async Promise.
19059 * @return {Promise|SyncPromise} A promise which fulfills when the names are
19060 * added to nameList.
19061 */
19062IdentityStorage.prototype.getAllKeyNamesOfIdentityPromise = function
19063 (identityName, nameList, isDefault, useSync)
19064{
19065 return SyncPromise.reject(new Error
19066 ("IdentityStorage.getAllKeyNamesOfIdentityPromise is not implemented"));
19067};
19068
19069/**
19070 * Append all the certificate names of a particular key name to the nameList.
19071 * @param {Name} keyName The key name to search for.
19072 * @param {Array<Name>} nameList Append result names to nameList.
19073 * @param {boolean} isDefault If true, add only the default certificate name.
19074 * If false, add only the non-default certificate names.
19075 * @param {boolean} useSync (optional) If true then return a rejected promise
19076 * since this only supports async code.
19077 * @return {Promise} A promise which fulfills when the names are added to
19078 * nameList.
19079 */
19080IdentityStorage.prototype.getAllCertificateNamesOfKeyPromise = function
19081 (keyName, nameList, isDefault, useSync)
19082{
19083 return SyncPromise.reject(new Error
19084 ("IdentityStorage.getAllCertificateNamesOfKeyPromise is not implemented"));
19085};
19086
19087/**
19088 * Append all the key names of a particular identity to the nameList.
19089 * @param {Name} identityName The identity name to search for.
19090 * @param {Array<Name>} nameList Append result names to nameList.
19091 * @param {boolean} isDefault If true, add only the default key name. If false,
19092 * add only the non-default key names.
19093 * @throws Error If getAllKeyNamesOfIdentityPromise doesn't return a
19094 * SyncPromise which is already fulfilled.
19095 */
19096IdentityStorage.prototype.getAllKeyNamesOfIdentity = function
19097 (identityName, nameList, isDefault)
19098{
19099 return SyncPromise.getValue
19100 (this.getAllKeyNamesOfIdentityPromise(identityName, nameList, isDefault, true));
19101};
19102
19103/**
19104 * Set the default identity. If the identityName does not exist, then clear the
19105 * default identity so that getDefaultIdentity() throws an exception.
19106 * @param {Name} identityName The default identity name.
19107 * @param {boolean} useSync (optional) If true then return a SyncPromise which
19108 * is already fulfilled. If omitted or false, this may return a SyncPromise or
19109 * an async Promise.
19110 * @return {Promise|SyncPromise} A promise which fulfills when the default
19111 * identity is set.
19112 */
19113IdentityStorage.prototype.setDefaultIdentityPromise = function
19114 (identityName, useSync)
19115{
19116 return SyncPromise.reject(new Error
19117 ("IdentityStorage.setDefaultIdentityPromise is not implemented"));
19118};
19119
19120/**
19121 * Set the default identity. If the identityName does not exist, then clear the
19122 * default identity so that getDefaultIdentity() throws an exception.
19123 * @param {Name} identityName The default identity name.
19124 * @throws Error If setDefaultIdentityPromise doesn't return a SyncPromise which
19125 * is already fulfilled.
19126 */
19127IdentityStorage.prototype.setDefaultIdentity = function(identityName)
19128{
19129 return SyncPromise.getValue
19130 (this.setDefaultIdentityPromise(identityName, true));
19131};
19132
19133/**
19134 * Set a key as the default key of an identity. The identity name is inferred
19135 * from keyName.
19136 * @param {Name} keyName The name of the key.
19137 * @param {Name} identityNameCheck (optional) The identity name to check that the
19138 * keyName contains the same identity name. If an empty name, it is ignored.
19139 * @param {boolean} useSync (optional) If true then return a SyncPromise which
19140 * is already fulfilled. If omitted or false, this may return a SyncPromise or
19141 * an async Promise.
19142 * @return {Promise|SyncPromise} A promise which fulfills when the default key
19143 * name is set.
19144 */
19145IdentityStorage.prototype.setDefaultKeyNameForIdentityPromise = function
19146 (keyName, identityNameCheck, useSync)
19147{
19148 return SyncPromise.reject(new Error
19149 ("IdentityStorage.setDefaultKeyNameForIdentityPromise is not implemented"));
19150};
19151
19152/**
19153 * Set a key as the default key of an identity. The identity name is inferred
19154 * from keyName.
19155 * @param {Name} keyName The name of the key.
19156 * @param {Name} identityNameCheck (optional) The identity name to check that the
19157 * keyName contains the same identity name. If an empty name, it is ignored.
19158 * @throws Error If setDefaultKeyNameForIdentityPromise doesn't return a
19159 * SyncPromise which is already fulfilled.
19160 */
19161IdentityStorage.prototype.setDefaultKeyNameForIdentity = function
19162 (keyName, identityNameCheck)
19163{
19164 return SyncPromise.getValue
19165 (this.setDefaultKeyNameForIdentityPromise(keyName, identityNameCheck, true));
19166};
19167
19168/**
19169 * Set the default key name for the specified identity.
19170 * @param {Name} keyName The key name.
19171 * @param {Name} certificateName The certificate name.
19172 * @param {boolean} useSync (optional) If true then return a SyncPromise which
19173 * is already fulfilled. If omitted or false, this may return a SyncPromise or
19174 * an async Promise.
19175 * @return {Promise|SyncPromise} A promise which fulfills when the default
19176 * certificate name is set.
19177 */
19178IdentityStorage.prototype.setDefaultCertificateNameForKeyPromise = function
19179 (keyName, certificateName, useSync)
19180{
19181 return SyncPromise.reject(new Error
19182 ("IdentityStorage.setDefaultCertificateNameForKeyPromise is not implemented"));
19183};
19184
19185/**
19186 * Set the default key name for the specified identity.
19187 * @param {Name} keyName The key name.
19188 * @param {Name} certificateName The certificate name.
19189 * @throws Error If setDefaultCertificateNameForKeyPromise doesn't return a
19190 * SyncPromise which is already fulfilled.
19191 */
19192IdentityStorage.prototype.setDefaultCertificateNameForKey = function
19193 (keyName, certificateName)
19194{
19195 return SyncPromise.getValue
19196 (this.setDefaultCertificateNameForKeyPromise(keyName, certificateName, true));
19197};
19198
19199/**
19200 * Get the certificate of the default identity.
19201 * @param {boolean} useSync (optional) If true then return a SyncPromise which
19202 * is already fulfilled. If omitted or false, this may return a SyncPromise or
19203 * an async Promise.
19204 * @return {Promise|SyncPromise} A promise which returns the requested
19205 * IdentityCertificate or null if not found.
19206 */
19207IdentityStorage.prototype.getDefaultCertificatePromise = function(useSync)
19208{
19209 var thisStorage = this;
19210 return this.getDefaultIdentityPromise(useSync)
19211 .then(function(identityName) {
19212 return thisStorage.getDefaultCertificateNameForIdentityPromise
19213 (identityName, useSync);
19214 }, function(ex) {
19215 // The default is not defined.
19216 return SyncPromise.resolve(null);
19217 })
19218 .then(function(certName) {
19219 if (certName == null)
19220 return SyncPromise.resolve(null);
19221
19222 return thisStorage.getCertificatePromise(certName, useSync);
19223 });
19224};
19225
19226/**
19227 * Get the certificate of the default identity.
19228 * @return {IdentityCertificate} The requested certificate. If not found,
19229 * return null.
19230 * @throws Error If getDefaultCertificatePromise doesn't return a SyncPromise
19231 * which is already fulfilled.
19232 */
19233IdentityStorage.prototype.getDefaultCertificate = function()
19234{
19235 return SyncPromise.getValue
19236 (this.getDefaultCertificatePromise(true));
19237};
19238
19239/*****************************************
19240 * Delete Methods *
19241 *****************************************/
19242
19243/**
19244 * Delete a certificate.
19245 * @param {Name} certificateName The certificate name.
19246 * @param {boolean} useSync (optional) If true then return a SyncPromise which
19247 * is already fulfilled. If omitted or false, this may return a SyncPromise or
19248 * an async Promise.
19249 * @return {Promise|SyncPromise} A promise which fulfills when the certificate
19250 * info is deleted.
19251 */
19252IdentityStorage.prototype.deleteCertificateInfoPromise = function
19253 (certificateName, useSync)
19254{
19255 return SyncPromise.reject(new Error
19256 ("IdentityStorage.deleteCertificateInfoPromise is not implemented"));
19257};
19258
19259/**
19260 * Delete a certificate.
19261 * @param {Name} certificateName The certificate name.
19262 * @throws Error If deleteCertificateInfoPromise doesn't return a SyncPromise
19263 * which is already fulfilled.
19264 */
19265IdentityStorage.prototype.deleteCertificateInfo = function(certificateName)
19266{
19267 return SyncPromise.getValue
19268 (this.deleteCertificateInfoPromise(certificateName, true));
19269};
19270
19271/**
19272 * Delete a public key and related certificates.
19273 * @param {Name} keyName The key name.
19274 * @param {boolean} useSync (optional) If true then return a SyncPromise which
19275 * is already fulfilled. If omitted or false, this may return a SyncPromise or
19276 * an async Promise.
19277 * @return {Promise|SyncPromise} A promise which fulfills when the public key
19278 * info is deleted.
19279 */
19280IdentityStorage.prototype.deletePublicKeyInfoPromise = function(keyName, useSync)
19281{
19282 return SyncPromise.reject
19283 (new Error("IdentityStorage.deletePublicKeyInfoPromise is not implemented"));
19284};
19285
19286/**
19287 * Delete a public key and related certificates.
19288 * @param {Name} keyName The key name.
19289 * @throws Error If deletePublicKeyInfoPromise doesn't return a SyncPromise
19290 * which is already fulfilled.
19291 */
19292IdentityStorage.prototype.deletePublicKeyInfo = function(keyName)
19293{
19294 return SyncPromise.getValue
19295 (this.deletePublicKeyInfoPromise(keyName, true));
19296};
19297
19298/**
19299 * Delete an identity and related public keys and certificates.
19300 * @param {Name} identityName The identity name.
19301 * @param {boolean} useSync (optional) If true then return a SyncPromise which
19302 * is already fulfilled. If omitted or false, this may return a SyncPromise or
19303 * an async Promise.
19304 * @return {Promise|SyncPromise} A promise which fulfills when the identity info
19305 * is deleted.
19306 */
19307IdentityStorage.prototype.deleteIdentityInfoPromise = function
19308 (identityName, useSync)
19309{
19310 return SyncPromise.reject(new Error
19311 ("IdentityStorage.deleteIdentityInfoPromise is not implemented"));
19312};
19313
19314/**
19315 * Delete an identity and related public keys and certificates.
19316 * @param {Name} identityName The identity name.
19317 * @throws Error If deleteIdentityInfoPromise doesn't return a SyncPromise
19318 * which is already fulfilled.
19319 */
19320IdentityStorage.prototype.deleteIdentityInfo = function(identityName)
19321{
19322 return SyncPromise.getValue
19323 (this.deleteIdentityInfoPromise(identityName, true));
19324};
19325
19326// Track the lastTimestamp so that each timestamp is unique.
19327IdentityStorage.lastTimestamp = Math.floor(new Date().getTime() / 1000.0);
19328/**
19329 * Copyright (C) 2015-2016 Regents of the University of California.
19330 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
19331 *
19332 * This program is free software: you can redistribute it and/or modify
19333 * it under the terms of the GNU Lesser General Public License as published by
19334 * the Free Software Foundation, either version 3 of the License, or
19335 * (at your option) any later version.
19336 *
19337 * This program is distributed in the hope that it will be useful,
19338 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19339 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19340 * GNU Lesser General Public License for more details.
19341 *
19342 * You should have received a copy of the GNU Lesser General Public License
19343 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19344 * A copy of the GNU Lesser General Public License is in the file COPYING.
19345 */
19346
19347// Don't require modules since this is meant for the browser, not Node.js.
19348
19349/**
19350 * IndexedDbIdentityStorage extends IdentityStorage and implements its methods
19351 * to store identity, public key and certificate objects using the browser's
19352 * IndexedDB service.
19353 * @constructor
19354 */
19355var IndexedDbIdentityStorage = function IndexedDbIdentityStorage()
19356{
19357 IdentityStorage.call(this);
19358
19359 this.database = new Dexie("ndnsec-public-info");
19360 // The database schema imitates MemoryIdentityStorage.
19361 this.database.version(1).stores({
19362 // A table for global values. It currently only has the defaultIdentityUri.
19363 // "key" is the key like "defaultIdentityUri" // string
19364 // "value" is the value. For "defaultIdentityUri" the value is the
19365 // default identity name URI, or absent if not defined. // string
19366 globals: "key",
19367
19368 // "identityNameUri" is the identity name URI // string
19369 // "defaultKeyUri" is the default key name URI or null // string
19370 identity: "identityNameUri",
19371
19372 // "keyNameUri" is the key name URI // string
19373 // "keyType" is the type of the public key // number from KeyType
19374 // "keyDer" is the public key DER // Uint8Array
19375 // "defaultCertificateUri" is the default cert name URI or null // string
19376 publicKey: "keyNameUri",
19377
19378 // "certificateNameUri" is the certificate name URI // string
19379 // "encoding" is the certificate wire encoding // Uint8Array
19380 certificate: "certificateNameUri"
19381 });
19382 this.database.open();
19383};
19384
19385IndexedDbIdentityStorage.prototype = new IdentityStorage();
19386IndexedDbIdentityStorage.prototype.name = "IndexedDbIdentityStorage";
19387
19388/**
19389 * Check if the specified identity already exists.
19390 * @param {Name} identityName The identity name.
19391 * @param {boolean} useSync (optional) If true then return a rejected promise
19392 * since this only supports async code.
19393 * @return {Promise} A promise which returns true if the identity exists.
19394 */
19395IndexedDbIdentityStorage.prototype.doesIdentityExistPromise = function
19396 (identityName, useSync)
19397{
19398 if (useSync)
19399 return Promise.reject(new SecurityException(new Error
19400 ("IndexedDbIdentityStorage.doesIdentityExistPromise is only supported for async")));
19401
19402 return this.database.identity.where("identityNameUri").equals
19403 (identityName.toUri())
19404 .count()
19405 .then(function(count) {
19406 return Promise.resolve(count > 0);
19407 });
19408};
19409
19410/**
19411 * Add a new identity. Do nothing if the identity already exists.
19412 * @param {Name} identityName The identity name to be added.
19413 * @param {boolean} useSync (optional) If true then return a rejected promise
19414 * since this only supports async code.
19415 * @return {Promise} A promise which fulfills when the identity is added.
19416 */
19417IndexedDbIdentityStorage.prototype.addIdentityPromise = function
19418 (identityName, useSync)
19419{
19420 if (useSync)
19421 return Promise.reject(new SecurityException(new Error
19422 ("IndexedDbIdentityStorage.addIdentityPromise is only supported for async")));
19423
19424 var thisStorage = this;
19425 return this.doesIdentityExistPromise(identityName)
19426 .then(function(exists) {
19427 if (exists)
19428 // Do nothing.
19429 return Promise.resolve();
19430
19431 return thisStorage.database.identity.put
19432 ({ identityNameUri: identityName.toUri(), defaultKeyUri: null });
19433 });
19434};
19435
19436/**
19437 * Check if the specified key already exists.
19438 * @param {Name} keyName The name of the key.
19439 * @param {boolean} useSync (optional) If true then return a rejected promise
19440 * since this only supports async code.
19441 * @return {Promise} A promise which returns true if the key exists.
19442 */
19443IndexedDbIdentityStorage.prototype.doesKeyExistPromise = function
19444 (keyName, useSync)
19445{
19446 if (useSync)
19447 return Promise.reject(new SecurityException(new Error
19448 ("IndexedDbIdentityStorage.doesKeyExistPromise is only supported for async")));
19449
19450 return this.database.publicKey.where("keyNameUri").equals(keyName.toUri())
19451 .count()
19452 .then(function(count) {
19453 return Promise.resolve(count > 0);
19454 });
19455};
19456
19457/**
19458 * Add a public key to the identity storage. Also call addIdentity to ensure
19459 * that the identityName for the key exists. However, if the key already
19460 * exists, do nothing.
19461 * @param {Name} keyName The name of the public key to be added.
19462 * @param {number} keyType Type of the public key to be added from KeyType, such
19463 * as KeyType.RSA..
19464 * @param {Blob} publicKeyDer A blob of the public key DER to be added.
19465 * @param {boolean} useSync (optional) If true then return a rejected promise
19466 * since this only supports async code.
19467 * @return {Promise} A promise which fulfills when complete.
19468 */
19469IndexedDbIdentityStorage.prototype.addKeyPromise = function
19470 (keyName, keyType, publicKeyDer, useSync)
19471{
19472 if (useSync)
19473 return Promise.reject(new SecurityException(new Error
19474 ("IndexedDbIdentityStorage.addKeyPromise is only supported for async")));
19475
19476 if (keyName.size() === 0)
19477 return Promise.resolve();
19478
19479 var thisStorage = this;
19480 return this.doesKeyExistPromise(keyName)
19481 .then(function(exists) {
19482 if (exists)
19483 return Promise.resolve();
19484
19485 var identityName = keyName.getPrefix(-1);
19486 return thisStorage.addIdentityPromise(identityName)
19487 .then(function() {
19488 return thisStorage.database.publicKey.put
19489 ({ keyNameUri: keyName.toUri(), keyType: keyType,
19490 keyDer: new Blob(publicKeyDer, true).buf(),
19491 defaultCertificate: null });
19492 });
19493 });
19494};
19495
19496/**
19497 * Get the public key DER blob from the identity storage.
19498 * @param {Name} keyName The name of the requested public key.
19499 * @param {boolean} useSync (optional) If true then return a rejected promise
19500 * since this only supports async code.
19501 * @return {Promise} A promise which returns the DER Blob, or a promise rejected
19502 * with SecurityException if the key doesn't exist.
19503 */
19504IndexedDbIdentityStorage.prototype.getKeyPromise = function(keyName, useSync)
19505{
19506 if (useSync)
19507 return Promise.reject(new SecurityException(new Error
19508 ("IndexedDbIdentityStorage.getKeyPromise is only supported for async")));
19509
19510 if (keyName.size() === 0)
19511 return Promise.reject(new SecurityException(new Error
19512 ("IndexedDbIdentityStorage::getKeyPromise: Empty keyName")));
19513
19514 return this.database.publicKey.get(keyName.toUri())
19515 .then(function(publicKeyEntry) {
19516 if (publicKeyEntry)
19517 return Promise.resolve(new Blob(publicKeyEntry.keyDer));
19518 else
19519 return Promise.reject(new SecurityException(new Error
19520 ("IndexedDbIdentityStorage::getKeyPromise: The key does not exist")));
19521 });
19522};
19523
19524/**
19525 * Check if the specified certificate already exists.
19526 * @param {Name} certificateName The name of the certificate.
19527 * @param {boolean} useSync (optional) If true then return a rejected promise
19528 * since this only supports async code.
19529 * @return {Promise} A promise which returns true if the certificate exists.
19530 */
19531IndexedDbIdentityStorage.prototype.doesCertificateExistPromise = function
19532 (certificateName, useSync)
19533{
19534 if (useSync)
19535 return Promise.reject(new SecurityException(new Error
19536 ("IndexedDbIdentityStorage.doesCertificateExistPromise is only supported for async")));
19537
19538 return this.database.certificate.where("certificateNameUri").equals
19539 (certificateName.toUri())
19540 .count()
19541 .then(function(count) {
19542 return Promise.resolve(count > 0);
19543 });
19544};
19545
19546/**
19547 * Add a certificate to the identity storage. Also call addKey to ensure that
19548 * the certificate key exists. If the certificate is already installed, don't
19549 * replace it.
19550 * @param {IdentityCertificate} certificate The certificate to be added. This
19551 * makes a copy of the certificate.
19552 * @param {boolean} useSync (optional) If true then return a rejected promise
19553 * since this only supports async code.
19554 * @return {Promise} A promise which fulfills when finished.
19555 */
19556IndexedDbIdentityStorage.prototype.addCertificatePromise = function
19557 (certificate, useSync)
19558{
19559 if (useSync)
19560 return Promise.reject(new SecurityException(new Error
19561 ("IndexedDbIdentityStorage.addCertificatePromise is only supported for async")));
19562
19563 var certificateName = certificate.getName();
19564 var keyName = certificate.getPublicKeyName();
19565
19566 var thisStorage = this;
19567 return this.addKeyPromise
19568 (keyName, certificate.getPublicKeyInfo().getKeyType(),
19569 certificate.getPublicKeyInfo().getKeyDer(), useSync)
19570 .then(function() {
19571 return thisStorage.doesCertificateExistPromise(certificateName);
19572 })
19573 .then(function(exists) {
19574 if (exists)
19575 return Promise.resolve();
19576
19577 // Insert the certificate.
19578 // wireEncode returns the cached encoding if available.
19579 return thisStorage.database.certificate.put
19580 ({ certificateNameUri: certificateName.toUri(),
19581 encoding: certificate.wireEncode().buf() });
19582 });
19583};
19584
19585/**
19586 * Get a certificate from the identity storage.
19587 * @param {Name} certificateName The name of the requested certificate.
19588 * @param {boolean} useSync (optional) If true then return a rejected promise
19589 * since this only supports async code.
19590 * @return {Promise} A promise which returns the requested
19591 * IdentityCertificate, or a promise rejected with SecurityException if the
19592 * certificate doesn't exist.
19593 */
19594IndexedDbIdentityStorage.prototype.getCertificatePromise = function
19595 (certificateName, useSync)
19596{
19597 if (useSync)
19598 return Promise.reject(new SecurityException(new Error
19599 ("IndexedDbIdentityStorage.getCertificatePromise is only supported for async")));
19600
19601 return this.database.certificate.get(certificateName.toUri())
19602 .then(function(certificateEntry) {
19603 if (certificateEntry) {
19604 var certificate = new IdentityCertificate();
19605 try {
19606 certificate.wireDecode(certificateEntry.encoding);
19607 } catch (ex) {
19608 return Promise.reject(new SecurityException(new Error
19609 ("IndexedDbIdentityStorage::getCertificatePromise: The certificate cannot be decoded")));
19610 }
19611 return Promise.resolve(certificate);
Alexander Afanasyev1663a412013-03-02 13:52:00 -080019612 }
19613 else
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080019614 return Promise.reject(new SecurityException(new Error
19615 ("IndexedDbIdentityStorage::getCertificatePromise: The certificate does not exist")));
19616 });
19617};
Alexander Afanasyev1663a412013-03-02 13:52:00 -080019618
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080019619/*****************************************
19620 * Get/Set Default *
19621 *****************************************/
19622
19623/**
19624 * Get the default identity.
19625 * @param {boolean} useSync (optional) If true then return a rejected promise
19626 * since this only supports async code.
19627 * @return {Promise} A promise which returns the Name of default identity,
19628 * or a promise rejected with SecurityException if the default identity is not
19629 * set.
19630 */
19631IndexedDbIdentityStorage.prototype.getDefaultIdentityPromise = function(useSync)
19632{
19633 return this.database.globals.get("defaultIdentityUri")
19634 .then(function(defaultIdentityEntry) {
19635 if (defaultIdentityEntry)
19636 return Promise.resolve(new Name(defaultIdentityEntry.value));
19637 else
19638 throw new SecurityException(new Error
19639 ("IndexedDbIdentityStorage.getDefaultIdentity: The default identity is not defined"));
19640 });
19641};
19642
19643/**
19644 * Get the default key name for the specified identity.
19645 * @param {Name} identityName The identity name.
19646 * @param {boolean} useSync (optional) If true then return a rejected promise
19647 * since this only supports async code.
19648 * @return {Promise} A promise which returns the default key Name, or a
19649 * promise rejected with SecurityException if the default key name for the
19650 * identity is not set.
19651 */
19652IndexedDbIdentityStorage.prototype.getDefaultKeyNameForIdentityPromise = function
19653 (identityName, useSync)
19654{
19655 if (useSync)
19656 return Promise.reject(new SecurityException(new Error
19657 ("IndexedDbIdentityStorage.getDefaultKeyNameForIdentityPromise is only supported for async")));
19658
19659 return this.database.identity.get(identityName.toUri())
19660 .then(function(identityEntry) {
19661 if (identityEntry) {
19662 if (identityEntry.defaultKeyUri != null)
19663 return Promise.resolve(new Name(identityEntry.defaultKeyUri));
19664 else
19665 throw new SecurityException(new Error("No default key set."));
19666 }
19667 else
19668 throw new SecurityException(new Error("Identity not found."));
19669 });
19670};
19671
19672/**
19673 * Get the default certificate name for the specified key.
19674 * @param {Name} keyName The key name.
19675 * @param {boolean} useSync (optional) If true then return a rejected promise
19676 * since this only supports async code.
19677 * @return {Promise} A promise which returns the default certificate Name,
19678 * or a promise rejected with SecurityException if the default certificate name
19679 * for the key name is not set.
19680 */
19681IndexedDbIdentityStorage.prototype.getDefaultCertificateNameForKeyPromise = function
19682 (keyName, useSync)
19683{
19684 if (useSync)
19685 return Promise.reject(new SecurityException(new Error
19686 ("IndexedDbIdentityStorage.getDefaultCertificateNameForKeyPromise is only supported for async")));
19687
19688 return this.database.publicKey.get(keyName.toUri())
19689 .then(function(publicKeyEntry) {
19690 if (publicKeyEntry) {
19691 if (publicKeyEntry.defaultCertificateUri != null)
19692 return Promise.resolve(new Name(publicKeyEntry.defaultCertificateUri));
19693 else
19694 throw new SecurityException(new Error("No default certificate set."));
19695 }
19696 else
19697 throw new SecurityException(new Error("Key not found."));
19698 });
19699};
19700
19701/**
19702 * Append all the identity names to the nameList.
19703 * @param {Array<Name>} nameList Append result names to nameList.
19704 * @param {boolean} isDefault If true, add only the default identity name. If
19705 * false, add only the non-default identity names.
19706 * @param {boolean} useSync (optional) If true then return a rejected promise
19707 * since this only supports async code.
19708 * @return {Promise} A promise which fulfills when the names are added to
19709 * nameList.
19710 */
19711IndexedDbIdentityStorage.prototype.getAllIdentitiesPromise = function
19712 (nameList, isDefault, useSync)
19713{
19714 if (useSync)
19715 return Promise.reject(new SecurityException(new Error
19716 ("IndexedDbIdentityStorage.getAllIdentitiesPromise is only supported for async")));
19717
19718 var defaultIdentityName = null;
19719 var thisStorage = this;
19720 return this.getDefaultIdentityPromise()
19721 .then(function(localDefaultIdentityName) {
19722 defaultIdentityName = localDefaultIdentityName;
19723 return SyncPromise.resolve();
19724 }, function(err) {
19725 // The default identity name was not found.
19726 return SyncPromise.resolve();
19727 })
19728 .then(function() {
19729 return thisStorage.database.identity.each(function(identityEntry) {
19730 var identityName = new Name(identityEntry.identityNameUri);
19731 var identityNameIsDefault =
19732 (defaultIdentityName !== null && identityName.equals(defaultIdentityName));
19733 if (isDefault && identityNameIsDefault)
19734 nameList.push(identityName);
19735 else if (!isDefault && !identityNameIsDefault)
19736 nameList.push(identityName);
19737 });
19738 });
19739};
19740
19741/**
19742 * Append all the key names of a particular identity to the nameList.
19743 * @param {Name} identityName The identity name to search for.
19744 * @param {Array<Name>} nameList Append result names to nameList.
19745 * @param {boolean} isDefault If true, add only the default key name. If false,
19746 * add only the non-default key names.
19747 * @param {boolean} useSync (optional) If true then return a rejected promise
19748 * since this only supports async code.
19749 * @return {Promise} A promise which fulfills when the names are added to
19750 * nameList.
19751 */
19752IndexedDbIdentityStorage.prototype.getAllKeyNamesOfIdentityPromise = function
19753 (identityName, nameList, isDefault, useSync)
19754{
19755 if (useSync)
19756 return Promise.reject(new SecurityException(new Error
19757 ("IndexedDbIdentityStorage.getAllKeyNamesOfIdentityPromise is only supported for async")));
19758
19759 var defaultKeyName = null;
19760 var thisStorage = this;
19761 return this.getDefaultKeyNameForIdentityPromise(identityName)
19762 .then(function(localDefaultKeyName) {
19763 defaultKeyName = localDefaultKeyName;
19764 return SyncPromise.resolve();
19765 }, function(err) {
19766 // The default key name was not found.
19767 return SyncPromise.resolve();
19768 })
19769 .then(function() {
19770 // Iterate through each publicKey a to find ones that match identityName.
19771 // This is a little inefficient, but we don't expect the in-browser
19772 // database to be very big, we don't expect to use this function often (for
19773 // deleting an identity), and this is simpler than complicating the database
19774 // schema to store the identityName with each publicKey.
19775 return thisStorage.database.publicKey.each(function(publicKeyEntry) {
19776 var keyName = new Name(publicKeyEntry.keyNameUri);
19777 var keyIdentityName = keyName.getPrefix(-1);
19778
19779 if (keyIdentityName.equals(identityName)) {
19780 var keyNameIsDefault =
19781 (defaultKeyName !== null && keyName.equals(defaultKeyName));
19782 if (isDefault && keyNameIsDefault)
19783 nameList.push(keyName);
19784 else if (!isDefault && !keyNameIsDefault)
19785 nameList.push(keyName);
19786 }
19787 });
19788 });
19789};
19790
19791/**
19792 * Append all the certificate names of a particular key name to the nameList.
19793 * @param {Name} keyName The key name to search for.
19794 * @param {Array<Name>} nameList Append result names to nameList.
19795 * @param {boolean} isDefault If true, add only the default certificate name.
19796 * If false, add only the non-default certificate names.
19797 * @param {boolean} useSync (optional) If true then return a rejected promise
19798 * since this only supports async code.
19799 * @return {Promise} A promise which fulfills when the names are added to
19800 * nameList.
19801 */
19802IndexedDbIdentityStorage.prototype.getAllCertificateNamesOfKeyPromise = function
19803 (keyName, nameList, isDefault, useSync)
19804{
19805 if (useSync)
19806 return Promise.reject(new SecurityException(new Error
19807 ("IndexedDbIdentityStorage.getAllCertificateNamesOfKeyPromise is only supported for async")));
19808
19809 var defaultCertificateName = null;
19810 var thisStorage = this;
19811 return this.getDefaultCertificateNameForKeyPromise(keyName)
19812 .then(function(localDefaultCertificateName) {
19813 defaultCertificateName = localDefaultCertificateName;
19814 return SyncPromise.resolve();
19815 }, function(err) {
19816 // The default certificate name was not found.
19817 return SyncPromise.resolve();
19818 })
19819 .then(function() {
19820 // Iterate through each certificate record a to find ones that match keyName.
19821 // This is a little inefficient, but we don't expect the in-browser
19822 // database to be very big, we don't expect to use this function often (for
19823 // deleting an identity), and this is simpler than complicating the database
19824 // schema to store the keyName with each certificate record.
19825 return thisStorage.database.certificate.each(function(certificateEntry) {
19826 var certificateName = new Name(certificateEntry.certificateNameUri);
19827 var certificateKeyName = IdentityCertificate.certificateNameToPublicKeyName
19828 (certificateName);
19829
19830 if (certificateKeyName.equals(keyName)) {
19831 var certificateNameIsDefault =
19832 (defaultCertificateName !== null &&
19833 certificateName.equals(defaultCertificateName));
19834 if (isDefault && certificateNameIsDefault)
19835 nameList.push(certificateName);
19836 else if (!isDefault && !certificateNameIsDefault)
19837 nameList.push(certificateName);
19838 }
19839 });
19840 });
19841};
19842
19843/**
19844 * Set the default identity. If the identityName does not exist, then clear the
19845 * default identity so that getDefaultIdentity() throws an exception.
19846 * @param {Name} identityName The default identity name.
19847 * @param {boolean} useSync (optional) If true then return a rejected promise
19848 * since this only supports async code.
19849 * @return {Promise} A promise which fulfills when the default identity is set.
19850 */
19851IndexedDbIdentityStorage.prototype.setDefaultIdentityPromise = function
19852 (identityName, useSync)
19853{
19854 if (useSync)
19855 return Promise.reject(new SecurityException(new Error
19856 ("IndexedDbIdentityStorage.setDefaultIdentityPromise is only supported for async")));
19857
19858 var thisStorage = this;
19859 return this.doesIdentityExistPromise(identityName)
19860 .then(function(exists) {
19861 if (exists)
19862 return thisStorage.database.globals.put
19863 ({ key: "defaultIdentityUri", value: identityName.toUri() });
19864 else
19865 // The identity doesn't exist, so clear the default.
19866 return thisStorage.database.globals.delete("defaultIdentityUri");
19867 });
19868};
19869
19870/**
19871 * Set a key as the default key of an identity. The identity name is inferred
19872 * from keyName.
19873 * @param {Name} keyName The name of the key.
19874 * @param {Name} identityNameCheck (optional) The identity name to check that the
19875 * keyName contains the same identity name. If an empty name, it is ignored.
19876 * @param {boolean} useSync (optional) If true then return a rejected promise
19877 * since this only supports async code.
19878 * @return {Promise} A promise which fulfills when the default key name is
19879 * set.
19880 */
19881IndexedDbIdentityStorage.prototype.setDefaultKeyNameForIdentityPromise = function
19882 (keyName, identityNameCheck, useSync)
19883{
19884 useSync = (typeof identityNameCheck === "boolean") ? identityNameCheck : useSync;
19885 identityNameCheck = (identityNameCheck instanceof Name) ? identityNameCheck : null;
19886
19887 if (useSync)
19888 return Promise.reject(new SecurityException(new Error
19889 ("IndexedDbIdentityStorage.setDefaultKeyNameForIdentityPromise is only supported for async")));
19890
19891 var identityName = keyName.getPrefix(-1);
19892
19893 if (identityNameCheck != null && identityNameCheck.size() > 0 &&
19894 !identityNameCheck.equals(identityName))
19895 return Promise.reject(new SecurityException(new Error
19896 ("The specified identity name does not match the key name")));
19897
19898 // update does nothing if the identityName doesn't exist.
19899 return this.database.identity.update
19900 (identityName.toUri(), { defaultKeyUri: keyName.toUri() });
19901};
19902
19903/**
19904 * Set the default key name for the specified identity.
19905 * @param {Name} keyName The key name.
19906 * @param {Name} certificateName The certificate name.
19907 * @param {boolean} useSync (optional) If true then return a rejected promise
19908 * since this only supports async code.
19909 * @return {Promise} A promise which fulfills when the default certificate
19910 * name is set.
19911 */
19912IndexedDbIdentityStorage.prototype.setDefaultCertificateNameForKeyPromise = function
19913 (keyName, certificateName, useSync)
19914{
19915 if (useSync)
19916 return Promise.reject(new SecurityException(new Error
19917 ("IndexedDbIdentityStorage.setDefaultCertificateNameForKeyPromise is only supported for async")));
19918
19919 // update does nothing if the keyName doesn't exist.
19920 return this.database.publicKey.update
19921 (keyName.toUri(), { defaultCertificateUri: certificateName.toUri() });
19922};
19923
19924/*****************************************
19925 * Delete Methods *
19926 *****************************************/
19927
19928/**
19929 * Delete a certificate.
19930 * @param {Name} certificateName The certificate name.
19931 * @param {boolean} useSync (optional) If true then return a rejected promise
19932 * since this only supports async code.
19933 * @return {Promise} A promise which fulfills when the certificate info is
19934 * deleted.
19935 */
19936IndexedDbIdentityStorage.prototype.deleteCertificateInfoPromise = function
19937 (certificateName, useSync)
19938{
19939 if (useSync)
19940 return Promise.reject(new SecurityException(new Error
19941 ("IndexedDbIdentityStorage.deleteCertificateInfoPromise is only supported for async")));
19942
19943 if (certificateName.size() === 0)
19944 return Promise.resolve();
19945
19946 return this.database.certificate.delete(certificateName.toUri());
19947};
19948
19949/**
19950 * Delete a public key and related certificates.
19951 * @param {Name} keyName The key name.
19952 * @param {boolean} useSync (optional) If true then return a rejected promise
19953 * since this only supports async code.
19954 * @return {Promise} A promise which fulfills when the public key info is
19955 * deleted.
19956 */
19957IndexedDbIdentityStorage.prototype.deletePublicKeyInfoPromise = function
19958 (keyName, useSync)
19959{
19960 if (useSync)
19961 return Promise.reject(new SecurityException(new Error
19962 ("IndexedDbIdentityStorage.deletePublicKeyInfoPromise is only supported for async")));
19963
19964 if (keyName.size() === 0)
19965 return Promise.resolve();
19966
19967 var thisStorage = this;
19968 return this.database.publicKey.delete(keyName.toUri())
19969 .then(function() {
19970 // Iterate through each certificate to find ones that match keyName. This is
19971 // a little inefficient, but we don't expect the in-browswer database to be
19972 // very big, we don't expect to delete often, and this is simpler than
19973 // complicating the database schema to store the keyName with each certificate.
19974 return thisStorage.database.certificate.each(function(certificateEntry) {
19975 if (IdentityCertificate.certificateNameToPublicKeyName
19976 (new Name(certificateEntry.certificateNameUri)).equals(keyName))
19977 thisStorage.database.certificate.delete
19978 (certificateEntry.certificateNameUri);
19979 });
19980 });
19981};
19982
19983/**
19984 * Delete an identity and related public keys and certificates.
19985 * @param {Name} identityName The identity name.
19986 * @param {boolean} useSync (optional) If true then return a rejected promise
19987 * since this only supports async code.
19988 * @return {Promise} A promise which fulfills when the identity info is
19989 * deleted.
19990 */
19991IndexedDbIdentityStorage.prototype.deleteIdentityInfoPromise = function
19992 (identityName, useSync)
19993{
19994 if (useSync)
19995 return Promise.reject(new SecurityException(new Error
19996 ("IndexedDbIdentityStorage.deleteIdentityInfoPromise is only supported for async")));
19997
19998 var thisStorage = this;
19999 return this.database.identity.delete(identityName.toUri())
20000 // Iterate through each publicKey and certificate to find ones that match
20001 // identityName. This is a little inefficient, but we don't expect the
20002 // in-browswer database to be very big, we don't expect to delete often, and
20003 // this is simpler than complicating the database schema to store the
20004 // identityName with each publicKey and certificate.
20005 .then(function() {
20006 return thisStorage.database.publicKey.each(function(publicKeyEntry) {
20007 var keyIdentityName = new Name(publicKeyEntry.keyNameUri).getPrefix(-1);
20008 if (keyIdentityName.equals(identityName))
20009 thisStorage.database.publicKey.delete(publicKeyEntry.keyNameUri);
20010 });
20011 })
20012 .then(function() {
20013 return thisStorage.database.certificate.each(function(certificateEntry) {
20014 var certificateKeyName = IdentityCertificate.certificateNameToPublicKeyName
20015 (new Name(certificateEntry.certificateNameUri));
20016 var certificateIdentityName = certificateKeyName.getPrefix(-1);
20017 if (certificateIdentityName.equals(identityName))
20018 thisStorage.database.certificate.delete
20019 (certificateEntry.certificateNameUri);
20020 });
20021 });
20022};
20023/**
20024 * Copyright (C) 2014-2016 Regents of the University of California.
20025 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
20026 * From ndn-cxx security by Yingdi Yu <yingdi@cs.ucla.edu>.
20027 *
20028 * This program is free software: you can redistribute it and/or modify
20029 * it under the terms of the GNU Lesser General Public License as published by
20030 * the Free Software Foundation, either version 3 of the License, or
20031 * (at your option) any later version.
20032 *
20033 * This program is distributed in the hope that it will be useful,
20034 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20035 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20036 * GNU Lesser General Public License for more details.
20037 *
20038 * You should have received a copy of the GNU Lesser General Public License
20039 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20040 * A copy of the GNU Lesser General Public License is in the file COPYING.
20041 */
20042
20043/** @ignore */
20044var Name = require('../../name.js').Name; /** @ignore */
20045var Blob = require('../../util/blob.js').Blob; /** @ignore */
20046var SecurityException = require('../security-exception.js').SecurityException; /** @ignore */
20047var IdentityCertificate = require('../certificate/identity-certificate.js').IdentityCertificate; /** @ignore */
20048var SyncPromise = require('../../util/sync-promise.js').SyncPromise; /** @ignore */
20049var IdentityStorage = require('./identity-storage.js').IdentityStorage;
20050
20051/**
20052 * MemoryIdentityStorage extends IdentityStorage and implements its methods to
20053 * store identity, public key and certificate objects in memory. The application
20054 * must get the objects through its own means and add the objects to the
20055 * MemoryIdentityStorage object. To use permanent file-based storage, see
20056 * BasicIdentityStorage.
20057 * @constructor
20058 */
20059var MemoryIdentityStorage = function MemoryIdentityStorage()
20060{
20061 // Call the base constructor.
20062 IdentityStorage.call(this);
20063
20064 // The map key is the identityName.toUri(). The value is the object
20065 // {defaultKey // Name
20066 // }.
20067 this.identityStore = {};
20068 // The default identity in identityStore, or "" if not defined.
20069 this.defaultIdentity = "";
20070 // The key is the keyName.toUri(). The value is the object
20071 // {keyType, // number from KeyType
20072 // keyDer // Blob
20073 // defaultCertificate // Name
20074 // }.
20075 this.keyStore = {};
20076 // The key is the key is the certificateName.toUri(). The value is the
20077 // encoded certificate.
20078 this.certificateStore = {};
20079};
20080
20081MemoryIdentityStorage.prototype = new IdentityStorage();
20082MemoryIdentityStorage.prototype.name = "MemoryIdentityStorage";
20083
20084exports.MemoryIdentityStorage = MemoryIdentityStorage;
20085/**
20086 * Check if the specified identity already exists.
20087 * @param {Name} identityName The identity name.
20088 * @return {SyncPromise} A promise which returns true if the identity exists.
20089 */
20090MemoryIdentityStorage.prototype.doesIdentityExistPromise = function(identityName)
20091{
20092 return SyncPromise.resolve
20093 (this.identityStore[identityName.toUri()] !== undefined);
20094};
20095
20096/**
20097 * Add a new identity. Do nothing if the identity already exists.
20098 * @param {Name} identityName The identity name to be added.
20099 * @return {SyncPromise} A promise which fulfills when the identity is added.
20100 */
20101MemoryIdentityStorage.prototype.addIdentityPromise = function(identityName)
20102{
20103 var identityUri = identityName.toUri();
20104 if (this.identityStore[identityUri] === undefined)
20105 this.identityStore[identityUri] = { defaultKey: null };
20106
20107 return SyncPromise.resolve();
20108};
20109
20110/**
20111 * Check if the specified key already exists.
20112 * @param {Name} keyName The name of the key.
20113 * @return {SyncPromise} A promise which returns true if the key exists.
20114 */
20115MemoryIdentityStorage.prototype.doesKeyExistPromise = function(keyName)
20116{
20117 return SyncPromise.resolve(this.keyStore[keyName.toUri()] !== undefined);
20118};
20119
20120/**
20121 * Add a public key to the identity storage. Also call addIdentity to ensure
20122 * that the identityName for the key exists. However, if the key already
20123 * exists, do nothing.
20124 * @param {Name} keyName The name of the public key to be added.
20125 * @param {number} keyType Type of the public key to be added from KeyType, such
20126 * as KeyType.RSA..
20127 * @param {Blob} publicKeyDer A blob of the public key DER to be added.
20128 * @return {SyncPromise} A promise which fulfills when complete.
20129 */
20130MemoryIdentityStorage.prototype.addKeyPromise = function
20131 (keyName, keyType, publicKeyDer)
20132{
20133 if (keyName.size() === 0)
20134 return SyncPromise.resolve();
20135
20136 if (this.doesKeyExist(keyName))
20137 return SyncPromise.resolve();
20138
20139 var identityName = keyName.getSubName(0, keyName.size() - 1);
20140
20141 this.addIdentity(identityName);
20142
20143 this.keyStore[keyName.toUri()] =
20144 { keyType: keyType, keyDer: new Blob(publicKeyDer), defaultCertificate: null };
20145
20146 return SyncPromise.resolve();
20147};
20148
20149/**
20150 * Get the public key DER blob from the identity storage.
20151 * @param {Name} keyName The name of the requested public key.
20152 * @return {SyncPromise} A promise which returns the DER Blob, or a promise
20153 * rejected with SecurityException if the key doesn't exist.
20154 */
20155MemoryIdentityStorage.prototype.getKeyPromise = function(keyName)
20156{
20157 if (keyName.size() === 0)
20158 return SyncPromise.reject(new SecurityException(new Error
20159 ("MemoryIdentityStorage::getKeyPromise: Empty keyName")));
20160
20161 var keyNameUri = keyName.toUri();
20162 var entry = this.keyStore[keyNameUri];
20163 if (entry === undefined)
20164 return SyncPromise.reject(new SecurityException(new Error
20165 ("MemoryIdentityStorage::getKeyPromise: The key does not exist")));
20166
20167 return SyncPromise.resolve(entry.keyDer);
20168};
20169
20170/**
20171 * Check if the specified certificate already exists.
20172 * @param {Name} certificateName The name of the certificate.
20173 * @return {SyncPromise} A promise which returns true if the certificate exists.
20174 */
20175MemoryIdentityStorage.prototype.doesCertificateExistPromise = function
20176 (certificateName)
20177{
20178 return SyncPromise.resolve
20179 (this.certificateStore[certificateName.toUri()] !== undefined);
20180};
20181
20182/**
20183 * Add a certificate to the identity storage. Also call addKey to ensure that
20184 * the certificate key exists. If the certificate is already installed, don't
20185 * replace it.
20186 * @param {IdentityCertificate} certificate The certificate to be added. This
20187 * makes a copy of the certificate.
20188 * @return {SyncPromise} A promise which fulfills when finished.
20189 */
20190MemoryIdentityStorage.prototype.addCertificatePromise = function(certificate)
20191{
20192 var certificateName = certificate.getName();
20193 var keyName = certificate.getPublicKeyName();
20194
20195 this.addKey(keyName, certificate.getPublicKeyInfo().getKeyType(),
20196 certificate.getPublicKeyInfo().getKeyDer());
20197
20198 if (this.doesCertificateExist(certificateName))
20199 return SyncPromise.resolve();
20200
20201 // Insert the certificate.
20202 // wireEncode returns the cached encoding if available.
20203 this.certificateStore[certificateName.toUri()] = certificate.wireEncode();
20204
20205 return SyncPromise.resolve();
20206};
20207
20208/**
20209 * Get a certificate from the identity storage.
20210 * @param {Name} certificateName The name of the requested certificate.
20211 * @return {SyncPromise} A promise which returns the requested
20212 * IdentityCertificate, or a promise rejected with SecurityException if the
20213 * certificate doesn't exist.
20214 */
20215MemoryIdentityStorage.prototype.getCertificatePromise = function
20216 (certificateName)
20217{
20218 var certificateNameUri = certificateName.toUri();
20219 if (this.certificateStore[certificateNameUri] === undefined)
20220 return SyncPromise.reject(new SecurityException(new Error
20221 ("MemoryIdentityStorage::getCertificatePromise: The certificate does not exist")));
20222
20223 var certificate = new IdentityCertificate();
20224 try {
20225 certificate.wireDecode(this.certificateStore[certificateNameUri]);
20226 } catch (ex) {
20227 return SyncPromise.reject(new SecurityException(new Error
20228 ("MemoryIdentityStorage::getCertificatePromise: The certificate cannot be decoded")));
20229 }
20230 return SyncPromise.resolve(certificate);
20231};
20232
20233/**
20234 * Get the TPM locator associated with this storage.
20235 * @param {boolean} useSync (optional) If true then return a rejected promise
20236 * since this only supports async code.
20237 * @return {Promise|SyncPromise} A promise which returns the TPM locator, or a
20238 * promise rejected with SecurityException if the TPM locator doesn't exist.
20239 */
20240IdentityStorage.prototype.getTpmLocatorPromise = function(useSync)
20241{
20242 return SyncPromise.resolve("tpm-memory:");
20243};
20244
20245/*****************************************
20246 * Get/Set Default *
20247 *****************************************/
20248
20249/**
20250 * Get the default identity.
20251 * @return {SyncPromise} A promise which returns the Name of default identity,
20252 * or a promise rejected with SecurityException if the default identity is not
20253 * set.
20254 */
20255MemoryIdentityStorage.prototype.getDefaultIdentityPromise = function()
20256{
20257 if (this.defaultIdentity.length === 0)
20258 return SyncPromise.reject(new SecurityException(new Error
20259 ("MemoryIdentityStorage.getDefaultIdentity: The default identity is not defined")));
20260
20261 return SyncPromise.resolve(new Name(this.defaultIdentity));
20262};
20263
20264/**
20265 * Get the default key name for the specified identity.
20266 * @param {Name} identityName The identity name.
20267 * @return {SyncPromise} A promise which returns the default key Name, or a
20268 * promise rejected with SecurityException if the default key name for the
20269 * identity is not set.
20270 */
20271MemoryIdentityStorage.prototype.getDefaultKeyNameForIdentityPromise = function
20272 (identityName)
20273{
20274 var identityUri = identityName.toUri();
20275 if (this.identityStore[identityUri] !== undefined) {
20276 if (this.identityStore[identityUri].defaultKey != null)
20277 return SyncPromise.resolve(this.identityStore[identityUri].defaultKey);
20278 else
20279 return SyncPromise.reject(new SecurityException(new Error
20280 ("No default key set.")));
20281 }
20282 else
20283 return SyncPromise.reject(new SecurityException(new Error("Identity not found.")));
20284};
20285
20286/**
20287 * Get the default certificate name for the specified key.
20288 * @param {Name} keyName The key name.
20289 * @return {SyncPromise} A promise which returns the default certificate Name,
20290 * or a promise rejected with SecurityException if the default certificate name
20291 * for the key name is not set.
20292 */
20293MemoryIdentityStorage.prototype.getDefaultCertificateNameForKeyPromise = function
20294 (keyName)
20295{
20296 var keyUri = keyName.toUri();
20297 if (this.keyStore[keyUri] !== undefined) {
20298 if (this.keyStore[keyUri].defaultCertificate != null)
20299 return SyncPromise.resolve(this.keyStore[keyUri].defaultCertificate);
20300 else
20301 return SyncPromise.reject(new SecurityException(new Error
20302 ("No default certificate set.")));
20303 }
20304 else
20305 return SyncPromise.reject(new SecurityException(new Error("Key not found.")));
20306};
20307
20308/**
20309 * Set the default identity. If the identityName does not exist, then clear the
20310 * default identity so that getDefaultIdentity() throws an exception.
20311 * @param {Name} identityName The default identity name.
20312 * @return {SyncPromise} A promise which fulfills when the default identity is set.
20313 */
20314MemoryIdentityStorage.prototype.setDefaultIdentityPromise = function
20315 (identityName)
20316{
20317 var identityUri = identityName.toUri();
20318 if (this.identityStore[identityUri] !== undefined)
20319 this.defaultIdentity = identityUri;
20320 else
20321 // The identity doesn't exist, so clear the default.
20322 this.defaultIdentity = "";
20323
20324 return SyncPromise.resolve();
20325};
20326
20327/**
20328 * Set a key as the default key of an identity. The identity name is inferred
20329 * from keyName.
20330 * @param {Name} keyName The name of the key.
20331 * @param {Name} identityNameCheck (optional) The identity name to check that the
20332 * keyName contains the same identity name. If an empty name, it is ignored.
20333 * @return {SyncPromise} A promise which fulfills when the default key name is
20334 * set.
20335 */
20336MemoryIdentityStorage.prototype.setDefaultKeyNameForIdentityPromise = function
20337 (keyName, identityNameCheck)
20338{
20339 identityNameCheck = (identityNameCheck instanceof Name) ? identityNameCheck : null;
20340
20341 var identityName = keyName.getPrefix(-1);
20342
20343 if (identityNameCheck != null && identityNameCheck.size() > 0 &&
20344 !identityNameCheck.equals(identityName))
20345 return SyncPromise.reject(new SecurityException(new Error
20346 ("The specified identity name does not match the key name")));
20347
20348 var identityUri = identityName.toUri();
20349 if (this.identityStore[identityUri] !== undefined)
20350 this.identityStore[identityUri].defaultKey = new Name(keyName);
20351
20352 return SyncPromise.resolve();
20353};
20354
20355/**
20356 * Set the default key name for the specified identity.
20357 * @param {Name} keyName The key name.
20358 * @param {Name} certificateName The certificate name.
20359 * @return {SyncPromise} A promise which fulfills when the default certificate
20360 * name is set.
20361 */
20362MemoryIdentityStorage.prototype.setDefaultCertificateNameForKeyPromise = function
20363 (keyName, certificateName)
20364{
20365 var keyUri = keyName.toUri();
20366 if (this.keyStore[keyUri] !== undefined)
20367 this.keyStore[keyUri].defaultCertificate = new Name(certificateName);
20368
20369 return SyncPromise.resolve();
20370};
20371
20372/*****************************************
20373 * Delete Methods *
20374 *****************************************/
20375
20376/**
20377 * Delete a certificate.
20378 * @param {Name} certificateName The certificate name.
20379 * @return {SyncPromise} A promise which fulfills when the certificate
20380 * info is deleted.
20381 */
20382MemoryIdentityStorage.prototype.deleteCertificateInfoPromise = function
20383 (certificateName)
20384{
20385 return SyncPromise.reject(new Error
20386 ("MemoryIdentityStorage.deleteCertificateInfoPromise is not implemented"));
20387};
20388
20389/**
20390 * Delete a public key and related certificates.
20391 * @param {Name} keyName The key name.
20392 * @return {SyncPromise} A promise which fulfills when the public key info is
20393 * deleted.
20394 */
20395MemoryIdentityStorage.prototype.deletePublicKeyInfoPromise = function(keyName)
20396{
20397 return SyncPromise.reject(new Error
20398 ("MemoryIdentityStorage.deletePublicKeyInfoPromise is not implemented"));
20399};
20400
20401/**
20402 * Delete an identity and related public keys and certificates.
20403 * @param {Name} identity The identity name.
20404 * @return {SyncPromise} A promise which fulfills when the identity info is
20405 * deleted.
20406 */
20407MemoryIdentityStorage.prototype.deleteIdentityInfoPromise = function(identity)
20408{
20409 return SyncPromise.reject(new Error
20410 ("MemoryIdentityStorage.deleteIdentityInfoPromise is not implemented"));
20411};
20412/**
20413 * Copyright (C) 2014-2016 Regents of the University of California.
20414 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
20415 * From ndn-cxx security by Yingdi Yu <yingdi@cs.ucla.edu>.
20416 *
20417 * This program is free software: you can redistribute it and/or modify
20418 * it under the terms of the GNU Lesser General Public License as published by
20419 * the Free Software Foundation, either version 3 of the License, or
20420 * (at your option) any later version.
20421 *
20422 * This program is distributed in the hope that it will be useful,
20423 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20424 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20425 * GNU Lesser General Public License for more details.
20426 *
20427 * You should have received a copy of the GNU Lesser General Public License
20428 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20429 * A copy of the GNU Lesser General Public License is in the file COPYING.
20430 */
20431
20432/** @ignore */
20433var SyncPromise = require('../../util/sync-promise.js').SyncPromise; /** @ignore */
20434var DerNode = require('../../encoding/der/der-node.js').DerNode;
20435
20436/**
20437 * PrivateKeyStorage is an abstract class which declares methods for working
20438 * with a private key storage. You should use a subclass.
20439 * @constructor
20440 */
20441var PrivateKeyStorage = function PrivateKeyStorage()
20442{
20443};
20444
20445exports.PrivateKeyStorage = PrivateKeyStorage;
20446
20447/**
20448 * Generate a pair of asymmetric keys.
20449 * @param {Name} keyName The name of the key pair.
20450 * @param {KeyParams} params The parameters of the key.
20451 * @param {boolean} (optional) useSync If true then return a SyncPromise which
20452 * is already fulfilled. If omitted or false, this may return a SyncPromise or
20453 * an async Promise.
20454 * @return {Promise|SyncPromise} A promise that fulfills when the pair is
20455 * generated.
20456 */
20457PrivateKeyStorage.prototype.generateKeyPairPromise = function
20458 (keyName, params, useSync)
20459{
20460 return SyncPromise.reject(new Error
20461 ("PrivateKeyStorage.generateKeyPairPromise is not implemented"));
20462};
20463
20464/**
20465 * Generate a pair of asymmetric keys.
20466 * @param {Name} keyName The name of the key pair.
20467 * @param {KeyParams} params The parameters of the key.
20468 * @throws Error If generateKeyPairPromise doesn't return a SyncPromise which
20469 * is already fulfilled.
20470 */
20471PrivateKeyStorage.prototype.generateKeyPair = function(keyName, params)
20472{
20473 SyncPromise.getValue(this.generateKeyPairPromise(keyName, params, true));
20474};
20475
20476/**
20477 * Delete a pair of asymmetric keys. If the key doesn't exist, do nothing.
20478 * @param {Name} keyName The name of the key pair.
20479 * @param {boolean} useSync (optional) If true then return a SyncPromise which
20480 * is already fulfilled. If omitted or false, this may return a SyncPromise or
20481 * an async Promise.
20482 * @return {Promise|SyncPromise} A promise that fulfills when the key pair is
20483 * deleted.
20484 */
20485PrivateKeyStorage.prototype.deleteKeyPairPromise = function(keyName, useSync)
20486{
20487 return SyncPromise.reject(new Error
20488 ("PrivateKeyStorage.deleteKeyPairPromise is not implemented"));
20489};
20490
20491/**
20492 * Delete a pair of asymmetric keys. If the key doesn't exist, do nothing.
20493 * @param {Name} keyName The name of the key pair.
20494 * @throws Error If deleteKeyPairPromise doesn't return a SyncPromise which
20495 * is already fulfilled.
20496 */
20497PrivateKeyStorage.prototype.deleteKeyPair = function(keyName)
20498{
20499 SyncPromise.getValue(this.deleteKeyPairPromise(keyName, true));
20500};
20501
20502/**
20503 * Get the public key
20504 * @param {Name} keyName The name of public key.
20505 * @param {boolean} useSync (optional) If true then return a SyncPromise which
20506 * is already fulfilled. If omitted or false, this may return a SyncPromise or
20507 * an async Promise.
20508 * @return {Promise|SyncPromise} A promise that returns the PublicKey.
20509 */
20510PrivateKeyStorage.prototype.getPublicKeyPromise = function(keyName, useSync)
20511{
20512 return SyncPromise.reject(new Error
20513 ("PrivateKeyStorage.getPublicKeyPromise is not implemented"));
20514};
20515
20516/**
20517 * Get the public key
20518 * @param {Name} keyName The name of public key.
20519 * @return {PublicKey} The public key.
20520 * @throws Error If getPublicKeyPromise doesn't return a SyncPromise which
20521 * is already fulfilled.
20522 */
20523PrivateKeyStorage.prototype.getPublicKey = function(keyName)
20524{
20525 return SyncPromise.getValue(this.getPublicKeyPromise(keyName, true));
20526};
20527
20528/**
20529 * Fetch the private key for keyName and sign the data to produce a signature Blob.
20530 * @param {Buffer} data Pointer to the input byte array.
20531 * @param {Name} keyName The name of the signing key.
20532 * @param {number} digestAlgorithm (optional) The digest algorithm from
20533 * DigestAlgorithm, such as DigestAlgorithm.SHA256. If omitted, use
20534 * DigestAlgorithm.SHA256.
20535 * @param {boolean} useSync (optional) If true then return a SyncPromise which
20536 * is already fulfilled. If omitted or false, this may return a SyncPromise or
20537 * an async Promise.
20538 * @return {Promise|SyncPromise} A promise that returns the signature Blob.
20539 */
20540PrivateKeyStorage.prototype.signPromise = function
20541 (data, keyName, digestAlgorithm, useSync)
20542{
20543 return SyncPromise.reject(new Error("PrivateKeyStorage.sign is not implemented"));
20544};
20545
20546/**
20547 * Fetch the private key for keyName and sign the data to produce a signature Blob.
20548 * @param {Buffer} data Pointer to the input byte array.
20549 * @param {Name} keyName The name of the signing key.
20550 * @param {number} digestAlgorithm (optional) The digest algorithm from
20551 * DigestAlgorithm, such as DigestAlgorithm.SHA256. If omitted, use
20552 * DigestAlgorithm.SHA256.
20553 * @return {Blob} The signature Blob.
20554 * @throws Error If signPromise doesn't return a SyncPromise which is already
20555 * fulfilled.
20556 */
20557PrivateKeyStorage.prototype.sign = function(data, keyName, digestAlgorithm)
20558{
20559 return SyncPromise.getValue
20560 (this.signPromise(data, keyName, digestAlgorithm, true));
20561};
20562
20563/**
20564 * Decrypt data.
20565 * @param {Name} keyName The name of the decrypting key.
20566 * @param {Buffer} data The byte to be decrypted.
20567 * @param {boolean} isSymmetric (optional) If true symmetric encryption is used,
20568 * otherwise asymmetric encryption is used. If omitted, use asymmetric
20569 * encryption.
20570 * @return {Blob} The decrypted data.
20571 */
20572PrivateKeyStorage.prototype.decrypt = function(keyName, data, isSymmetric)
20573{
20574 throw new Error("PrivateKeyStorage.decrypt is not implemented");
20575};
20576
20577/**
20578 * Encrypt data.
20579 * @param {Name} keyName The name of the encrypting key.
20580 * @param {Buffer} data The byte to be encrypted.
20581 * @param {boolean} isSymmetric (optional) If true symmetric encryption is used,
20582 * otherwise asymmetric encryption is used. If omitted, use asymmetric
20583 * encryption.
20584 * @return {Blob} The encrypted data.
20585 */
20586PrivateKeyStorage.prototype.encrypt = function(keyName, data, isSymmetric)
20587{
20588 throw new Error("PrivateKeyStorage.encrypt is not implemented");
20589};
20590
20591/**
20592 * @brief Generate a symmetric key.
20593 * @param {Name} keyName The name of the key.
20594 * @param {KeyParams} params The parameters of the key.
20595 */
20596PrivateKeyStorage.prototype.generateKey = function(keyName, params)
20597{
20598 throw new Error("PrivateKeyStorage.generateKey is not implemented");
20599};
20600
20601/**
20602 * Check if a particular key exists.
20603 * @param {Name} keyName The name of the key.
20604 * @param {number} keyClass The class of the key, e.g. KeyClass.PUBLIC,
20605 * KeyClass.PRIVATE, or KeyClass.SYMMETRIC.
20606 * @param {boolean} useSync (optional) If true then return a SyncPromise which
20607 * is already fulfilled. If omitted or false, this may return a SyncPromise or
20608 * an async Promise.
20609 * @return {Promise|SyncPromise} A promise which returns true if the key exists.
20610 */
20611PrivateKeyStorage.prototype.doesKeyExistPromise = function
20612 (keyName, keyClass, useSync)
20613{
20614 return SyncPromise.reject(new Error
20615 ("PrivateKeyStorage.doesKeyExist is not implemented"));
20616};
20617
20618/**
20619 * Check if a particular key exists.
20620 * @param {Name} keyName The name of the key.
20621 * @param {number} keyClass The class of the key, e.g. KeyClass.PUBLIC,
20622 * KeyClass.PRIVATE, or KeyClass.SYMMETRIC.
20623 * @return {boolean} True if the key exists.
20624 * @throws Error If doesKeyExistPromise doesn't return a SyncPromise which
20625 * is already fulfilled.
20626 */
20627PrivateKeyStorage.prototype.doesKeyExist = function(keyName, keyClass)
20628{
20629 return SyncPromise.getValue(this.doesKeyExistPromise(keyName, keyClass, true));
20630};
20631
20632/**
20633 * Encode the private key to a PKCS #8 private key. We do this explicitly here
20634 * to avoid linking to extra OpenSSL libraries.
20635 * @param {Buffer} privateKeyDer The input private key DER.
20636 * @param {OID} oid The OID of the privateKey.
20637 * @param {DerNode} parameters The DerNode of the parameters for the OID.
20638 * @return {Blob} The PKCS #8 private key DER.
20639 */
20640PrivateKeyStorage.encodePkcs8PrivateKey = function
20641 (privateKeyDer, oid, parameters)
20642{
20643 var algorithmIdentifier = new DerNode.DerSequence();
20644 algorithmIdentifier.addChild(new DerNode.DerOid(oid));
20645 algorithmIdentifier.addChild(parameters);
20646
20647 var result = new DerNode.DerSequence();
20648 result.addChild(new DerNode.DerInteger(0));
20649 result.addChild(algorithmIdentifier);
20650 result.addChild(new DerNode.DerOctetString(privateKeyDer));
20651
20652 return result.encode();
20653};
20654
20655/**
20656 * Encode the RSAKey private key as a PKCS #1 private key.
20657 * @param {RSAKey} rsaKey The RSAKey private key.
20658 * @return {Blob} The PKCS #1 private key DER.
20659 */
20660PrivateKeyStorage.encodePkcs1PrivateKeyFromRSAKey = function(rsaKey)
20661{
20662 // Imitate KJUR getEncryptedPKCS5PEMFromRSAKey.
20663 var result = new DerNode.DerSequence();
20664
20665 result.addChild(new DerNode.DerInteger(0));
20666 result.addChild(new DerNode.DerInteger(PrivateKeyStorage.bigIntegerToBuffer(rsaKey.n)));
20667 result.addChild(new DerNode.DerInteger(rsaKey.e));
20668 result.addChild(new DerNode.DerInteger(PrivateKeyStorage.bigIntegerToBuffer(rsaKey.d)));
20669 result.addChild(new DerNode.DerInteger(PrivateKeyStorage.bigIntegerToBuffer(rsaKey.p)));
20670 result.addChild(new DerNode.DerInteger(PrivateKeyStorage.bigIntegerToBuffer(rsaKey.q)));
20671 result.addChild(new DerNode.DerInteger(PrivateKeyStorage.bigIntegerToBuffer(rsaKey.dmp1)));
20672 result.addChild(new DerNode.DerInteger(PrivateKeyStorage.bigIntegerToBuffer(rsaKey.dmq1)));
20673 result.addChild(new DerNode.DerInteger(PrivateKeyStorage.bigIntegerToBuffer(rsaKey.coeff)));
20674
20675 return result.encode();
20676};
20677
20678/**
20679 * Encode the public key values in the RSAKey private key as a
20680 * SubjectPublicKeyInfo.
20681 * @param {RSAKey} rsaKey The RSAKey private key with the public key values.
20682 * @return {Blob} The SubjectPublicKeyInfo DER.
20683 */
20684PrivateKeyStorage.encodePublicKeyFromRSAKey = function(rsaKey)
20685{
20686 var rsaPublicKey = new DerNode.DerSequence();
20687
20688 rsaPublicKey.addChild(new DerNode.DerInteger(PrivateKeyStorage.bigIntegerToBuffer(rsaKey.n)));
20689 rsaPublicKey.addChild(new DerNode.DerInteger(rsaKey.e));
20690
20691 var algorithmIdentifier = new DerNode.DerSequence();
20692 algorithmIdentifier.addChild
20693 (new DerNode.DerOid(new OID(PrivateKeyStorage.RSA_ENCRYPTION_OID)));
20694 algorithmIdentifier.addChild(new DerNode.DerNull());
20695
20696 var result = new DerNode.DerSequence();
20697
20698 result.addChild(algorithmIdentifier);
20699 result.addChild(new DerNode.DerBitString(rsaPublicKey.encode().buf(), 0));
20700
20701 return result.encode();
20702};
20703
20704/**
20705 * Convert a BigInteger to a Buffer.
20706 * @param {BigInteger} bigInteger The BigInteger.
20707 * @return {Buffer} The Buffer.
20708 */
20709PrivateKeyStorage.bigIntegerToBuffer = function(bigInteger)
20710{
20711 // Imitate KJUR.asn1.ASN1Util.bigIntToMinTwosComplementsHex.
20712 var hex = bigInteger.toString(16);
20713 if (hex.substr(0, 1) == "-")
20714 throw new Error
20715 ("PrivateKeyStorage.bigIntegerToBuffer: Negative integers are not currently supported");
20716
20717 if (hex.length % 2 == 1)
20718 // Odd number of characters.
20719 hex = "0" + hex;
20720 else {
20721 if (! hex.match(/^[0-7]/))
20722 // The first byte is >= 0x80, so prepend a zero to keep it positive.
20723 hex = "00" + hex;
20724 }
20725
20726 return new Buffer(hex, 'hex');
20727};
20728
20729PrivateKeyStorage.RSA_ENCRYPTION_OID = "1.2.840.113549.1.1.1";
20730PrivateKeyStorage.EC_ENCRYPTION_OID = "1.2.840.10045.2.1";
20731/**
20732 * Copyright (C) 2014-2016 Regents of the University of California.
20733 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
20734 * From ndn-cxx security by Yingdi Yu <yingdi@cs.ucla.edu>.
20735 *
20736 * This program is free software: you can redistribute it and/or modify
20737 * it under the terms of the GNU Lesser General Public License as published by
20738 * the Free Software Foundation, either version 3 of the License, or
20739 * (at your option) any later version.
20740 *
20741 * This program is distributed in the hope that it will be useful,
20742 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20743 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20744 * GNU Lesser General Public License for more details.
20745 *
20746 * You should have received a copy of the GNU Lesser General Public License
20747 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20748 * A copy of the GNU Lesser General Public License is in the file COPYING.
20749 */
20750
20751// Use capitalized Crypto to not clash with the browser's crypto.subtle.
20752/** @ignore */
20753var Crypto = require('../../crypto.js'); /** @ignore */
20754var Blob = require('../../util/blob.js').Blob; /** @ignore */
20755var SecurityException = require('../security-exception.js').SecurityException; /** @ignore */
20756var PublicKey = require('../certificate/public-key.js').PublicKey; /** @ignore */
20757var KeyClass = require('../security-types.js').KeyClass; /** @ignore */
20758var KeyType = require('../security-types').KeyType; /** @ignore */
20759var DigestAlgorithm = require('../security-types.js').DigestAlgorithm; /** @ignore */
20760var DataUtils = require('../../encoding/data-utils.js').DataUtils; /** @ignore */
20761var PrivateKeyStorage = require('./private-key-storage.js').PrivateKeyStorage; /** @ignore */
20762var DerNode = require('../../encoding/der/der-node.js').DerNode; /** @ignore */
20763var OID = require('../../encoding/oid.js').OID; /** @ignore */
20764var SyncPromise = require('../../util/sync-promise.js').SyncPromise; /** @ignore */
20765var UseSubtleCrypto = require('../../use-subtle-crypto-node.js').UseSubtleCrypto; /** @ignore */
20766var rsaKeygen = null;
20767try {
20768 // This should be installed with: sudo npm install rsa-keygen
20769 rsaKeygen = require('rsa-keygen');
20770}
20771catch (e) {}
20772
20773/**
20774 * MemoryPrivateKeyStorage class extends PrivateKeyStorage to implement private
20775 * key storage in memory.
20776 * @constructor
20777 */
20778var MemoryPrivateKeyStorage = function MemoryPrivateKeyStorage()
20779{
20780 // Call the base constructor.
20781 PrivateKeyStorage.call(this);
20782
20783 // The key is the keyName.toUri(). The value is security.certificate.PublicKey.
20784 this.publicKeyStore = {};
20785 // The key is the keyName.toUri(). The value is the object
20786 // {keyType, // number from KeyType
20787 // privateKey // The PEM-encoded private key.
20788 // }.
20789 this.privateKeyStore = {};
20790};
20791
20792MemoryPrivateKeyStorage.prototype = new PrivateKeyStorage();
20793MemoryPrivateKeyStorage.prototype.name = "MemoryPrivateKeyStorage";
20794
20795exports.MemoryPrivateKeyStorage = MemoryPrivateKeyStorage;
20796
20797/**
20798 * Set the public key for the keyName.
20799 * @param {Name} keyName The key name.
20800 * @param {number} keyType The KeyType, such as KeyType.RSA.
20801 * @param {Buffer} publicKeyDer The public key DER byte array.
20802 */
20803MemoryPrivateKeyStorage.prototype.setPublicKeyForKeyName = function
20804 (keyName, keyType, publicKeyDer)
20805{
20806 this.publicKeyStore[keyName.toUri()] = new PublicKey
20807 (new Blob(publicKeyDer, true));
20808};
20809
20810/**
20811 * Set the private key for the keyName.
20812 * @param {Name} keyName The key name.
20813 * @param {number} keyType The KeyType, such as KeyType.RSA.
20814 * @param {Buffer} privateKeyDer The private key DER byte array.
20815 */
20816MemoryPrivateKeyStorage.prototype.setPrivateKeyForKeyName = function
20817 (keyName, keyType, privateKeyDer)
20818{
20819 // Encode the DER as PEM.
20820 var keyBase64 = privateKeyDer.toString('base64');
20821 var keyPem;
20822 if (keyType === KeyType.RSA) {
20823 keyPem = "-----BEGIN RSA PRIVATE KEY-----\n";
20824 for (var i = 0; i < keyBase64.length; i += 64)
20825 keyPem += (keyBase64.substr(i, 64) + "\n");
20826 keyPem += "-----END RSA PRIVATE KEY-----";
20827 }
20828 else if (keyType === KeyType.ECDSA) {
20829 keyPem = "-----BEGIN EC PRIVATE KEY-----\n";
20830 for (var i = 0; i < keyBase64.length; i += 64)
20831 keyPem += (keyBase64.substr(i, 64) + "\n");
20832 keyPem += "-----END EC PRIVATE KEY-----";
20833 }
20834 else
20835 throw new SecurityException(new Error
20836 ("MemoryPrivateKeyStorage: KeyType is not supported"));
20837
20838 this.privateKeyStore[keyName.toUri()] =
20839 { keyType: keyType, privateKey: keyPem };
20840};
20841
20842/**
20843 * Set the public and private key for the keyName.
20844 * @param {Name} keyName The key name.
20845 * @param {number} keyType The KeyType, such as KeyType.RSA.
20846 * @param {Buffer} publicKeyDer The public key DER byte array.
20847 * @param {Buffer} privateKeyDer The private key DER byte array.
20848 */
20849MemoryPrivateKeyStorage.prototype.setKeyPairForKeyName = function
20850 (keyName, keyType, publicKeyDer, privateKeyDer)
20851{
20852 this.setPublicKeyForKeyName(keyName, keyType, publicKeyDer);
20853 this.setPrivateKeyForKeyName(keyName, keyType, privateKeyDer);
20854};
20855
20856/**
20857 * Generate a pair of asymmetric keys.
20858 * @param {Name} keyName The name of the key pair.
20859 * @param {KeyParams} params The parameters of the key.
20860 * @param {boolean} useSync (optional) If true then use blocking crypto and
20861 * return a SyncPromise which is already fulfilled. If omitted or false, if
20862 * possible use crypto.subtle and return an async Promise, otherwise use
20863 * blocking crypto and return a SyncPromise.
20864 * @return {Promise|SyncPromise} A promise that fulfills when the pair is
20865 * generated.
20866 */
20867MemoryPrivateKeyStorage.prototype.generateKeyPairPromise = function
20868 (keyName, params, useSync)
20869{
20870 if (this.doesKeyExist(keyName, KeyClass.PUBLIC))
20871 return SyncPromise.reject(new SecurityException(new Error
20872 ("Public key already exists")));
20873 if (this.doesKeyExist(keyName, KeyClass.PRIVATE))
20874 return SyncPromise.reject(new SecurityException(new Error
20875 ("Private key already exists")));
20876
20877 var thisStore = this;
20878
20879 if (UseSubtleCrypto() && !useSync) {
20880 if (params.getKeyType() === KeyType.RSA) {
20881 var privateKey = null;
20882 var publicKeyDer = null;
20883
20884 return crypto.subtle.generateKey
20885 ({ name: "RSASSA-PKCS1-v1_5", modulusLength: params.getKeySize(),
20886 publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
20887 hash: {name: "SHA-256"} },
20888 true, ["sign", "verify"])
20889 .then(function(key) {
20890 privateKey = key.privateKey;
20891
20892 // Export the public key to DER.
20893 return crypto.subtle.exportKey("spki", key.publicKey);
20894 })
20895 .then(function(exportedPublicKey) {
20896 publicKeyDer = new Blob(new Uint8Array(exportedPublicKey), false).buf();
20897
20898 // Export the private key to DER.
20899 return crypto.subtle.exportKey("pkcs8", privateKey);
20900 })
20901 .then(function(pkcs8Der) {
20902 // Crypto.subtle exports the private key as PKCS #8. Decode it to find
20903 // the inner private key DER.
20904 var parsedNode = DerNode.parse
20905 (new Blob(new Uint8Array(pkcs8Der), false).buf());
20906 // Get the value of the 3rd child which is the octet string.
20907 var privateKeyDer = parsedNode.getChildren()[2].toVal();
20908
20909 // Save the key pair.
20910 thisStore.setKeyPairForKeyName
20911 (keyName, params.getKeyType(), publicKeyDer, privateKeyDer.buf());
20912
20913 // sign will use subtleKey directly.
20914 thisStore.privateKeyStore[keyName.toUri()].subtleKey = privateKey;
20915
20916 return Promise.resolve();
20917 });
20918 }
20919 else
20920 return SyncPromise.reject(new SecurityException(new Error
20921 ("Only RSA key generation currently supported")));
20922 }
20923 else {
20924 return SyncPromise.resolve()
20925 .then(function() {
20926 if (typeof RSAKey !== 'undefined') {
20927 // Assume we are in the browser.
20928 if (params.getKeyType() === KeyType.RSA) {
20929 var rsaKey = new RSAKey();
20930 rsaKey.generate(params.getKeySize(), '010001');
20931 thisStore.setKeyPairForKeyName
20932 (keyName, params.getKeyType(),
20933 PrivateKeyStorage.encodePublicKeyFromRSAKey(rsaKey).buf(),
20934 PrivateKeyStorage.encodePkcs1PrivateKeyFromRSAKey(rsaKey).buf());
Alexander Afanasyev1663a412013-03-02 13:52:00 -080020935 }
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080020936 else
20937 return SyncPromise.reject(new SecurityException(new Error
20938 ("Only RSA key generation currently supported")));
20939 }
20940 else {
20941 // Assume we are in Node.js.
20942 var publicKeyDer;
20943 var privateKeyPem;
20944
20945 if (params.getKeyType() === KeyType.RSA) {
20946 if (!rsaKeygen)
20947 return SyncPromise.reject(new SecurityException(new Error
20948 ("Need to install rsa-keygen: sudo npm install rsa-keygen")));
20949
20950 var keyPair = rsaKeygen.generate(params.getKeySize());
20951
20952 // Get the public key DER from the PEM string.
20953 var publicKeyBase64 = keyPair.public_key.toString().replace
20954 ("-----BEGIN PUBLIC KEY-----", "").replace
20955 ("-----END PUBLIC KEY-----", "");
20956 publicKeyDer = new Buffer(publicKeyBase64, 'base64');
20957
20958 privateKeyPem = keyPair.private_key.toString();
20959 }
20960 else
20961 return SyncPromise.reject(new SecurityException(new Error
20962 ("Only RSA key generation currently supported")));
20963
20964 thisStore.setPublicKeyForKeyName(keyName, params.getKeyType(), publicKeyDer);
20965 thisStore.privateKeyStore[keyName.toUri()] =
20966 { keyType: params.getKeyType(), privateKey: privateKeyPem };
20967 }
20968
20969 return SyncPromise.resolve();
20970 });
20971 }
Alexander Afanasyev1663a412013-03-02 13:52:00 -080020972};
20973
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080020974/**
20975 * Delete a pair of asymmetric keys. If the key doesn't exist, do nothing.
20976 * @param {Name} keyName The name of the key pair.
20977 * @return {SyncPromise} A promise that fulfills when the key pair is deleted.
20978 */
20979MemoryPrivateKeyStorage.prototype.deleteKeyPairPromise = function(keyName)
20980{
20981 var keyUri = keyName.toUri();
20982
20983 delete this.publicKeyStore[keyUri];
20984 delete this.privateKeyStore[keyUri];
20985
20986 return SyncPromise.resolve();
20987};
20988
20989/**
20990 * Get the public key
20991 * @param {Name} keyName The name of public key.
20992 * @return {SyncPromise} A promise that returns the PublicKey.
20993 */
20994MemoryPrivateKeyStorage.prototype.getPublicKeyPromise = function(keyName)
20995{
20996 var keyUri = keyName.toUri();
20997 var publicKey = this.publicKeyStore[keyUri];
20998 if (publicKey === undefined)
20999 return SyncPromise.reject(new SecurityException(new Error
21000 ("MemoryPrivateKeyStorage: Cannot find public key " + keyName.toUri())));
21001
21002 return SyncPromise.resolve(publicKey);
21003};
21004
21005/**
21006 * Fetch the private key for keyName and sign the data to produce a signature Blob.
21007 * @param {Buffer} data Pointer to the input byte array.
21008 * @param {Name} keyName The name of the signing key.
21009 * @param {number} digestAlgorithm (optional) The digest algorithm from
21010 * DigestAlgorithm, such as DigestAlgorithm.SHA256. If omitted, use
21011 * DigestAlgorithm.SHA256.
21012 * @param {boolean} useSync (optional) If true then use blocking crypto and
21013 * return a SyncPromise which is already fulfilled. If omitted or false, if
21014 * possible use crypto.subtle and return an async Promise, otherwise use
21015 * blocking crypto and return a SyncPromise.
21016 * @return {Promise|SyncPromise} A promise that returns the signature Blob.
21017 */
21018MemoryPrivateKeyStorage.prototype.signPromise = function
21019 (data, keyName, digestAlgorithm, useSync)
21020{
21021 useSync = (typeof digestAlgorithm === "boolean") ? digestAlgorithm : useSync;
21022 digestAlgorithm = (typeof digestAlgorithm === "boolean" || !digestAlgorithm) ? DigestAlgorithm.SHA256 : digestAlgorithm;
21023
21024 if (digestAlgorithm != DigestAlgorithm.SHA256)
21025 return SyncPromise.reject(new SecurityException(new Error
21026 ("MemoryPrivateKeyStorage.sign: Unsupported digest algorithm")));
21027
21028 // Find the private key.
21029 var keyUri = keyName.toUri();
21030 var privateKey = this.privateKeyStore[keyUri];
21031 if (privateKey === undefined)
21032 return SyncPromise.reject(new SecurityException(new Error
21033 ("MemoryPrivateKeyStorage: Cannot find private key " + keyUri)));
21034
21035 if (UseSubtleCrypto() && !useSync){
21036 var algo = {name:"RSASSA-PKCS1-v1_5",hash:{name:"SHA-256"}};
21037
21038 if (!privateKey.subtleKey){
21039 //this is the first time in the session that we're using crypto subtle with this key
21040 //so we have to convert to pkcs8 and import it.
21041 //assigning it to privateKey.subtleKey means we only have to do this once per session,
21042 //giving us a small, but not insignificant, performance boost.
21043 var privateDER = DataUtils.privateKeyPemToDer(privateKey.privateKey);
21044 var pkcs8 = PrivateKeyStorage.encodePkcs8PrivateKey
21045 (privateDER, new OID(PrivateKeyStorage.RSA_ENCRYPTION_OID),
21046 new DerNode.DerNull()).buf();
21047
21048 var promise = crypto.subtle.importKey("pkcs8", pkcs8.buffer, algo, true, ["sign"]).then(function(subtleKey){
21049 //cache the crypto.subtle key object
21050 privateKey.subtleKey = subtleKey;
21051 return crypto.subtle.sign(algo, subtleKey, data);
21052 });
21053 } else {
21054 // The crypto.subtle key has been cached on a previous sign or from keygen.
21055 var promise = crypto.subtle.sign(algo, privateKey.subtleKey, data);
21056 }
21057
21058 return promise.then(function(signature){
21059 var result = new Blob(new Uint8Array(signature), true);
21060 return Promise.resolve(result);
21061 });
21062 } else {
21063 var signer;
21064 if (privateKey.keyType === KeyType.RSA)
21065 signer = Crypto.createSign("RSA-SHA256");
21066 else if (privateKey.keyType === KeyType.ECDSA)
21067 // Just create a "sha256". The Crypto library will infer ECDSA from the key.
21068 signer = Crypto.createSign("sha256");
21069 else
21070 // We don't expect this to happen since setPrivateKeyForKeyName already checked.
21071 return SyncPromise.reject(new SecurityException(new Error
21072 ("MemoryPrivateKeyStorage.sign: Unrecognized private key type")));
21073
21074 signer.update(data);
21075 var signature = new Buffer
21076 (DataUtils.toNumbersIfString(signer.sign(privateKey.privateKey)));
21077 var result = new Blob(signature, false);
21078
21079 return SyncPromise.resolve(result);
21080 }
21081};
21082
21083/**
21084 * Check if a particular key exists.
21085 * @param {Name} keyName The name of the key.
21086 * @param {number} keyClass The class of the key, e.g. KeyClass.PUBLIC,
21087 * KeyClass.PRIVATE, or KeyClass.SYMMETRIC.
21088 * @return {SyncPromise} A promise which returns true if the key exists.
21089 */
21090MemoryPrivateKeyStorage.prototype.doesKeyExistPromise = function
21091 (keyName, keyClass)
21092{
21093 var keyUri = keyName.toUri();
21094 var result = false;
21095 if (keyClass == KeyClass.PUBLIC)
21096 result = this.publicKeyStore[keyUri] !== undefined;
21097 else if (keyClass == KeyClass.PRIVATE)
21098 result = this.privateKeyStore[keyUri] !== undefined;
21099
21100 return SyncPromise.resolve(result);
21101};
21102/**
21103 * Copyright (C) 2015-2016 Regents of the University of California.
21104 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
21105 *
21106 * This program is free software: you can redistribute it and/or modify
21107 * it under the terms of the GNU Lesser General Public License as published by
21108 * the Free Software Foundation, either version 3 of the License, or
21109 * (at your option) any later version.
21110 *
21111 * This program is distributed in the hope that it will be useful,
21112 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21113 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21114 * GNU Lesser General Public License for more details.
21115 *
21116 * You should have received a copy of the GNU Lesser General Public License
21117 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21118 * A copy of the GNU Lesser General Public License is in the file COPYING.
21119 */
21120
21121// Use capitalized Crypto to not clash with the browser's crypto.subtle.
21122var Crypto = require('../../crypto.js');
21123// Don't require other modules since this is meant for the browser, not Node.js.
21124
21125/**
21126 * IndexedDbPrivateKeyStorage extends PrivateKeyStorage to implement private key
21127 * storage using the browser's IndexedDB service.
21128 * @constructor
21129 */
21130var IndexedDbPrivateKeyStorage = function IndexedDbPrivateKeyStorage()
21131{
21132 PrivateKeyStorage.call(this);
21133
21134 this.database = new Dexie("ndnsec-tpm");
21135 this.database.version(1).stores({
21136 // "nameHash" is transformName(keyName) // string
21137 // "encoding" is the public key DER // Uint8Array
21138 publicKey: "nameHash",
21139
21140 // "nameHash" is transformName(keyName) // string
21141 // "encoding" is the PKCS 8 private key DER // Uint8Array
21142 privateKey: "nameHash"
21143 });
21144 this.database.open();
21145};
21146
21147IndexedDbPrivateKeyStorage.prototype = new PrivateKeyStorage();
21148IndexedDbPrivateKeyStorage.prototype.name = "IndexedDbPrivateKeyStorage";
21149
21150/**
21151 * Generate a pair of asymmetric keys.
21152 * @param {Name} keyName The name of the key pair.
21153 * @param {KeyParams} params The parameters of the key.
21154 * @param {boolean} useSync (optional) If true then return a rejected promise
21155 * since this only supports async code.
21156 * @return {Promise} A promise that fulfills when the pair is generated.
21157 */
21158IndexedDbPrivateKeyStorage.prototype.generateKeyPairPromise = function
21159 (keyName, params, useSync)
21160{
21161 if (useSync)
21162 return Promise.reject(new SecurityException(new Error
21163 ("IndexedDbPrivateKeyStorage.generateKeyPairPromise is only supported for async")));
21164
21165 var thisStorage = this;
21166
21167 return thisStorage.doesKeyExistPromise(keyName, KeyClass.PUBLIC)
21168 .then(function(exists) {
21169 if (exists)
21170 throw new Error("Public key already exists");
21171
21172 return thisStorage.doesKeyExistPromise(keyName, KeyClass.PRIVATE);
21173 })
21174 .then(function(exists) {
21175 if (exists)
21176 throw new Error("Private key already exists");
21177
21178 if (params.getKeyType() === KeyType.RSA) {
21179 var privateKey = null;
21180 var publicKeyDer = null;
21181
21182 return crypto.subtle.generateKey
21183 ({ name: "RSASSA-PKCS1-v1_5", modulusLength: params.getKeySize(),
21184 publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
21185 hash: {name: "SHA-256"} },
21186 true, ["sign", "verify"])
21187 .then(function(key) {
21188 privateKey = key.privateKey;
21189
21190 // Export the public key to DER.
21191 return crypto.subtle.exportKey("spki", key.publicKey);
21192 })
21193 .then(function(exportedPublicKey) {
21194 publicKeyDer = new Uint8Array(exportedPublicKey);
21195
21196 // Export the private key to DER.
21197 return crypto.subtle.exportKey("pkcs8", privateKey);
21198 })
21199 .then(function(pkcs8Der) {
21200 // Save the key pair
21201 return thisStorage.database.transaction
21202 ("rw", thisStorage.database.privateKey, thisStorage.database.publicKey, function () {
21203 thisStorage.database.publicKey.put
21204 ({nameHash: IndexedDbPrivateKeyStorage.transformName(keyName),
21205 encoding: publicKeyDer});
21206 thisStorage.database.privateKey.put
21207 ({nameHash: IndexedDbPrivateKeyStorage.transformName(keyName),
21208 encoding: new Uint8Array(pkcs8Der)});
21209 });
21210 });
21211 }
21212 else
21213 throw new Error("Only RSA key generation currently supported");
21214 });
21215};
21216
21217
21218/**
21219 * Delete a pair of asymmetric keys. If the key doesn't exist, do nothing.
21220 * @param {Name} keyName The name of the key pair.
21221 * @param {boolean} useSync (optional) If true then return a rejected promise
21222 * since this only supports async code.
21223 * @return {Promise} A promise that fulfills when the key pair is deleted.
21224 */
21225IndexedDbPrivateKeyStorage.prototype.deleteKeyPairPromise = function
21226 (keyName, useSync)
21227{
21228 if (useSync)
21229 return Promise.reject(new SecurityException(new Error
21230 ("IndexedDbPrivateKeyStorage.deleteKeyPairPromise is only supported for async")));
21231
21232 var thisStorage = this;
21233 // delete does nothing if the key doesn't exist.
21234 return this.database.publicKey.delete
21235 (IndexedDbPrivateKeyStorage.transformName(keyName))
21236 .then(function() {
21237 return thisStorage.database.privateKey.delete
21238 (IndexedDbPrivateKeyStorage.transformName(keyName));
21239 });
21240};
21241
21242/**
21243 * Get the public key
21244 * @param {Name} keyName The name of public key.
21245 * @param {boolean} useSync (optional) If true then return a rejected promise
21246 * since this only supports async code.
21247 * @return {Promise} A promise that returns the PublicKey.
21248 */
21249IndexedDbPrivateKeyStorage.prototype.getPublicKeyPromise = function
21250 (keyName, useSync)
21251{
21252 if (useSync)
21253 return Promise.reject(new SecurityException(new Error
21254 ("IndexedDbPrivateKeyStorage.getPublicKeyPromise is only supported for async")));
21255
21256 return this.database.publicKey.get
21257 (IndexedDbPrivateKeyStorage.transformName(keyName))
21258 .then(function(publicKeyEntry) {
21259 return Promise.resolve(new PublicKey(new Blob(publicKeyEntry.encoding)));
21260 });
21261};
21262
21263/**
21264 * Fetch the private key for keyName and sign the data to produce a signature Blob.
21265 * @param {Buffer} data Pointer to the input byte array.
21266 * @param {Name} keyName The name of the signing key.
21267 * @param {number} digestAlgorithm (optional) The digest algorithm from
21268 * DigestAlgorithm, such as DigestAlgorithm.SHA256. If omitted, use
21269 * DigestAlgorithm.SHA256.
21270 * @param {boolean} useSync (optional) If true then return a rejected promise
21271 * since this only supports async code.
21272 * @return {Promise} A promise that returns the signature Blob.
21273 */
21274IndexedDbPrivateKeyStorage.prototype.signPromise = function
21275 (data, keyName, digestAlgorithm, useSync)
21276{
21277 useSync = (typeof digestAlgorithm === "boolean") ? digestAlgorithm : useSync;
21278 digestAlgorithm = (typeof digestAlgorithm === "boolean" || !digestAlgorithm) ? DigestAlgorithm.SHA256 : digestAlgorithm;
21279
21280 if (useSync)
21281 return Promise.reject(new SecurityException(new Error
21282 ("IndexedDbPrivateKeyStorage.signPromise is only supported for async")));
21283
21284 if (digestAlgorithm != DigestAlgorithm.SHA256)
21285 return Promise.reject(new SecurityException(new Error
21286 ("IndexedDbPrivateKeyStorage.sign: Unsupported digest algorithm")));
21287
21288 // TODO: Support non-RSA keys.
21289 var algo = { name: "RSASSA-PKCS1-v1_5", hash: {name: "SHA-256" }};
21290
21291 // Find the private key.
21292 return this.database.privateKey.get
21293 (IndexedDbPrivateKeyStorage.transformName(keyName))
21294 .then(function(privateKeyEntry) {
21295 return crypto.subtle.importKey
21296 ("pkcs8", new Blob(privateKeyEntry.encoding).buf(), algo, true, ["sign"]);
21297 })
21298 .then(function(privateKey) {
21299 return crypto.subtle.sign(algo, privateKey, data);
21300 })
21301 .then(function(signature) {
21302 return Promise.resolve(new Blob(new Uint8Array(signature), true));
21303 });
21304};
21305
21306/**
21307 * Check if a particular key exists.
21308 * @param {Name} keyName The name of the key.
21309 * @param {number} keyClass The class of the key, e.g. KeyClass.PUBLIC,
21310 * KeyClass.PRIVATE, or KeyClass.SYMMETRIC.
21311 * @param {boolean} useSync (optional) If true then return a rejected promise
21312 * since this only supports async code.
21313 * @return {Promise} A promise which returns true if the key exists.
21314 */
21315IndexedDbPrivateKeyStorage.prototype.doesKeyExistPromise = function
21316 (keyName, keyClass, useSync)
21317{
21318 if (useSync)
21319 return Promise.reject(new SecurityException(new Error
21320 ("IndexedDbPrivateKeyStorage.doesKeyExistPromise is only supported for async")));
21321
21322 var table = null;
21323 if (keyClass == KeyClass.PUBLIC)
21324 table = this.database.publicKey;
21325 else if (keyClass == KeyClass.PRIVATE)
21326 table = this.database.privateKey;
21327 else
21328 // Silently say that anything else doesn't exist.
21329 return Promise.resolve(false);
21330
21331 return table.where("nameHash").equals
21332 (IndexedDbPrivateKeyStorage.transformName(keyName))
21333 .count()
21334 .then(function(count) {
21335 return Promise.resolve(count > 0);
21336 });
21337};
21338
21339/**
21340 * Transform the key name into the base64 encoding of the hash (the same as in
21341 * FilePrivateKeyStorage without the file name extension).
21342 */
21343IndexedDbPrivateKeyStorage.transformName = function(keyName)
21344{
21345 var hash = Crypto.createHash('sha256');
21346 hash.update(new Buffer(keyName.toUri()));
21347 var fileName = hash.digest('base64');
21348 return fileName.replace(/\//g, '%');
21349};
21350/**
21351 * Copyright (C) 2014-2016 Regents of the University of California.
21352 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
21353 * From ndn-cxx security by Yingdi Yu <yingdi@cs.ucla.edu>.
21354 *
21355 * This program is free software: you can redistribute it and/or modify
21356 * it under the terms of the GNU Lesser General Public License as published by
21357 * the Free Software Foundation, either version 3 of the License, or
21358 * (at your option) any later version.
21359 *
21360 * This program is distributed in the hope that it will be useful,
21361 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21362 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21363 * GNU Lesser General Public License for more details.
21364 *
21365 * You should have received a copy of the GNU Lesser General Public License
21366 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21367 * A copy of the GNU Lesser General Public License is in the file COPYING.
21368 */
21369
21370// Use capitalized Crypto to not clash with the browser's crypto.subtle.
21371/** @ignore */
21372var Crypto = require('../../crypto.js'); /** @ignore */
21373var Name = require('../../name.js').Name; /** @ignore */
21374var Data = require('../../data.js').Data; /** @ignore */
21375var Blob = require('../../util/blob.js').Blob; /** @ignore */
21376var ConfigFile = require('../../util/config-file.js').ConfigFile; /** @ignore */
21377var DigestSha256Signature = require('../../digest-sha256-signature.js').DigestSha256Signature; /** @ignore */
21378var Sha256WithRsaSignature = require('../../sha256-with-rsa-signature.js').Sha256WithRsaSignature; /** @ignore */
21379var Sha256WithEcdsaSignature = require('../../sha256-with-ecdsa-signature.js').Sha256WithEcdsaSignature; /** @ignore */
21380var KeyLocatorType = require('../../key-locator.js').KeyLocatorType; /** @ignore */
21381var WireFormat = require('../../encoding/wire-format.js').WireFormat; /** @ignore */
21382var SecurityException = require('../security-exception.js').SecurityException; /** @ignore */
21383var DigestAlgorithm = require('../security-types.js').DigestAlgorithm; /** @ignore */
21384var KeyType = require('../security-types.js').KeyType; /** @ignore */
21385var RsaKeyParams = require('../key-params.js').RsaKeyParams; /** @ignore */
21386var IdentityCertificate = require('../certificate/identity-certificate.js').IdentityCertificate; /** @ignore */
21387var PublicKey = require('../certificate/public-key.js').PublicKey; /** @ignore */
21388var CertificateSubjectDescription = require('../certificate/certificate-subject-description.js').CertificateSubjectDescription; /** @ignore */
21389var SyncPromise = require('../../util/sync-promise.js').SyncPromise; /** @ignore */
21390var BasicIdentityStorage = require('./basic-identity-storage.js').BasicIdentityStorage; /** @ignore */
21391var FilePrivateKeyStorage = require('./file-private-key-storage.js').FilePrivateKeyStorage;
21392
21393/**
21394 * An IdentityManager is the interface of operations related to identity, keys,
21395 * and certificates.
21396 *
21397 * Create a new IdentityManager to use the IdentityStorage and
21398 * PrivateKeyStorage.
21399 * @param {IdentityStorage} identityStorage An object of a subclass of
21400 * IdentityStorage. In Node.js, if this is omitted then use BasicIdentityStorage.
21401 * @param {PrivateKeyStorage} privateKeyStorage An object of a subclass of
21402 * PrivateKeyStorage. In Node.js, if this is omitted then use the default
21403 * PrivateKeyStorage for your system, which is FilePrivateKeyStorage for any
21404 * system other than OS X. (OS X key chain storage is not yet implemented, so
21405 * you must supply a different PrivateKeyStorage.)
21406 * @throws SecurityException if this is not in Node.js and identityStorage or
21407 * privateKeyStorage is omitted.
21408 * @constructor
21409 */
21410var IdentityManager = function IdentityManager
21411 (identityStorage, privateKeyStorage)
21412{
21413 if (privateKeyStorage) {
21414 // Don't call checkTpm() when using a custom PrivateKeyStorage.
21415 if (!identityStorage)
21416 // We don't expect this to happen.
21417 throw new Error
21418 ("IdentityManager: A custom privateKeyStorage is supplied with a null identityStorage")
21419
21420 this.identityStorage = identityStorage;
21421 this.privateKeyStorage = privateKeyStorage;
21422 }
21423 else {
21424 if (!ConfigFile)
21425 // Assume we are in the browser.
21426 throw new SecurityException(new Error
21427 ("IdentityManager: If not in Node.js then you must supply identityStorage and privateKeyStorage."));
21428 var config = new ConfigFile();
21429
21430 var canonicalTpmLocator = [null];
21431 var thisStorage = this;
21432 // Make the function that BasicIdentityStorage will call the first time it
21433 // is used. It has to be an async promise becuase getTpmLocatorPromise is async.
21434 function initialCheckPromise()
21435 {
21436 return thisStorage.checkTpmPromise_(canonicalTpmLocator[0]);
21437 }
21438
21439 this.identityStorage = identityStorage ? identityStorage
21440 : IdentityManager.getDefaultIdentityStorage_(config, initialCheckPromise);
21441 this.privateKeyStorage = IdentityManager.getDefaultPrivateKeyStorage_
21442 (config, canonicalTpmLocator);
21443 }
21444};
21445
21446exports.IdentityManager = IdentityManager;
21447
21448/**
21449 * Create an identity by creating a pair of Key-Signing-Key (KSK) for this
21450 * identity and a self-signed certificate of the KSK. If a key pair or
21451 * certificate for the identity already exists, use it.
21452 * @param {Name} identityName The name of the identity.
21453 * @params {KeyParams} params The key parameters if a key needs to be generated
21454 * for the identity.
21455 * @param {boolean} useSync (optional) If true then return a SyncPromise which
21456 * is already fulfilled. If omitted or false, this may return a SyncPromise or
21457 * an async Promise.
21458 * @return {Promise|SyncPromise} A promise which returns the name of the default
21459 * certificate of the identity.
21460 */
21461IdentityManager.prototype.createIdentityAndCertificatePromise = function
21462 (identityName, params, useSync)
21463{
21464 var thisManager = this;
21465 var generateKey = true;
21466 var keyName = null;
21467
21468 return this.identityStorage.addIdentityPromise(identityName, useSync)
21469 .then(function() {
21470 return thisManager.identityStorage.getDefaultKeyNameForIdentityPromise
21471 (identityName, useSync)
21472 .then(function(localKeyName) {
21473 keyName = localKeyName;
21474
21475 // Set generateKey.
21476 return thisManager.identityStorage.getKeyPromise(keyName, useSync)
21477 .then(function(publicKeyDer) {
21478 var key = new PublicKey(publicKeyDer);
21479 if (key.getKeyType() == params.getKeyType())
21480 // The key exists and has the same type, so don't need to generate one.
21481 generateKey = false;
21482 return SyncPromise.resolve();
21483 });
21484 }, function(err) {
21485 if (!(err instanceof SecurityException))
21486 throw err;
21487
21488 // The key doesn't exist, so leave generateKey true.
21489 return SyncPromise.resolve();
21490 });
21491 })
21492 .then(function() {
21493 if (generateKey)
21494 return thisManager.generateKeyPairPromise(identityName, true, params, useSync)
21495 .then(function(localKeyName) {
21496 keyName = localKeyName;
21497 return thisManager.identityStorage.setDefaultKeyNameForIdentityPromise
21498 (keyName, useSync);
21499 });
21500 else
21501 // Don't generate a key pair. Use the existing keyName.
21502 return SyncPromise.resolve();
21503 })
21504 .then(function() {
21505 return thisManager.identityStorage.getDefaultCertificateNameForKeyPromise
21506 (keyName, useSync)
21507 .then(function(certName) {
21508 // The cert exists, so don't need to make it.
21509 return SyncPromise.resolve(certName);
21510 }, function(err) {
21511 if (!(err instanceof SecurityException))
21512 throw err;
21513
21514 // The cert doesn't exist, so make one.
21515 var certName;
21516 return thisManager.selfSignPromise(keyName, useSync)
21517 .then(function(selfCert) {
21518 certName = selfCert.getName();
21519 return thisManager.addCertificateAsIdentityDefaultPromise(selfCert, useSync);
21520 })
21521 .then(function() {
21522 return SyncPromise.resolve(certName);
21523 });
21524 });
21525 });
21526};
21527
21528/**
21529 * Create an identity by creating a pair of Key-Signing-Key (KSK) for this
21530 * identity and a self-signed certificate of the KSK. If a key pair or
21531 * certificate for the identity already exists, use it.
21532 * @param {Name} identityName The name of the identity.
21533 * @params {KeyParams} params The key parameters if a key needs to be generated
21534 * for the identity.
21535 * @param {function} onComplete (optional) This calls onComplete(certificateName)
21536 * with the name of the default certificate of the identity. If omitted, the
21537 * return value is described below. (Some crypto libraries only use a callback,
21538 * so onComplete is required to use these.)
21539 * @param {function} onError (optional) If defined, then onComplete must be
21540 * defined and if there is an exception, then this calls onError(exception)
21541 * with the exception. If onComplete is defined but onError is undefined, then
21542 * this will log any thrown exception. (Some crypto libraries only use a
21543 * callback, so onError is required to be notified of an exception.)
21544 * @return {Name} If onComplete is omitted, return the name of the default
21545 * certificate of the identity. Otherwise, if onComplete is supplied then return
21546 * undefined and use onComplete as described above.
21547 */
21548IdentityManager.prototype.createIdentityAndCertificate = function
21549 (identityName, params, onComplete, onError)
21550{
21551 return SyncPromise.complete(onComplete, onError,
21552 this.createIdentityAndCertificatePromise(identityName, params, !onComplete));
21553};
21554
21555/**
21556 * Create an identity by creating a pair of Key-Signing-Key (KSK) for this
21557 * identity and a self-signed certificate of the KSK. If a key pair or
21558 * certificate for the identity already exists, use it.
21559 * @deprecated Use createIdentityAndCertificate which returns the
21560 * certificate name instead of the key name. You can use
21561 * IdentityCertificate.certificateNameToPublicKeyName to convert the
21562 * certificate name to the key name.
21563 * @param {Name} identityName The name of the identity.
21564 * @params {KeyParams} params The key parameters if a key needs to be generated
21565 * for the identity.
21566 * @return {Name} The key name of the auto-generated KSK of the identity.
21567 */
21568IdentityManager.prototype.createIdentity = function(identityName, params)
21569{
21570 return IdentityCertificate.certificateNameToPublicKeyName
21571 (this.createIdentityAndCertificate(identityName, params));
21572};
21573
21574/**
21575 * Delete the identity from the public and private key storage. If the
21576 * identity to be deleted is the current default system default, this will not
21577 * delete the identity and will return immediately.
21578 * @param {Name} identityName The name of the identity.
21579 * @param {function} onComplete (optional) This calls onComplete() when the
21580 * operation is complete. If omitted, do not use it. (Some database libraries
21581 * only use a callback, so onComplete is required to use these.)
21582 * @param {function} onError (optional) If defined, then onComplete must be
21583 * defined and if there is an exception, then this calls onError(exception)
21584 * with the exception. If onComplete is defined but onError is undefined, then
21585 * this will log any thrown exception. (Some database libraries only use a
21586 * callback, so onError is required to be notified of an exception.)
21587 */
21588IdentityManager.prototype.deleteIdentity = function
21589 (identityName, onComplete, onError)
21590{
21591 var useSync = !onComplete;
21592 var thisManager = this;
21593
21594 var doDelete = true;
21595
21596 var mainPromise = this.identityStorage.getDefaultIdentityPromise(useSync)
21597 .then(function(defaultIdentityName) {
21598 if (defaultIdentityName.equals(identityName))
21599 // Don't delete the default identity!
21600 doDelete = false;
21601
21602 return SyncPromise.resolve();
21603 }, function(err) {
21604 // There is no default identity to check.
21605 return SyncPromise.resolve();
21606 })
21607 .then(function() {
21608 if (!doDelete)
21609 return SyncPromise.resolve();
21610
21611 var keysToDelete = [];
21612 return thisManager.identityStorage.getAllKeyNamesOfIdentityPromise
21613 (identityName, keysToDelete, true)
21614 .then(function() {
21615 return thisManager.identityStorage.getAllKeyNamesOfIdentityPromise
21616 (identityName, keysToDelete, false);
21617 })
21618 .then(function() {
21619 return thisManager.identityStorage.deleteIdentityInfoPromise(identityName);
21620 })
21621 .then(function() {
21622 // Recursively loop through keysToDelete, calling deleteKeyPairPromise.
21623 function deleteKeyLoop(i) {
21624 if (i >= keysToDelete.length)
21625 return SyncPromise.resolve();
21626
21627 return thisManager.privateKeyStorage.deleteKeyPairPromise(keysToDelete[i])
21628 .then(function() {
21629 return deleteKeyLoop(i + 1);
21630 });
21631 }
21632
21633 return deleteKeyLoop(0);
21634 });
21635 });
21636
21637 return SyncPromise.complete(onComplete, onError, mainPromise);
21638};
21639
21640/**
21641 * Set the default identity. If the identityName does not exist, then clear the
21642 * default identity so that getDefaultIdentity() throws an exception.
21643 * @param {Name} identityName The default identity name.
21644 * @param {boolean} useSync (optional) If true then return a SyncPromise which
21645 * is already fulfilled. If omitted or false, this may return a SyncPromise or
21646 * an async Promise.
21647 * @return {Promise|SyncPromise} A promise which fulfills when the default
21648 * identity is set.
21649 */
21650IdentityManager.prototype.setDefaultIdentityPromise = function
21651 (identityName, useSync)
21652{
21653 return this.identityStorage.setDefaultIdentityPromise(identityName, useSync);
21654};
21655
21656/**
21657 * Set the default identity. If the identityName does not exist, then clear the
21658 * default identity so that getDefaultIdentity() throws an exception.
21659 * @param {Name} identityName The default identity name.
21660 * @param {function} onComplete (optional) This calls onComplete() when complete.
21661 * (Some database libraries only use a callback, so onComplete is required to
21662 * use these.)
21663 * @param {function} onError (optional) If defined, then onComplete must be
21664 * defined and if there is an exception, then this calls onError(exception)
21665 * with the exception. If onComplete is defined but onError is undefined, then
21666 * this will log any thrown exception. (Some database libraries only use a
21667 * callback, so onError is required to be notified of an exception.)
21668 */
21669IdentityManager.prototype.setDefaultIdentity = function
21670 (identityName, onComplete, onError)
21671{
21672 return SyncPromise.complete(onComplete, onError,
21673 this.identityStorage.setDefaultIdentityPromise(identityName, !onComplete));
21674};
21675
21676/**
21677 * Get the default identity.
21678 * @param {boolean} useSync (optional) If true then return a SyncPromise which
21679 * is already fulfilled. If omitted or false, this may return a SyncPromise or
21680 * an async Promise.
21681 * @return {Promise|SyncPromise} A promise which returns the Name of default
21682 * identity, or a promise rejected with SecurityException if the default
21683 * identity is not set.
21684 */
21685IdentityManager.prototype.getDefaultIdentityPromise = function(useSync)
21686{
21687 return this.identityStorage.getDefaultIdentityPromise(useSync);
21688};
21689
21690/**
21691 * Get the default identity.
21692 * @param {function} onComplete (optional) This calls onComplete(identityName)
21693 * with name of the default identity. If omitted, the return value is described
21694 * below. (Some database libraries only use a callback, so onComplete is required
21695 * to use these.)
21696 * @param {function} onError (optional) If defined, then onComplete must be
21697 * defined and if there is an exception, then this calls onError(exception)
21698 * with the exception. If onComplete is defined but onError is undefined, then
21699 * this will log any thrown exception. (Some database libraries only use a
21700 * callback, so onError is required to be notified of an exception.)
21701 * @return {Name} If onComplete is omitted, return the name of the default
21702 * identity. Otherwise, if onComplete is supplied then return undefined and use
21703 * onComplete as described above.
21704 * @throws SecurityException if the default identity is not set. However, if
21705 * onComplete and onError are defined, then if there is an exception return
21706 * undefined and call onError(exception).
21707 */
21708IdentityManager.prototype.getDefaultIdentity = function(onComplete, onError)
21709{
21710 return SyncPromise.complete(onComplete, onError,
21711 this.identityStorage.getDefaultIdentityPromise(!onComplete));
21712};
21713
21714/**
21715 * Get the certificate of the default identity.
21716 * @param {boolean} useSync (optional) If true then return a SyncPromise which
21717 * is already fulfilled. If omitted or false, this may return a SyncPromise or
21718 * an async Promise.
21719 * @return {Promise|SyncPromise} A promise which returns the requested
21720 * IdentityCertificate or null if not found.
21721 */
21722IdentityManager.prototype.getDefaultCertificatePromise = function(useSync)
21723{
21724 return this.identityStorage.getDefaultCertificatePromise(useSync);
21725};
21726
21727/**
21728 * Generate a pair of RSA keys for the specified identity.
21729 * @param {Name} identityName The name of the identity.
21730 * @param {boolean} isKsk True for generating a Key-Signing-Key (KSK), false for
21731 * a Data-Signing-Key (DSK).
21732 * @param {number} keySize The size of the key.
21733 * @return {Name} The generated key name.
21734 */
21735IdentityManager.prototype.generateRSAKeyPair = function
21736 (identityName, isKsk, keySize)
21737{
21738 // For now, require sync. This method may be removed from the API.
21739 return SyncPromise.getValue
21740 (this.generateKeyPairPromise
21741 (identityName, isKsk, new RsaKeyParams(keySize), true));
21742};
21743
21744/**
21745 * Set a key as the default key of an identity. The identity name is inferred
21746 * from keyName.
21747 * @param {Name} keyName The name of the key.
21748 * @param {Name} identityNameCheck (optional) The identity name to check that the
21749 * keyName contains the same identity name. If an empty name, it is ignored.
21750 * @param {function} onComplete (optional) This calls onComplete() when complete.
21751 * (Some database libraries only use a callback, so onComplete is required to
21752 * use these.)
21753 * @param {function} onError (optional) If defined, then onComplete must be
21754 * defined and if there is an exception, then this calls onError(exception)
21755 * with the exception. If onComplete is defined but onError is undefined, then
21756 * this will log any thrown exception. (Some database libraries only use a
21757 * callback, so onError is required to be notified of an exception.)
21758 */
21759IdentityManager.prototype.setDefaultKeyForIdentity = function
21760 (keyName, identityNameCheck, onComplete, onError)
21761{
21762 onError = (typeof identityNameCheck === "function") ? onComplete : onError;
21763 onComplete = (typeof identityNameCheck === "function") ?
21764 identityNameCheck : onComplete;
21765 identityNameCheck = (typeof identityNameCheck === "function" || !identityNameCheck) ?
21766 new Name() : identityNameCheck;
21767
21768 return SyncPromise.complete(onComplete, onError,
21769 this.identityStorage.setDefaultKeyNameForIdentityPromise
21770 (keyName, identityNameCheck, !onComplete));
21771};
21772
21773/**
21774 * Get the default key for an identity.
21775 * @param {Name} identityName The name of the identity.
21776 * @param {function} onComplete (optional) This calls onComplete(keyName)
21777 * with name of the default key. If omitted, the return value is described
21778 * below. (Some database libraries only use a callback, so onComplete is required
21779 * to use these.)
21780 * @param {function} onError (optional) If defined, then onComplete must be
21781 * defined and if there is an exception, then this calls onError(exception)
21782 * with the exception. If onComplete is defined but onError is undefined, then
21783 * this will log any thrown exception. (Some database libraries only use a
21784 * callback, so onError is required to be notified of an exception.)
21785 * @return {Name} If onComplete is omitted, return the default key name.
21786 * Otherwise, if onComplete is supplied then return undefined and use onComplete
21787 * as described above.
21788 * @throws SecurityException if the default key name for the identity is not set.
21789 * However, if onComplete and onError are defined, then if there is an exception
21790 * return undefined and call onError(exception).
21791 */
21792IdentityManager.prototype.getDefaultKeyNameForIdentity = function
21793 (identityName, onComplete, onError)
21794{
21795 return SyncPromise.complete(onComplete, onError,
21796 this.identityStorage.getDefaultKeyNameForIdentityPromise
21797 (identityName, !onComplete));
21798};
21799
21800/**
21801 * Generate a pair of RSA keys for the specified identity and set it as default
21802 * key for the identity.
21803 * @param {Name} identityName The name of the identity.
21804 * @param {boolean} isKsk True for generating a Key-Signing-Key (KSK), false for
21805 * a Data-Signing-Key (DSK).
21806 * @param {number} keySize The size of the key.
21807 * @param {boolean} useSync (optional) If true then return a SyncPromise which
21808 * is already fulfilled. If false, this may return a SyncPromise or an async
21809 * Promise.
21810 * @return {Promise|SyncPromise} A promise which returns the generated key name.
21811 */
21812IdentityManager.prototype.generateRSAKeyPairAsDefaultPromise = function
21813 (identityName, isKsk, keySize, useSync)
21814{
21815 var newKeyName;
21816 var thisManager = this;
21817 return this.generateKeyPairPromise(identityName, isKsk, new RsaKeyParams(keySize))
21818 .then(function(localKeyName) {
21819 newKeyName = localKeyName;
21820
21821 return thisManager.identityStorage.setDefaultKeyNameForIdentityPromise
21822 (newKeyName);
21823 })
21824 .then(function() {
21825 return SyncPromise.resolve(newKeyName);
21826 });
21827};
21828
21829/**
21830 * Generate a pair of RSA keys for the specified identity and set it as default
21831 * key for the identity.
21832 * @param {Name} identityName The name of the identity.
21833 * @param {boolean} isKsk True for generating a Key-Signing-Key (KSK), false for
21834 * a Data-Signing-Key (DSK).
21835 * @param {number} keySize The size of the key.
21836 * @return {Name} The generated key name.
21837 */
21838IdentityManager.prototype.generateRSAKeyPairAsDefault = function
21839 (identityName, isKsk, keySize)
21840{
21841 return SyncPromise.getValue
21842 (this.generateRSAKeyPairAsDefaultPromise(identityName, isKsk, keySize, true));
21843};
21844
21845/**
21846 * Get the public key with the specified name.
21847 * @param {Name} keyName The name of the key.
21848 * @param {function} onComplete (optional) This calls onComplete(publicKey)
21849 * with PublicKey. If omitted, the return value is described below. (Some database
21850 * libraries only use a callback, so onComplete is required to use these.)
21851 * @param {function} onError (optional) If defined, then onComplete must be
21852 * defined and if there is an exception, then this calls onError(exception)
21853 * with the exception. If onComplete is defined but onError is undefined, then
21854 * this will log any thrown exception. (Some database libraries only use a
21855 * callback, so onError is required to be notified of an exception.)
21856 * @return {PublicKey} If onComplete is omitted, return the public key.
21857 * Otherwise, if onComplete is supplied then return undefined and use onComplete
21858 * as described above.
21859 */
21860IdentityManager.prototype.getPublicKey = function(keyName, onComplete, onError)
21861{
21862 return SyncPromise.complete(onComplete, onError,
21863 this.identityStorage.getKeyPromise(keyName, !onComplete)
21864 .then(function(keyDer) {
21865 return SyncPromise.resolve(new PublicKey(keyDer));
21866 }));
21867};
21868
21869// TODO: Add two versions of createIdentityCertificate.
21870
21871/**
21872 * Prepare an unsigned identity certificate.
21873 * @param {Name} keyName The key name, e.g., `/{identity_name}/ksk-123456`.
21874 * @param {PublicKey} publicKey (optional) The public key to sign. If ommited,
21875 * use the keyName to get the public key from the identity storage.
21876 * @param {Name} signingIdentity The signing identity.
21877 * @param {number} notBefore See IdentityCertificate.
21878 * @param {number} notAfter See IdentityCertificate.
21879 * @param {Array<CertificateSubjectDescription>} subjectDescription A list of
21880 * CertificateSubjectDescription. See IdentityCertificate. If null or empty,
21881 * this adds a an ATTRIBUTE_NAME based on the keyName.
21882 * @param {Name} certPrefix (optional) The prefix before the `KEY` component. If
21883 * null or omitted, this infers the certificate name according to the relation
21884 * between the signingIdentity and the subject identity. If the signingIdentity
21885 * is a prefix of the subject identity, `KEY` will be inserted after the
21886 * signingIdentity, otherwise `KEY` is inserted after subject identity (i.e.,
21887 * before `ksk-...`).
21888 * @param {function} onComplete (optional) This calls onComplete(certificate)
21889 * with the unsigned IdentityCertificate, or null if the inputs are invalid. If
21890 * omitted, the return value is described below. (Some database libraries only
21891 * use a callback, so onComplete is required to use these.)
21892 * @param {function} onError (optional) If defined, then onComplete must be
21893 * defined and if there is an exception, then this calls onError(exception)
21894 * with the exception. If onComplete is defined but onError is undefined, then
21895 * this will log any thrown exception. (Some database libraries only use a
21896 * callback, so onError is required to be notified of an exception.)
21897 * @return {IdentityCertificate} If onComplete is omitted, return the the
21898 * unsigned IdentityCertificate, or null if the inputs are invalid. Otherwise,
21899 * if onComplete is supplied then return undefined and use onComplete as
21900 * described above.
21901 */
21902IdentityManager.prototype.prepareUnsignedIdentityCertificate = function
21903 (keyName, publicKey, signingIdentity, notBefore, notAfter, subjectDescription,
21904 certPrefix, onComplete, onError)
21905{
21906 if (!(publicKey instanceof PublicKey)) {
21907 // The publicKey was omitted. Shift arguments.
21908 onError = onComplete;
21909 onComplete = certPrefix;
21910 certPrefix = subjectDescription;
21911 subjectDescription = notAfter;
21912 notAfter = notBefore;
21913 notBefore = signingIdentity;
21914 signingIdentity = publicKey;
21915 publicKey = null;
21916 }
21917
21918 // certPrefix may be omitted or null, so check for it and the following args.
21919 var arg7 = certPrefix;
21920 var arg8 = onComplete;
21921 var arg9 = onError;
21922 if (arg7 instanceof Name)
21923 certPrefix = arg7;
21924 else
21925 certPrefix = null;
21926
21927 if (typeof arg7 === 'function') {
21928 onComplete = arg7;
21929 onError = arg8;
21930 }
21931 else if (typeof arg8 === 'function') {
21932 onComplete = arg8;
21933 onError = arg9;
21934 }
21935 else {
21936 onComplete = null;
21937 onError = null;
21938 }
21939
21940 var promise;
21941 if (publicKey == null)
21942 promise = this.prepareUnsignedIdentityCertificatePromise
21943 (keyName, signingIdentity, notBefore, notAfter, subjectDescription,
21944 certPrefix, !onComplete);
21945 else
21946 promise = this.prepareUnsignedIdentityCertificatePromise
21947 (keyName, publicKey, signingIdentity, notBefore, notAfter,
21948 subjectDescription, certPrefix, !onComplete);
21949 return SyncPromise.complete(onComplete, onError, promise);
21950};
21951
21952/**
21953 * Prepare an unsigned identity certificate.
21954 * @param {Name} keyName The key name, e.g., `/{identity_name}/ksk-123456`.
21955 * @param {PublicKey} publicKey (optional) The public key to sign. If ommited,
21956 * use the keyName to get the public key from the identity storage.
21957 * @param {Name} signingIdentity The signing identity.
21958 * @param {number} notBefore See IdentityCertificate.
21959 * @param {number} notAfter See IdentityCertificate.
21960 * @param {Array<CertificateSubjectDescription>} subjectDescription A list of
21961 * CertificateSubjectDescription. See IdentityCertificate. If null or empty,
21962 * this adds a an ATTRIBUTE_NAME based on the keyName.
21963 * @param {Name} certPrefix (optional) The prefix before the `KEY` component. If
21964 * null or omitted, this infers the certificate name according to the relation
21965 * between the signingIdentity and the subject identity. If the signingIdentity
21966 * is a prefix of the subject identity, `KEY` will be inserted after the
21967 * signingIdentity, otherwise `KEY` is inserted after subject identity (i.e.,
21968 * before `ksk-...`).
21969 * @param {boolean} useSync (optional) If true then return a SyncPromise which
21970 * is already fulfilled. If omitted or false, this may return a SyncPromise or
21971 * an async Promise.
21972 * @return {Promise|SyncPromise} A promise that returns the unsigned
21973 * IdentityCertificate, or that returns null if the inputs are invalid.
21974 */
21975IdentityManager.prototype.prepareUnsignedIdentityCertificatePromise = function
21976 (keyName, publicKey, signingIdentity, notBefore, notAfter, subjectDescription,
21977 certPrefix, useSync)
21978{
21979 if (!(publicKey instanceof PublicKey)) {
21980 // The publicKey was omitted. Shift arguments.
21981 useSync = certPrefix;
21982 certPrefix = subjectDescription;
21983 subjectDescription = notAfter;
21984 notAfter = notBefore;
21985 notBefore = signingIdentity;
21986 signingIdentity = publicKey;
21987 publicKey = null;
21988 }
21989
21990 // certPrefix may be omitted or null, so check for it and the following arg.
21991 var arg7 = certPrefix;
21992 var arg8 = useSync;
21993 if (arg7 instanceof Name)
21994 certPrefix = arg7;
21995 else
21996 certPrefix = null;
21997
21998 if (typeof arg7 === 'boolean')
21999 useSync = arg7;
22000 else if (typeof arg8 === 'boolean')
22001 useSync = arg8;
22002 else
22003 useSync = false;
22004
22005 var promise;
22006 if (publicKey == null) {
22007 promise = this.identityStorage.getKeyPromise(keyName, useSync)
22008 .then(function(keyDer) {
22009 publicKey = new PublicKey(keyDer);
22010 return SyncPromise.resolve();
22011 });
22012 }
22013 else
22014 promise = SyncPromise.resolve();
22015
22016 return promise
22017 .then(function() {
22018 return SyncPromise.resolve
22019 (IdentityManager.prepareUnsignedIdentityCertificateHelper_
22020 (keyName, publicKey, signingIdentity, notBefore, notAfter,
22021 subjectDescription, certPrefix));
22022 });
22023};
22024
22025/**
22026 * A helper for prepareUnsignedIdentityCertificatePromise where the publicKey
22027 * is known.
22028 */
22029IdentityManager.prepareUnsignedIdentityCertificateHelper_ = function
22030 (keyName, publicKey, signingIdentity, notBefore, notAfter, subjectDescription,
22031 certPrefix)
22032{
22033 if (keyName.size() < 1)
22034 return null;
22035
22036 var tempKeyIdPrefix = keyName.get(-1).toEscapedString();
22037 if (tempKeyIdPrefix.length < 4)
22038 return null;
22039 keyIdPrefix = tempKeyIdPrefix.substr(0, 4);
22040 if (keyIdPrefix != "ksk-" && keyIdPrefix != "dsk-")
22041 return null;
22042
22043 var certificate = new IdentityCertificate();
22044 var certName = new Name();
22045
22046 if (certPrefix == null) {
22047 // No certificate prefix hint, so infer the prefix.
22048 if (signingIdentity.match(keyName))
22049 certName.append(signingIdentity)
22050 .append("KEY")
22051 .append(keyName.getSubName(signingIdentity.size()))
22052 .append("ID-CERT")
22053 .appendVersion(new Date().getTime());
22054 else
22055 certName.append(keyName.getPrefix(-1))
22056 .append("KEY")
22057 .append(keyName.get(-1))
22058 .append("ID-CERT")
22059 .appendVersion(new Date().getTime());
22060 }
22061 else {
22062 // A cert prefix hint is supplied, so determine the cert name.
22063 if (certPrefix.match(keyName) && !certPrefix.equals(keyName))
22064 certName.append(certPrefix)
22065 .append("KEY")
22066 .append(keyName.getSubName(certPrefix.size()))
22067 .append("ID-CERT")
22068 .appendVersion(new Date().getTime());
22069 else
22070 return null;
22071 }
22072
22073 certificate.setName(certName);
22074 certificate.setNotBefore(notBefore);
22075 certificate.setNotAfter(notAfter);
22076 certificate.setPublicKeyInfo(publicKey);
22077
22078 if (subjectDescription == null || subjectDescription.length === 0)
22079 certificate.addSubjectDescription(new CertificateSubjectDescription
22080 ("2.5.4.41", keyName.getPrefix(-1).toUri()));
22081 else {
22082 for (var i = 0; i < subjectDescription.length; ++i)
22083 certificate.addSubjectDescription(subjectDescription[i]);
22084 }
22085
22086 try {
22087 certificate.encode();
22088 } catch (ex) {
22089 throw SecurityException(new Error("DerEncodingException: " + ex));
22090 }
22091
22092 return certificate;
22093};
22094
22095/**
22096 * Add a certificate into the public key identity storage.
22097 * @param {IdentityCertificate} certificate The certificate to to added. This
22098 * makes a copy of the certificate.
22099 * @param {function} onComplete (optional) This calls onComplete() when complete.
22100 * (Some database libraries only use a callback, so onComplete is required to
22101 * use these.)
22102 * @param {function} onError (optional) If defined, then onComplete must be
22103 * defined and if there is an exception, then this calls onError(exception)
22104 * with the exception. If onComplete is defined but onError is undefined, then
22105 * this will log any thrown exception. (Some database libraries only use a
22106 * callback, so onError is required to be notified of an exception.)
22107 */
22108IdentityManager.prototype.addCertificate = function
22109 (certificate, onComplete, onError)
22110{
22111 return SyncPromise.complete(onComplete, onError,
22112 this.identityStorage.addCertificatePromise(certificate, !onComplete));
22113};
22114
22115/**
22116 * Set the certificate as the default for its corresponding key.
22117 * @param {IdentityCertificate} certificate The certificate.
22118 * @param {boolean} useSync (optional) If true then return a SyncPromise which
22119 * is already fulfilled. If false, this may return a SyncPromise or an async
22120 * Promise.
22121 * @return {Promise|SyncPromise} A promise which fulfills when the default
22122 * certificate is set.
22123 */
22124IdentityManager.prototype.setDefaultCertificateForKeyPromise = function
22125 (certificate, useSync)
22126{
22127 var thisManager = this;
22128
22129 var keyName = certificate.getPublicKeyName();
22130 return this.identityStorage.doesKeyExistPromise(keyName, useSync)
22131 .then(function(exists) {
22132 if (!exists)
22133 throw new SecurityException(new Error
22134 ("No corresponding Key record for certificate!"));
22135
22136 return thisManager.identityStorage.setDefaultCertificateNameForKeyPromise
22137 (keyName, certificate.getName(), useSync);
22138 });
22139};
22140
22141/**
22142 * Set the certificate as the default for its corresponding key.
22143 * @param {IdentityCertificate} certificate The certificate.
22144 * @param {function} onComplete (optional) This calls onComplete() when complete.
22145 * (Some database libraries only use a callback, so onComplete is required to
22146 * use these.)
22147 * @param {function} onError (optional) If defined, then onComplete must be
22148 * defined and if there is an exception, then this calls onError(exception)
22149 * with the exception. If onComplete is defined but onError is undefined, then
22150 * this will log any thrown exception. (Some database libraries only use a
22151 * callback, so onError is required to be notified of an exception.)
22152 */
22153IdentityManager.prototype.setDefaultCertificateForKey = function
22154 (certificate, onComplete, onError)
22155{
22156 return SyncPromise.complete(onComplete, onError,
22157 this.setDefaultCertificateForKeyPromise(certificate, !onComplete));
22158};
22159
22160/**
22161 * Add a certificate into the public key identity storage and set the
22162 * certificate as the default for its corresponding identity.
22163 * @param {IdentityCertificate} certificate The certificate to be added. This
22164 * makes a copy of the certificate.
22165 * @param {boolean} useSync (optional) If true then return a SyncPromise which
22166 * is already fulfilled. If false, this may return a SyncPromise or an async
22167 * Promise.
22168 * @return {Promise|SyncPromise} A promise which fulfills when the certificate
22169 * is added.
22170 */
22171IdentityManager.prototype.addCertificateAsIdentityDefaultPromise = function
22172 (certificate, useSync)
22173{
22174 var thisManager = this;
22175 return this.identityStorage.addCertificatePromise(certificate, useSync)
22176 .then(function() {
22177 var keyName = certificate.getPublicKeyName();
22178 return thisManager.identityStorage.setDefaultKeyNameForIdentityPromise
22179 (keyName, useSync);
22180 })
22181 .then(function() {
22182 return thisManager.setDefaultCertificateForKeyPromise(certificate, useSync);
22183 });
22184};
22185
22186/**
22187 * Add a certificate into the public key identity storage and set the
22188 * certificate as the default of its corresponding key.
22189 * @param {IdentityCertificate} certificate The certificate to be added. This
22190 * makes a copy of the certificate.
22191 * @param {function} onComplete (optional) This calls onComplete() when complete.
22192 * (Some database libraries only use a callback, so onComplete is required to use
22193 * these.)
22194 * @param {function} onError (optional) If defined, then onComplete must be
22195 * defined and if there is an exception, then this calls onError(exception)
22196 * with the exception. If onComplete is defined but onError is undefined, then
22197 * this will log any thrown exception. (Some database libraries only use a
22198 * callback, so onError is required to be notified of an exception.)
22199 */
22200IdentityManager.prototype.addCertificateAsDefault = function
22201 (certificate, onComplete, onError)
22202{
22203 var useSync = !onComplete;
22204 var thisManager = this;
22205
22206 return SyncPromise.complete(onComplete, onError,
22207 this.identityStorage.addCertificatePromise(certificate, useSync)
22208 .then(function() {
22209 return thisManager.setDefaultCertificateForKeyPromise(certificate, useSync);
22210 }));
22211};
22212
22213/**
22214 * Get a certificate which is still valid with the specified name.
22215 * @param {Name} certificateName The name of the requested certificate.
22216 * @param {function} onComplete (optional) This calls onComplete(certificate)
22217 * with the requested IdentityCertificate. If omitted, the return value is
22218 * described below. (Some database libraries only use a callback, so onComplete
22219 * is required to use these.)
22220 * @param {function} onError (optional) If defined, then onComplete must be
22221 * defined and if there is an exception, then this calls onError(exception)
22222 * with the exception. If onComplete is defined but onError is undefined, then
22223 * this will log any thrown exception. (Some database libraries only use a
22224 * callback, so onError is required to be notified of an exception.)
22225 * @return {IdentityCertificate} If onComplete is omitted, return the requested
22226 * certificate. Otherwise, if onComplete is supplied then return undefined and
22227 * use onComplete as described above.
22228 */
22229IdentityManager.prototype.getCertificate = function
22230 (certificateName, onComplete, onError)
22231{
22232 return SyncPromise.complete(onComplete, onError,
22233 this.identityStorage.getCertificatePromise
22234 (certificateName, false, !onComplete));
22235};
22236
22237/**
22238 * Get the default certificate name for the specified identity.
22239 * @param {Name} identityName The identity name.
22240 * @param {boolean} useSync (optional) If true then return a SyncPromise which
22241 * is already fulfilled. If omitted or false, this may return a SyncPromise or
22242 * an async Promise.
22243 * @return {Promise|SyncPromise} A promise which returns the default certificate
22244 * Name, or a promise rejected with SecurityException if the default key name
22245 * for the identity is not set or the default certificate name for the key name
22246 * is not set.
22247 */
22248IdentityManager.prototype.getDefaultCertificateNameForIdentityPromise = function
22249 (identityName, useSync)
22250{
22251 return this.identityStorage.getDefaultCertificateNameForIdentityPromise
22252 (identityName, useSync);
22253}
22254
22255/**
22256 * Get the default certificate name for the specified identity, which will be
22257 * used when signing is performed based on identity.
22258 * @param {Name} identityName The name of the specified identity.
22259 * @param {function} onComplete (optional) This calls onComplete(certificateName)
22260 * with name of the default certificate. If omitted, the return value is described
22261 * below. (Some database libraries only use a callback, so onComplete is required
22262 * to use these.)
22263 * @param {function} onError (optional) If defined, then onComplete must be
22264 * defined and if there is an exception, then this calls onError(exception)
22265 * with the exception. If onComplete is defined but onError is undefined, then
22266 * this will log any thrown exception. (Some database libraries only use a
22267 * callback, so onError is required to be notified of an exception.)
22268 * @return {Name} If onComplete is omitted, return the default certificate name.
22269 * Otherwise, if onComplete is supplied then return undefined and use
22270 * onComplete as described above.
22271 * @throws SecurityException if the default key name for the identity is not
22272 * set or the default certificate name for the key name is not set. However, if
22273 * onComplete and onError are defined, then if there is an exception return
22274 * undefined and call onError(exception).
22275 */
22276IdentityManager.prototype.getDefaultCertificateNameForIdentity = function
22277 (identityName, onComplete, onError)
22278{
22279 return SyncPromise.complete(onComplete, onError,
22280 this.identityStorage.getDefaultCertificateNameForIdentityPromise
22281 (identityName, !onComplete));
22282};
22283
22284/**
22285 * Get the default certificate name of the default identity, which will be used
22286 * when signing is based on identity and the identity is not specified.
22287 * @param {function} onComplete (optional) This calls onComplete(certificateName)
22288 * with name of the default certificate. If omitted, the return value is described
22289 * below. (Some database libraries only use a callback, so onComplete is required
22290 * to use these.)
22291 * @param {function} onError (optional) If defined, then onComplete must be
22292 * defined and if there is an exception, then this calls onError(exception)
22293 * with the exception. If onComplete is defined but onError is undefined, then
22294 * this will log any thrown exception. (Some database libraries only use a
22295 * callback, so onError is required to be notified of an exception.)
22296 * @return {Name} If onComplete is omitted, return the default certificate name.
22297 * Otherwise, if onComplete is supplied then return undefined and use
22298 * onComplete as described above.
22299 * @throws SecurityException if the default identity is not set or the default
22300 * key name for the identity is not set or the default certificate name for
22301 * the key name is not set. However, if onComplete and onError are defined, then
22302 * if there is an exception return undefined and call onError(exception).
22303 */
22304IdentityManager.prototype.getDefaultCertificateName = function
22305 (onComplete, onError)
22306{
22307 var useSync = !onComplete;
22308 var thisManager = this;
22309
22310 return SyncPromise.complete(onComplete, onError,
22311 this.identityStorage.getDefaultIdentityPromise(useSync)
22312 .then(function(identityName) {
22313 return thisManager.identityStorage.getDefaultCertificateNameForIdentityPromise
22314 (identityName, useSync);
22315 }));
22316};
22317
22318/**
22319 * Append all the identity names to the nameList.
22320 * @param {Array<Name>} nameList Append result names to nameList.
22321 * @param {boolean} isDefault If true, add only the default identity name. If
22322 * false, add only the non-default identity names.
22323 * @param {function} onComplete (optional) This calls onComplete() when finished
22324 * adding to nameList. If omitted, this returns when complete. (Some database
22325 * libraries only use a callback, so onComplete is required to use these.)
22326 * @param {function} onError (optional) If defined, then onComplete must be
22327 * defined and if there is an exception, then this calls onError(exception)
22328 * with the exception. If onComplete is defined but onError is undefined, then
22329 * this will log any thrown exception. (Some database libraries only use a
22330 * callback, so onError is required to be notified of an exception.)
22331 * @return {void} If onComplete is omitted, return when complete. Otherwise, if
22332 * onComplete is supplied then return undefined and use onComplete as described
22333 * above.
22334 */
22335IdentityManager.prototype.getAllIdentities = function
22336 (nameList, isDefault, onComplete, onError)
22337{
22338 return SyncPromise.complete(onComplete, onError,
22339 this.identityStorage.getAllIdentitiesPromise
22340 (nameList, isDefault, !onComplete));
22341};
22342
22343/**
22344 * Append all the key names of a particular identity to the nameList.
22345 * @param {Name} identityName The identity name to search for.
22346 * @param {Array<Name>} nameList Append result names to nameList.
22347 * @param {boolean} isDefault If true, add only the default key name. If false,
22348 * add only the non-default key names.
22349 * @param {function} onComplete (optional) This calls onComplete() when finished
22350 * adding to nameList. If omitted, this returns when complete. (Some database
22351 * libraries only use a callback, so onComplete is required to use these.)
22352 * @param {function} onError (optional) If defined, then onComplete must be
22353 * defined and if there is an exception, then this calls onError(exception)
22354 * with the exception. If onComplete is defined but onError is undefined, then
22355 * this will log any thrown exception. (Some database libraries only use a
22356 * callback, so onError is required to be notified of an exception.)
22357 * @return {void} If onComplete is omitted, return when complete. Otherwise, if
22358 * onComplete is supplied then return undefined and use onComplete as described
22359 * above.
22360 */
22361IdentityManager.prototype.getAllKeyNamesOfIdentity = function
22362 (identityName, nameList, isDefault, onComplete, onError)
22363{
22364 return SyncPromise.complete(onComplete, onError,
22365 this.identityStorage.getAllKeyNamesOfIdentityPromise
22366 (identityName, nameList, isDefault, !onComplete));
22367};
22368
22369/**
22370 * Append all the certificate names of a particular key name to the nameList.
22371 * @param {Name} keyName The key name to search for.
22372 * @param {Array<Name>} nameList Append result names to nameList.
22373 * @param {boolean} isDefault If true, add only the default certificate name. If
22374 * false, add only the non-default certificate names.
22375 * @param {function} onComplete (optional) This calls onComplete() when finished
22376 * adding to nameList. If omitted, this returns when complete. (Some database
22377 * libraries only use a callback, so onComplete is required to use these.)
22378 * @param {function} onError (optional) If defined, then onComplete must be
22379 * defined and if there is an exception, then this calls onError(exception)
22380 * with the exception. If onComplete is defined but onError is undefined, then
22381 * this will log any thrown exception. (Some database libraries only use a
22382 * callback, so onError is required to be notified of an exception.)
22383 * @return {void} If onComplete is omitted, return when complete. Otherwise, if
22384 * onComplete is supplied then return undefined and use onComplete as described
22385 * above.
22386 */
22387IdentityManager.prototype.getAllCertificateNamesOfKey = function
22388 (keyName, nameList, isDefault, onComplete, onError)
22389{
22390 return SyncPromise.complete(onComplete, onError,
22391 this.identityStorage.getAllCertificateNamesOfKeyPromise
22392 (keyName, nameList, isDefault, !onComplete));
22393};
22394
22395/**
22396 * Sign the Data packet or byte array data based on the certificate name.
22397 * @param {Data|Buffer} target If this is a Data object, wire encode for signing,
22398 * update its signature and key locator field and wireEncoding. If it is a
22399 * Buffer, sign it to produce a Signature object.
22400 * @param {Name} certificateName The Name identifying the certificate which
22401 * identifies the signing key.
22402 * @param {WireFormat} (optional) The WireFormat for calling encodeData, or
22403 * WireFormat.getDefaultWireFormat() if omitted.
22404 * @param {boolean} useSync (optional) If true then return a SyncPromise which
22405 * is already fulfilled. If omitted or false, this may return a SyncPromise or
22406 * an async Promise.
22407 * @return {Promise|SyncPromise} A promise that returns the generated Signature
22408 * object (if target is a Buffer) or the target (if target is Data).
22409 */
22410IdentityManager.prototype.signByCertificatePromise = function
22411 (target, certificateName, wireFormat, useSync)
22412{
22413 useSync = (typeof wireFormat === "boolean") ? wireFormat : useSync;
22414 wireFormat = (typeof wireFormat === "boolean" || !wireFormat) ? WireFormat.getDefaultWireFormat() : wireFormat;
22415
22416 var keyName = IdentityManager.certificateNameToPublicKeyName(certificateName);
22417
22418 var thisManager = this;
22419 if (target instanceof Data) {
22420 var data = target;
22421 var digestAlgorithm = [0];
22422
22423 return this.makeSignatureByCertificatePromise
22424 (certificateName, digestAlgorithm, useSync)
22425 .then(function(signature) {
22426 data.setSignature(signature);
22427 // Encode once to get the signed portion.
22428 var encoding = data.wireEncode(wireFormat);
22429
22430 return thisManager.privateKeyStorage.signPromise
22431 (encoding.signedBuf(), keyName, digestAlgorithm[0], useSync);
22432 })
22433 .then(function(signatureValue) {
22434 data.getSignature().setSignature(signatureValue);
22435 // Encode again to include the signature.
22436 data.wireEncode(wireFormat);
22437
22438 return SyncPromise.resolve(data);
22439 });
22440 }
22441 else {
22442 var digestAlgorithm = [0];
22443 return this.makeSignatureByCertificatePromise
22444 (certificateName, digestAlgorithm, useSync)
22445 .then(function(signature) {
22446 return thisManager.privateKeyStorage.signPromise
22447 (target, keyName, digestAlgorithm[0], useSync);
22448 })
22449 .then(function (signatureValue) {
22450 signature.setSignature(signatureValue);
22451 return SyncPromise.resolve(signature);
22452 });
22453 }
22454};
22455
22456/**
22457 * Sign the Data packet or byte array data based on the certificate name.
22458 * @param {Data|Buffer} target If this is a Data object, wire encode for signing,
22459 * update its signature and key locator field and wireEncoding. If it is a
22460 * Buffer, sign it to produce a Signature object.
22461 * @param {Name} certificateName The Name identifying the certificate which
22462 * identifies the signing key.
22463 * @param {WireFormat} (optional) The WireFormat for calling encodeData, or
22464 * WireFormat.getDefaultWireFormat() if omitted.
22465 * @param {function} onComplete (optional) If target is a Data object, this calls
22466 * onComplete(data) with the supplied Data object which has been modified to set
22467 * its signature. If target is a Buffer, this calls onComplete(signature) where
22468 * signature is the produced Signature object. If omitted, the return value is
22469 * described below. (Some crypto libraries only use a callback, so onComplete is
22470 * required to use these.)
22471 * @param {function} onError (optional) If defined, then onComplete must be
22472 * defined and if there is an exception, then this calls onError(exception)
22473 * with the exception. If onComplete is defined but onError is undefined, then
22474 * this will log any thrown exception. (Some crypto libraries only use a
22475 * callback, so onError is required to be notified of an exception.)
22476 * @return {Signature} If onComplete is omitted, return the generated Signature
22477 * object (if target is a Buffer) or the target (if target is Data). Otherwise,
22478 * if onComplete is supplied then return undefined and use onComplete as described
22479 * above.
22480 */
22481IdentityManager.prototype.signByCertificate = function
22482 (target, certificateName, wireFormat, onComplete, onError)
22483{
22484 onError = (typeof wireFormat === "function") ? onComplete : onError;
22485 onComplete = (typeof wireFormat === "function") ? wireFormat : onComplete;
22486 wireFormat = (typeof wireFormat === "function" || !wireFormat) ? WireFormat.getDefaultWireFormat() : wireFormat;
22487
22488 return SyncPromise.complete(onComplete, onError,
22489 this.signByCertificatePromise
22490 (target, certificateName, wireFormat, !onComplete));
22491};
22492
22493/**
22494 * Append a SignatureInfo to the Interest name, sign the name components and
22495 * append a final name component with the signature bits.
22496 * @param {Interest} interest The Interest object to be signed. This appends
22497 * name components of SignatureInfo and the signature bits.
22498 * @param {Name} certificateName The certificate name of the key to use for
22499 * signing.
22500 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
22501 * the input. If omitted, use WireFormat getDefaultWireFormat().
22502 * @param {boolean} useSync (optional) If true then return a SyncPromise which
22503 * is already fulfilled. If omitted or false, this may return a SyncPromise or
22504 * an async Promise.
22505 * @return {Promise|SyncPromise} A promise that returns the supplied Interest.
22506 */
22507IdentityManager.prototype.signInterestByCertificatePromise = function
22508 (interest, certificateName, wireFormat, useSync)
22509{
22510 useSync = (typeof wireFormat === "boolean") ? wireFormat : useSync;
22511 wireFormat = (typeof wireFormat === "boolean" || !wireFormat) ? WireFormat.getDefaultWireFormat() : wireFormat;
22512
22513 var thisManager = this;
22514 var signature;
22515 var digestAlgorithm = [0];
22516 return this.makeSignatureByCertificatePromise
22517 (certificateName, digestAlgorithm, useSync)
22518 .then(function(localSignature) {
22519 signature = localSignature;
22520 // Append the encoded SignatureInfo.
22521 interest.getName().append(wireFormat.encodeSignatureInfo(signature));
22522
22523 // Append an empty signature so that the "signedPortion" is correct.
22524 interest.getName().append(new Name.Component());
22525 // Encode once to get the signed portion.
22526 var encoding = interest.wireEncode(wireFormat);
22527 var keyName = IdentityManager.certificateNameToPublicKeyName
22528 (certificateName);
22529
22530 return thisManager.privateKeyStorage.signPromise
22531 (encoding.signedBuf(), keyName, digestAlgorithm[0], useSync);
22532 })
22533 .then(function(signatureValue) {
22534 signature.setSignature(signatureValue);
22535
22536 // Remove the empty signature and append the real one.
22537 interest.setName(interest.getName().getPrefix(-1).append
22538 (wireFormat.encodeSignatureValue(signature)));
22539 return SyncPromise.resolve(interest);
22540 });
22541};
22542
22543/**
22544 * Append a SignatureInfo to the Interest name, sign the name components and
22545 * append a final name component with the signature bits.
22546 * @param {Interest} interest The Interest object to be signed. This appends
22547 * name components of SignatureInfo and the signature bits.
22548 * @param {Name} certificateName The certificate name of the key to use for
22549 * signing.
22550 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
22551 * the input. If omitted, use WireFormat getDefaultWireFormat().
22552 * @param {function} onComplete (optional) This calls onComplete(interest) with
22553 * the supplied Interest object which has been modified to set its signature. If
22554 * omitted, then return when the interest has been signed. (Some crypto
22555 * libraries only use a callback, so onComplete is required to use these.)
22556 * @param {function} onError (optional) If defined, then onComplete must be
22557 * defined and if there is an exception, then this calls onError(exception)
22558 * with the exception. If onComplete is defined but onError is undefined, then
22559 * this will log any thrown exception. (Some crypto libraries only use a
22560 * callback, so onError is required to be notified of an exception.)
22561 * @return {Signature} If onComplete is omitted, return the interest. Otherwise,
22562 * if onComplete is supplied then return undefined and use onComplete as
22563 * described above.
22564 */
22565IdentityManager.prototype.signInterestByCertificate = function
22566 (interest, certificateName, wireFormat, onComplete, onError)
22567{
22568 onError = (typeof wireFormat === "function") ? onComplete : onError;
22569 onComplete = (typeof wireFormat === "function") ? wireFormat : onComplete;
22570 wireFormat = (typeof wireFormat === "function" || !wireFormat) ? WireFormat.getDefaultWireFormat() : wireFormat;
22571
22572 return SyncPromise.complete(onComplete, onError,
22573 this.signInterestByCertificatePromise
22574 (interest, certificateName, wireFormat, !onComplete));
22575};
22576
22577/**
22578 * Wire encode the Data object, digest it and set its SignatureInfo to a
22579 * DigestSha256.
22580 * @param {Data} data The Data object to be signed. This updates its signature
22581 * and wireEncoding.
22582 * @param {WireFormat} (optional) The WireFormat for calling encodeData, or
22583 * WireFormat.getDefaultWireFormat() if omitted.
22584 */
22585IdentityManager.prototype.signWithSha256 = function(data, wireFormat)
22586{
22587 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
22588
22589 data.setSignature(new DigestSha256Signature());
22590 // Encode once to get the signed portion.
22591 var encoding = data.wireEncode(wireFormat);
22592
22593 // Digest and set the signature.
22594 var hash = Crypto.createHash('sha256');
22595 hash.update(encoding.signedBuf());
22596 data.getSignature().setSignature(new Blob(hash.digest(), false));
22597
22598 // Encode again to include the signature.
22599 data.wireEncode(wireFormat);
22600};
22601
22602/**
22603 * Append a SignatureInfo for DigestSha256 to the Interest name, digest the
22604 * name components and append a final name component with the signature bits
22605 * (which is the digest).
22606 * @param {Interest} interest The Interest object to be signed. This appends
22607 * name components of SignatureInfo and the signature bits.
22608 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
22609 * the input. If omitted, use WireFormat getDefaultWireFormat().
22610 */
22611IdentityManager.prototype.signInterestWithSha256 = function(interest, wireFormat)
22612{
22613 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
22614
22615 var signature = new DigestSha256Signature();
22616
22617 // Append the encoded SignatureInfo.
22618 interest.getName().append(wireFormat.encodeSignatureInfo(signature));
22619
22620 // Append an empty signature so that the "signedPortion" is correct.
22621 interest.getName().append(new Name.Component());
22622 // Encode once to get the signed portion.
22623 var encoding = interest.wireEncode(wireFormat);
22624
22625 // Digest and set the signature.
22626 var hash = Crypto.createHash('sha256');
22627 hash.update(encoding.signedBuf());
22628 signature.setSignature(new Blob(hash.digest(), false));
22629
22630 // Remove the empty signature and append the real one.
22631 interest.setName(interest.getName().getPrefix(-1).append
22632 (wireFormat.encodeSignatureValue(signature)));
22633};
22634
22635/**
22636 * Generate a self-signed certificate for a public key.
22637 * @param {Name} keyName The name of the public key.
22638 * @param {boolean} useSync (optional) If true then return a SyncPromise which
22639 * is already fulfilled. If false, this may return a SyncPromise or an async
22640 * Promise.
22641 * @return {Promise|SyncPromise} A promise which returns the generated
22642 * IdentityCertificate.
22643 */
22644IdentityManager.prototype.selfSignPromise = function(keyName, useSync)
22645{
22646 var certificate = new IdentityCertificate();
22647
22648 var thisManager = this;
22649 return this.identityStorage.getKeyPromise(keyName, useSync)
22650 .then(function(keyBlob) {
22651 var publicKey = new PublicKey(keyBlob);
22652
22653 var notBefore = new Date().getTime();
22654 var notAfter = notBefore + 2 * 365 * 24 * 3600 * 1000; // about 2 years
22655
22656 certificate.setNotBefore(notBefore);
22657 certificate.setNotAfter(notAfter);
22658
22659 var certificateName = keyName.getPrefix(-1).append("KEY").append
22660 (keyName.get(-1)).append("ID-CERT").appendVersion(certificate.getNotBefore());
22661 certificate.setName(certificateName);
22662
22663 certificate.setPublicKeyInfo(publicKey);
22664 certificate.addSubjectDescription(new CertificateSubjectDescription
22665 ("2.5.4.41", keyName.toUri()));
22666 certificate.encode();
22667
22668 return thisManager.signByCertificatePromise
22669 (certificate, certificate.getName(), useSync);
22670 })
22671};
22672
22673/**
22674 * Generate a self-signed certificate for a public key.
22675 * @param {Name} keyName The name of the public key.
22676 * @param {function} onComplete (optional) This calls onComplete(certificate)
22677 * with the the generated IdentityCertificate. If omitted, the return value is
22678 * described below. (Some crypto libraries only use a callback, so onComplete is
22679 * required to use these.)
22680 * @return {IdentityCertificate} If onComplete is omitted, return the
22681 * generated certificate. Otherwise, if onComplete is supplied then return
22682 * undefined and use onComplete as described above.
22683 * @param {function} onError (optional) If defined, then onComplete must be
22684 * defined and if there is an exception, then this calls onError(exception)
22685 * with the exception. If onComplete is defined but onError is undefined, then
22686 * this will log any thrown exception. (Some crypto libraries only use a
22687 * callback, so onError is required to be notified of an exception.)
22688 */
22689IdentityManager.prototype.selfSign = function(keyName, onComplete, onError)
22690{
22691 return SyncPromise.complete(onComplete, onError,
22692 this.selfSignPromise(keyName, !onComplete));
22693};
22694
22695/**
22696 * Get the public key name from the full certificate name.
22697 *
22698 * @param {Name} certificateName The full certificate name.
22699 * @return {Name} The related public key name.
22700 * TODO: Move this to IdentityCertificate
22701 */
22702IdentityManager.certificateNameToPublicKeyName = function(certificateName)
22703{
22704 var i = certificateName.size() - 1;
22705 var idString = "ID-CERT";
22706 while (i >= 0) {
22707 if (certificateName.get(i).toEscapedString() == idString)
22708 break;
22709 --i;
22710 }
22711
22712 var tmpName = certificateName.getSubName(0, i);
22713 var keyString = "KEY";
22714 i = 0;
22715 while (i < tmpName.size()) {
22716 if (tmpName.get(i).toEscapedString() == keyString)
22717 break;
22718 ++i;
22719 }
22720
22721 return tmpName.getSubName(0, i).append(tmpName.getSubName
22722 (i + 1, tmpName.size() - i - 1));
22723};
22724
22725/**
22726 * Return a new Signature object based on the signature algorithm of the public
22727 * key with keyName (derived from certificateName).
22728 * @param {Name} certificateName The certificate name.
22729 * @param {Array} digestAlgorithm Set digestAlgorithm[0] to the signature
22730 * algorithm's digest algorithm, e.g. DigestAlgorithm.SHA256.
22731 * @param {boolean} useSync (optional) If true then return a SyncPromise which
22732 * is already fulfilled. If false, this may return a SyncPromise or an async
22733 * Promise.
22734 * @return {Promise|SyncPromise} A promise which returns a new object of the
22735 * correct subclass of Signature.
22736 */
22737IdentityManager.prototype.makeSignatureByCertificatePromise = function
22738 (certificateName, digestAlgorithm, useSync)
22739{
22740 var keyName = IdentityManager.certificateNameToPublicKeyName(certificateName);
22741 return this.privateKeyStorage.getPublicKeyPromise(keyName, useSync)
22742 .then(function(publicKey) {
22743 var keyType = publicKey.getKeyType();
22744
22745 var signature = null;
22746 if (keyType == KeyType.RSA) {
22747 signature = new Sha256WithRsaSignature();
22748 digestAlgorithm[0] = DigestAlgorithm.SHA256;
22749
22750 signature.getKeyLocator().setType(KeyLocatorType.KEYNAME);
22751 signature.getKeyLocator().setKeyName(certificateName.getPrefix(-1));
22752 }
22753 else if (keyType == KeyType.ECDSA) {
22754 signature = new Sha256WithEcdsaSignature();
22755 digestAlgorithm[0] = DigestAlgorithm.SHA256;
22756
22757 signature.getKeyLocator().setType(KeyLocatorType.KEYNAME);
22758 signature.getKeyLocator().setKeyName(certificateName.getPrefix(-1));
22759 }
22760 else
22761 throw new SecurityException(new Error("Key type is not recognized"));
22762
22763 return SyncPromise.resolve(signature);
22764 });
22765};
22766
22767/**
22768 * A private method to generate a pair of keys for the specified identity.
22769 * @param {Name} identityName The name of the identity.
22770 * @param {boolean} isKsk true for generating a Key-Signing-Key (KSK), false for
22771 * a Data-Signing-Key (DSK).
22772 * @param {KeyParams} params The parameters of the key.
22773 * @param {boolean} useSync (optional) If true then return a SyncPromise which
22774 * is already fulfilled. If false, this may return a SyncPromise or an async
22775 * Promise.
22776 * @return {Promise|SyncPromise} A promise which returns the generated key name.
22777 */
22778IdentityManager.prototype.generateKeyPairPromise = function
22779 (identityName, isKsk, params, useSync)
22780{
22781 var keyName;
22782 var thisManager = this;
22783 return this.identityStorage.getNewKeyNamePromise(identityName, isKsk, useSync)
22784 .then(function(localKeyName) {
22785 keyName = localKeyName;
22786 return thisManager.privateKeyStorage.generateKeyPairPromise
22787 (keyName, params, useSync);
22788 })
22789 .then(function() {
22790 return thisManager.privateKeyStorage.getPublicKeyPromise
22791 (keyName, useSync);
22792 })
22793 .then(function(publicKey) {
22794 return thisManager.identityStorage.addKeyPromise
22795 (keyName, params.getKeyType(), publicKey.getKeyDer());
22796 })
22797 .then(function() {
22798 return SyncPromise.resolve(keyName);
22799 });
22800};
22801
22802/**
22803 * Get the IdentityStorage from the pib value in the configuration file if
22804 * supplied. Otherwise, get the default for this platform.
22805 * @param {ConfigFile} config The configuration file to check.
22806 * @param {function} initialCheckPromise This is passed to the
22807 * BasicIdentityStorage constructor. See it for details.
22808 * @return {IdentityStorage} A new IdentityStorage.
22809 */
22810IdentityManager.getDefaultIdentityStorage_ = function(config, initialCheckPromise)
22811{
22812 // Assume we are in Node.js.
22813 var pibLocator = config.get("pib", "");
22814
22815 if (pibLocator !== "") {
22816 // Don't support non-default locations for now.
22817 if (pibLocator !== "pib-sqlite3")
22818 throw new SecurityException(new Error
22819 ("Invalid config file pib value: " + pibLocator));
22820 }
22821
22822 return new BasicIdentityStorage(initialCheckPromise);
22823};
22824
22825/**
22826 * Get the PrivateKeyStorage from the tpm value in the configuration file if
22827 * supplied. Otherwise, get the default for this platform.
22828 * @param {ConfigFile} config The configuration file to check.
22829 * @param {Array<string>} canonicalTpmLocator Set canonicalTpmLocator[0] to the
22830 * canonical value including the colon, * e.g. "tpm-file:".
22831 * @return A new PrivateKeyStorage.
22832 */
22833IdentityManager.getDefaultPrivateKeyStorage_ = function
22834 (config, canonicalTpmLocator)
22835{
22836 var tpmLocator = config.get("tpm", "");
22837
22838 if (tpmLocator === "") {
22839 // Assume we are in Node.js, so check the system.
22840 if (process.platform === "darwin") {
22841 canonicalTpmLocator[0] = "tpm-osxkeychain:";
22842 throw new SecurityException(new Error
22843 ("IdentityManager: OS X key chain storage is not yet implemented. You must supply a privateKeyStorage."));
22844 }
22845 else {
22846 canonicalTpmLocator[0] = "tpm-file:";
22847 return new FilePrivateKeyStorage();
22848 }
22849 }
22850 else if (tpmLocator === "tpm-osxkeychain") {
22851 canonicalTpmLocator[0] = "tpm-osxkeychain:";
22852 throw new SecurityException(new Error
22853 ("IdentityManager: tpm-osxkeychain is not yet implemented."));
22854 }
22855 else if (tpmLocator === "tpm-file") {
22856 canonicalTpmLocator[0] = "tpm-file:";
22857 return new FilePrivateKeyStorage();
22858 }
22859 else
22860 throw new SecurityException(new Error
22861 ("Invalid config file tpm value: " + tpmLocator));
22862};
22863
22864/**
22865 * Check that identityStorage.getTpmLocatorPromise() (if defined) matches the
22866 * canonicalTpmLocator. This has to be an async Promise because it calls async
22867 * getTpmLocatorPromise.
22868 * @param canonicalTpmLocator The canonical locator from
22869 * getDefaultPrivateKeyStorage().
22870 * @return {Promise} A promise which resolves if canonicalTpmLocator is OK, or a
22871 * promise rejected with SecurityException if the private key storage does not
22872 * match.
22873 */
22874IdentityManager.prototype.checkTpmPromise_ = function(canonicalTpmLocator)
22875{
22876 return this.identityStorage.getTpmLocatorPromise()
22877 .then(function(tpmLocator) {
22878 // Just check. If a PIB reset is required, expect ndn-cxx/NFD to do it.
22879 if (tpmLocator !== "" && tpmLocator !== canonicalTpmLocator)
22880 return Promise.reject(new SecurityException(new Error
22881 ("The TPM locator supplied does not match the TPM locator in the PIB: " +
22882 tpmLocator + " != " + canonicalTpmLocator)));
22883 else
22884 return Promise.resolve();
22885 }, function(err) {
22886 // The TPM locator is not set in the PIB yet.
22887 return Promise.resolve();
22888 });
22889};
22890/**
22891 * Copyright (C) 2014-2016 Regents of the University of California.
22892 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
22893 * From ndn-cxx security by Yingdi Yu <yingdi@cs.ucla.edu>.
22894 *
22895 * This program is free software: you can redistribute it and/or modify
22896 * it under the terms of the GNU Lesser General Public License as published by
22897 * the Free Software Foundation, either version 3 of the License, or
22898 * (at your option) any later version.
22899 *
22900 * This program is distributed in the hope that it will be useful,
22901 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22902 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22903 * GNU Lesser General Public License for more details.
22904 *
22905 * You should have received a copy of the GNU Lesser General Public License
22906 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22907 * A copy of the GNU Lesser General Public License is in the file COPYING.
22908 */
22909
22910/**
22911 * A ValidationRequest is used to return information from
22912 * PolicyManager.checkVerificationPolicy.
22913 *
22914 * Create a new ValidationRequest with the given values.
22915 * @param {Interest} interest An interest for fetching more data.
22916 * @param {function} onVerified If the signature is verified, this calls
22917 * onVerified(data).
22918 * @param {function} onValidationFailed If the signature check fails, this calls
22919 * onValidationFailed(data, reason).
22920 * @param {number} retry The number of retrials when there is an interest timeout.
22921 * @param {number} stepCount The number of verification steps that have been
22922 * done, used to track the verification progress.
22923 * @constructor
22924 */
22925var ValidationRequest = function ValidationRequest
22926 (interest, onVerified, onValidationFailed, retry, stepCount)
22927{
22928 this.interest = interest;
22929 this.onVerified = onVerified;
22930 this.onValidationFailed = onValidationFailed;
22931 this.retry = retry;
22932 this.stepCount = stepCount;
22933};
22934
22935exports.ValidationRequest = ValidationRequest;
22936/**
22937 * Copyright (C) 2014-2016 Regents of the University of California.
22938 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
22939 * From ndn-cxx security by Yingdi Yu <yingdi@cs.ucla.edu>.
22940 *
22941 * This program is free software: you can redistribute it and/or modify
22942 * it under the terms of the GNU Lesser General Public License as published by
22943 * the Free Software Foundation, either version 3 of the License, or
22944 * (at your option) any later version.
22945 *
22946 * This program is distributed in the hope that it will be useful,
22947 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22948 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22949 * GNU Lesser General Public License for more details.
22950 *
22951 * You should have received a copy of the GNU Lesser General Public License
22952 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22953 * A copy of the GNU Lesser General Public License is in the file COPYING.
22954 */
22955
22956// Use capitalized Crypto to not clash with the browser's crypto.subtle.
22957/** @ignore */
22958var Crypto = require('../../crypto.js'); /** @ignore */
22959var Blob = require('../../util/blob.js').Blob; /** @ignore */
22960var DataUtils = require('../../encoding/data-utils.js').DataUtils; /** @ignore */
22961var SecurityException = require('../security-exception.js').SecurityException; /** @ignore */
22962var DigestSha256Signature = require('../../digest-sha256-signature.js').DigestSha256Signature; /** @ignore */
22963var Sha256WithRsaSignature = require('../../sha256-with-rsa-signature.js').Sha256WithRsaSignature; /** @ignore */
22964var Sha256WithEcdsaSignature = require('../../sha256-with-ecdsa-signature.js').Sha256WithEcdsaSignature; /** @ignore */
22965var UseSubtleCrypto = require("../../use-subtle-crypto-node.js").UseSubtleCrypto;
22966
22967/**
22968 * A PolicyManager is an abstract base class to represent the policy for
22969 * verifying data packets. You must create an object of a subclass.
22970 * @constructor
22971 */
22972var PolicyManager = function PolicyManager()
22973{
22974};
22975
22976exports.PolicyManager = PolicyManager;
22977
22978/**
22979 * Check if the received data packet or signed interest can escape from
22980 * verification and be trusted as valid.
22981 * Your derived class should override.
22982 *
22983 * @param {Data|Interest} dataOrInterest The received data packet or interest.
22984 * @return {boolean} True if the data or interest does not need to be verified
22985 * to be trusted as valid, otherwise false.
22986 */
22987PolicyManager.prototype.skipVerifyAndTrust = function(dataOrInterest)
22988{
22989 throw new Error("PolicyManager.skipVerifyAndTrust is not implemented");
22990};
22991
22992/**
22993 * Check if this PolicyManager has a verification rule for the received data
22994 * packet or signed interest.
22995 * Your derived class should override.
22996 *
22997 * @param {Data|Interest} dataOrInterest The received data packet or interest.
22998 * @return {boolean} True if the data or interest must be verified, otherwise
22999 * false.
23000 */
23001PolicyManager.prototype.requireVerify = function(dataOrInterest)
23002{
23003 throw new Error("PolicyManager.requireVerify is not implemented");
23004};
23005
23006/**
23007 * Check whether the received data or interest packet complies with the
23008 * verification policy, and get the indication of the next verification step.
23009 * Your derived class should override.
23010 *
23011 * @param {Data|Interest} dataOrInterest The Data object or interest with the
23012 * signature to check.
23013 * @param {number} stepCount The number of verification steps that have been
23014 * done, used to track the verification progress.
23015 * @param {function} onVerified If the signature is verified, this calls
23016 * onVerified(dataOrInterest).
23017 * NOTE: The library will log any exceptions thrown by this callback, but for
23018 * better error handling the callback should catch and properly handle any
23019 * exceptions.
23020 * @param {function} onValidationFailed If the signature check fails, this calls
23021 * onValidationFailed(dataOrInterest, reason).
23022 * NOTE: The library will log any exceptions thrown by this callback, but for
23023 * better error handling the callback should catch and properly handle any
23024 * exceptions.
23025 * @param {WireFormat} wireFormat
23026 * @return {ValidationRequest} The indication of next verification step, or
23027 * null if there is no further step.
23028 */
23029PolicyManager.prototype.checkVerificationPolicy = function
23030 (dataOrInterest, stepCount, onVerified, onValidationFailed, wireFormat)
23031{
23032 throw new Error("PolicyManager.checkVerificationPolicy is not implemented");
23033};
23034
23035/**
23036 * Check if the signing certificate name and data name satisfy the signing
23037 * policy.
23038 * Your derived class should override.
23039 *
23040 * @param {Name} dataName The name of data to be signed.
23041 * @param {Name} certificateName The name of signing certificate.
23042 * @return {boolean} True if the signing certificate can be used to sign the
23043 * data, otherwise false.
23044 */
23045PolicyManager.prototype.checkSigningPolicy = function(dataName, certificateName)
23046{
23047 throw new Error("PolicyManager.checkSigningPolicy is not implemented");
23048};
23049
23050/**
23051 * Infer the signing identity name according to the policy. If the signing
23052 * identity cannot be inferred, return an empty name.
23053 * Your derived class should override.
23054 *
23055 * @param {Name} dataName The name of data to be signed.
23056 * @return {Name} The signing identity or an empty name if cannot infer.
23057 */
23058PolicyManager.prototype.inferSigningIdentity = function(dataName)
23059{
23060 throw new Error("PolicyManager.inferSigningIdentity is not implemented");
23061};
23062
23063// The first time verify is called, it sets this to determine if a signature
23064// buffer needs to be converted to a string for the crypto verifier.
23065PolicyManager.verifyUsesString_ = null;
23066PolicyManager.setVerifyUsesString_ = function()
23067{
23068 var hashResult = Crypto.createHash('sha256').digest();
23069 // If the hash result is a string, we assume that this is a version of
23070 // crypto where verify also uses a string signature.
23071 PolicyManager.verifyUsesString_ = (typeof hashResult === 'string');
23072};
23073
23074/**
23075 * Check the type of signature and use the publicKeyDer to verify the
23076 * signedBlob using the appropriate signature algorithm.
23077 * @param {Signature} signature An object of a subclass of Signature, e.g.
23078 * Sha256WithRsaSignature.
23079 * @param {SignedBlob} signedBlob the SignedBlob with the signed portion to
23080 * verify.
23081 * @param {Blob} publicKeyDer The DER-encoded public key used to verify the
23082 * signature.
23083 * @param {function} onComplete This calls onComplete(true) if the signature
23084 * verifies, otherwise onComplete(false).
23085 * @throws SecurityException if the signature type is not recognized or if
23086 * publicKeyDer can't be decoded.
23087 */
23088PolicyManager.verifySignature = function
23089 (signature, signedBlob, publicKeyDer, onComplete)
23090{
23091 if (signature instanceof Sha256WithRsaSignature) {
23092 if (publicKeyDer.isNull()) {
23093 onComplete(false);
23094 return;
23095 }
23096 PolicyManager.verifySha256WithRsaSignature
23097 (signature.getSignature(), signedBlob, publicKeyDer, onComplete);
23098 }
23099 else if (signature instanceof Sha256WithEcdsaSignature) {
23100 if (publicKeyDer.isNull()) {
23101 onComplete(false);
23102 return;
23103 }
23104 PolicyManager.verifySha256WithEcdsaSignature
23105 (signature.getSignature(), signedBlob, publicKeyDer, onComplete);
23106 }
23107 else if (signature instanceof DigestSha256Signature)
23108 PolicyManager.verifyDigestSha256Signature
23109 (signature.getSignature(), signedBlob, onComplete);
23110 else
23111 // We don't expect this to happen.
23112 throw new SecurityException(new Error
23113 ("PolicyManager.verify: Signature type is unknown"));
23114};
23115
23116/**
23117 * Verify the RSA signature on the SignedBlob using the given public key.
23118 * @param {Blob} signature The signature bits.
23119 * @param {SignedBlob} signedBlob the SignedBlob with the signed portion to
23120 * verify.
23121 * @param {Blob} publicKeyDer The DER-encoded public key used to verify the
23122 * signature.
23123 * @param {function} onComplete This calls onComplete(true) if the signature
23124 * verifies, otherwise onComplete(false).
23125 */
23126PolicyManager.verifySha256WithRsaSignature = function
23127 (signature, signedBlob, publicKeyDer, onComplete)
23128{
23129 if (UseSubtleCrypto()){
23130 var algo = {name:"RSASSA-PKCS1-v1_5",hash:{name:"SHA-256"}};
23131
23132 crypto.subtle.importKey("spki", publicKeyDer.buf().buffer, algo, true, ["verify"]).then(function(publicKey){
23133 return crypto.subtle.verify(algo, publicKey, signature.buf(), signedBlob.signedBuf())
23134 }).then(function(verified){
23135 onComplete(verified);
23136 });
23137 } else {
23138 if (PolicyManager.verifyUsesString_ === null)
23139 PolicyManager.setVerifyUsesString_();
23140
23141 // The crypto verifier requires a PEM-encoded public key.
23142 var keyBase64 = publicKeyDer.buf().toString('base64');
23143 var keyPem = "-----BEGIN PUBLIC KEY-----\n";
23144 for (var i = 0; i < keyBase64.length; i += 64)
23145 keyPem += (keyBase64.substr(i, 64) + "\n");
23146 keyPem += "-----END PUBLIC KEY-----";
23147
23148 var verifier = Crypto.createVerify('RSA-SHA256');
23149 verifier.update(signedBlob.signedBuf());
23150 var signatureBytes = PolicyManager.verifyUsesString_ ?
23151 DataUtils.toString(signature.buf()) : signature.buf();
23152 onComplete(verifier.verify(keyPem, signatureBytes));
23153 }
23154};
23155
23156/**
23157 * Verify the ECDSA signature on the SignedBlob using the given public key.
23158 * @param {Blob} signature The signature bits.
23159 * @param {SignedBlob} signedBlob the SignedBlob with the signed portion to
23160 * verify.
23161 * @param {Blob} publicKeyDer The DER-encoded public key used to verify the
23162 * signature.
23163 * @param {function} onComplete This calls onComplete(true) if the signature
23164 * verifies, otherwise onComplete(false).
23165 */
23166PolicyManager.verifySha256WithEcdsaSignature = function
23167 (signature, signedBlob, publicKeyDer, onComplete)
23168{
23169 if (UseSubtleCrypto()) {
Alexander Afanasyev1663a412013-03-02 13:52:00 -080023170/*
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080023171 var algo = {name:"RSASSA-PKCS1-v1_5",hash:{name:"SHA-256"}};
23172
23173 crypto.subtle.importKey("spki", publicKeyDer.buf().buffer, algo, true, ["verify"]).then(function(publicKey){
23174 return crypto.subtle.verify(algo, publicKey, signature.buf(), signedBlob.signedBuf())
23175 }).then(function(verified){
23176 onComplete(verified);
23177 });
23178*/ onComplete(false);
23179 } else {
23180 if (PolicyManager.verifyUsesString_ === null)
23181 PolicyManager.setVerifyUsesString_();
23182
23183 // The crypto verifier requires a PEM-encoded public key.
23184 var keyBase64 = publicKeyDer.buf().toString("base64");
23185 var keyPem = "-----BEGIN PUBLIC KEY-----\n";
23186 for (var i = 0; i < keyBase64.length; i += 64)
23187 keyPem += (keyBase64.substr(i, 64) + "\n");
23188 keyPem += "-----END PUBLIC KEY-----";
23189
23190 // Just create a "sha256". The Crypto library will infer ECDSA from the key.
23191 var verifier = Crypto.createVerify("sha256");
23192 verifier.update(signedBlob.signedBuf());
23193 var signatureBytes = PolicyManager.verifyUsesString_ ?
23194 DataUtils.toString(signature.buf()) : signature.buf();
23195 onComplete(verifier.verify(keyPem, signatureBytes));
23196 }
23197};
23198
23199/**
23200 * Verify the DigestSha256 signature on the SignedBlob by verifying that the
23201 * digest of SignedBlob equals the signature.
23202 * @param {Blob} signature The signature bits.
23203 * @param {SignedBlob} signedBlob the SignedBlob with the signed portion to
23204 * verify.
23205 * @param {function} onComplete This calls onComplete(true) if the signature
23206 * verifies, otherwise onComplete(false).
23207 */
23208PolicyManager.verifyDigestSha256Signature = function
23209 (signature, signedBlob, onComplete)
23210{
23211 // Set signedPortionDigest to the digest of the signed portion of the signedBlob.
23212 var hash = Crypto.createHash('sha256');
23213 hash.update(signedBlob.signedBuf());
23214 var signedPortionDigest = new Blob(hash.digest(), false);
23215
23216 onComplete(signedPortionDigest.equals(signature));
23217};
23218/**
23219 * Copyright (C) 2014-2016 Regents of the University of California.
23220 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
23221 * From PyNDN certificate_cache.py by Adeola Bannis.
23222 * Originally from Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>.
23223 *
23224 * This program is free software: you can redistribute it and/or modify
23225 * it under the terms of the GNU Lesser General Public License as published by
23226 * the Free Software Foundation, either version 3 of the License, or
23227 * (at your option) any later version.
23228 *
23229 * This program is distributed in the hope that it will be useful,
23230 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23231 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23232 * GNU Lesser General Public License for more details.
23233 *
23234 * You should have received a copy of the GNU Lesser General Public License
23235 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23236 * A copy of the GNU Lesser General Public License is in the file COPYING.
23237 */
23238
23239/** @ignore */
23240var IdentityCertificate = require('../certificate/identity-certificate.js').IdentityCertificate;
23241
23242/**
23243 * A CertificateCache is used to save other users' certificate during
23244 * verification.
23245 * @constructor
23246 */
23247var CertificateCache = function CertificateCache()
23248{
23249 // The key is the certificate name URI. The value is the wire encoding Blob.
23250 this.cache = {};
23251};
23252
23253exports.CertificateCache = CertificateCache;
23254
23255/**
23256 * Insert the certificate into the cache. Assumes the timestamp is not yet
23257 * removed from the name.
23258 * @param {IdentityCertificate} certificate The certificate to insert.
23259 */
23260CertificateCache.prototype.insertCertificate = function(certificate)
23261{
23262 var certName = certificate.getName().getPrefix(-1);
23263 this.cache[certName.toUri()] = certificate.wireEncode();
23264};
23265
23266/**
23267 * Remove a certificate from the cache. This does nothing if it is not present.
23268 * @param {Name} certificateName The name of the certificate to remove. This
23269 * assumes there is no timestamp in the name.
23270 */
23271CertificateCache.prototype.deleteCertificate = function(certificateName)
23272{
23273 delete this.cache[certificateName.toUri()];
23274};
23275
23276/**
23277 * Fetch a certificate from the cache.
23278 * @param {Name} certificateName The name of the certificate to remove. This
23279 * assumes there is no timestamp in the name.
23280 * @return {IdentityCertificate} A new copy of the IdentityCertificate, or null
23281 * if not found.
23282 */
23283CertificateCache.prototype.getCertificate = function(certificateName)
23284{
23285 var certData = this.cache[certificateName.toUri()];
23286 if (certData === undefined)
23287 return null;
23288
23289 var cert = new IdentityCertificate();
23290 cert.wireDecode(certData);
23291 return cert;
23292};
23293
23294/**
23295 * Clear all certificates from the store.
23296 */
23297CertificateCache.prototype.reset = function()
23298{
23299 this.cache = {};
23300};
23301/**
23302 * Copyright (C) 2014-2016 Regents of the University of California.
23303 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
23304 * From PyNDN config_policy_manager.py by Adeola Bannis.
23305 * Originally from Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>.
23306 *
23307 * This program is free software: you can redistribute it and/or modify
23308 * it under the terms of the GNU Lesser General Public License as published by
23309 * the Free Software Foundation, either version 3 of the License, or
23310 * (at your option) any later version.
23311 *
23312 * This program is distributed in the hope that it will be useful,
23313 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23314 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23315 * GNU Lesser General Public License for more details.
23316 *
23317 * You should have received a copy of the GNU Lesser General Public License
23318 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23319 * A copy of the GNU Lesser General Public License is in the file COPYING.
23320 */
23321
23322/** @ignore */
23323var fs = require('fs'); /** @ignore */
23324var path = require('path'); /** @ignore */
23325var Name = require('../../name.js').Name; /** @ignore */
23326var Data = require('../../data.js').Data; /** @ignore */
23327var Interest = require('../../interest.js').Interest; /** @ignore */
23328var KeyLocator = require('../../key-locator.js').KeyLocator; /** @ignore */
23329var KeyLocatorType = require('../../key-locator.js').KeyLocatorType; /** @ignore */
23330var Blob = require('../../util/blob.js').Blob; /** @ignore */
23331var IdentityCertificate = require('../certificate/identity-certificate.js').IdentityCertificate; /** @ignore */
23332var BoostInfoParser = require('../../util/boost-info-parser.js').BoostInfoParser; /** @ignore */
23333var NdnRegexMatcher = require('../../util/ndn-regex-matcher.js').NdnRegexMatcher; /** @ignore */
23334var CertificateCache = require('./certificate-cache.js').CertificateCache; /** @ignore */
23335var ValidationRequest = require('./validation-request.js').ValidationRequest; /** @ignore */
23336var SecurityException = require('../security-exception.js').SecurityException; /** @ignore */
23337var WireFormat = require('../../encoding/wire-format.js').WireFormat; /** @ignore */
23338var PolicyManager = require('./policy-manager.js').PolicyManager; /** @ignore */
23339var NdnCommon = require('../../util/ndn-common.js').NdnCommon;
23340
23341/**
23342 * ConfigPolicyManager manages trust according to a configuration file in the
23343 * Validator Configuration File Format
23344 * (http://redmine.named-data.net/projects/ndn-cxx/wiki/CommandValidatorConf)
23345 *
23346 * Once a rule is matched, the ConfigPolicyManager looks in the
23347 * CertificateCache for the IdentityCertificate matching the name in the KeyLocator
23348 * and uses its public key to verify the data packet or signed interest. If the
23349 * certificate can't be found, it is downloaded, verified and installed. A chain
23350 * of certificates will be followed to a maximum depth.
23351 * If the new certificate is accepted, it is used to complete the verification.
23352 *
23353 * The KeyLocators of data packets and signed interests MUST contain a name for
23354 * verification to succeed.
23355 *
23356 * Create a new ConfigPolicyManager which will act on the rules specified in the
23357 * configuration and download unknown certificates when necessary.
23358 *
23359 * @param {string} configFileName (optional) If not null or empty, the path to
23360 * the configuration file containing verification rules. (This only works in
23361 * Node.js since it reads files using the "fs" module.) Otherwise, you should
23362 * separately call load().
23363 * @param {CertificateCache} certificateCache (optional) A CertificateCache to
23364 * hold known certificates. If this is null or omitted, then create an internal
23365 * CertificateCache.
23366 * @param {number} searchDepth (optional) The maximum number of links to follow
23367 * when verifying a certificate chain. If omitted, use a default.
23368 * @param {number} graceInterval (optional) The window of time difference
23369 * (in milliseconds) allowed between the timestamp of the first interest signed with
23370 * a new public key and the validation time. If omitted, use a default value.
23371 * @param {number} keyTimestampTtl (optional) How long a public key's last-used
23372 * timestamp is kept in the store (milliseconds). If omitted, use a default value.
23373 * @param {number} maxTrackedKeys The maximum number of public key use
23374 * timestamps to track. If omitted, use a default.
23375 * @constructor
23376 */
23377var ConfigPolicyManager = function ConfigPolicyManager
23378 (configFileName, certificateCache, searchDepth, graceInterval,
23379 keyTimestampTtl, maxTrackedKeys)
23380{
23381 // Call the base constructor.
23382 PolicyManager.call(this);
23383
23384 if (certificateCache == undefined)
23385 certificateCache = null;
23386 if (searchDepth == undefined)
23387 searchDepth = 5;
23388 if (graceInterval == undefined)
23389 graceInterval = 3000;
23390 if (keyTimestampTtl == undefined)
23391 keyTimestampTtl = 3600000;
23392 if (maxTrackedKeys == undefined)
23393 maxTrackedKeys = 1000;
23394
23395 if (certificateCache == null)
23396 this.certificateCache = new CertificateCache();
23397 else
23398 this.certificateCache = certificateCache;
23399 this.maxDepth = searchDepth;
23400 this.keyGraceInterval = graceInterval;
23401 this.keyTimestampTtl = keyTimestampTtl;
23402 this.maxTrackedKeys = maxTrackedKeys;
23403
23404 this.reset();
23405
23406 if (configFileName != null && configFileName != "")
23407 this.load(configFileName);
23408};
23409
23410ConfigPolicyManager.prototype = new PolicyManager();
23411ConfigPolicyManager.prototype.name = "ConfigPolicyManager";
23412
23413exports.ConfigPolicyManager = ConfigPolicyManager;
23414
23415/**
23416 * Reset the certificate cache and other fields to the constructor state.
23417 */
23418ConfigPolicyManager.prototype.reset = function()
23419{
23420 this.certificateCache.reset();
23421
23422 // Stores the fixed-signer certificate name associated with validation rules
23423 // so we don't keep loading from files.
23424 this.fixedCertificateCache = {};
23425
23426 // Stores the timestamps for each public key used in command interests to
23427 // avoid replay attacks.
23428 // Key is public key name, value is last timestamp.
23429 this.keyTimestamps = {};
23430
23431 this.requiresVerification = true;
23432
23433 this.config = new BoostInfoParser();
23434 this.refreshManager = new ConfigPolicyManager.TrustAnchorRefreshManager();
23435};
23436
23437/**
23438 * Call reset() and load the configuration rules from the file name or the input
23439 * string. There are two forms:
23440 * load(configFileName) reads configFileName from the file system. (This only
23441 * works in Node.js since it reads files using the "fs" module.)
23442 * load(input, inputName) reads from the input, in which case inputName is used
23443 * only for log messages, etc.
23444 * @param {string} configFileName The path to the file containing configuration
23445 * rules.
23446 * @param {string} input The contents of the configuration rules, with lines
23447 * separated by "\n" or "\r\n".
23448 * @param {string} inputName Use with input for log messages, etc.
23449 */
23450ConfigPolicyManager.prototype.load = function(configFileNameOrInput, inputName)
23451{
23452 this.reset();
23453 this.config.read(configFileNameOrInput, inputName);
23454 this.loadTrustAnchorCertificates();
23455}
23456
23457/**
23458 * Check if this PolicyManager has a verification rule for the received data.
23459 * If the configuration file contains the trust anchor 'any', nothing is
23460 * verified.
23461 *
23462 * @param {Data|Interest} dataOrInterest The received data packet or interest.
23463 * @return {boolean} true if the data must be verified, otherwise false.
23464 */
23465ConfigPolicyManager.prototype.requireVerify = function(dataOrInterest)
23466{
23467 return this.requiresVerification;
23468};
23469
23470/**
23471 * Override to always indicate that the signing certificate name and data name
23472 * satisfy the signing policy.
23473 *
23474 * @param {Name} dataName The name of data to be signed.
23475 * @param {Name} certificateName The name of signing certificate.
23476 * @return {boolean} True to indicate that the signing certificate can be used
23477 * to sign the data.
23478 */
23479ConfigPolicyManager.prototype.checkSigningPolicy = function
23480 (dataName, certificateName)
23481{
23482 return true;
23483};
23484
23485/**
23486 * Check if the received signed interest can escape from verification and be
23487 * trusted as valid. If the configuration file contains the trust anchor
23488 * 'any', nothing is verified.
23489 *
23490 * @param {Data|Interest} dataOrInterest The received data packet or interest.
23491 * @return {boolean} true if the data or interest does not need to be verified
23492 * to be trusted as valid, otherwise false.
23493 */
23494ConfigPolicyManager.prototype.skipVerifyAndTrust = function(dataOrInterest)
23495{
23496 return !this.requiresVerification;
23497};
23498
23499/**
23500 * Check whether the received data packet or interest complies with the
23501 * verification policy, and get the indication of the next verification step.
23502 *
23503 * @param {Data|Interest} dataOrInterest The Data object or interest with the
23504 * signature to check.
23505 * @param {number} stepCount The number of verification steps that have been
23506 * done, used to track the verification progress.
23507 * @param {function} onVerified If the signature is verified, this calls
23508 * onVerified(dataOrInterest).
23509 * NOTE: The library will log any exceptions thrown by this callback, but for
23510 * better error handling the callback should catch and properly handle any
23511 * exceptions.
23512 * @param {function} onValidationFailed If the signature check fails, this calls
23513 * onValidationFailed(dataOrInterest, reason).
23514 * NOTE: The library will log any exceptions thrown by this callback, but for
23515 * better error handling the callback should catch and properly handle any
23516 * exceptions.
23517 * @param {WireFormat} wireFormat
23518 * @return {ValidationRequest} The indication of next verification step, or
23519 * null if there is no further step.
23520 */
23521ConfigPolicyManager.prototype.checkVerificationPolicy = function
23522 (dataOrInterest, stepCount, onVerified, onValidationFailed, wireFormat)
23523{
23524 if (stepCount > this.maxDepth) {
23525 try {
23526 onValidationFailed
23527 (dataOrInterest, "The verification stepCount " + stepCount +
23528 " exceeded the maxDepth " + this.maxDepth);
23529 } catch (ex) {
23530 console.log("Error in onValidationFailed: " + NdnCommon.getErrorWithStackTrace(ex));
23531 }
23532 return null;
23533 }
23534
23535 var signature = ConfigPolicyManager.extractSignature(dataOrInterest, wireFormat);
23536 // No signature -> fail.
23537 if (signature == null) {
23538 try {
23539 onValidationFailed
23540 (dataOrInterest, "Cannot extract the signature from " +
23541 dataOrInterest.getName().toUri());
23542 } catch (ex) {
23543 console.log("Error in onValidationFailed: " + NdnCommon.getErrorWithStackTrace(ex));
23544 }
23545 return null;
23546 }
23547
23548 if (!KeyLocator.canGetFromSignature(signature)) {
23549 // We only support signature types with key locators.
23550 try {
23551 onValidationFailed
23552 (dataOrInterest, "The signature type does not support a KeyLocator");
23553 } catch (ex) {
23554 console.log("Error in onValidationFailed: " + NdnCommon.getErrorWithStackTrace(ex));
23555 }
23556 return null;
23557 }
23558
23559 var keyLocator = null;
23560 try {
23561 keyLocator = KeyLocator.getFromSignature(signature);
23562 }
23563 catch (ex) {
23564 // No key locator -> fail.
23565 try {
23566 onValidationFailed
23567 (dataOrInterest, "Error in KeyLocator.getFromSignature: " + ex);
23568 } catch (ex) {
23569 console.log("Error in onValidationFailed: " + NdnCommon.getErrorWithStackTrace(ex));
23570 }
23571 return null;
23572 }
23573
23574 var signatureName = keyLocator.getKeyName();
23575 // No key name in KeyLocator -> fail.
23576 if (signatureName.size() == 0) {
23577 try {
23578 onValidationFailed
23579 (dataOrInterest, "The signature KeyLocator doesn't have a key name");
23580 } catch (ex) {
23581 console.log("Error in onValidationFailed: " + NdnCommon.getErrorWithStackTrace(ex));
23582 }
23583 return null;
23584 }
23585
23586 var objectName = dataOrInterest.getName();
23587 var matchType = "data";
23588
23589 // For command interests, we need to ignore the last 4 components when
23590 // matching the name.
23591 if (dataOrInterest instanceof Interest) {
23592 objectName = objectName.getPrefix(-4);
23593 matchType = "interest";
23594 }
23595
23596 // First see if we can find a rule to match this packet.
23597 var matchedRule = this.findMatchingRule(objectName, matchType);
23598
23599 // No matching rule -> fail.
23600 if (matchedRule == null) {
23601 try {
23602 onValidationFailed
23603 (dataOrInterest, "No matching rule found for " + objectName.toUri());
23604 } catch (ex) {
23605 console.log("Error in onValidationFailed: " + NdnCommon.getErrorWithStackTrace(ex));
23606 }
23607 return null;
23608 }
23609
23610 var failureReason = ["unknown"];
23611 var signatureMatches = this.checkSignatureMatch
23612 (signatureName, objectName, matchedRule, failureReason);
23613 if (!signatureMatches) {
23614 try {
23615 onValidationFailed(dataOrInterest, failureReason[0]);
23616 } catch (ex) {
23617 console.log("Error in onValidationFailed: " + NdnCommon.getErrorWithStackTrace(ex));
23618 }
23619 return null;
23620 }
23621
23622 // Before we look up keys, refresh any certificate directories.
23623 this.refreshManager.refreshAnchors();
23624
23625 // Now finally check that the data or interest was signed correctly.
23626 // If we don't actually have the certificate yet, create a
23627 // ValidationRequest for it.
23628 var foundCert = this.refreshManager.getCertificate(signatureName);
23629 if (foundCert == null)
23630 foundCert = this.certificateCache.getCertificate(signatureName);
23631 var thisManager = this;
23632 if (foundCert == null) {
23633 var certificateInterest = new Interest(signatureName);
23634 var onCertificateDownloadComplete = function(data) {
23635 var certificate;
23636 try {
23637 certificate = new IdentityCertificate(data);
23638 } catch (ex) {
23639 try {
23640 onValidationFailed
23641 (dataOrInterest, "Cannot decode certificate " + data.getName().toUri());
23642 } catch (ex) {
23643 console.log("Error in onValidationFailed: " + NdnCommon.getErrorWithStackTrace(ex));
23644 }
23645 return null;
23646 }
23647 thisManager.certificateCache.insertCertificate(certificate);
23648 thisManager.checkVerificationPolicy
23649 (dataOrInterest, stepCount + 1, onVerified, onValidationFailed);
23650 };
23651
23652 var nextStep = new ValidationRequest
23653 (certificateInterest, onCertificateDownloadComplete, onValidationFailed,
23654 2, stepCount + 1);
23655
23656 return nextStep;
23657 }
23658
23659 // For interests, we must check that the timestamp is fresh enough.
23660 // We do this after (possibly) downloading the certificate to avoid
23661 // filling the cache with bad keys.
23662 if (dataOrInterest instanceof Interest) {
23663 var keyName = foundCert.getPublicKeyName();
23664 var timestamp = dataOrInterest.getName().get(-4).toNumber();
23665
23666 if (!this.interestTimestampIsFresh(keyName, timestamp, failureReason)) {
23667 try {
23668 onValidationFailed(dataOrInterest, failureReason[0]);
23669 } catch (ex) {
23670 console.log("Error in onValidationFailed: " + NdnCommon.getErrorWithStackTrace(ex));
23671 }
23672 return null;
23673 }
23674 }
23675
23676 // Certificate is known, so verify the signature.
23677 this.verify(signature, dataOrInterest.wireEncode(), function (verified, reason) {
23678 if (verified) {
23679 try {
23680 onVerified(dataOrInterest);
23681 } catch (ex) {
23682 console.log("Error in onVerified: " + NdnCommon.getErrorWithStackTrace(ex));
23683 }
23684 if (dataOrInterest instanceof Interest)
23685 thisManager.updateTimestampForKey(keyName, timestamp);
23686 }
23687 else {
23688 try {
23689 onValidationFailed(dataOrInterest, reason);
23690 } catch (ex) {
23691 console.log("Error in onValidationFailed: " + NdnCommon.getErrorWithStackTrace(ex));
23692 }
23693 }
23694 });
23695};
23696
23697/**
23698 * The configuration file allows 'trust anchor' certificates to be preloaded.
23699 * The certificates may also be loaded from a directory, and if the 'refresh'
23700 * option is set to an interval, the certificates are reloaded at the specified
23701 * interval.
23702 */
23703ConfigPolicyManager.prototype.loadTrustAnchorCertificates = function()
23704{
23705 var anchors = this.config.getRoot().get("validator/trust-anchor");
23706
23707 for (var i = 0; i < anchors.length; ++i) {
23708 var anchor = anchors[i];
23709
23710 var typeName = anchor.get("type")[0].getValue();
23711 var isPath = false;
23712 var certID;
23713 if (typeName == 'file') {
23714 certID = anchor.get("file-name")[0].getValue();
23715 isPath = true;
23716 }
23717 else if (typeName == 'base64') {
23718 certID = anchor.get("base64-string")[0].getValue();
23719 isPath = false;
23720 }
23721 else if (typeName == "dir") {
23722 var dirName = anchor.get("dir")[0].getValue();
23723
23724 var refreshPeriod = 0;
23725 var refreshTrees = anchor.get("refresh");
23726 if (refreshTrees.length >= 1) {
23727 var refreshPeriodStr = refreshTrees[0].getValue();
23728
23729 var refreshMatch = refreshPeriodStr.match(/(\d+)([hms])/);
23730 if (refreshMatch == null)
23731 refreshPeriod = 0;
23732 else {
23733 refreshPeriod = parseInt(refreshMatch[1]);
23734 if (refreshMatch[2] != 's') {
23735 refreshPeriod *= 60;
23736 if (refreshMatch[2] != 'm')
23737 refreshPeriod *= 60;
23738 }
23739 }
23740 }
23741
23742 // Convert refreshPeriod from seconds to milliseconds.
23743 this.refreshManager.addDirectory(dirName, refreshPeriod * 1000);
23744 continue;
23745 }
23746 else if (typeName == "any") {
23747 // This disables all security!
23748 this.requiresVerification = false;
23749 break;
23750 }
23751
23752 this.lookupCertificate(certID, isPath);
23753 }
23754};
23755
23756/**
23757 * Once a rule is found to match data or a signed interest, the name in the
23758 * KeyLocator must satisfy the condition in the 'checker' section of the rule,
23759 * else the data or interest is rejected.
23760 * @param {Name} signatureName The certificate name from the KeyLocator.
23761 * @param {Name} objectName The name of the data packet or interest. In the case
23762 * of signed interests, this excludes the timestamp, nonce and signature
23763 * components.
23764 * @param {BoostInfoTree} rule The rule from the configuration file that matches
23765 * the data or interest.
23766 * @param {Array<string>} failureReason If matching fails, set failureReason[0]
23767 * to the failure reason.
23768 * @return {boolean} True if matches.
23769 */
23770ConfigPolicyManager.prototype.checkSignatureMatch = function
23771 (signatureName, objectName, rule, failureReason)
23772{
23773 var checker = rule.get("checker")[0];
23774 var checkerType = checker.get("type")[0].getValue();
23775 if (checkerType == "fixed-signer") {
23776 var signerInfo = checker.get("signer")[0];
23777 var signerType = signerInfo.get("type")[0].getValue();
23778
23779 var cert;
23780 if (signerType == "file") {
23781 cert = this.lookupCertificate
23782 (signerInfo.get("file-name")[0].getValue(), true);
23783 if (cert == null) {
23784 failureReason[0] = "Can't find fixed-signer certificate file: " +
23785 signerInfo.get("file-name")[0].getValue();
23786 return false;
23787 }
23788 }
23789 else if (signerType == "base64") {
23790 cert = this.lookupCertificate
23791 (signerInfo.get("base64-string")[0].getValue(), false);
23792 if (cert == null) {
23793 failureReason[0] = "Can't find fixed-signer certificate base64: " +
23794 signerInfo.get("base64-string")[0].getValue();
23795 return false;
23796 }
23797 }
23798 else {
23799 failureReason[0] = "Unrecognized fixed-signer signerType: " + signerType;
23800 return false;
23801 }
23802
23803 if (cert.getName().equals(signatureName))
23804 return true;
23805 else {
23806 failureReason[0] = "fixed-signer cert name \"" + cert.getName().toUri() +
23807 "\" does not equal signatureName \"" + signatureName.toUri() + "\"";
23808 return false;
23809 }
23810 }
23811 else if (checkerType == "hierarchical") {
23812 // This just means the data/interest name has the signing identity as a prefix.
23813 // That means everything before "ksk-?" in the key name.
23814 var identityRegex = "^([^<KEY>]*)<KEY>(<>*)<ksk-.+><ID-CERT>";
23815 var identityMatch = NdnRegexMatcher.match(identityRegex, signatureName);
23816 if (identityMatch != null) {
23817 var identityPrefix = new Name(identityMatch[1]).append
23818 (new Name(identityMatch[2]));
23819 if (ConfigPolicyManager.matchesRelation
23820 (objectName, identityPrefix, "is-prefix-of"))
23821 return true;
23822 else {
23823 failureReason[0] = "The hierarchical objectName \"" + objectName.toUri() +
23824 "\" is not a prefix of \"" + identityPrefix.toUri() + "\"";
23825 return false;
23826 }
23827 }
23828 else {
23829 failureReason[0] = "The hierarchical identityRegex \"" + identityRegex +
23830 "\" does not match signatureName \"" + signatureName.toUri() + "\"";
23831 return false;
23832 }
23833 }
23834 else if (checkerType == "customized") {
23835 var keyLocatorInfo = checker.get("key-locator")[0];
23836 // Not checking type - only name is supported.
23837
23838 // Is this a simple relation?
23839 var relationType = keyLocatorInfo.getFirstValue("relation");
23840 if (relationType != null) {
23841 var matchName = new Name(keyLocatorInfo.get("name")[0].getValue());
23842 if (ConfigPolicyManager.matchesRelation
23843 (signatureName, matchName, relationType))
23844 return true;
23845 else {
23846 failureReason[0] = "The custom signatureName \"" + signatureName.toUri() +
23847 "\" does not match matchName \"" + matchName.toUri() +
23848 "\" using relation " + relationType;
23849 return false;
23850 }
23851 }
23852
23853 // Is this a simple regex?
23854 var keyRegex = keyLocatorInfo.getFirstValue("regex");
23855 if (keyRegex != null) {
23856 if (NdnRegexMatcher.match(keyRegex, signatureName) != null)
23857 return true;
23858 else {
23859 failureReason[0] = "The custom signatureName \"" + signatureName.toUri() +
23860 "\" does not regex match simpleKeyRegex \"" + keyRegex + "\"";
23861 return false;
23862 }
23863 }
23864
23865 // Is this a hyper-relation?
23866 var hyperRelationList = keyLocatorInfo.get("hyper-relation");
23867 if (hyperRelationList.length >= 1) {
23868 var hyperRelation = hyperRelationList[0];
23869
23870 var keyRegex = hyperRelation.getFirstValue("k-regex");
23871 var keyExpansion = hyperRelation.getFirstValue("k-expand");
23872 var nameRegex = hyperRelation.getFirstValue("p-regex");
23873 var nameExpansion = hyperRelation.getFirstValue("p-expand");
23874 var relationType = hyperRelation.getFirstValue("h-relation");
23875 if (keyRegex != null && keyExpansion != null && nameRegex != null &&
23876 nameExpansion != null && relationType != null) {
23877 var keyMatch = NdnRegexMatcher.match(keyRegex, signatureName);
23878 if (keyMatch == null || keyMatch[1] === undefined) {
23879 failureReason[0] = "The custom hyper-relation signatureName \"" +
23880 signatureName.toUri() + "\" does not match the keyRegex \"" +
23881 keyRegex + "\"";
23882 return false;
23883 }
23884 var keyMatchPrefix = ConfigPolicyManager.expand(keyMatch, keyExpansion);
23885
23886 var nameMatch = NdnRegexMatcher.match(nameRegex, objectName);
23887 if (nameMatch == null || nameMatch[1] === undefined) {
23888 failureReason[0] = "The custom hyper-relation objectName \"" +
23889 objectName.toUri() + "\" does not match the nameRegex \"" +
23890 nameRegex + "\"";
23891 return false;
23892 }
23893 var nameMatchStr = ConfigPolicyManager.expand(nameMatch, nameExpansion);
23894
23895 if (ConfigPolicyManager.matchesRelation
23896 (new Name(nameMatchStr), new Name(keyMatchPrefix), relationType))
23897 return true;
23898 else {
23899 failureReason[0] = "The custom hyper-relation nameMatch \"" +
23900 nameMatchStr + "\" does not match the keyMatchPrefix \"" +
23901 keyMatchPrefix + "\" using relation " + relationType;
23902 return false;
23903 }
23904 }
23905 }
23906 }
23907
23908 failureReason[0] = "Unrecognized checkerType: " + checkerType;
23909 return false;
23910};
23911
23912/**
23913 * Similar to Python expand, return expansion where every \1, \2, etc. is
23914 * replaced by match[1], match[2], etc. Note: Even though this is a general
23915 * utility function, we define it locally because it is only tested to work in
23916 * the cases used by this class.
23917 * @param {Object} match The match object from String.match.
23918 * @param {string} expansion The string with \1, \2, etc. to replace from match.
23919 * @return {string} The expanded string.
23920 */
23921ConfigPolicyManager.expand = function(match, expansion)
23922{
23923 return expansion.replace
23924 (/\\(\d)/g,
23925 function(fullMatch, n) { return match[parseInt(n)];})
23926};
23927
23928/**
23929 * This looks up certificates specified as base64-encoded data or file names.
23930 * These are cached by filename or encoding to avoid repeated reading of files
23931 * or decoding.
23932 * @param {string} certID
23933 * @param {boolean} isPath
23934 * @return {IdentityCertificate} The certificate object, or null if not found.
23935 */
23936ConfigPolicyManager.prototype.lookupCertificate = function(certID, isPath)
23937{
23938 var cert;
23939
23940 var cachedCertUri = this.fixedCertificateCache[certID];
23941 if (cachedCertUri === undefined) {
23942 if (isPath)
23943 // load the certificate data (base64 encoded IdentityCertificate)
23944 cert = ConfigPolicyManager.TrustAnchorRefreshManager.loadIdentityCertificateFromFile
23945 (certID);
23946 else {
23947 var certData = new Buffer(certID, 'base64');
23948 cert = new IdentityCertificate();
23949 cert.wireDecode(certData);
23950 }
23951
23952 var certUri = cert.getName().getPrefix(-1).toUri();
23953 this.fixedCertificateCache[certID] = certUri;
23954 this.certificateCache.insertCertificate(cert);
23955 }
23956 else
23957 cert = this.certificateCache.getCertificate(new Name(cachedCertUri));
23958
23959 return cert;
23960};
23961
23962/**
23963 * Search the configuration file for the first rule that matches the data or
23964 * signed interest name. In the case of interests, the name to match should
23965 * exclude the timestamp, nonce, and signature components.
23966 * @param {Name} objName The name to be matched.
23967 * @param {string} matchType The rule type to match, "data" or "interest".
23968 * @return {BoostInfoTree} The matching rule, or null if not found.
23969 */
23970ConfigPolicyManager.prototype.findMatchingRule = function(objName, matchType)
23971{
23972 var rules = this.config.getRoot().get("validator/rule");
23973 for (var iRule = 0; iRule < rules.length; ++iRule) {
23974 var r = rules[iRule];
23975
23976 if (r.get('for')[0].getValue() == matchType) {
23977 var passed = true;
23978 var filters = r.get('filter');
23979 if (filters.length == 0)
23980 // No filters means we pass!
23981 return r;
23982 else {
23983 for (var iFilter = 0; iFilter < filters.length; ++iFilter) {
23984 var f = filters[iFilter];
23985
23986 // Don't check the type - it can only be name for now.
23987 // We need to see if this is a regex or a relation.
23988 var regexPattern = f.getFirstValue("regex");
23989 if (regexPattern === null) {
23990 var matchRelation = f.get('relation')[0].getValue();
23991 var matchUri = f.get('name')[0].getValue();
23992 var matchName = new Name(matchUri);
23993 passed = ConfigPolicyManager.matchesRelation(objName, matchName, matchRelation);
23994 }
23995 else
23996 passed = (NdnRegexMatcher.match(regexPattern, objName) !== null);
23997
23998 if (!passed)
23999 break;
24000 }
24001
24002 if (passed)
24003 return r;
24004 }
24005 }
24006 }
24007
24008 return null;
24009};
24010
24011/**
24012 * Determines if a name satisfies the relation to matchName.
24013 * @param {Name} name
24014 * @param {Name} matchName
24015 * @param {string} matchRelation Can be one of:
24016 * 'is-prefix-of' - passes if the name is equal to or has the other
24017 * name as a prefix
24018 * 'is-strict-prefix-of' - passes if the name has the other name as a
24019 * prefix, and is not equal
24020 * 'equal' - passes if the two names are equal
24021 * @return {boolean}
24022 */
24023ConfigPolicyManager.matchesRelation = function(name, matchName, matchRelation)
24024{
24025 var passed = false;
24026 if (matchRelation == 'is-strict-prefix-of') {
24027 if (matchName.size() == name.size())
24028 passed = false;
24029 else if (matchName.match(name))
24030 passed = true;
24031 }
24032 else if (matchRelation == 'is-prefix-of') {
24033 if (matchName.match(name))
24034 passed = true;
24035 }
24036 else if (matchRelation == 'equal') {
24037 if (matchName.equals(name))
24038 passed = true;
24039 }
24040 return passed;
24041};
24042
24043/**
24044 * Extract the signature information from the interest name or from the data
24045 * packet or interest.
24046 * @param {Data|Interest} dataOrInterest The object whose signature is needed.
24047 * @param {WireFormat} wireFormat (optional) The wire format used to decode
24048 * signature information from the interest name.
24049 * @return {Signature} The object of a sublcass of Signature or null if can't
24050 * decode.
24051 */
24052ConfigPolicyManager.extractSignature = function(dataOrInterest, wireFormat)
24053{
24054 if (dataOrInterest instanceof Data)
24055 return dataOrInterest.getSignature();
24056 else if (dataOrInterest instanceof Interest) {
24057 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
24058 try {
24059 var signature = wireFormat.decodeSignatureInfoAndValue
24060 (dataOrInterest.getName().get(-2).getValue().buf(),
24061 dataOrInterest.getName().get(-1).getValue().buf(), false);
24062 }
24063 catch (e) {
24064 return null;
24065 }
24066
24067 return signature;
24068 }
24069
24070 return null;
24071};
24072
24073/**
24074 * Determine whether the timestamp from the interest is newer than the last use
24075 * of this key, or within the grace interval on first use.
24076 * @param {Name} keyName The name of the public key used to sign the interest.
24077 * @param {number} timestamp The timestamp extracted from the interest name.
24078 * @param {Array<string>} failureReason If matching fails, set failureReason[0]
24079 * to the failure reason.
24080 * @return {boolean} True if timestamp is fresh as described above.
24081 */
24082ConfigPolicyManager.prototype.interestTimestampIsFresh = function
24083 (keyName, timestamp, failureReason)
24084{
24085 var lastTimestamp = this.keyTimestamps[keyName.toUri()];
24086 if (lastTimestamp == undefined) {
24087 var now = new Date().getTime();
24088 var notBefore = now - this.keyGraceInterval;
24089 var notAfter = now + this.keyGraceInterval;
24090 if (!(timestamp > notBefore && timestamp < notAfter)) {
24091 failureReason[0] =
24092 "The command interest timestamp is not within the first use grace period of " +
24093 this.keyGraceInterval + " milliseconds.";
24094 return false;
24095 }
24096 else
24097 return true;
24098 }
24099 else {
24100 if (timestamp <= lastTimestamp) {
24101 failureReason[0] =
24102 "The command interest timestamp is not newer than the previous timestamp";
24103 return false;
24104 }
24105 else
24106 return true;
24107 }
24108};
24109
24110/**
24111 * Trim the table size down if necessary, and insert/update the latest interest
24112 * signing timestamp for the key. Any key which has not been used within the TTL
24113 * period is purged. If the table is still too large, the oldest key is purged.
24114 * @param {Name} keyName The name of the public key used to sign the interest.
24115 * @param {number} timestamp The timestamp extracted from the interest name.
24116 */
24117ConfigPolicyManager.prototype.updateTimestampForKey = function
24118 (keyName, timestamp)
24119{
24120 this.keyTimestamps[keyName.toUri()] = timestamp;
24121
24122 // JavaScript does have a direct way to get the number of entries, so first
24123 // get the keysToErase while counting.
24124 var keyTimestampsSize = 0;
24125 var keysToErase = [];
24126
24127 var now = new Date().getTime();
24128 var oldestTimestamp = now;
24129 var oldestKey = null;
24130 for (var keyUri in this.keyTimestamps) {
24131 ++keyTimestampsSize;
24132 var ts = this.keyTimestamps[keyUri];
24133 if (now - ts > this.keyTimestampTtl)
24134 keysToErase.push(keyUri);
24135 else if (ts < oldestTimestamp) {
24136 oldestTimestamp = ts;
24137 oldestKey = keyUri;
24138 }
24139 }
24140
24141 if (keyTimestampsSize >= this.maxTrackedKeys) {
24142 // Now delete the expired keys.
24143 for (var i = 0; i < keysToErase.length; ++i) {
24144 delete this.keyTimestamps[keysToErase[i]];
24145 --keyTimestampsSize;
24146 }
24147
24148 if (keyTimestampsSize > this.maxTrackedKeys)
24149 // We have not removed enough.
24150 delete this.keyTimestamps[oldestKey];
24151 }
24152};
24153
24154/**
24155 * Check the type of signatureInfo to get the KeyLocator. Look in the
24156 * IdentityStorage for the public key with the name in the KeyLocator and use it
24157 * to verify the signedBlob. If the public key can't be found, return false.
24158 * (This is a generalized method which can verify both a data packet and an
24159 * interest.)
24160 * @param {Signature} signatureInfo An object of a subclass of Signature, e.g.
24161 * Sha256WithRsaSignature.
24162 * @param {SignedBlob} signedBlob The SignedBlob with the signed portion to
24163 * verify.
24164 * @param {function} onComplete This calls onComplete(true, undefined) if the
24165 * signature verifies, otherwise onComplete(false, reason).
24166 */
24167ConfigPolicyManager.prototype.verify = function
24168 (signatureInfo, signedBlob, onComplete)
24169{
24170 // We have already checked once that there is a key locator.
24171 var keyLocator = KeyLocator.getFromSignature(signatureInfo);
24172
24173 if (keyLocator.getType() == KeyLocatorType.KEYNAME) {
24174 // Assume the key name is a certificate name.
24175 var signatureName = keyLocator.getKeyName();
24176 var certificate = this.refreshManager.getCertificate(signatureName);
24177 if (certificate == null)
24178 certificate = this.certificateCache.getCertificate(signatureName);
24179 if (certificate == null) {
24180 onComplete(false, "Cannot find a certificate with name " +
24181 signatureName.toUri());
24182 return;
24183 }
24184
24185 var publicKeyDer = certificate.getPublicKeyInfo().getKeyDer();
24186 if (publicKeyDer.isNull()) {
24187 // Can't find the public key with the name.
24188 onComplete(false, "There is no public key in the certificate with name " +
24189 certificate.getName().toUri());
24190 return;
24191 }
24192
24193 PolicyManager.verifySignature
24194 (signatureInfo, signedBlob, publicKeyDer, function(verified) {
24195 if (verified)
24196 onComplete(true);
24197 else
24198 onComplete
24199 (false,
24200 "The signature did not verify with the given public key");
24201 });
24202 }
24203 else
24204 onComplete(false, "The KeyLocator does not have a key name");
24205};
24206
24207ConfigPolicyManager.TrustAnchorRefreshManager =
24208 function ConfigPolicyManagerTrustAnchorRefreshManager()
24209{
24210 this.certificateCache = new CertificateCache();
24211 // Maps the directory name to certificate names so they can be deleted when
24212 // necessary. The key is the directory name string. The value is the object
24213 // {certificateNames, // array of string
24214 // nextRefresh, // number
24215 // refreshPeriod // number
24216 // }.
24217 this.refreshDirectories = {};
24218};
24219
24220ConfigPolicyManager.TrustAnchorRefreshManager.loadIdentityCertificateFromFile =
24221 function(fileName)
24222{
24223 var encodedData = fs.readFileSync(fileName).toString();
24224 var decodedData = new Buffer(encodedData, 'base64');
24225 var cert = new IdentityCertificate();
24226 cert.wireDecode(new Blob(decodedData, false));
24227 return cert;
24228};
24229
24230ConfigPolicyManager.TrustAnchorRefreshManager.prototype.getCertificate = function
24231 (certificateName)
24232{
24233 // This assumes the timestamp is already removed.
24234 return this.certificateCache.getCertificate(certificateName);
24235};
24236
24237// refreshPeriod in milliseconds.
24238ConfigPolicyManager.TrustAnchorRefreshManager.prototype.addDirectory = function
24239 (directoryName, refreshPeriod)
24240{
24241 var allFiles;
24242 try {
24243 allFiles = fs.readdirSync(directoryName);
24244 }
24245 catch (e) {
24246 throw new SecurityException(new Error
24247 ("Cannot list files in directory " + directoryName));
24248 }
24249
24250 var certificateNames = [];
24251 for (var i = 0; i < allFiles.length; ++i) {
24252 var cert;
24253 try {
24254 var fullPath = path.join(directoryName, allFiles[i]);
24255 cert = ConfigPolicyManager.TrustAnchorRefreshManager.loadIdentityCertificateFromFile
24256 (fullPath);
24257 }
24258 catch (e) {
24259 // Allow files that are not certificates.
24260 continue;
24261 }
24262
24263 // Cut off the timestamp so it matches the KeyLocator Name format.
24264 var certUri = cert.getName().getPrefix(-1).toUri();
24265 this.certificateCache.insertCertificate(cert);
24266 certificateNames.push(certUri);
24267 }
24268
24269 this.refreshDirectories[directoryName] = {
24270 certificates: certificateNames,
24271 nextRefresh: new Date().getTime() + refreshPeriod,
24272 refreshPeriod: refreshPeriod };
24273};
24274
24275ConfigPolicyManager.TrustAnchorRefreshManager.prototype.refreshAnchors = function()
24276{
24277 var refreshTime = new Date().getTime();
24278 for (var directory in this.refreshDirectories) {
24279 var info = this.refreshDirectories[directory];
24280 var nextRefreshTime = info.nextRefresh;
24281 if (nextRefreshTime <= refreshTime) {
24282 var certificateList = info.certificates.slice(0);
24283 // Delete the certificates associated with this directory if possible
24284 // then re-import.
24285 // IdentityStorage subclasses may not support deletion.
24286 for (var c in certificateList)
24287 this.certificateCache.deleteCertificate(new Name(c));
24288
24289 this.addDirectory(directory, info.refreshPeriod);
24290 }
24291 }
24292};
24293/**
24294 * Copyright (C) 2014-2016 Regents of the University of California.
24295 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
24296 * From ndn-cxx security by Yingdi Yu <yingdi@cs.ucla.edu>.
24297 *
24298 * This program is free software: you can redistribute it and/or modify
24299 * it under the terms of the GNU Lesser General Public License as published by
24300 * the Free Software Foundation, either version 3 of the License, or
24301 * (at your option) any later version.
24302 *
24303 * This program is distributed in the hope that it will be useful,
24304 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24305 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24306 * GNU Lesser General Public License for more details.
24307 *
24308 * You should have received a copy of the GNU Lesser General Public License
24309 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24310 * A copy of the GNU Lesser General Public License is in the file COPYING.
24311 */
24312
24313/** @ignore */
24314var Name = require('../../name.js').Name; /** @ignore */
24315var PolicyManager = require('./policy-manager.js').PolicyManager; /** @ignore */
24316var NdnCommon = require('../../util/ndn-common.js').NdnCommon;
24317
24318/**
24319 * @constructor
24320 */
24321var NoVerifyPolicyManager = function NoVerifyPolicyManager()
24322{
24323 // Call the base constructor.
24324 PolicyManager.call(this);
24325};
24326
24327NoVerifyPolicyManager.prototype = new PolicyManager();
24328NoVerifyPolicyManager.prototype.name = "NoVerifyPolicyManager";
24329
24330exports.NoVerifyPolicyManager = NoVerifyPolicyManager;
24331
24332/**
24333 * Override to always skip verification and trust as valid.
24334 *
24335 * @param {Data|Interest} dataOrInterest The received data packet or interest.
24336 * @return {boolean} True.
24337 */
24338NoVerifyPolicyManager.prototype.skipVerifyAndTrust = function(dataOrInterest)
24339{
24340 return true;
24341};
24342
24343/**
24344 * Override to return false for no verification rule for the received data or
24345 * signed interest.
24346 *
24347 * @param {Data|Interest} dataOrInterest The received data packet or interest.
24348 * @return {boolean} False.
24349 */
24350NoVerifyPolicyManager.prototype.requireVerify = function(dataOrInterest)
24351{
24352 return false;
24353};
24354
24355/**
24356 * Override to call onVerified(data) and to indicate no further verification
24357 * step.
24358 *
24359 * @param {Data|Interest} dataOrInterest The Data object or interest with the
24360 * signature to check.
24361 * @param {number} stepCount The number of verification steps that have been
24362 * done, used to track the verification progress.
24363 * @param {function} onVerified This does override to call
24364 * onVerified(dataOrInterest).
24365 * NOTE: The library will log any exceptions thrown by this callback, but for
24366 * better error handling the callback should catch and properly handle any
24367 * exceptions.
24368 * @param {function} onValidationFailed Override to ignore this.
24369 * @param {WireFormat} wireFormat
24370 * @return {ValidationRequest} null for no further step for looking up a
24371 * certificate chain.
24372 */
24373NoVerifyPolicyManager.prototype.checkVerificationPolicy = function
24374 (dataOrInterest, stepCount, onVerified, onValidationFailed, wireFormat)
24375{
24376 try {
24377 onVerified(dataOrInterest);
24378 } catch (ex) {
24379 console.log("Error in onVerified: " + NdnCommon.getErrorWithStackTrace(ex));
24380 }
24381 return null;
24382};
24383
24384/**
24385 * Override to always indicate that the signing certificate name and data name
24386 * satisfy the signing policy.
24387 *
24388 * @param {Name} dataName The name of data to be signed.
24389 * @param {Name} certificateName The name of signing certificate.
24390 * @return {boolean} True to indicate that the signing certificate can be used
24391 * to sign the data.
24392 */
24393NoVerifyPolicyManager.prototype.checkSigningPolicy = function
24394 (dataName, certificateName)
24395{
24396 return true;
24397};
24398
24399/**
24400 * Override to indicate that the signing identity cannot be inferred.
24401 *
24402 * @param {Name} dataName The name of data to be signed.
24403 * @return {Name} An empty name because cannot infer.
24404 */
24405NoVerifyPolicyManager.prototype.inferSigningIdentity = function(dataName)
24406{
24407 return new Name();
24408};
24409/**
24410 * Copyright (C) 2014-2016 Regents of the University of California.
24411 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
24412 * From ndn-cxx security by Yingdi Yu <yingdi@cs.ucla.edu>.
24413 *
24414 * This program is free software: you can redistribute it and/or modify
24415 * it under the terms of the GNU Lesser General Public License as published by
24416 * the Free Software Foundation, either version 3 of the License, or
24417 * (at your option) any later version.
24418 *
24419 * This program is distributed in the hope that it will be useful,
24420 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24421 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24422 * GNU Lesser General Public License for more details.
24423 *
24424 * You should have received a copy of the GNU Lesser General Public License
24425 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24426 * A copy of the GNU Lesser General Public License is in the file COPYING.
24427 */
24428
24429/** @ignore */
24430var Name = require('../../name.js').Name; /** @ignore */
24431var Interest = require('../../interest.js').Interest; /** @ignore */
24432var Data = require('../../data.js').Data; /** @ignore */
24433var Blob = require('../../util/blob.js').Blob; /** @ignore */
24434var IdentityCertificate = require('../certificate/identity-certificate.js').IdentityCertificate; /** @ignore */
24435var KeyLocator = require('../../key-locator.js').KeyLocator; /** @ignore */
24436var KeyLocatorType = require('../../key-locator.js').KeyLocatorType; /** @ignore */
24437var SecurityException = require('../security-exception.js').SecurityException; /** @ignore */
24438var WireFormat = require('../../encoding/wire-format.js').WireFormat; /** @ignore */
24439var SyncPromise = require('../../util/sync-promise.js').SyncPromise; /** @ignore */
24440var PolicyManager = require('./policy-manager.js').PolicyManager; /** @ignore */
24441var NdnCommon = require('../../util/ndn-common.js').NdnCommon;
24442
24443/**
24444 * A SelfVerifyPolicyManager implements a PolicyManager to look in the
24445 * IdentityStorage for the public key with the name in the KeyLocator (if
24446 * available) and use it to verify the data packet, without searching a
24447 * certificate chain. If the public key can't be found, the verification fails.
24448 *
24449 * @param {IdentityStorage} identityStorage (optional) The IdentityStorage for
24450 * looking up the public key. This object must remain valid during the life of
24451 * this SelfVerifyPolicyManager. If omitted, then don't look for a public key
24452 * with the name in the KeyLocator and rely on the KeyLocator having the full
24453 * public key DER.
24454 * @constructor
24455 */
24456var SelfVerifyPolicyManager = function SelfVerifyPolicyManager(identityStorage)
24457{
24458 // Call the base constructor.
24459 PolicyManager.call(this);
24460
24461 this.identityStorage = identityStorage;
24462};
24463
24464SelfVerifyPolicyManager.prototype = new PolicyManager();
24465SelfVerifyPolicyManager.prototype.name = "SelfVerifyPolicyManager";
24466
24467exports.SelfVerifyPolicyManager = SelfVerifyPolicyManager;
24468
24469/**
24470 * Never skip verification.
24471 *
24472 * @param {Data|Interest} dataOrInterest The received data packet or interest.
24473 * @return {boolean} False.
24474 */
24475SelfVerifyPolicyManager.prototype.skipVerifyAndTrust = function(dataOrInterest)
24476{
24477 return false;
24478};
24479
24480/**
24481 * Always return true to use the self-verification rule for the received data.
24482 *
24483 * @param {Data|Interest} dataOrInterest The received data packet or interest.
24484 * @return {boolean} True.
24485 */
24486SelfVerifyPolicyManager.prototype.requireVerify = function(dataOrInterest)
24487{
24488 return true;
24489};
24490
24491/**
24492 * Look in the IdentityStorage for the public key with the name in the
24493 * KeyLocator (if available) and use it to verify the data packet. If the
24494 * public key can't be found, call onValidationFailed.
24495 *
24496 * @param {Data|Interest} dataOrInterest The Data object or interest with the
24497 * signature to check.
24498 * @param {number} stepCount The number of verification steps that have been
24499 * done, used to track the verification progress.
24500 * @param {function} onVerified If the signature is verified, this calls
24501 * onVerified(dataOrInterest).
24502 * NOTE: The library will log any exceptions thrown by this callback, but for
24503 * better error handling the callback should catch and properly handle any
24504 * exceptions.
24505 * @param {function} onValidationFailed If the signature check fails, this calls
24506 * onValidationFailed(dataOrInterest, reason).
24507 * NOTE: The library will log any exceptions thrown by this callback, but for
24508 * better error handling the callback should catch and properly handle any
24509 * exceptions.
24510 * @param {WireFormat} wireFormat
24511 * @return {ValidationRequest} null for no further step for looking up a
24512 * certificate chain.
24513 */
24514SelfVerifyPolicyManager.prototype.checkVerificationPolicy = function
24515 (dataOrInterest, stepCount, onVerified, onValidationFailed, wireFormat)
24516{
24517 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
24518
24519 if (dataOrInterest instanceof Data) {
24520 var data = dataOrInterest;
24521 // wireEncode returns the cached encoding if available.
24522 this.verify(data.getSignature(), data.wireEncode(), function(verified, reason) {
24523 if (verified) {
24524 try {
24525 onVerified(data);
24526 } catch (ex) {
24527 console.log("Error in onVerified: " + NdnCommon.getErrorWithStackTrace(ex));
24528 }
24529 }
24530 else {
24531 try {
24532 onValidationFailed(data, reason);
24533 } catch (ex) {
24534 console.log("Error in onValidationFailed: " + NdnCommon.getErrorWithStackTrace(ex));
24535 }
24536 }
24537 });
24538 }
24539 else if (dataOrInterest instanceof Interest) {
24540 var interest = dataOrInterest;
24541
24542 if (interest.getName().size() < 2) {
24543 try {
24544 onValidationFailed
24545 (interest, "The signed interest has less than 2 components: " +
24546 interest.getName().toUri());
24547 } catch (ex) {
24548 console.log("Error in onValidationFailed: " + NdnCommon.getErrorWithStackTrace(ex));
24549 }
24550 return;
24551 }
24552
24553 // Decode the last two name components of the signed interest
24554 var signature;
24555 try {
24556 signature = wireFormat.decodeSignatureInfoAndValue
24557 (interest.getName().get(-2).getValue().buf(),
24558 interest.getName().get(-1).getValue().buf(), false);
24559 } catch (ex) {
24560 try {
24561 onValidationFailed
24562 (interest, "Error decoding the signed interest signature: " + ex);
24563 } catch (ex) {
24564 console.log("Error in onValidationFailed: " + NdnCommon.getErrorWithStackTrace(ex));
24565 }
24566 return;
24567 }
24568
24569 // wireEncode returns the cached encoding if available.
24570 this.verify(signature, interest.wireEncode(), function(verified, reason) {
24571 if (verified) {
24572 try {
24573 onVerified(interest);
24574 } catch (ex) {
24575 console.log("Error in onVerified: " + NdnCommon.getErrorWithStackTrace(ex));
24576 }
24577 }
24578 else {
24579 try {
24580 onValidationFailed(interest, reason);
24581 } catch (ex) {
24582 console.log("Error in onValidationFailed: " + NdnCommon.getErrorWithStackTrace(ex));
24583 }
24584 }
24585 });
24586 }
24587 else
24588 throw new SecurityException(new Error
24589 ("checkVerificationPolicy: unrecognized type for dataOrInterest"));
24590
24591 // No more steps, so return null.
24592 return null;
24593};
24594
24595/**
24596 * Override to always indicate that the signing certificate name and data name
24597 * satisfy the signing policy.
24598 *
24599 * @param {Name} dataName The name of data to be signed.
24600 * @param {Name} certificateName The name of signing certificate.
24601 * @return {boolean} True to indicate that the signing certificate can be used
24602 * to sign the data.
24603 */
24604SelfVerifyPolicyManager.prototype.checkSigningPolicy = function
24605 (dataName, certificateName)
24606{
24607 return true;
24608};
24609
24610/**
24611 * Override to indicate that the signing identity cannot be inferred.
24612 *
24613 * @param {Name} dataName The name of data to be signed.
24614 * @return {Name} An empty name because cannot infer.
24615 */
24616SelfVerifyPolicyManager.prototype.inferSigningIdentity = function(dataName)
24617{
24618 return new Name();
24619};
24620
24621/**
24622 * Check the type of signatureInfo to get the KeyLocator. Look in the
24623 * IdentityStorage for the public key with the name in the KeyLocator (if
24624 * available) and use it to verify the signedBlob. If the public key can't be
24625 * found, return false. (This is a generalized method which can verify both a
24626 * Data packet and an interest.)
24627 * @param {Signature} signatureInfo An object of a subclass of Signature, e.g.
24628 * Sha256WithRsaSignature.
24629 * @param {SignedBlob} signedBlob the SignedBlob with the signed portion to
24630 * verify.
24631 * @param {function} onComplete This calls onComplete(true, undefined) if the
24632 * signature verifies, otherwise onComplete(false, reason).
24633 */
24634SelfVerifyPolicyManager.prototype.verify = function
24635 (signatureInfo, signedBlob, onComplete)
24636{
24637 if (KeyLocator.canGetFromSignature(signatureInfo)) {
24638 this.getPublicKeyDer
24639 (KeyLocator.getFromSignature(signatureInfo), function(publicKeyDer, reason) {
24640 if (publicKeyDer.isNull())
24641 onComplete(false, reason);
24642 else {
24643 try {
24644 PolicyManager.verifySignature
24645 (signatureInfo, signedBlob, publicKeyDer, function(verified) {
24646 if (verified)
24647 onComplete(true);
24648 else
24649 onComplete
24650 (false,
24651 "The signature did not verify with the given public key");
24652 });
24653 } catch (ex) {
24654 onComplete(false, "Error in verifySignature: " + ex);
24655 }
24656 }
24657 });
24658 }
24659 else {
24660 try {
24661 // Assume that the signature type does not require a public key.
24662 PolicyManager.verifySignature
24663 (signatureInfo, signedBlob, null, function(verified) {
24664 if (verified)
24665 onComplete(true);
24666 else
24667 onComplete
24668 (false, "The signature did not verify with the given public key");
24669 });
24670 } catch (ex) {
24671 onComplete(false, "Error in verifySignature: " + ex);
24672 }
24673 }
24674};
24675
24676/**
24677 * Look in the IdentityStorage for the public key with the name in the
24678 * KeyLocator (if available). If the public key can't be found, return and empty
24679 * Blob.
24680 * @param {KeyLocator} keyLocator The KeyLocator.
24681 * @param {function} onComplete This calls
24682 * onComplete(publicKeyDer, reason) where publicKeyDer is the public key
24683 * DER Blob or an isNull Blob if not found and reason is the reason
24684 * string if not found.
24685 */
24686SelfVerifyPolicyManager.prototype.getPublicKeyDer = function
24687 (keyLocator, onComplete)
24688{
24689 if (keyLocator.getType() == KeyLocatorType.KEYNAME &&
24690 this.identityStorage != null) {
24691 var keyName;
24692 try {
24693 // Assume the key name is a certificate name.
24694 keyName = IdentityCertificate.certificateNameToPublicKeyName
24695 (keyLocator.getKeyName());
24696 } catch (ex) {
24697 onComplete
24698 (new Blob(), "Cannot get a public key name from the certificate named: " +
24699 keyLocator.getKeyName().toUri());
24700 return;
24701 }
24702 SyncPromise.complete
24703 (onComplete,
24704 function(err) {
24705 // The storage doesn't have the key.
24706 onComplete
24707 (new Blob(), "The identityStorage doesn't have the key named " +
24708 keyName.toUri());
24709 },
24710 this.identityStorage.getKeyPromise(keyName));
24711 }
24712 else
24713 // Can't find a key to verify.
24714 onComplete(new Blob(), "The signature KeyLocator doesn't have a key name");
24715};
24716/**
24717 * Copyright (C) 2014-2016 Regents of the University of California.
24718 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
24719 * From ndn-cxx security by Yingdi Yu <yingdi@cs.ucla.edu>.
24720 *
24721 * This program is free software: you can redistribute it and/or modify
24722 * it under the terms of the GNU Lesser General Public License as published by
24723 * the Free Software Foundation, either version 3 of the License, or
24724 * (at your option) any later version.
24725 *
24726 * This program is distributed in the hope that it will be useful,
24727 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24728 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24729 * GNU Lesser General Public License for more details.
24730 *
24731 * You should have received a copy of the GNU Lesser General Public License
24732 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24733 * A copy of the GNU Lesser General Public License is in the file COPYING.
24734 */
24735
24736/** @ignore */
24737var Crypto = require('../crypto.js'); /** @ignore */
24738var Name = require('../name.js').Name; /** @ignore */
24739var Interest = require('../interest.js').Interest; /** @ignore */
24740var Data = require('../data.js').Data; /** @ignore */
24741var Blob = require('../util/blob.js').Blob; /** @ignore */
24742var WireFormat = require('../encoding/wire-format.js').WireFormat; /** @ignore */
24743var SecurityException = require('./security-exception.js').SecurityException; /** @ignore */
24744var RsaKeyParams = require('./key-params.js').RsaKeyParams; /** @ignore */
24745var IdentityCertificate = require('./certificate/identity-certificate.js').IdentityCertificate; /** @ignore */
24746var SyncPromise = require('../util/sync-promise.js').SyncPromise; /** @ignore */
24747var NdnCommon = require('../util/ndn-common.js').NdnCommon; /** @ignore */
24748var IdentityManager = require('./identity/identity-manager.js').IdentityManager; /** @ignore */
24749var NoVerifyPolicyManager = require('./policy/no-verify-policy-manager.js').NoVerifyPolicyManager;
24750
24751/**
24752 * A KeyChain provides a set of interfaces to the security library such as
24753 * identity management, policy configuration and packet signing and verification.
24754 * Note: This class is an experimental feature. See the API docs for more detail at
24755 * http://named-data.net/doc/ndn-ccl-api/key-chain.html .
24756 *
24757 * Create a new KeyChain with the identityManager and policyManager.
24758 * @param {IdentityManager} identityManager (optional) The identity manager as a
24759 * subclass of IdentityManager. If omitted, use the default IdentityManager
24760 * constructor.
24761 * @param {PolicyManager} policyManager (optional) The policy manager as a
24762 * subclass of PolicyManager. If omitted, use NoVerifyPolicyManager.
24763 * @throws SecurityException if this is not in Node.js and this uses the default
24764 * IdentityManager constructor. (See IdentityManager for details.)
24765 * @constructor
24766 */
24767var KeyChain = function KeyChain(identityManager, policyManager)
24768{
24769 if (!identityManager)
24770 identityManager = new IdentityManager();
24771 if (!policyManager)
24772 policyManager = new NoVerifyPolicyManager();
24773
24774 this.identityManager = identityManager;
24775 this.policyManager = policyManager;
24776 this.face = null;
24777};
24778
24779exports.KeyChain = KeyChain;
24780
24781/*****************************************
24782 * Identity Management *
24783 *****************************************/
24784
24785/**
24786 * Create an identity by creating a pair of Key-Signing-Key (KSK) for this
24787 * identity and a self-signed certificate of the KSK. If a key pair or
24788 * certificate for the identity already exists, use it.
24789 * @param {Name} identityName The name of the identity.
24790 * @param {KeyParams} params (optional) The key parameters if a key needs to be
24791 * generated for the identity. If omitted, use KeyChain.DEFAULT_KEY_PARAMS.
24792 * @param {function} onComplete (optional) This calls onComplete(certificateName)
24793 * with name of the default certificate of the identity. If omitted, the return
24794 * value is described below. (Some crypto libraries only use a callback, so
24795 * onComplete is required to use these.)
24796 * NOTE: The library will log any exceptions thrown by this callback, but for
24797 * better error handling the callback should catch and properly handle any
24798 * exceptions.
24799 * @param {function} onError (optional) If defined, then onComplete must be
24800 * defined and if there is an exception, then this calls onError(exception)
24801 * with the exception. If onComplete is defined but onError is undefined, then
24802 * this will log any thrown exception. (Some database libraries only use a
24803 * callback, so onError is required to be notified of an exception.)
24804 * NOTE: The library will log any exceptions thrown by this callback, but for
24805 * better error handling the callback should catch and properly handle any
24806 * exceptions.
24807 * @return {Name} If onComplete is omitted, return the name of the default
24808 * certificate of the identity. Otherwise, if onComplete is supplied then return
24809 * undefined and use onComplete as described above.
24810 */
24811KeyChain.prototype.createIdentityAndCertificate = function
24812 (identityName, params, onComplete, onError)
24813{
24814 onError = (typeof params === "function") ? onComplete : onError;
24815 onComplete = (typeof params === "function") ? params : onComplete;
24816 params = (typeof params === "function" || !params) ?
24817 KeyChain.DEFAULT_KEY_PARAMS : params;
24818
24819 return this.identityManager.createIdentityAndCertificate
24820 (identityName, params, onComplete, onError);
24821};
24822
24823/**
24824 * Create an identity by creating a pair of Key-Signing-Key (KSK) for this
24825 * identity and a self-signed certificate of the KSK. If a key pair or
24826 * certificate for the identity already exists, use it.
24827 * @deprecated Use createIdentityAndCertificate which returns the
24828 * certificate name instead of the key name. You can use
24829 * IdentityCertificate.certificateNameToPublicKeyName to convert the
24830 * certificate name to the key name.
24831 * @param {Name} identityName The name of the identity.
24832 * @param {KeyParams} params (optional) The key parameters if a key needs to be
24833 * generated for the identity. If omitted, use KeyChain.DEFAULT_KEY_PARAMS.
24834 * @return {Name} The key name of the auto-generated KSK of the identity.
24835 */
24836KeyChain.prototype.createIdentity = function(identityName, params)
24837{
24838 return IdentityCertificate.certificateNameToPublicKeyName
24839 (this.createIdentityAndCertificate(identityName, params));
24840};
24841
24842/**
24843 * Delete the identity from the public and private key storage. If the
24844 * identity to be deleted is the current default system default, this will not
24845 * delete the identity and will return immediately.
24846 * @param {Name} identityName The name of the identity.
24847 * @param {function} onComplete (optional) This calls onComplete() when the
24848 * operation is complete. If omitted, do not use it. (Some database libraries
24849 * only use a callback, so onComplete is required to use these.)
24850 * NOTE: The library will log any exceptions thrown by this callback, but for
24851 * better error handling the callback should catch and properly handle any
24852 * exceptions.
24853 * @param {function} onError (optional) If defined, then onComplete must be
24854 * defined and if there is an exception, then this calls onError(exception)
24855 * with the exception. If onComplete is defined but onError is undefined, then
24856 * this will log any thrown exception. (Some database libraries only use a
24857 * callback, so onError is required to be notified of an exception.)
24858 * NOTE: The library will log any exceptions thrown by this callback, but for
24859 * better error handling the callback should catch and properly handle any
24860 * exceptions.
24861 */
24862KeyChain.prototype.deleteIdentity = function
24863 (identityName, onComplete, onError)
24864{
24865 this.identityManager.deleteIdentity(identityName, onComplete, onError);
24866};
24867
24868/**
24869 * Get the default identity.
24870 * @param {function} onComplete (optional) This calls onComplete(identityName)
24871 * with name of the default identity. If omitted, the return value is described
24872 * below. (Some crypto libraries only use a callback, so onComplete is required
24873 * to use these.)
24874 * NOTE: The library will log any exceptions thrown by this callback, but for
24875 * better error handling the callback should catch and properly handle any
24876 * exceptions.
24877 * @param {function} onError (optional) If defined, then onComplete must be
24878 * defined and if there is an exception, then this calls onError(exception)
24879 * with the exception. If onComplete is defined but onError is undefined, then
24880 * this will log any thrown exception. (Some database libraries only use a
24881 * callback, so onError is required to be notified of an exception.)
24882 * @return {Name} If onComplete is omitted, return the name of the default
24883 * identity. Otherwise, if onComplete is supplied then return undefined and use
24884 * onComplete as described above.
24885 * NOTE: The library will log any exceptions thrown by this callback, but for
24886 * better error handling the callback should catch and properly handle any
24887 * exceptions.
24888 * @throws SecurityException if the default identity is not set. However, if
24889 * onComplete and onError are defined, then if there is an exception return
24890 * undefined and call onError(exception).
24891 */
24892KeyChain.prototype.getDefaultIdentity = function(onComplete, onError)
24893{
24894 return this.identityManager.getDefaultIdentity(onComplete, onError);
24895};
24896
24897/**
24898 * Get the default certificate name of the default identity, which will be used
24899 * when signing is based on identity and the identity is not specified.
24900 * @param {function} onComplete (optional) This calls onComplete(certificateName)
24901 * with name of the default certificate. If omitted, the return value is described
24902 * below. (Some crypto libraries only use a callback, so onComplete is required
24903 * to use these.)
24904 * NOTE: The library will log any exceptions thrown by this callback, but for
24905 * better error handling the callback should catch and properly handle any
24906 * exceptions.
24907 * @param {function} onError (optional) If defined, then onComplete must be
24908 * defined and if there is an exception, then this calls onError(exception)
24909 * with the exception. If onComplete is defined but onError is undefined, then
24910 * this will log any thrown exception. (Some database libraries only use a
24911 * callback, so onError is required to be notified of an exception.)
24912 * NOTE: The library will log any exceptions thrown by this callback, but for
24913 * better error handling the callback should catch and properly handle any
24914 * exceptions.
24915 * @return {Name} If onComplete is omitted, return the default certificate name.
24916 * Otherwise, if onComplete is supplied then return undefined and use onComplete
24917 * as described above.
24918 * @throws SecurityException if the default identity is not set or the default
24919 * key name for the identity is not set or the default certificate name for
24920 * the key name is not set. However, if onComplete and onError are defined, then
24921 * if there is an exception return undefined and call onError(exception).
24922 */
24923KeyChain.prototype.getDefaultCertificateName = function(onComplete, onError)
24924{
24925 return this.identityManager.getDefaultCertificateName(onComplete, onError);
24926};
24927
24928/**
24929 * Generate a pair of RSA keys for the specified identity.
24930 * @param {Name} identityName The name of the identity.
24931 * @param {boolean} isKsk (optional) true for generating a Key-Signing-Key (KSK),
24932 * false for a Data-Signing-Key (DSK). If omitted, generate a Data-Signing-Key.
24933 * @param {number} keySize (optional) The size of the key. If omitted, use a
24934 * default secure key size.
24935 * @return {Name} The generated key name.
24936 */
24937KeyChain.prototype.generateRSAKeyPair = function(identityName, isKsk, keySize)
24938{
24939 keySize = (typeof isKsk === "boolean") ? isKsk : keySize;
24940 isKsk = (typeof isKsk === "boolean") ? isKsk : false;
24941
24942 if (!keySize)
24943 keySize = 2048;
24944
24945 return this.identityManager.generateRSAKeyPair(identityName, isKsk, keySize);
24946};
24947
24948/**
24949 * Set a key as the default key of an identity. The identity name is inferred
24950 * from keyName.
24951 * @param {Name} keyName The name of the key.
24952 * @param {Name} identityNameCheck (optional) The identity name to check that the
24953 * keyName contains the same identity name. If an empty name, it is ignored.
24954 * @param {function} onComplete (optional) This calls onComplete() when complete.
24955 * (Some database libraries only use a callback, so onComplete is required to
24956 * use these.)
24957 * NOTE: The library will log any exceptions thrown by this callback, but for
24958 * better error handling the callback should catch and properly handle any
24959 * exceptions.
24960 * @param {function} onError (optional) If defined, then onComplete must be
24961 * defined and if there is an exception, then this calls onError(exception)
24962 * with the exception. If onComplete is defined but onError is undefined, then
24963 * this will log any thrown exception. (Some database libraries only use a
24964 * callback, so onError is required to be notified of an exception.)
24965 * NOTE: The library will log any exceptions thrown by this callback, but for
24966 * better error handling the callback should catch and properly handle any
24967 * exceptions.
24968 */
24969KeyChain.prototype.setDefaultKeyForIdentity = function
24970 (keyName, identityNameCheck, onComplete, onError)
24971{
24972 return this.identityManager.setDefaultKeyForIdentity
24973 (keyName, identityNameCheck, onComplete, onError);
24974};
24975
24976/**
24977 * Generate a pair of RSA keys for the specified identity and set it as default
24978 * key for the identity.
24979 * @param {Name} identityName The name of the identity.
24980 * @param {boolean} isKsk (optional) true for generating a Key-Signing-Key (KSK),
24981 * false for a Data-Signing-Key (DSK). If omitted, generate a Data-Signing-Key.
24982 * @param {number} keySize (optional) The size of the key. If omitted, use a
24983 * default secure key size.
24984 * @return {Name} The generated key name.
24985 */
24986KeyChain.prototype.generateRSAKeyPairAsDefault = function
24987 (identityName, isKsk, keySize)
24988{
24989 return this.identityManager.generateRSAKeyPairAsDefault
24990 (identityName, isKsk, keySize);
24991};
24992
24993/**
24994 * Create a public key signing request.
24995 * @param {Name} keyName The name of the key.
24996 * @return {Blob} The signing request data.
24997 */
24998KeyChain.prototype.createSigningRequest = function(keyName)
24999{
25000 return this.identityManager.getPublicKey(keyName).getKeyDer();
25001};
25002
25003/**
25004 * Install an identity certificate into the public key identity storage.
25005 * @param {IdentityCertificate} certificate The certificate to to added.
25006 * @param {function} onComplete (optional) This calls onComplete() when complete.
25007 * (Some database libraries only use a callback, so onComplete is required to
25008 * use these.)
25009 * NOTE: The library will log any exceptions thrown by this callback, but for
25010 * better error handling the callback should catch and properly handle any
25011 * exceptions.
25012 * @param {function} onError (optional) If defined, then onComplete must be
25013 * defined and if there is an exception, then this calls onError(exception)
25014 * with the exception. If onComplete is defined but onError is undefined, then
25015 * this will log any thrown exception. (Some database libraries only use a
25016 * callback, so onError is required to be notified of an exception.)
25017 * NOTE: The library will log any exceptions thrown by this callback, but for
25018 * better error handling the callback should catch and properly handle any
25019 * exceptions.
25020 */
25021KeyChain.prototype.installIdentityCertificate = function
25022 (certificate, onComplete, onError)
25023{
25024 this.identityManager.addCertificate(certificate, onComplete, onError);
25025};
25026
25027/**
25028 * Set the certificate as the default for its corresponding key.
25029 * @param {IdentityCertificate} certificate The certificate.
25030 * @param {function} onComplete (optional) This calls onComplete() when complete.
25031 * (Some database libraries only use a callback, so onComplete is required to
25032 * use these.)
25033 * NOTE: The library will log any exceptions thrown by this callback, but for
25034 * better error handling the callback should catch and properly handle any
25035 * exceptions.
25036 * @param {function} onError (optional) If defined, then onComplete must be
25037 * defined and if there is an exception, then this calls onError(exception)
25038 * with the exception. If onComplete is defined but onError is undefined, then
25039 * this will log any thrown exception. (Some database libraries only use a
25040 * callback, so onError is required to be notified of an exception.)
25041 * NOTE: The library will log any exceptions thrown by this callback, but for
25042 * better error handling the callback should catch and properly handle any
25043 * exceptions.
25044 */
25045KeyChain.prototype.setDefaultCertificateForKey = function
25046 (certificate, onComplete, onError)
25047{
25048 this.identityManager.setDefaultCertificateForKey
25049 (certificate, onComplete, onError);
25050};
25051
25052/**
25053 * Get a certificate which is still valid with the specified name.
25054 * @param {Name} certificateName The name of the requested certificate.
25055 * @param {function} onComplete (optional) This calls onComplete(certificate)
25056 * with the requested IdentityCertificate. If omitted, the return value is
25057 * described below. (Some crypto libraries only use a callback, so onComplete is
25058 * required to use these.)
25059 * NOTE: The library will log any exceptions thrown by this callback, but for
25060 * better error handling the callback should catch and properly handle any
25061 * exceptions.
25062 * @param {function} onError (optional) If defined, then onComplete must be
25063 * defined and if there is an exception, then this calls onError(exception)
25064 * with the exception. If onComplete is defined but onError is undefined, then
25065 * this will log any thrown exception. (Some database libraries only use a
25066 * callback, so onError is required to be notified of an exception.)
25067 * NOTE: The library will log any exceptions thrown by this callback, but for
25068 * better error handling the callback should catch and properly handle any
25069 * exceptions.
25070 * @return {IdentityCertificate} If onComplete is omitted, return the requested
25071 * certificate. Otherwise, if onComplete is supplied then return undefined and
25072 * use onComplete as described above.
25073 */
25074KeyChain.prototype.getCertificate = function
25075 (certificateName, onComplete, onError)
25076{
25077 return this.identityManager.getCertificate
25078 (certificateName, onComplete, onError);
25079};
25080
25081/**
25082 * @deprecated Use getCertificate.
25083 */
25084KeyChain.prototype.getIdentityCertificate = function
25085 (certificateName, onComplete, onError)
25086{
25087 return this.identityManager.getCertificate
25088 (certificateName, onComplete, onError);
25089};
25090
25091/**
25092 * Revoke a key.
25093 * @param {Name} keyName The name of the key that will be revoked.
25094 */
25095KeyChain.prototype.revokeKey = function(keyName)
25096{
25097 //TODO: Implement
25098};
25099
25100/**
25101 * Revoke a certificate.
25102 * @param {Name} certificateName The name of the certificate that will be
25103 * revoked.
25104 */
25105KeyChain.prototype.revokeCertificate = function(certificateName)
25106{
25107 //TODO: Implement
25108};
25109
25110/**
25111 * Get the identity manager given to or created by the constructor.
25112 * @return {IdentityManager} The identity manager.
25113 */
25114KeyChain.prototype.getIdentityManager = function()
25115{
25116 return this.identityManager;
25117};
25118
25119/*****************************************
25120 * Policy Management *
25121 *****************************************/
25122
25123/**
25124 * Get the policy manager given to or created by the constructor.
25125 * @return {PolicyManager} The policy manager.
25126 */
25127KeyChain.prototype.getPolicyManager = function()
25128{
25129 return this.policyManager;
25130};
25131
25132/*****************************************
25133 * Sign/Verify *
25134 *****************************************/
25135
25136/**
25137 * Sign the target. If it is a Data or Interest object, set its signature. If it
25138 * is an array, produce a Signature object. There are two forms of sign:
25139 * sign(target, certificateName [, wireFormat] [, onComplete] [, onError]).
25140 * sign(target [, wireFormat] [, onComplete] [, onError]).
25141 * @param {Data|Interest|Buffer} target If this is a Data object, wire encode for
25142 * signing, update its signature and key locator field and wireEncoding. If this
25143 * is an Interest object, wire encode for signing, append a SignatureInfo to the
25144 * Interest name, sign the name components and append a final name component
25145 * with the signature bits. If it is an array, sign it and produce a Signature
25146 * object.
25147 * @param {Name} certificateName (optional) The certificate name of the key to
25148 * use for signing. If omitted, use the default identity in the identity storage.
25149 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
25150 * the input. If omitted, use WireFormat getDefaultWireFormat().
25151 * @param {function} onComplete (optional) If target is a Data object, this calls
25152 * onComplete(data) with the supplied Data object which has been modified to set
25153 * its signature. If target is an Interest object, this calls
25154 * onComplete(interest) with the supplied Interest object which has been
25155 * modified to set its signature. If target is a Buffer, this calls
25156 * onComplete(signature) where signature is the produced Signature object. If
25157 * omitted, the return value is described below. (Some crypto libraries only use
25158 * a callback, so onComplete is required to use these.)
25159 * NOTE: The library will log any exceptions thrown by this callback, but for
25160 * better error handling the callback should catch and properly handle any
25161 * exceptions.
25162 * @param {function} onError (optional) If defined, then onComplete must be
25163 * defined and if there is an exception, then this calls onError(exception)
25164 * with the exception. If onComplete is defined but onError is undefined, then
25165 * this will log any thrown exception. (Some database libraries only use a
25166 * callback, so onError is required to be notified of an exception.)
25167 * NOTE: The library will log any exceptions thrown by this callback, but for
25168 * better error handling the callback should catch and properly handle any
25169 * exceptions.
25170 * @return {Signature} If onComplete is omitted, return the generated Signature
25171 * object (if target is a Buffer) or the target (if target is Data or Interest).
25172 * Otherwise, if onComplete is supplied then return undefined and use onComplete as
25173 * described above.
25174 */
25175KeyChain.prototype.sign = function
25176 (target, certificateName, wireFormat, onComplete, onError)
25177{
25178 var arg2 = certificateName;
25179 var arg3 = wireFormat;
25180 var arg4 = onComplete;
25181 var arg5 = onError;
25182 // arg2, arg3, arg4, arg5
25183 // certificateName, wireFormat, onComplete, onError
25184 // certificateName, wireFormat, null, null
25185 // certificateName, onComplete, onError, null
25186 // certificateName, null, null, null
25187 // wireFormat, onComplete, onError, null
25188 // wireFormat, null, null, null
25189 // onComplete, onError, null, null
25190 // null, null, null, null
25191 if (arg2 instanceof Name)
25192 certificateName = arg2;
25193 else
25194 certificateName = null;
25195
25196 if (arg2 instanceof WireFormat)
25197 wireFormat = arg2;
25198 else if (arg3 instanceof WireFormat)
25199 wireFormat = arg3;
25200 else
25201 wireFormat = null;
25202
25203 if (typeof arg2 === "function") {
25204 onComplete = arg2;
25205 onError = arg3;
25206 }
25207 else if (typeof arg3 === "function") {
25208 onComplete = arg3;
25209 onError = arg4;
25210 }
25211 else if (typeof arg4 === "function") {
25212 onComplete = arg4;
25213 onError = arg5;
25214 }
25215 else {
25216 onComplete = null;
25217 onError = null;
25218 }
25219
25220 return SyncPromise.complete(onComplete, onError,
25221 this.signPromise(target, certificateName, wireFormat, !onComplete));
25222};
25223
25224/**
25225 * Sign the target. If it is a Data or Interest object, set its signature. If it
25226 * is an array, produce a Signature object. There are two forms of signPromise:
25227 * signPromise(target, certificateName [, wireFormat] [, useSync]).
25228 * sign(target [, wireFormat] [, useSync]).
25229 * @param {Data|Interest|Buffer} target If this is a Data object, wire encode for
25230 * signing, update its signature and key locator field and wireEncoding. If this
25231 * is an Interest object, wire encode for signing, append a SignatureInfo to the
25232 * Interest name, sign the name components and append a final name component
25233 * with the signature bits. If it is an array, sign it and produce a Signature
25234 * object.
25235 * @param {Name} certificateName (optional) The certificate name of the key to
25236 * use for signing. If omitted, use the default identity in the identity storage.
25237 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
25238 * the input. If omitted, use WireFormat getDefaultWireFormat().
25239 * @param {boolean} useSync (optional) If true then return a SyncPromise which
25240 * is already fulfilled. If omitted or false, this may return a SyncPromise or
25241 * an async Promise.
25242 * @return {Promise|SyncPromise} A promise that returns the generated Signature
25243 * object (if target is a Buffer) or the target (if target is Data or Interest).
25244 */
25245KeyChain.prototype.signPromise = function
25246 (target, certificateName, wireFormat, useSync)
25247{
25248 var arg2 = certificateName;
25249 var arg3 = wireFormat;
25250 var arg4 = useSync;
25251 // arg2, arg3, arg4
25252 // certificateName, wireFormat, useSync
25253 // certificateName, wireFormat, null
25254 // certificateName, useSync, null
25255 // certificateName, null, null
25256 // wireFormat, useSync, null
25257 // wireFormat, null, null
25258 // useSync, null, null
25259 // null, null, null
25260 if (arg2 instanceof Name)
25261 certificateName = arg2;
25262 else
25263 certificateName = null;
25264
25265 if (arg2 instanceof WireFormat)
25266 wireFormat = arg2;
25267 else if (arg3 instanceof WireFormat)
25268 wireFormat = arg3;
25269 else
25270 wireFormat = null;
25271
25272 if (typeof arg2 === 'boolean')
25273 useSync = arg2;
25274 else if (typeof arg3 === 'boolean')
25275 useSync = arg3;
25276 else if (typeof arg4 === 'boolean')
25277 useSync = arg4;
25278 else
25279 useSync = false;
25280
25281 var thisKeyChain = this;
25282 return SyncPromise.resolve()
25283 .then(function() {
25284 if (certificateName != null)
25285 return SyncPromise.resolve();
25286
25287 // Get the default certificate name.
25288 return thisKeyChain.identityManager.getDefaultCertificatePromise(useSync)
25289 .then(function(signingCertificate) {
25290 if (signingCertificate != null) {
25291 certificateName = signingCertificate.getName();
25292 return SyncPromise.resolve();
25293 }
25294
25295 // Set the default certificate and default certificate name again.
25296 return thisKeyChain.prepareDefaultCertificateNamePromise_(useSync)
25297 .then(function(localCertificateName) {
25298 certificateName =localCertificateName;
25299 return SyncPromise.resolve();
25300 });
25301 });
25302 })
25303 .then(function() {
25304 // certificateName is now set. Do the actual signing.
25305 if (target instanceof Interest)
25306 return thisKeyChain.identityManager.signInterestByCertificatePromise
25307 (target, certificateName, wireFormat, useSync);
25308 else if (target instanceof Data)
25309 return thisKeyChain.identityManager.signByCertificatePromise
25310 (target, certificateName, wireFormat, useSync);
25311 else
25312 return thisKeyChain.identityManager.signByCertificatePromise
25313 (target, certificateName, useSync);
25314 });
25315};
25316
25317/**
25318 * Sign the target. If it is a Data object, set its signature. If it is an
25319 * array, produce a signature object.
25320 * @param {Data|Buffer} target If this is a Data object, wire encode for
25321 * signing, update its signature and key locator field and wireEncoding. If it
25322 * is an array, sign it and return a Signature object.
25323 * @param {Name} identityName (optional) The identity name for the key to use for
25324 * signing. If omitted, infer the signing identity from the data packet name.
25325 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
25326 * the input. If omitted, use WireFormat getDefaultWireFormat().
25327 * @param {function} onComplete (optional) If target is a Data object, this calls
25328 * onComplete(data) with the supplied Data object which has been modified to set
25329 * its signature. If target is a Buffer, this calls
25330 * onComplete(signature) where signature is the produced Signature object. If
25331 * omitted, the return value is described below. (Some crypto libraries only use
25332 * a callback, so onComplete is required to use these.)
25333 * NOTE: The library will log any exceptions thrown by this callback, but for
25334 * better error handling the callback should catch and properly handle any
25335 * exceptions.
25336 * @param {function} onError (optional) If defined, then onComplete must be
25337 * defined and if there is an exception, then this calls onError(exception)
25338 * with the exception. If onComplete is defined but onError is undefined, then
25339 * this will log any thrown exception. (Some database libraries only use a
25340 * callback, so onError is required to be notified of an exception.)
25341 * NOTE: The library will log any exceptions thrown by this callback, but for
25342 * better error handling the callback should catch and properly handle any
25343 * exceptions.
25344 * @return {Signature} If onComplete is omitted, return the generated Signature
25345 * object (if target is a Buffer) or undefined (if target is Data).
25346 * Otherwise, if onComplete is supplied then return undefined and use onComplete
25347 * as described above.
25348 */
25349KeyChain.prototype.signByIdentity = function
25350 (target, identityName, wireFormat, onComplete, onError)
25351{
25352 onError = (typeof wireFormat === "function") ? onComplete : onError;
25353 onComplete = (typeof wireFormat === "function") ? wireFormat : onComplete;
25354 wireFormat = (typeof wireFormat === "function" || !wireFormat) ? WireFormat.getDefaultWireFormat() : wireFormat;
25355
25356 var useSync = !onComplete;
25357 var thisKeyChain = this;
25358
25359 if (identityName == null)
25360 identityName = new Name();
25361
25362 if (target instanceof Data) {
25363 var data = target;
25364
25365 var mainPromise = SyncPromise.resolve()
25366 .then(function() {
25367 if (identityName.size() == 0) {
25368 var inferredIdentity = thisKeyChain.policyManager.inferSigningIdentity
25369 (data.getName());
25370 if (inferredIdentity.size() == 0)
25371 return thisKeyChain.identityManager.getDefaultCertificateNamePromise
25372 (useSync);
25373 else
25374 return thisKeyChain.identityManager.getDefaultCertificateNameForIdentityPromise
25375 (inferredIdentity, useSync);
25376 }
25377 else
25378 return thisKeyChain.identityManager.getDefaultCertificateNameForIdentityPromise
25379 (identityName, useSync);
25380 })
25381 .then(function(signingCertificateName) {
25382 if (signingCertificateName.size() == 0)
25383 throw new SecurityException(new Error
25384 ("No qualified certificate name found!"));
25385
25386 if (!thisKeyChain.policyManager.checkSigningPolicy
25387 (data.getName(), signingCertificateName))
25388 throw new SecurityException(new Error
25389 ("Signing Cert name does not comply with signing policy"));
25390
25391 return thisKeyChain.identityManager.signByCertificatePromise
25392 (data, signingCertificateName, wireFormat, useSync);
25393 });
25394
25395 return SyncPromise.complete(onComplete, onError, mainPromise);
25396 }
25397 else {
25398 var array = target;
25399
25400 return SyncPromise.complete(onComplete, onError,
25401 this.identityManager.getDefaultCertificateNameForIdentityPromise
25402 (identityName, useSync)
25403 .then(function(signingCertificateName) {
25404 if (signingCertificateName.size() == 0)
25405 throw new SecurityException(new Error
25406 ("No qualified certificate name found!"));
25407
25408 return thisKeyChain.identityManager.signByCertificatePromise
25409 (array, signingCertificateName, wireFormat, useSync);
25410 }));
25411 }
25412};
25413
25414/**
25415 * Sign the target using DigestSha256.
25416 * @param {Data|Interest} target If this is a Data object, wire encode for
25417 * signing, digest it and set its SignatureInfo to a DigestSha256, updating its
25418 * signature and wireEncoding. If this is an Interest object, wire encode for
25419 * signing, append a SignatureInfo for DigestSha256 to the Interest name, digest
25420 * the name components and append a final name component with the signature bits.
25421 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
25422 * the input. If omitted, use WireFormat getDefaultWireFormat().
25423 */
25424KeyChain.prototype.signWithSha256 = function(target, wireFormat)
25425{
25426 if (target instanceof Interest)
25427 this.identityManager.signInterestWithSha256(target, wireFormat);
25428 else
25429 this.identityManager.signWithSha256(target, wireFormat);
25430};
25431
25432/**
25433 * Check the signature on the Data object and call either onVerify or
25434 * onValidationFailed. We use callback functions because verify may fetch
25435 * information to check the signature.
25436 * @param {Data} data The Data object with the signature to check.
25437 * @param {function} onVerified If the signature is verified, this calls
25438 * onVerified(data).
25439 * NOTE: The library will log any exceptions thrown by this callback, but for
25440 * better error handling the callback should catch and properly handle any
25441 * exceptions.
25442 * @param {function} onValidationFailed If the signature check fails, this calls
25443 * onValidationFailed(data, reason) with the Data object and reason string.
25444 * NOTE: The library will log any exceptions thrown by this callback, but for
25445 * better error handling the callback should catch and properly handle any
25446 * exceptions.
25447 * @param {number} stepCount
25448 */
25449KeyChain.prototype.verifyData = function
25450 (data, onVerified, onValidationFailed, stepCount)
25451{
25452 if (stepCount == null)
25453 stepCount = 0;
25454
25455 if (this.policyManager.requireVerify(data)) {
25456 var nextStep = this.policyManager.checkVerificationPolicy
25457 (data, stepCount, onVerified, onValidationFailed);
25458 if (nextStep != null) {
25459 var thisKeyChain = this;
25460 this.face.expressInterest
25461 (nextStep.interest,
25462 function(callbackInterest, callbackData) {
25463 thisKeyChain.onCertificateData(callbackInterest, callbackData, nextStep);
25464 },
25465 function(callbackInterest) {
25466 thisKeyChain.onCertificateInterestTimeout
25467 (callbackInterest, nextStep.retry, onValidationFailed, data, nextStep);
25468 });
25469 }
25470 }
25471 else if (this.policyManager.skipVerifyAndTrust(data)) {
25472 try {
25473 onVerified(data);
25474 } catch (ex) {
25475 console.log("Error in onVerified: " + NdnCommon.getErrorWithStackTrace(ex));
25476 }
25477 }
25478 else {
25479 try {
25480 onValidationFailed
25481 (data, "The packet has no verify rule but skipVerifyAndTrust is false");
25482 } catch (ex) {
25483 console.log("Error in onValidationFailed: " + NdnCommon.getErrorWithStackTrace(ex));
25484 }
25485 }
25486};
25487
25488/**
25489 * Check the signature on the signed interest and call either onVerify or
25490 * onValidationFailed. We use callback functions because verify may fetch
25491 * information to check the signature.
25492 * @param {Interest} interest The interest with the signature to check.
25493 * @param {function} onVerified If the signature is verified, this calls
25494 * onVerified(interest).
25495 * NOTE: The library will log any exceptions thrown by this callback, but for
25496 * better error handling the callback should catch and properly handle any
25497 * exceptions.
25498 * @param {function} onValidationFailed If the signature check fails, this calls
25499 * onValidationFailed(interest, reason) with the Interest object and reason
25500 * string.
25501 * NOTE: The library will log any exceptions thrown by this callback, but for
25502 * better error handling the callback should catch and properly handle any
25503 * exceptions.
25504 */
25505KeyChain.prototype.verifyInterest = function
25506 (interest, onVerified, onValidationFailed, stepCount, wireFormat)
25507{
25508 if (stepCount == null)
25509 stepCount = 0;
25510 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
25511
25512 if (this.policyManager.requireVerify(interest)) {
25513 var nextStep = this.policyManager.checkVerificationPolicy
25514 (interest, stepCount, onVerified, onValidationFailed, wireFormat);
25515 if (nextStep != null) {
25516 var thisKeyChain = this;
25517 this.face.expressInterest
25518 (nextStep.interest,
25519 function(callbackInterest, callbackData) {
25520 thisKeyChain.onCertificateData(callbackInterest, callbackData, nextStep);
25521 },
25522 function(callbackInterest) {
25523 thisKeyChain.onCertificateInterestTimeout
25524 (callbackInterest, nextStep.retry, onValidationFailed, interest,
25525 nextStep);
25526 });
25527 }
25528 }
25529 else if (this.policyManager.skipVerifyAndTrust(interest)) {
25530 try {
25531 onVerified(interest);
25532 } catch (ex) {
25533 console.log("Error in onVerified: " + NdnCommon.getErrorWithStackTrace(ex));
25534 }
25535 }
25536 else {
25537 try {
25538 onValidationFailed
25539 (interest,
25540 "The packet has no verify rule but skipVerifyAndTrust is false");
25541 } catch (ex) {
25542 console.log("Error in onValidationFailed: " + NdnCommon.getErrorWithStackTrace(ex));
25543 }
25544 }
25545};
25546
25547/**
25548 * Set the Face which will be used to fetch required certificates.
25549 * @param {Face} face A pointer to the Face object.
25550 */
25551KeyChain.prototype.setFace = function(face)
25552{
25553 this.face = face;
25554};
25555
25556/**
25557 * Wire encode the target, compute an HmacWithSha256 and update the signature
25558 * value.
25559 * Note: This method is an experimental feature. The API may change.
25560 * @param {Data} target If this is a Data object, update its signature and wire
25561 * encoding.
25562 * @param {Blob} key The key for the HmacWithSha256.
25563 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
25564 * the target. If omitted, use WireFormat getDefaultWireFormat().
25565 */
25566KeyChain.signWithHmacWithSha256 = function(target, key, wireFormat)
25567{
25568 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
25569
25570 if (target instanceof Data) {
25571 var data = target;
25572 // Encode once to get the signed portion.
25573 var encoding = data.wireEncode(wireFormat);
25574
25575 var signer = Crypto.createHmac('sha256', key.buf());
25576 signer.update(encoding.signedBuf());
25577 data.getSignature().setSignature(
25578 new Blob(signer.digest(), false));
25579 }
25580 else
25581 throw new SecurityException(new Error
25582 ("signWithHmacWithSha256: Unrecognized target type"));
25583};
25584
25585/**
25586 * Compute a new HmacWithSha256 for the target and verify it against the
25587 * signature value.
25588 * Note: This method is an experimental feature. The API may change.
25589 * @param {Data} target The Data object to verify.
25590 * @param {Blob} key The key for the HmacWithSha256.
25591 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
25592 * the target. If omitted, use WireFormat getDefaultWireFormat().
25593 * @return {boolean} True if the signature verifies, otherwise false.
25594 */
25595KeyChain.verifyDataWithHmacWithSha256 = function(data, key, wireFormat)
25596{
25597 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
25598
25599 // wireEncode returns the cached encoding if available.
25600 var encoding = data.wireEncode(wireFormat);
25601
25602 var signer = Crypto.createHmac('sha256', key.buf());
25603 signer.update(encoding.signedBuf());
25604 var newSignatureBits = new Blob(signer.digest(), false);
25605
25606 // Use the flexible Blob.equals operator.
25607 return newSignatureBits.equals(data.getSignature().getSignature());
25608};
25609
25610KeyChain.DEFAULT_KEY_PARAMS = new RsaKeyParams();
25611
25612KeyChain.prototype.onCertificateData = function(interest, data, nextStep)
25613{
25614 // Try to verify the certificate (data) according to the parameters in nextStep.
25615 this.verifyData
25616 (data, nextStep.onVerified, nextStep.onValidationFailed, nextStep.stepCount);
25617};
25618
25619KeyChain.prototype.onCertificateInterestTimeout = function
25620 (interest, retry, onValidationFailed, originalDataOrInterest, nextStep)
25621{
25622 if (retry > 0) {
25623 // Issue the same expressInterest as in verifyData except decrement retry.
25624 var thisKeyChain = this;
25625 this.face.expressInterest
25626 (interest,
25627 function(callbackInterest, callbackData) {
25628 thisKeyChain.onCertificateData(callbackInterest, callbackData, nextStep);
25629 },
25630 function(callbackInterest) {
25631 thisKeyChain.onCertificateInterestTimeout
25632 (callbackInterest, retry - 1, onValidationFailed,
25633 originalDataOrInterest, nextStep);
25634 });
25635 }
25636 else {
25637 try {
25638 onValidationFailed
25639 (originalDataOrInterest, "The retry count is zero after timeout for fetching " +
25640 interest.getName().toUri());
25641 } catch (ex) {
25642 console.log("Error in onValidationFailed: " + NdnCommon.getErrorWithStackTrace(ex));
25643 }
25644 }
25645};
25646
25647/**
25648 * Get the default certificate from the identity storage and return its name.
25649 * If there is no default identity or default certificate, then create one.
25650 * @param {boolean} useSync (optional) If true then return a SyncPromise which
25651 * is already fulfilled. If omitted or false, this may return a SyncPromise or
25652 * an async Promise.
25653 * @return {Promise|SyncPromise} A promise that returns the default certificate
25654 * name.
25655 */
25656KeyChain.prototype.prepareDefaultCertificateNamePromise_ = function(useSync)
25657{
25658 var signingCertificate;
25659 var thisKeyChain = this;
25660 return this.identityManager.getDefaultCertificatePromise(useSync)
25661 .then(function(localCertificate) {
25662 signingCertificate = localCertificate;
25663 if (signingCertificate != null)
25664 return SyncPromise.resolve();
25665
25666 // Set the default certificate and get the certificate again.
25667 return thisKeyChain.setDefaultCertificatePromise_(useSync)
25668 .then(function() {
25669 return thisKeyChain.identityManager.getDefaultCertificatePromise(useSync);
25670 })
25671 .then(function(localCertificate) {
25672 signingCertificate = localCertificate;
25673 return SyncPromise.resolve();
25674 });
25675 })
25676 .then(function() {
25677 return SyncPromise.resolve(signingCertificate.getName());
25678 });
25679}
25680
25681/**
25682 * Create the default certificate if it is not initialized. If there is no
25683 * default identity yet, creating a new tmp-identity.
25684 * @param {boolean} useSync (optional) If true then return a SyncPromise which
25685 * is already fulfilled. If omitted or false, this may return a SyncPromise or
25686 * an async Promise.
25687 * @return {Promise|SyncPromise} A promise that resolves when the default
25688 * certificate is set.
25689 */
25690KeyChain.prototype.setDefaultCertificatePromise_ = function(useSync)
25691{
25692 var thisKeyChain = this;
25693
25694 return this.identityManager.getDefaultCertificatePromise(useSync)
25695 .then(function(certificate) {
25696 if (certificate != null)
25697 // We already have a default certificate.
25698 return SyncPromise.resolve();
25699
25700 var defaultIdentity;
25701 return thisKeyChain.identityManager.getDefaultIdentityPromise(useSync)
25702 .then(function(localDefaultIdentity) {
25703 defaultIdentity = localDefaultIdentity;
25704 return SyncPromise.resolve();
25705 }, function(ex) {
25706 // Create a default identity name.
25707 randomComponent = Crypto.randomBytes(4);
25708 defaultIdentity = new Name().append("tmp-identity")
25709 .append(new Blob(randomComponent, false));
25710
25711 return SyncPromise.resolve();
25712 })
25713 .then(function() {
25714 return thisKeyChain.identityManager.createIdentityAndCertificatePromise
25715 (defaultIdentity, KeyChain.DEFAULT_KEY_PARAMS, useSync);
25716 })
25717 .then(function() {
25718 return thisKeyChain.identityManager.setDefaultIdentityPromise
25719 (defaultIdentity, useSync);
25720 });
25721 });
25722};
25723/**
25724 * This class represents an Interest Exclude.
25725 * Copyright (C) 2014-2016 Regents of the University of California.
25726 * @author: Meki Cheraoui
25727 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
25728 *
25729 * This program is free software: you can redistribute it and/or modify
25730 * it under the terms of the GNU Lesser General Public License as published by
25731 * the Free Software Foundation, either version 3 of the License, or
25732 * (at your option) any later version.
25733 *
25734 * This program is distributed in the hope that it will be useful,
25735 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25736 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25737 * GNU Lesser General Public License for more details.
25738 *
25739 * You should have received a copy of the GNU Lesser General Public License
25740 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25741 * A copy of the GNU Lesser General Public License is in the file COPYING.
25742 */
25743
25744/** @ignore */
25745var Name = require('./name.js').Name; /** @ignore */
25746var DataUtils = require('./encoding/data-utils.js').DataUtils; /** @ignore */
25747var Blob = require('./util/blob.js').Blob;
25748
25749/**
25750 * Create a new Exclude.
25751 * @constructor
25752 * @param {Array<Name.Component|Buffer|Exclude.ANY>} values (optional) An array where each element is either a Name.Component, Buffer component or Exclude.ANY.
25753 */
25754var Exclude = function Exclude(values)
25755{
25756 this.values = [];
25757
25758 if (typeof values === 'object' && values instanceof Exclude)
25759 // Copy the exclude.
25760 this.values = values.values.slice(0);
25761 else if (values) {
25762 // Set the changeCount now since append expects it.
25763 this.changeCount = 0;
25764 for (var i = 0; i < values.length; ++i) {
25765 if (values[i] == Exclude.ANY)
25766 this.appendAny();
25767 else
25768 this.appendComponent(values[i]);
25769 }
25770 }
25771
25772 this.changeCount = 0;
25773};
25774
25775exports.Exclude = Exclude;
25776
25777Exclude.ANY = "*";
25778
25779/**
25780 * Get the number of entries.
25781 * @return {number} The number of entries.
25782 */
25783Exclude.prototype.size = function() { return this.values.length; };
25784
25785/**
25786 * Get the entry at the given index.
25787 * @param {number} i The index of the entry, starting from 0.
25788 * @return {Exclude.ANY|Name.Component} Exclude.ANY or a Name.Component.
25789 */
25790Exclude.prototype.get = function(i) { return this.values[i]; };
25791
25792/**
25793 * Append an Exclude.ANY element.
25794 * @return This Exclude so that you can chain calls to append.
25795 */
25796Exclude.prototype.appendAny = function()
25797{
25798 this.values.push(Exclude.ANY);
25799 ++this.changeCount;
25800 return this;
25801};
25802
25803/**
25804 * Append a component entry, copying from component.
25805 * @param {Name.Component|Buffer} component
25806 * @return This Exclude so that you can chain calls to append.
25807 */
25808Exclude.prototype.appendComponent = function(component)
25809{
25810 this.values.push(new Name.Component(component));
25811 ++this.changeCount;
25812 return this;
25813};
25814
25815/**
25816 * Clear all the entries.
25817 */
25818Exclude.prototype.clear = function()
25819{
25820 ++this.changeCount;
25821 this.values = [];
25822};
25823
25824/**
25825 * Return a string with elements separated by "," and Exclude.ANY shown as "*".
25826 */
25827Exclude.prototype.toUri = function()
25828{
25829 if (this.values == null || this.values.length == 0)
25830 return "";
25831
25832 var result = "";
25833 for (var i = 0; i < this.values.length; ++i) {
25834 if (i > 0)
25835 result += ",";
25836
25837 if (this.values[i] == Exclude.ANY)
25838 result += "*";
25839 else
25840 result += this.values[i].toEscapedString();
25841 }
25842 return result;
25843};
25844
25845/**
25846 * Return true if the component matches any of the exclude criteria.
25847 */
25848Exclude.prototype.matches = function(component)
25849{
25850 if (!(typeof component == 'object' && component instanceof Name.Component))
25851 component = new Name.Component(component);
25852
25853 for (var i = 0; i < this.values.length; ++i) {
25854 if (this.values[i] == Exclude.ANY) {
25855 var lowerBound = null;
25856 if (i > 0)
25857 lowerBound = this.values[i - 1];
25858
25859 // Find the upper bound, possibly skipping over multiple ANY in a row.
25860 var iUpperBound;
25861 var upperBound = null;
25862 for (iUpperBound = i + 1; iUpperBound < this.values.length; ++iUpperBound) {
25863 if (this.values[iUpperBound] != Exclude.ANY) {
25864 upperBound = this.values[iUpperBound];
25865 break;
25866 }
25867 }
25868
25869 // If lowerBound != null, we already checked component equals lowerBound on the last pass.
25870 // If upperBound != null, we will check component equals upperBound on the next pass.
25871 if (upperBound != null) {
25872 if (lowerBound != null) {
25873 if (component.compare(lowerBound) > 0 &&
25874 component.compare(upperBound) < 0)
25875 return true;
25876 }
25877 else {
25878 if (component.compare(upperBound) < 0)
25879 return true;
25880 }
25881
25882 // Make i equal iUpperBound on the next pass.
25883 i = iUpperBound - 1;
25884 }
25885 else {
25886 if (lowerBound != null) {
25887 if (component.compare(lowerBound) > 0)
25888 return true;
25889 }
25890 else
25891 // this.values has only ANY.
25892 return true;
25893 }
25894 }
25895 else {
25896 if (component.equals(this.values[i]))
25897 return true;
25898 }
25899 }
25900
25901 return false;
25902};
25903
25904/**
25905 * Return -1 if component1 is less than component2, 1 if greater or 0 if equal.
25906 * A component is less if it is shorter, otherwise if equal length do a byte comparison.
25907 */
25908Exclude.compareComponents = function(component1, component2)
25909{
25910 if (typeof component1 == 'object' && component1 instanceof Name.Component)
25911 component1 = component1.getValue().buf();
25912 if (typeof component2 == 'object' && component2 instanceof Name.Component)
25913 component2 = component2.getValue().buf();
25914
25915 return Name.Component.compareBuffers(component1, component2);
25916};
25917
25918/**
25919 * Get the change count, which is incremented each time this object is changed.
25920 * @return {number} The change count.
25921 */
25922Exclude.prototype.getChangeCount = function()
25923{
25924 return this.changeCount;
25925};
25926/**
25927 * This class represents Interest Objects
25928 * Copyright (C) 2013-2016 Regents of the University of California.
25929 * @author: Meki Cheraoui
25930 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
25931 *
25932 * This program is free software: you can redistribute it and/or modify
25933 * it under the terms of the GNU Lesser General Public License as published by
25934 * the Free Software Foundation, either version 3 of the License, or
25935 * (at your option) any later version.
25936 *
25937 * This program is distributed in the hope that it will be useful,
25938 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25939 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25940 * GNU Lesser General Public License for more details.
25941 *
25942 * You should have received a copy of the GNU Lesser General Public License
25943 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25944 * A copy of the GNU Lesser General Public License is in the file COPYING.
25945 */
25946
25947/** @ignore */
25948var Crypto = require('./crypto.js'); /** @ignore */
25949var Blob = require('./util/blob.js').Blob; /** @ignore */
25950var SignedBlob = require('./util/signed-blob.js').SignedBlob; /** @ignore */
25951var ChangeCounter = require('./util/change-counter.js').ChangeCounter; /** @ignore */
25952var Name = require('./name.js').Name; /** @ignore */
25953var Exclude = require('./exclude.js').Exclude; /** @ignore */
25954var Link = require('./link.js').Link; /** @ignore */
25955var KeyLocator = require('./key-locator.js').KeyLocator; /** @ignore */
25956var IncomingFaceId = require('./lp/incoming-face-id.js').IncomingFaceId; /** @ignore */
25957var WireFormat = require('./encoding/wire-format.js').WireFormat;
25958
25959/**
25960 * Create a new Interest with the optional values.
25961 *
25962 * @constructor
25963 * @param {Name|Interest} nameOrInterest If this is an Interest, copy values from the interest and ignore the
25964 * other arguments. Otherwise this is the optional name for the new Interest.
25965 * @param {number} minSuffixComponents
25966 * @param {number} maxSuffixComponents
25967 */
25968var Interest = function Interest
25969 (nameOrInterest, minSuffixComponents, maxSuffixComponents,
25970 publisherPublicKeyDigest, exclude, childSelector, answerOriginKind, scope,
25971 interestLifetimeMilliseconds, nonce)
25972{
25973 if (publisherPublicKeyDigest)
25974 throw new Error
25975 ("Interest constructor: PublisherPublicKeyDigest support has been removed.");
25976 if (answerOriginKind)
25977 throw new Error
25978 ("Interest constructor: answerOriginKind support has been removed. Use setMustBeFresh().");
25979 if (scope)
25980 throw new Error("Interest constructor: scope support has been removed.");
25981
25982 if (typeof nameOrInterest === 'object' && nameOrInterest instanceof Interest) {
25983 // Special case: this is a copy constructor. Ignore all but the first argument.
25984 var interest = nameOrInterest;
25985 // Copy the name.
25986 this.name_ = new ChangeCounter(new Name(interest.getName()));
25987 this.maxSuffixComponents_ = interest.maxSuffixComponents_;
25988 this.minSuffixComponents_ = interest.minSuffixComponents_;
25989
25990 this.keyLocator_ = new ChangeCounter(new KeyLocator(interest.getKeyLocator()));
25991 this.exclude_ = new ChangeCounter(new Exclude(interest.getExclude()));
25992 this.childSelector_ = interest.childSelector_;
25993 this.mustBeFresh_ = interest.mustBeFresh_;
25994 this.interestLifetimeMilliseconds_ = interest.interestLifetimeMilliseconds_;
25995 this.nonce_ = interest.nonce_;
25996 this.linkWireEncoding_ = interest.linkWireEncoding_;
25997 this.linkWireEncodingFormat_ = interest.linkWireEncodingFormat_;
25998 this.link_ = new ChangeCounter(null);
25999 if (interest.link_.get() != null)
26000 this.link_.set(new Link(interest.link_.get()));
26001 this.selectedDelegationIndex_ = interest.selectedDelegationIndex_;
26002 this.defaultWireEncoding_ = interest.getDefaultWireEncoding();
26003 this.defaultWireEncodingFormat_ = interest.defaultWireEncodingFormat_;
26004 }
26005 else {
26006 this.name_ = new ChangeCounter(typeof nameOrInterest === 'object' &&
26007 nameOrInterest instanceof Name ?
26008 new Name(nameOrInterest) : new Name());
26009 this.maxSuffixComponents_ = maxSuffixComponents;
26010 this.minSuffixComponents_ = minSuffixComponents;
26011
26012 this.keyLocator_ = new ChangeCounter(new KeyLocator());
26013 this.exclude_ = new ChangeCounter(typeof exclude === 'object' && exclude instanceof Exclude ?
26014 new Exclude(exclude) : new Exclude());
26015 this.childSelector_ = childSelector;
26016 this.mustBeFresh_ = true;
26017 this.interestLifetimeMilliseconds_ = interestLifetimeMilliseconds;
26018 this.nonce_ = typeof nonce === 'object' && nonce instanceof Blob ?
26019 nonce : new Blob(nonce, true);
26020 this.linkWireEncoding_ = new Blob();
26021 this.linkWireEncodingFormat_ = null;
26022 this.link_ = new ChangeCounter(null);
26023 this.selectedDelegationIndex_ = null;
26024 this.defaultWireEncoding_ = new SignedBlob();
26025 this.defaultWireEncodingFormat_ = null;
26026 }
26027
26028 this.getNonceChangeCount_ = 0;
26029 this.getDefaultWireEncodingChangeCount_ = 0;
26030 this.changeCount_ = 0;
26031 this.lpPacket_ = null;
26032};
26033
26034exports.Interest = Interest;
26035
26036Interest.RECURSIVE_POSTFIX = "*";
26037
26038Interest.CHILD_SELECTOR_LEFT = 0;
26039Interest.CHILD_SELECTOR_RIGHT = 1;
26040
26041/**
26042 * Check if this interest's name matches the given name (using Name.match) and
26043 * the given name also conforms to the interest selectors.
26044 * @param {Name} name The name to check.
26045 * @return {boolean} True if the name and interest selectors match, False otherwise.
26046 */
26047Interest.prototype.matchesName = function(name)
26048{
26049 if (!this.getName().match(name))
26050 return false;
26051
26052 if (this.minSuffixComponents_ != null &&
26053 // Add 1 for the implicit digest.
26054 !(name.size() + 1 - this.getName().size() >= this.minSuffixComponents_))
26055 return false;
26056 if (this.maxSuffixComponents_ != null &&
26057 // Add 1 for the implicit digest.
26058 !(name.size() + 1 - this.getName().size() <= this.maxSuffixComponents_))
26059 return false;
26060 if (this.getExclude() != null && name.size() > this.getName().size() &&
26061 this.getExclude().matches(name.get(this.getName().size())))
26062 return false;
26063
26064 return true;
26065};
26066
26067/**
26068 * @deprecated Use matchesName.
26069 */
26070Interest.prototype.matches_name = function(/*Name*/ name)
26071{
26072 return this.matchesName(name);
26073};
26074
26075/**
26076 * Check if the given Data packet can satisfy this Interest. This method
26077 * considers the Name, MinSuffixComponents, MaxSuffixComponents,
26078 * PublisherPublicKeyLocator, and Exclude. It does not consider the
26079 * ChildSelector or MustBeFresh. This uses the given wireFormat to get the
26080 * Data packet encoding for the full Name.
26081 * @param {Data} data The Data packet to check.
26082 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
26083 * the Data packet to get its full Name. If omitted, use
26084 * WireFormat.getDefaultWireFormat().
26085 * @return {boolean} True if the given Data packet can satisfy this Interest.
26086 */
26087Interest.prototype.matchesData = function(data, wireFormat)
26088{
26089 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
26090
26091 // Imitate ndn-cxx Interest::matchesData.
26092 var interestNameLength = this.getName().size();
26093 var dataName = data.getName();
26094 var fullNameLength = dataName.size() + 1;
26095
26096 // Check MinSuffixComponents.
26097 var hasMinSuffixComponents = (this.getMinSuffixComponents() != null);
26098 var minSuffixComponents =
26099 hasMinSuffixComponents ? this.getMinSuffixComponents() : 0;
26100 if (!(interestNameLength + minSuffixComponents <= fullNameLength))
26101 return false;
26102
26103 // Check MaxSuffixComponents.
26104 var hasMaxSuffixComponents = (this.getMaxSuffixComponents() != null);
26105 if (hasMaxSuffixComponents &&
26106 !(interestNameLength + this.getMaxSuffixComponents() >= fullNameLength))
26107 return false;
26108
26109 // Check the prefix.
26110 if (interestNameLength === fullNameLength) {
26111 if (this.getName().get(-1).isImplicitSha256Digest()) {
26112 if (!this.getName().equals(data.getFullName(wireFormat)))
26113 return false;
26114 }
26115 else
26116 // The Interest Name is the same length as the Data full Name, but the
26117 // last component isn't a digest so there's no possibility of matching.
26118 return false;
26119 }
26120 else {
26121 // The Interest Name should be a strict prefix of the Data full Name.
26122 if (!this.getName().isPrefixOf(dataName))
26123 return false;
26124 }
26125
26126 // Check the Exclude.
26127 // The Exclude won't be violated if the Interest Name is the same as the
26128 // Data full Name.
26129 if (this.getExclude().size() > 0 && fullNameLength > interestNameLength) {
26130 if (interestNameLength == fullNameLength - 1) {
26131 // The component to exclude is the digest.
26132 if (this.getExclude().matches
26133 (data.getFullName(wireFormat).get(interestNameLength)))
26134 return false;
26135 }
26136 else {
26137 // The component to exclude is not the digest.
26138 if (this.getExclude().matches(dataName.get(interestNameLength)))
26139 return false;
26140 }
26141 }
26142
26143 // Check the KeyLocator.
26144 var publisherPublicKeyLocator = this.getKeyLocator();
26145 if (publisherPublicKeyLocator.getType()) {
26146 var signature = data.getSignature();
26147 if (!KeyLocator.canGetFromSignature(signature))
26148 // No KeyLocator in the Data packet.
26149 return false;
26150 if (!publisherPublicKeyLocator.equals
26151 (KeyLocator.getFromSignature(signature)))
26152 return false;
26153 }
26154
26155 return true;
26156};
26157
26158/**
26159 * Return a new Interest with the same fields as this Interest.
26160 */
26161Interest.prototype.clone = function()
26162{
26163 return new Interest(this);
26164};
26165
26166/**
26167 * Get the interest Name.
26168 * @return {Name} The name. The name size() may be 0 if not specified.
26169 */
26170Interest.prototype.getName = function() { return this.name_.get(); };
26171
26172/**
26173 * Get the min suffix components.
26174 * @return {number} The min suffix components, or null if not specified.
26175 */
26176Interest.prototype.getMinSuffixComponents = function()
26177{
26178 return this.minSuffixComponents_;
26179};
26180
26181/**
26182 * Get the max suffix components.
26183 * @return {number} The max suffix components, or null if not specified.
26184 */
26185Interest.prototype.getMaxSuffixComponents = function()
26186{
26187 return this.maxSuffixComponents_;
26188};
26189
26190/**
26191 * Get the interest key locator.
26192 * @return {KeyLocator} The key locator. If its getType() is null,
26193 * then the key locator is not specified.
26194 */
26195Interest.prototype.getKeyLocator = function()
26196{
26197 return this.keyLocator_.get();
26198};
26199
26200/**
26201 * Get the exclude object.
26202 * @return {Exclude} The exclude object. If the exclude size() is zero, then
26203 * the exclude is not specified.
26204 */
26205Interest.prototype.getExclude = function() { return this.exclude_.get(); };
26206
26207/**
26208 * Get the child selector.
26209 * @return {number} The child selector, or null if not specified.
26210 */
26211Interest.prototype.getChildSelector = function()
26212{
26213 return this.childSelector_;
26214};
26215
26216/**
26217 * Get the must be fresh flag. If not specified, the default is true.
26218 * @return {boolean} The must be fresh flag.
26219 */
26220Interest.prototype.getMustBeFresh = function()
26221{
26222 return this.mustBeFresh_;
26223};
26224
26225/**
26226 * Return the nonce value from the incoming interest. If you change any of the
26227 * fields in this Interest object, then the nonce value is cleared.
26228 * @return {Blob} The nonce. If not specified, the value isNull().
26229 */
26230Interest.prototype.getNonce = function()
26231{
26232 if (this.getNonceChangeCount_ != this.getChangeCount()) {
26233 // The values have changed, so the existing nonce is invalidated.
26234 this.nonce_ = new Blob();
26235 this.getNonceChangeCount_ = this.getChangeCount();
26236 }
26237
26238 return this.nonce_;
26239};
26240
26241/**
26242 * @deprecated Use getNonce. This method returns a Buffer which is the former
26243 * behavior of getNonce, and should only be used while updating your code.
26244 */
26245Interest.prototype.getNonceAsBuffer = function()
26246{
26247 return this.getNonce().buf();
26248};
26249
26250/**
26251 * Check if this interest has a link object (or a link wire encoding which
26252 * can be decoded to make the link object).
26253 * @return {boolean} True if this interest has a link object, false if not.
26254 */
26255Interest.prototype.hasLink = function()
26256{
26257 return this.link_.get() != null || !this.linkWireEncoding_.isNull();
26258};
26259
26260/**
26261 * Get the link object. If necessary, decode it from the link wire encoding.
26262 * @return {Link} The link object, or null if not specified.
26263 * @throws DecodingException For error decoding the link wire encoding (if
26264 * necessary).
26265 */
26266Interest.prototype.getLink = function()
26267{
26268 if (this.link_.get() != null)
26269 return this.link_.get();
26270 else if (!this.linkWireEncoding_.isNull()) {
26271 // Decode the link object from linkWireEncoding_.
26272 var link = new Link();
26273 link.wireDecode(this.linkWireEncoding_, this.linkWireEncodingFormat_);
26274 this.link_.set(link);
26275
26276 // Clear linkWireEncoding_ since it is now managed by the link object.
26277 this.linkWireEncoding_ = new Blob();
26278 this.linkWireEncodingFormat_ = null;
26279
26280 return link;
26281 }
26282 else
26283 return null;
26284};
26285
26286/**
26287 * Get the wire encoding of the link object. If there is already a wire
26288 * encoding then return it. Otherwise encode from the link object (if
26289 * available).
26290 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
26291 * the Link. If omitted, use WireFormat.getDefaultWireFormat().
26292 * @return {Blob} The wire encoding, or an isNull Blob if the link is not
26293 * specified.
26294 */
26295Interest.prototype.getLinkWireEncoding = function(wireFormat)
26296{
26297 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
26298
26299 if (!this.linkWireEncoding_.isNull() && this.linkWireEncodingFormat_ == wireFormat)
26300 return this.linkWireEncoding_;
26301
26302 var link = this.getLink();
26303 if (link != null)
26304 return link.wireEncode(wireFormat);
26305 else
26306 return new Blob();
26307};
26308
26309/**
26310 * Get the selected delegation index.
26311 * @return {number} The selected delegation index. If not specified, return null.
26312 */
26313Interest.prototype.getSelectedDelegationIndex = function()
26314{
26315 return this.selectedDelegationIndex_;
26316};
26317
26318/**
26319 * Get the interest lifetime.
26320 * @return {number} The interest lifetime in milliseconds, or null if not
26321 * specified.
26322 */
26323Interest.prototype.getInterestLifetimeMilliseconds = function()
26324{
26325 return this.interestLifetimeMilliseconds_;
26326};
26327
26328/**
26329 * Return the default wire encoding, which was encoded with
26330 * getDefaultWireEncodingFormat().
26331 * @return {SignedBlob} The default wire encoding, whose isNull() may be true
26332 * if there is no default wire encoding.
26333 */
26334Interest.prototype.getDefaultWireEncoding = function()
26335{
26336 if (this.getDefaultWireEncodingChangeCount_ != this.getChangeCount()) {
26337 // The values have changed, so the default wire encoding is invalidated.
26338 this.defaultWireEncoding_ = new SignedBlob();
26339 this.defaultWireEncodingFormat_ = null;
26340 this.getDefaultWireEncodingChangeCount_ = this.getChangeCount();
26341 }
26342
26343 return this.defaultWireEncoding_;
26344};
26345
26346/**
26347 * Get the WireFormat which is used by getDefaultWireEncoding().
26348 * @return {WireFormat} The WireFormat, which is only meaningful if the
26349 * getDefaultWireEncoding() is not isNull().
26350 */
26351Interest.prototype.getDefaultWireEncodingFormat = function()
26352{
26353 return this.defaultWireEncodingFormat_;
26354};
26355
26356/**
26357 * Get the incoming face ID according to the incoming packet header.
26358 * @return {number} The incoming face ID. If not specified, return null.
26359 */
26360Interest.prototype.getIncomingFaceId = function()
26361{
26362 var field =
26363 this.lpPacket_ === null ? null : IncomingFaceId.getFirstHeader(this.lpPacket_);
26364 return field === null ? null : field.getFaceId();
26365};
26366
26367/**
26368 * Set the interest name.
26369 * Note: You can also call getName and change the name values directly.
26370 * @param {Name} name The interest name. This makes a copy of the name.
26371 * @return {Interest} This Interest so that you can chain calls to update values.
26372 */
26373Interest.prototype.setName = function(name)
26374{
26375 this.name_.set(typeof name === 'object' && name instanceof Name ?
26376 new Name(name) : new Name());
26377 ++this.changeCount_;
26378 return this;
26379};
26380
26381/**
26382 * Set the min suffix components count.
26383 * @param {number} minSuffixComponents The min suffix components count. If not
26384 * specified, set to undefined.
26385 * @return {Interest} This Interest so that you can chain calls to update values.
26386 */
26387Interest.prototype.setMinSuffixComponents = function(minSuffixComponents)
26388{
26389 this.minSuffixComponents_ = minSuffixComponents;
26390 ++this.changeCount_;
26391 return this;
26392};
26393
26394/**
26395 * Set the max suffix components count.
26396 * @param {number} maxSuffixComponents The max suffix components count. If not
26397 * specified, set to undefined.
26398 * @return {Interest} This Interest so that you can chain calls to update values.
26399 */
26400Interest.prototype.setMaxSuffixComponents = function(maxSuffixComponents)
26401{
26402 this.maxSuffixComponents_ = maxSuffixComponents;
26403 ++this.changeCount_;
26404 return this;
26405};
26406
26407/**
26408 * Set this interest to use a copy of the given KeyLocator object.
26409 * Note: You can also call getKeyLocator and change the key locator directly.
26410 * @param {KeyLocator} keyLocator The KeyLocator object. This makes a copy of the object.
26411 * If no key locator is specified, set to a new default KeyLocator(), or to a
26412 * KeyLocator with an unspecified type.
26413 * @return {Interest} This Interest so that you can chain calls to update values.
26414 */
26415Interest.prototype.setKeyLocator = function(keyLocator)
26416{
26417 this.keyLocator_.set
26418 (typeof keyLocator === 'object' && keyLocator instanceof KeyLocator ?
26419 new KeyLocator(keyLocator) : new KeyLocator());
26420 ++this.changeCount_;
26421 return this;
26422};
26423
26424/**
26425 * Set this interest to use a copy of the given exclude object. Note: You can
26426 * also call getExclude and change the exclude entries directly.
26427 * @param {Exclude} exclude The Exclude object. This makes a copy of the object.
26428 * If no exclude is specified, set to a new default Exclude(), or to an Exclude
26429 * with size() 0.
26430 * @return {Interest} This Interest so that you can chain calls to update values.
26431 */
26432Interest.prototype.setExclude = function(exclude)
26433{
26434 this.exclude_.set(typeof exclude === 'object' && exclude instanceof Exclude ?
26435 new Exclude(exclude) : new Exclude());
26436 ++this.changeCount_;
26437 return this;
26438};
26439
26440/**
26441 * Set the link wire encoding bytes, without decoding them. If there is
26442 * a link object, set it to null. If you later call getLink(), it will
26443 * decode the wireEncoding to create the link object.
26444 * @param {Blob} encoding The Blob with the bytes of the link wire encoding.
26445 * If no link is specified, set to an empty Blob() or call unsetLink().
26446 * @param {WireFormat} wireFormat The wire format of the encoding, to be used
26447 * later if necessary to decode. If omitted, use WireFormat.getDefaultWireFormat().
26448 * @return {Interest} This Interest so that you can chain calls to update values.
26449 */
26450Interest.prototype.setLinkWireEncoding = function(encoding, wireFormat)
26451{
26452 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
26453
26454 this.linkWireEncoding_ = encoding;
26455 this.linkWireEncodingFormat_ = wireFormat;
26456
26457 // Clear the link object, assuming that it has a different encoding.
26458 this.link_.set(null);
26459
26460 ++this.changeCount_;
26461 return this;
26462};
26463
26464/**
26465 * Clear the link wire encoding and link object so that getLink() returns null.
26466 * @return {Interest} This Interest so that you can chain calls to update values.
26467 */
26468Interest.prototype.unsetLink = function()
26469{
26470 return this.setLinkWireEncoding(new Blob(), null);
26471};
26472
26473/**
26474 * Set the selected delegation index.
26475 * @param {number} selectedDelegationIndex The selected delegation index. If not
26476 * specified, set to null.
26477 * @return {Interest} This Interest so that you can chain calls to update values.
26478 */
26479Interest.prototype.setSelectedDelegationIndex = function(selectedDelegationIndex)
26480{
26481 this.selectedDelegationIndex_ = selectedDelegationIndex;
26482 ++this.changeCount_;
26483 return this;
26484};
26485
26486/**
26487 * Set the child selector.
26488 * @param {number} childSelector The child selector. If not specified, set to
26489 * undefined.
26490 * @return {Interest} This Interest so that you can chain calls to update values.
26491 */
26492Interest.prototype.setChildSelector = function(childSelector)
26493{
26494 this.childSelector_ = childSelector;
26495 ++this.changeCount_;
26496 return this;
26497};
26498
26499/**
26500 * Set the MustBeFresh flag.
26501 * @param {boolean} mustBeFresh True if the content must be fresh, otherwise
26502 * false. If you do not set this flag, the default value is true.
26503 * @return {Interest} This Interest so that you can chain calls to update values.
26504 */
26505Interest.prototype.setMustBeFresh = function(mustBeFresh)
26506{
26507 this.mustBeFresh_ = (mustBeFresh ? true : false);
26508 ++this.changeCount_;
26509 return this;
26510};
26511
26512/**
26513 * Set the interest lifetime.
26514 * @param {number} interestLifetimeMilliseconds The interest lifetime in
26515 * milliseconds. If not specified, set to undefined.
26516 * @return {Interest} This Interest so that you can chain calls to update values.
26517 */
26518Interest.prototype.setInterestLifetimeMilliseconds = function(interestLifetimeMilliseconds)
26519{
26520 this.interestLifetimeMilliseconds_ = interestLifetimeMilliseconds;
26521 ++this.changeCount_;
26522 return this;
26523};
26524
26525/**
26526 * @deprecated You should let the wire encoder generate a random nonce
26527 * internally before sending the interest.
26528 */
26529Interest.prototype.setNonce = function(nonce)
26530{
26531 this.nonce_ = typeof nonce === 'object' && nonce instanceof Blob ?
26532 nonce : new Blob(nonce, true);
26533 // Set getNonceChangeCount_ so that the next call to getNonce() won't clear
26534 // this.nonce_.
26535 ++this.changeCount_;
26536 this.getNonceChangeCount_ = this.getChangeCount();
26537 return this;
26538};
26539
26540/**
26541 * Encode the name according to the "NDN URI Scheme". If there are interest selectors, append "?" and
26542 * added the selectors as a query string. For example "/test/name?ndn.ChildSelector=1".
26543 * Note: This is an experimental feature. See the API docs for more detail at
26544 * http://named-data.net/doc/ndn-ccl-api/interest.html#interest-touri-method .
26545 * @return {string} The URI string.
26546 */
26547Interest.prototype.toUri = function()
26548{
26549 var selectors = "";
26550
26551 if (this.minSuffixComponents_ != null)
26552 selectors += "&ndn.MinSuffixComponents=" + this.minSuffixComponents_;
26553 if (this.maxSuffixComponents_ != null)
26554 selectors += "&ndn.MaxSuffixComponents=" + this.maxSuffixComponents_;
26555 if (this.childSelector_ != null)
26556 selectors += "&ndn.ChildSelector=" + this.childSelector_;
26557 selectors += "&ndn.MustBeFresh=" + (this.mustBeFresh_ ? 1 : 0);
26558 if (this.interestLifetimeMilliseconds_ != null)
26559 selectors += "&ndn.InterestLifetime=" + this.interestLifetimeMilliseconds_;
26560 if (this.getNonce().size() > 0)
26561 selectors += "&ndn.Nonce=" + Name.toEscapedString(this.getNonce().buf());
26562 if (this.getExclude() != null && this.getExclude().size() > 0)
26563 selectors += "&ndn.Exclude=" + this.getExclude().toUri();
26564
26565 var result = this.getName().toUri();
26566 if (selectors != "")
26567 // Replace the first & with ?.
26568 result += "?" + selectors.substr(1);
26569
26570 return result;
26571};
26572
26573/**
26574 * Encode this Interest for a particular wire format. If wireFormat is the
26575 * default wire format, also set the defaultWireEncoding field to the encoded
26576 * result.
26577 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
26578 * this object. If omitted, use WireFormat.getDefaultWireFormat().
26579 * @return {SignedBlob} The encoded buffer in a SignedBlob object.
26580 */
26581Interest.prototype.wireEncode = function(wireFormat)
26582{
26583 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
26584
26585 if (!this.getDefaultWireEncoding().isNull() &&
26586 this.getDefaultWireEncodingFormat() == wireFormat)
26587 // We already have an encoding in the desired format.
26588 return this.getDefaultWireEncoding();
26589
26590 var result = wireFormat.encodeInterest(this);
26591 var wireEncoding = new SignedBlob
26592 (result.encoding, result.signedPortionBeginOffset,
26593 result.signedPortionEndOffset);
26594
26595 if (wireFormat == WireFormat.getDefaultWireFormat())
26596 // This is the default wire encoding.
26597 this.setDefaultWireEncoding
26598 (wireEncoding, WireFormat.getDefaultWireFormat());
26599 return wireEncoding;
26600};
26601
26602/**
26603 * Decode the input using a particular wire format and update this Interest. If
26604 * wireFormat is the default wire format, also set the defaultWireEncoding to
26605 * another pointer to the input.
26606 * @param {Blob|Buffer} input The buffer with the bytes to decode.
26607 * @param {WireFormat} wireFormat (optional) A WireFormat object used to decode
26608 * this object. If omitted, use WireFormat.getDefaultWireFormat().
26609 */
26610Interest.prototype.wireDecode = function(input, wireFormat)
26611{
26612 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
26613
26614 var result;
26615 if (typeof input === 'object' && input instanceof Blob)
26616 // Input is a blob, so get its buf() and set copy false.
26617 result = wireFormat.decodeInterest(this, input.buf(), false);
26618 else
26619 result = wireFormat.decodeInterest(this, input, true);
26620
26621 if (wireFormat == WireFormat.getDefaultWireFormat())
26622 // This is the default wire encoding. In the Blob constructor, set copy
26623 // true, but if input is already a Blob, it won't copy.
26624 this.setDefaultWireEncoding(new SignedBlob
26625 (new Blob(input, true), result.signedPortionBeginOffset,
26626 result.signedPortionEndOffset),
26627 WireFormat.getDefaultWireFormat());
26628 else
26629 this.setDefaultWireEncoding(new SignedBlob(), null);
26630};
26631
26632/**
26633 * Update the bytes of the nonce with new random values. This ensures that the
26634 * new nonce value is different than the current one. If the current nonce is
26635 * not specified, this does nothing.
26636 */
26637Interest.prototype.refreshNonce = function()
26638{
26639 var currentNonce = this.getNonce();
26640 if (currentNonce.size() === 0)
26641 return;
26642
26643 var newNonce;
26644 while (true) {
26645 newNonce = new Blob(Crypto.randomBytes(currentNonce.size()), false);
26646 if (!newNonce.equals(currentNonce))
26647 break;
26648 }
26649
26650 this.nonce_ = newNonce;
26651 // Set getNonceChangeCount_ so that the next call to getNonce() won't clear
26652 // this.nonce_.
26653 ++this.changeCount_;
26654 this.getNonceChangeCount_ = this.getChangeCount();
26655};
26656
26657/**
26658 * An internal library method to set the LpPacket for an incoming packet. The
26659 * application should not call this.
26660 * @param {LpPacket} lpPacket The LpPacket. This does not make a copy.
26661 * @return {Interest} This Interest so that you can chain calls to update values.
26662 * @note This is an experimental feature. This API may change in the future.
26663 */
26664Interest.prototype.setLpPacket = function(lpPacket)
26665{
26666 this.lpPacket_ = lpPacket;
26667 // Don't update changeCount_ since this doesn't affect the wire encoding.
26668 return this;
26669}
26670
26671/**
26672 * Get the change count, which is incremented each time this object (or a child
26673 * object) is changed.
26674 * @return {number} The change count.
26675 */
26676Interest.prototype.getChangeCount = function()
26677{
26678 // Make sure each of the checkChanged is called.
26679 var changed = this.name_.checkChanged();
26680 changed = this.keyLocator_.checkChanged() || changed;
26681 changed = this.exclude_.checkChanged() || changed;
26682 if (changed)
26683 // A child object has changed, so update the change count.
26684 ++this.changeCount_;
26685
26686 return this.changeCount_;
26687};
26688
26689Interest.prototype.setDefaultWireEncoding = function
26690 (defaultWireEncoding, defaultWireEncodingFormat)
26691{
26692 this.defaultWireEncoding_ = defaultWireEncoding;
26693 this.defaultWireEncodingFormat_ = defaultWireEncodingFormat;
26694 // Set getDefaultWireEncodingChangeCount_ so that the next call to
26695 // getDefaultWireEncoding() won't clear _defaultWireEncoding.
26696 this.getDefaultWireEncodingChangeCount_ = this.getChangeCount();
26697};
26698
26699// Define properties so we can change member variable types and implement changeCount_.
26700Object.defineProperty(Interest.prototype, "name",
26701 { get: function() { return this.getName(); },
26702 set: function(val) { this.setName(val); } });
26703Object.defineProperty(Interest.prototype, "minSuffixComponents",
26704 { get: function() { return this.getMinSuffixComponents(); },
26705 set: function(val) { this.setMinSuffixComponents(val); } });
26706Object.defineProperty(Interest.prototype, "maxSuffixComponents",
26707 { get: function() { return this.getMaxSuffixComponents(); },
26708 set: function(val) { this.setMaxSuffixComponents(val); } });
26709Object.defineProperty(Interest.prototype, "keyLocator",
26710 { get: function() { return this.getKeyLocator(); },
26711 set: function(val) { this.setKeyLocator(val); } });
26712Object.defineProperty(Interest.prototype, "exclude",
26713 { get: function() { return this.getExclude(); },
26714 set: function(val) { this.setExclude(val); } });
26715Object.defineProperty(Interest.prototype, "childSelector",
26716 { get: function() { return this.getChildSelector(); },
26717 set: function(val) { this.setChildSelector(val); } });
26718/**
26719 * @deprecated Use getInterestLifetimeMilliseconds and setInterestLifetimeMilliseconds.
26720 */
26721Object.defineProperty(Interest.prototype, "interestLifetime",
26722 { get: function() { return this.getInterestLifetimeMilliseconds(); },
26723 set: function(val) { this.setInterestLifetimeMilliseconds(val); } });
26724/**
26725 * @deprecated Use getNonce and setNonce.
26726 */
26727Object.defineProperty(Interest.prototype, "nonce",
26728 { get: function() { return this.getNonceAsBuffer(); },
26729 set: function(val) { this.setNonce(val); } });
26730/**
26731 * Copyright (C) 2013-2016 Regents of the University of California.
26732 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
26733 *
26734 * This program is free software: you can redistribute it and/or modify
26735 * it under the terms of the GNU Lesser General Public License as published by
26736 * the Free Software Foundation, either version 3 of the License, or
26737 * (at your option) any later version.
26738 *
26739 * This program is distributed in the hope that it will be useful,
26740 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26741 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26742 * GNU Lesser General Public License for more details.
26743 *
26744 * You should have received a copy of the GNU Lesser General Public License
26745 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26746 * A copy of the GNU Lesser General Public License is in the file COPYING.
26747 */
26748
26749/**
26750 * A ForwardingFlags object holds the flags which specify how the forwarding daemon should forward an interest for
26751 * a registered prefix. We use a separate ForwardingFlags object to retain future compatibility if the daemon forwarding
26752 * bits are changed, amended or deprecated.
26753 * Create a new ForwardingFlags with "childInherit" set and all other flags cleared.
26754 * @constructor
26755 */
26756var ForwardingFlags = function ForwardingFlags(value)
26757{
26758 if (typeof value === 'object' && value instanceof ForwardingFlags) {
26759 // Make a copy.
26760 this.childInherit = value.childInherit;
26761 this.capture = value.capture;
26762 }
26763 else {
26764 this.childInherit = true;
26765 this.capture = false;
26766 }
26767};
26768
26769exports.ForwardingFlags = ForwardingFlags;
26770
26771ForwardingFlags.NfdForwardingFlags_CHILD_INHERIT = 1;
26772ForwardingFlags.NfdForwardingFlags_CAPTURE = 2;
26773
26774/**
26775 * Get an integer with the bits set according to the NFD forwarding flags as
26776 * used in the ControlParameters of the command interest.
26777 * @return {number} An integer with the bits set.
26778 */
26779ForwardingFlags.prototype.getNfdForwardingFlags = function()
26780{
26781 var result = 0;
26782
26783 if (this.childInherit)
26784 result |= ForwardingFlags.NfdForwardingFlags_CHILD_INHERIT;
26785 if (this.capture)
26786 result |= ForwardingFlags.NfdForwardingFlags_CAPTURE;
26787
26788 return result;
26789};
26790
26791/**
26792 * Set the flags according to the NFD forwarding flags as used in the
26793 * ControlParameters of the command interest.
26794 * @param {number} nfdForwardingFlags An integer with the bits set.
26795 */
26796ForwardingFlags.prototype.setNfdForwardingFlags = function(nfdForwardingFlags)
26797{
26798 this.childInherit =
26799 ((nfdForwardingFlags & ForwardingFlags.NfdForwardingFlags_CHILD_INHERIT) != 0);
26800 this.capture =
26801 ((nfdForwardingFlags & ForwardingFlags.NfdForwardingFlags_CAPTURE) != 0);
26802};
26803
26804/**
26805 * Get the value of the "childInherit" flag.
26806 * @return {Boolean} true if the flag is set, false if it is cleared.
26807 */
26808ForwardingFlags.prototype.getChildInherit = function() { return this.childInherit; };
26809
26810/**
26811 * Get the value of the "capture" flag.
26812 * @return {Boolean} true if the flag is set, false if it is cleared.
26813 */
26814ForwardingFlags.prototype.getCapture = function() { return this.capture; };
26815
26816/**
26817 * Set the value of the "childInherit" flag
26818 * @param {number} value true to set the flag, false to clear it.
26819 */
26820ForwardingFlags.prototype.setChildInherit = function(value) { this.childInherit = value; };
26821
26822/**
26823 * Set the value of the "capture" flag
26824 * @param {number} value true to set the flag, false to clear it.
26825 */
26826ForwardingFlags.prototype.setCapture = function(value) { this.capture = value; };
26827/**
26828 * Copyright (C) 2014-2016 Regents of the University of California.
26829 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
26830 *
26831 * This program is free software: you can redistribute it and/or modify
26832 * it under the terms of the GNU Lesser General Public License as published by
26833 * the Free Software Foundation, either version 3 of the License, or
26834 * (at your option) any later version.
26835 *
26836 * This program is distributed in the hope that it will be useful,
26837 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26838 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26839 * GNU Lesser General Public License for more details.
26840 *
26841 * You should have received a copy of the GNU Lesser General Public License
26842 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26843 * A copy of the GNU Lesser General Public License is in the file COPYING.
26844 */
26845
26846/** @ignore */
26847var ForwardingFlags = require('./forwarding-flags.js').ForwardingFlags; /** @ignore */
26848var Name = require('./name.js').Name; /** @ignore */
26849var WireFormat = require('./encoding/wire-format.js').WireFormat; /** @ignore */
26850var Blob = require('./util/blob.js').Blob;
26851
26852/**
26853 * A ControlParameters which holds a Name and other fields for a
26854 * ControlParameters which is used, for example, in the command interest to
26855 * register a prefix with a forwarder. See
26856 * http://redmine.named-data.net/projects/nfd/wiki/ControlCommand#ControlParameters
26857 * @constructor
26858 */
26859var ControlParameters = function ControlParameters(value)
26860{
26861 if (typeof value === 'object' && value instanceof ControlParameters) {
26862 // Make a deep copy.
26863 this.name = value.name == null ? null : new Name(value.name);
26864 this.faceId = value.faceId;
26865 this.uri = value.uri;
26866 this.localControlFeature = value.localControlFeature;
26867 this.origin = value.origin;
26868 this.cost = value.cost;
26869 this.forwardingFlags = new ForwardingFlags(value.forwardingFlags);
26870 this.strategy = new Name(value.strategy);
26871 this.expirationPeriod = value.expirationPeriod;
26872 }
26873 else {
26874 this.name = null;
26875 this.faceId = null;
26876 this.uri = '';
26877 this.localControlFeature = null;
26878 this.origin = null;
26879 this.cost = null;
26880 this.forwardingFlags = new ForwardingFlags();
26881 this.strategy = new Name();
26882 this.expirationPeriod = null;
26883 }
26884};
26885
26886exports.ControlParameters = ControlParameters;
26887
26888ControlParameters.prototype.clear = function()
26889{
26890 this.name = null;
26891 this.faceId = null;
26892 this.uri = '';
26893 this.localControlFeature = null;
26894 this.origin = null;
26895 this.cost = null;
26896 this.forwardingFlags = new ForwardingFlags();
26897 this.strategy = new Name();
26898 this.expirationPeriod = null;
26899};
26900
26901/**
26902 * Encode this ControlParameters for a particular wire format.
26903 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
26904 * this object. If omitted, use WireFormat.getDefaultWireFormat().
26905 * @return {Blob} The encoded buffer in a Blob object.
26906 */
26907ControlParameters.prototype.wireEncode = function(wireFormat)
26908{
26909 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
26910 return wireFormat.encodeControlParameters(this);
26911};
26912
26913/**
26914 * Decode the input using a particular wire format and update this
26915 * ControlParameters.
26916 * @param {Blob|Buffer} input The buffer with the bytes to decode.
26917 * @param {WireFormat} wireFormat (optional) A WireFormat object used to decode
26918 * this object. If omitted, use WireFormat.getDefaultWireFormat().
26919 */
26920ControlParameters.prototype.wireDecode = function(input, wireFormat)
26921{
26922 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
26923 if (typeof input === 'object' && input instanceof Blob)
26924 // Input is a blob, so get its buf() and set copy false.
26925 wireFormat.decodeControlParameters(this, input.buf(), false);
26926 else
26927 wireFormat.decodeControlParameters(this, input, true);
26928};
26929
26930/**
26931 * Get the name.
26932 * @return {Name} The name. If not specified, return null.
26933 */
26934ControlParameters.prototype.getName = function()
26935{
26936 return this.name;
26937};
26938
26939/**
26940 * Get the face ID.
26941 * @return {number} The face ID, or null if not specified.
26942 */
26943ControlParameters.prototype.getFaceId = function()
26944{
26945 return this.faceId;
26946};
26947
26948/**
26949 * Get the URI.
26950 * @return {string} The face URI, or an empty string if not specified.
26951 */
26952ControlParameters.prototype.getUri = function()
26953{
26954 return this.uri;
26955};
26956
26957/**
26958 * Get the local control feature value.
26959 * @return {number} The local control feature value, or null if not specified.
26960 */
26961ControlParameters.prototype.getLocalControlFeature = function()
26962{
26963 return this.localControlFeature;
26964};
26965
26966/**
26967 * Get the origin value.
26968 * @return {number} The origin value, or null if not specified.
26969 */
26970ControlParameters.prototype.getOrigin = function()
26971{
26972 return this.origin;
26973};
26974
26975/**
26976 * Get the cost value.
26977 * @return {number} The cost value, or null if not specified.
26978 */
26979ControlParameters.prototype.getCost = function()
26980{
26981 return this.cost;
26982};
26983
26984/**
26985 * Get the ForwardingFlags object.
26986 * @return {ForwardingFlags} The ForwardingFlags object.
26987 */
26988ControlParameters.prototype.getForwardingFlags = function()
26989{
26990 return this.forwardingFlags;
26991};
26992
26993/**
26994 * Get the strategy.
26995 * @return {Name} The strategy or an empty Name
26996 */
26997ControlParameters.prototype.getStrategy = function()
26998{
26999 return this.strategy;
27000};
27001
27002/**
27003 * Get the expiration period.
27004 * @return {number} The expiration period in milliseconds, or null if not specified.
27005 */
27006ControlParameters.prototype.getExpirationPeriod = function()
27007{
27008 return this.expirationPeriod;
27009};
27010
27011/**
27012 * Set the name.
27013 * @param {Name} name The name. If not specified, set to null. If specified, this
27014 * makes a copy of the name.
27015 */
27016ControlParameters.prototype.setName = function(name)
27017{
27018 this.name = typeof name === 'object' && name instanceof Name ?
27019 new Name(name) : null;
27020};
27021
27022/**
27023 * Set the Face ID.
27024 * @param {number} faceId The new face ID, or null for not specified.
27025 */
27026ControlParameters.prototype.setFaceId = function(faceId)
27027{
27028 this.faceId = faceId;
27029};
27030
27031/**
27032 * Set the URI.
27033 * @param {string} uri The new uri, or an empty string for not specified.
27034 */
27035ControlParameters.prototype.setUri = function(uri)
27036{
27037 this.uri = uri || '';
27038};
27039
27040/**
27041 * Set the local control feature value.
27042 * @param {number} localControlFeature The new local control feature value, or
27043 * null for not specified.
27044 */
27045ControlParameters.prototype.setLocalControlFeature = function(localControlFeature)
27046{
27047 this.localControlFeature = localControlFeature;
27048};
27049
27050/**
27051 * Set the origin value.
27052 * @param {number} origin The new origin value, or null for not specified.
27053 */
27054ControlParameters.prototype.setOrigin = function(origin)
27055{
27056 this.origin = origin;
27057};
27058
27059/**
27060 * Set the cost value.
27061 * @param {number} cost The new cost value, or null for not specified.
27062 */
27063ControlParameters.prototype.setCost = function(cost)
27064{
27065 this.cost = cost;
27066};
27067
27068/**
27069 * Set the ForwardingFlags object to a copy of forwardingFlags. You can use
27070 * getForwardingFlags() and change the existing ForwardingFlags object.
27071 * @param {ForwardingFlags} forwardingFlags The new cost value, or null for not specified.
27072 */
27073ControlParameters.prototype.setForwardingFlags = function(forwardingFlags)
27074{
27075 this.forwardingFlags =
27076 typeof forwardingFlags === 'object' && forwardingFlags instanceof ForwardingFlags ?
27077 new ForwardingFlags(forwardingFlags) : new ForwardingFlags();
27078};
27079
27080/**
27081 * Set the strategy to a copy of the given Name.
27082 * @param {Name} strategy The Name to copy, or an empty Name if not specified.
27083 */
27084ControlParameters.prototype.setStrategy = function(strategy)
27085{
27086 this.strategy = typeof strategy === 'object' && strategy instanceof Name ?
27087 new Name(strategy) : new Name();
27088};
27089
27090/**
27091 * Set the expiration period.
27092 * @param {number} expirationPeriod The expiration period in milliseconds, or
27093 * null for not specified.
27094 */
27095ControlParameters.prototype.setExpirationPeriod = function(expirationPeriod)
27096{
27097 this.expirationPeriod = expirationPeriod;
27098};
27099/**
27100 * Copyright (C) 2016 Regents of the University of California.
27101 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
27102 *
27103 * This program is free software: you can redistribute it and/or modify
27104 * it under the terms of the GNU Lesser General Public License as published by
27105 * the Free Software Foundation, either version 3 of the License, or
27106 * (at your option) any later version.
27107 *
27108 * This program is distributed in the hope that it will be useful,
27109 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27110 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27111 * GNU Lesser General Public License for more details.
27112 *
27113 * You should have received a copy of the GNU Lesser General Public License
27114 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27115 * A copy of the GNU Lesser General Public License is in the file COPYING.
27116 */
27117
27118/** @ignore */
27119var ControlParameters = require('./control-parameters.js').ControlParameters; /** @ignore */
27120var WireFormat = require('./encoding/wire-format.js').WireFormat; /** @ignore */
27121var Blob = require('./util/blob.js').Blob;
27122
27123/**
27124 * A ControlResponse holds a status code, status text and other fields for a
27125 * ControlResponse which is used, for example, in the response from sending a
27126 * register prefix control command to a forwarder.
27127 * @see http://redmine.named-data.net/projects/nfd/wiki/ControlCommand
27128 * @constructor
27129 */
27130var ControlResponse = function ControlResponse(value)
27131{
27132 if (typeof value === 'object' && value instanceof ControlResponse) {
27133 // Make a deep copy.
27134 this.statusCode_ = value.statusCode_;
27135 this.statusText_ = value.statusText_;
27136 this.bodyAsControlParameters_ = value.bodyAsControlParameters_ == null ? null
27137 : new ControlParameters(value.bodyAsControlParameters_);
27138 }
27139 else {
27140 this.statusCode_ = null;
27141 this.statusText_ = "";
27142 this.bodyAsControlParameters_ = null;
27143 }
27144};
27145
27146exports.ControlResponse = ControlResponse;
27147
27148ControlResponse.prototype.clear = function()
27149{
27150 this.statusCode_ = null;
27151 this.statusText_ = "";
27152 this.bodyAsControlParameters_ = null;
27153};
27154
27155/**
27156 * Encode this ControlResponse for a particular wire format.
27157 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
27158 * this object. If omitted, use WireFormat.getDefaultWireFormat().
27159 * @return {Blob} The encoded buffer in a Blob object.
27160 */
27161ControlResponse.prototype.wireEncode = function(wireFormat)
27162{
27163 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
27164 return wireFormat.encodeControlResponse(this);
27165};
27166
27167/**
27168 * Decode the input using a particular wire format and update this
27169 * ControlResponse.
27170 * @param {Blob|Buffer} input The buffer with the bytes to decode.
27171 * @param {WireFormat} wireFormat (optional) A WireFormat object used to decode
27172 * this object. If omitted, use WireFormat.getDefaultWireFormat().
27173 */
27174ControlResponse.prototype.wireDecode = function(input, wireFormat)
27175{
27176 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
27177 if (typeof input === 'object' && input instanceof Blob)
27178 // Input is a blob, so get its buf() and set copy false.
27179 wireFormat.decodeControlResponse(this, input.buf(), false);
27180 else
27181 wireFormat.decodeControlResponse(this, input, true);
27182};
27183
27184/**
27185 * Get the status code.
27186 * @return {number} The status code. If not specified, return null.
27187 */
27188ControlResponse.prototype.getStatusCode = function()
27189{
27190 return this.statusCode_;
27191};
27192
27193/**
27194 * Get the status text.
27195 * @return {string} The status text. If not specified, return "".
27196 */
27197ControlResponse.prototype.getStatusText = function()
27198{
27199 return this.statusText_;
27200};
27201
27202/**
27203 * Get the control response body as a ControlParameters.
27204 * @return {ControlParameters} The ControlParameters, or null if the body is not
27205 * specified or if it is not a ControlParameters.
27206 */
27207ControlResponse.prototype.getBodyAsControlParameters = function()
27208{
27209 return this.bodyAsControlParameters_;
27210};
27211
27212/**
27213 * Set the status code.
27214 * @param statusCode {number} The status code. If not specified, set to null.
27215 * @return {ControlResponse} This ControlResponse so that you can chain calls to
27216 * update values.
27217 */
27218ControlResponse.prototype.setStatusCode = function(statusCode)
27219{
27220 this.statusCode_ = statusCode;
27221 return this;
27222};
27223
27224/**
27225 * Set the status text.
27226 * @param statusText {string} The status text. If not specified, set to "".
27227 * @return {ControlResponse} This ControlResponse so that you can chain calls to
27228 * update values.
27229 */
27230ControlResponse.prototype.setStatusText = function(statusText)
27231{
27232 this.statusText_ = statusText || "";
27233 return this;
27234};
27235
27236/**
27237 * Set the control response body as a ControlParameters.
27238 * @param {ControlParameters} controlParameters The ControlParameters for the
27239 * body. This makes a copy of the ControlParameters. If not specified or if the
27240 * body is not a ControlParameters, set to null.
27241 * @return {ControlResponse} This ControlResponse so that you can chain calls to
27242 * update values.
27243 */
27244ControlResponse.prototype.setBodyAsControlParameters = function(controlParameters)
27245{
27246 this.bodyAsControlParameters_ =
27247 typeof controlParameters === 'object' && controlParameters instanceof ControlParameters ?
27248 new ControlParameters(controlParameters) : null;
27249 return this;
27250};
27251/**
27252 * Copyright (C) 2015-2016 Regents of the University of California.
27253 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
27254 *
27255 * This program is free software: you can redistribute it and/or modify
27256 * it under the terms of the GNU Lesser General Public License as published by
27257 * the Free Software Foundation, either version 3 of the License, or
27258 * (at your option) any later version.
27259 *
27260 * This program is distributed in the hope that it will be useful,
27261 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27262 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27263 * GNU Lesser General Public License for more details.
27264 *
27265 * You should have received a copy of the GNU Lesser General Public License
27266 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27267 * A copy of the GNU Lesser General Public License is in the file COPYING.
27268 */
27269
27270/** @ignore */
27271var Name = require('./name.js').Name; /** @ignore */
27272var NdnRegexMatcher = require('./util/ndn-regex-matcher.js').NdnRegexMatcher;
27273
27274/**
27275 * An InterestFilter holds a Name prefix and optional regex match expression for
27276 * use in Face.setInterestFilter.
27277 *
27278 * Create an InterestFilter to match any Interest whose name starts with the
27279 * given prefix. If the optional regexFilter is provided then the remaining
27280 * components match the regexFilter regular expression as described in doesMatch.
27281 * @param {InterestFilter|Name|string} prefix If prefix is another
27282 * InterestFilter copy its values. If prefix is a Name then this makes a copy of
27283 * the Name. Otherwise this creates a Name from the URI string.
27284 * @param {string} regexFilter (optional) The regular expression for matching
27285 * the remaining name components.
27286 * @constructor
27287 */
27288var InterestFilter = function InterestFilter(prefix, regexFilter)
27289{
27290 if (typeof prefix === 'object' && prefix instanceof InterestFilter) {
27291 // The copy constructor.
27292 var interestFilter = prefix;
27293 this.prefix = new Name(interestFilter.prefix);
27294 this.regexFilter = interestFilter.regexFilter;
27295 this.regexFilterPattern = interestFilter.regexFilterPattern;
27296 }
27297 else {
27298 this.prefix = new Name(prefix);
27299 if (regexFilter) {
27300 this.regexFilter = regexFilter;
27301 this.regexFilterPattern = InterestFilter.makePattern(regexFilter);
27302 }
27303 else {
27304 this.regexFilter = null;
27305 this.regexFilterPattern = null;
27306 }
27307 }
27308};
27309
27310exports.InterestFilter = InterestFilter;
27311
27312/**
27313 * Check if the given name matches this filter. Match if name starts with this
27314 * filter's prefix. If this filter has the optional regexFilter then the
27315 * remaining components match the regexFilter regular expression.
27316 * For example, the following InterestFilter:
27317 *
27318 * InterestFilter("/hello", "<world><>+")
27319 *
27320 * will match all Interests, whose name has the prefix `/hello` which is
27321 * followed by a component `world` and has at least one more component after it.
27322 * Examples:
27323 *
27324 * /hello/world/!
27325 * /hello/world/x/y/z
27326 *
27327 * Note that the regular expression will need to match all remaining components
27328 * (e.g., there are implicit heading `^` and trailing `$` symbols in the
27329 * regular expression).
27330 * @param {Name} name The name to check against this filter.
27331 * @return {boolean} True if name matches this filter, otherwise false.
27332 */
27333InterestFilter.prototype.doesMatch = function(name)
27334{
27335 if (name.size() < this.prefix.size())
27336 return false;
27337
27338 if (this.hasRegexFilter()) {
27339 // Perform a prefix match and regular expression match for the remaining
27340 // components.
27341 if (!this.prefix.match(name))
27342 return false;
27343
27344 return null != NdnRegexMatcher.match
27345 (this.regexFilterPattern, name.getSubName(this.prefix.size()));
27346 }
27347 else
27348 // Just perform a prefix match.
27349 return this.prefix.match(name);
27350};
27351
27352/**
27353 * Get the prefix given to the constructor.
27354 * @return {Name} The prefix Name which you should not modify.
27355 */
27356InterestFilter.prototype.getPrefix = function() { return this.prefix; };
27357
27358/**
27359 * Check if a regexFilter was supplied to the constructor.
27360 * @return {boolean} True if a regexFilter was supplied to the constructor.
27361 */
27362InterestFilter.prototype.hasRegexFilter = function()
27363{
27364 return this.regexFilter != null;
27365};
27366
27367/**
27368 * Get the regex filter. This is only valid if hasRegexFilter() is true.
27369 * @return {string} The regular expression for matching the remaining name
27370 * components.
27371 */
27372InterestFilter.prototype.getRegexFilter = function() { return this.regexFilter; };
27373
27374/**
27375 * If regexFilter doesn't already have them, add ^ to the beginning and $ to
27376 * the end since these are required by NdnRegexMatcher.match.
27377 * @param {string} regexFilter The regex filter.
27378 * @return {string} The regex pattern with ^ and $.
27379 */
27380InterestFilter.makePattern = function(regexFilter)
27381{
27382 if (regexFilter.length == 0)
27383 // We don't expect this.
27384 return "^$";
27385
27386 var pattern = regexFilter;
27387 if (pattern[0] != '^')
27388 pattern = "^" + pattern;
27389 if (pattern[pattern.length - 1] != '$')
27390 pattern = pattern + "$";
27391
27392 return pattern;
27393};
27394/**
27395 * Copyright (C) 2016 Regents of the University of California.
27396 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
27397 *
27398 * This program is free software: you can redistribute it and/or modify
27399 * it under the terms of the GNU Lesser General Public License as published by
27400 * the Free Software Foundation, either version 3 of the License, or
27401 * (at your option) any later version.
27402 *
27403 * This program is distributed in the hope that it will be useful,
27404 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27405 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27406 * GNU Lesser General Public License for more details.
27407 *
27408 * You should have received a copy of the GNU Lesser General Public License
27409 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27410 * A copy of the GNU Lesser General Public License is in the file COPYING.
27411 */
27412
27413/** @ignore */
27414var Name = require('./name.js').Name; /** @ignore */
27415var Blob = require('./util/blob.js').Blob; /** @ignore */
27416var WireFormat = require('./encoding/wire-format.js').WireFormat;
27417
27418/**
27419 * A DelegationSet holds a list of DelegationSet.Delegation entries which is
27420 * used as the content of a Link instance. If you add elements with add(), then
27421 * the list is a set sorted by preference number then by name. But wireDecode
27422 * will add the elements from the wire encoding, preserving the given order and
27423 * possible duplicates (in which case a DelegationSet really holds a "list" and
27424 * not necessarily a "set").
27425 *
27426 * Create a new DelegationSet object, possibly copying values from another
27427 * object.
27428 *
27429 * @param {DelegationSet} value (optional) If value is a DelegationSet, copy its
27430 * values.
27431 * @constructor
27432 */
27433var DelegationSet = function DelegationSet(value)
27434{
27435 if (typeof value === 'object' && value instanceof DelegationSet)
27436 // Copy the list.
27437 this.delegations_ = value.delegations_.slice(0);
27438 else
27439 this.delegations_ = []; // of DelegationSet.Delegation.
27440};
27441
27442exports.DelegationSet = DelegationSet;
27443
27444/**
27445 * A DelegationSet.Delegation holds a preference number and delegation name.
27446 * Create a new DelegationSet.Delegation with the given values.
27447 * @param {number} preference The preference number.
27448 * @param {Name} name The delegation name. This makes a copy of the name.
27449 * @constructor
27450 */
27451DelegationSet.Delegation = function DelegationSetDelegation(preference, name)
27452{
27453 this.preference_ = preference;
27454 this.name_ = new Name(name);
27455};
27456
27457/**
27458 * Get the preference number.
27459 * @return {number} The preference number.
27460 */
27461DelegationSet.Delegation.prototype.getPreference = function()
27462{
27463 return this.preference_;
27464};
27465
27466/**
27467 * Get the delegation name.
27468 * @return {Name} The delegation name. NOTE: You must not change the name object -
27469 * if you need to change it then make a copy.
27470 */
27471DelegationSet.Delegation.prototype.getName = function()
27472{
27473 return this.name_;
27474};
27475
27476/**
27477 * Compare this Delegation with other according to the ordering, based first
27478 * on the preference number, then on the delegation name.
27479 * @param {DelegationSet.Delegation} other The other Delegation to compare with.
27480 * @return {number} 0 If they compare equal, -1 if this Delegation comes before
27481 * other in the ordering, or 1 if this Delegation comes after.
27482 */
27483DelegationSet.Delegation.prototype.compare = function(other)
27484{
27485 if (this.preference_ < other.preference_)
27486 return -1;
27487 if (this.preference_ > other.preference_)
27488 return 1;
27489
27490 return this.name_.compare(other.name_);
27491};
27492
27493/**
27494 * Add a new DelegationSet.Delegation to the list of delegations, sorted by
27495 * preference number then by name. If there is already a delegation with the
27496 * same name, update its preference, and remove any extra delegations with the
27497 * same name.
27498 * @param {number} preference The preference number.
27499 * @param {Name} name The delegation name. This makes a copy of the name.
27500 */
27501DelegationSet.prototype.add = function(preference, name)
27502{
27503 this.remove(name);
27504
27505 var newDelegation = new DelegationSet.Delegation(preference, name);
27506 // Find the index of the first entry where it is not less than newDelegation.
27507 var i = 0;
27508 while (i < this.delegations_.length) {
27509 if (this.delegations_[i].compare(newDelegation) >= 0)
27510 break;
27511
27512 ++i;
27513 }
27514
27515 this.delegations_.splice(i, 0, newDelegation);
27516};
27517
27518/**
27519 * Add a new DelegationSet.Delegation to the end of the list of delegations,
27520 * without sorting or updating any existing entries. This is useful for adding
27521 * preferences from a wire encoding, preserving the supplied ordering and
27522 * possible duplicates.
27523 * @param {number} preference The preference number.
27524 * @param {Name} name The delegation name. This makes a copy of the name.
27525 */
27526DelegationSet.prototype.addUnsorted = function(preference, name)
27527{
27528 this.delegations_.push(new DelegationSet.Delegation(preference, name));
27529};
27530
27531/**
27532 * Remove every DelegationSet.Delegation with the given name.
27533 * @param {Name} name The name to match the name of the delegation(s) to be
27534 * removed.
27535 * @return {boolean} True if a DelegationSet.Delegation was removed, otherwise
27536 * false.
27537 */
27538DelegationSet.prototype.remove = function(name)
27539{
27540 var wasRemoved = false;
27541 // Go backwards through the list so we can remove entries.
27542 for (var i = this.delegations_.length - 1; i >= 0; --i) {
27543 if (this.delegations_[i].getName().equals(name)) {
27544 wasRemoved = true;
27545 this.delegations_.splice(i, 1);
27546 }
27547 }
27548
27549 return wasRemoved;
27550};
27551
27552/**
27553 * Clear the list of delegations.
27554 */
27555DelegationSet.prototype.clear = function() { this.delegations_ = []; };
27556
27557/**
27558 * Get the number of delegation entries.
27559 * @return {number} The number of delegation entries.
27560 */
27561DelegationSet.prototype.size = function() { return this.delegations_.length; };
27562
27563/**
27564 * Get the delegation at the given index, according to the ordering described
27565 * in add().
27566 * @param {number} i The index of the component, starting from 0.
27567 * @return {DelegationSet.Delegation} The delegation at the index.
27568 */
27569DelegationSet.prototype.get = function(i) { return this.delegations_[i]; };
27570
27571/**
27572 * Find the first delegation with the given name and return its index.
27573 * @param {Name} name Then name of the delegation to find.
27574 * @return {number} The index of the delegation, or -1 if not found.
27575 */
27576DelegationSet.prototype.find = function(name)
27577{
27578 for (var i = 0; i < this.delegations_.length; ++i) {
27579 if (this.delegations_[i].getName().equals(name))
27580 return i;
27581 }
27582
27583 return -1;
27584};
27585
27586/**
27587 * Encode this DelegationSet for a particular wire format.
27588 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
27589 * this object. If omitted, use WireFormat.getDefaultWireFormat().
27590 * @return {Blob} The encoded buffer in a Blob object.
27591 */
27592DelegationSet.prototype.wireEncode = function(wireFormat)
27593{
27594 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
27595 return wireFormat.encodeDelegationSet(this);
27596};
27597
27598/**
27599 * Decode the input using a particular wire format and update this DelegationSet.
27600 * @param {Blob|Buffer} input The buffer with the bytes to decode.
27601 * @param {WireFormat} wireFormat (optional) A WireFormat object used to decode
27602 * this object. If omitted, use WireFormat.getDefaultWireFormat().
27603 */
27604DelegationSet.prototype.wireDecode = function(input, wireFormat)
27605{
27606 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
27607 if (typeof input === 'object' && input instanceof Blob)
27608 // Input is a blob, so get its buf() and set copy false.
27609 wireFormat.decodeDelegationSet(this, input.buf(), false);
27610 else
27611 wireFormat.decodeDelegationSet(this, input, true);
27612};
27613/**
27614 * Copyright (C) 2016 Regents of the University of California.
27615 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
27616 *
27617 * This program is free software: you can redistribute it and/or modify
27618 * it under the terms of the GNU Lesser General Public License as published by
27619 * the Free Software Foundation, either version 3 of the License, or
27620 * (at your option) any later version.
27621 *
27622 * This program is distributed in the hope that it will be useful,
27623 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27624 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27625 * GNU Lesser General Public License for more details.
27626 *
27627 * You should have received a copy of the GNU Lesser General Public License
27628 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27629 * A copy of the GNU Lesser General Public License is in the file COPYING.
27630 */
27631
27632/** @ignore */
27633var DelegationSet = require('./delegation-set.js').DelegationSet; /** @ignore */
27634var ContentType = require('./meta-info.js').ContentType; /** @ignore */
27635var WireFormat = require('./encoding/wire-format.js').WireFormat; /** @ignore */
27636var Data = require('./data.js').Data;
27637
27638/**
27639 * The Link class extends Data and represents a Link instance where the Data
27640 * content is an encoded delegation set. The format is defined in "link.pdf"
27641 * attached to Redmine issue http://redmine.named-data.net/issues/2587 .
27642 *
27643 * Create a new Link with the optional values. There are 3 forms of the constructor:
27644 * Link(name);
27645 * Link(data);
27646 * Link();
27647 * @param {Name} name The name for constructing the base Data.
27648 * @param {Data} data The Data object to copy values from. If the content can be
27649 * decoded using the default wire encoding, then update the list of delegations.
27650 * @constructor
27651 */
27652var Link = function Link(value)
27653{
27654 this.delegations_ = new DelegationSet();
27655
27656 if (value instanceof Data) {
27657 // Call the base constructor.
27658 Data.call(this, value);
27659
27660 if (!this.getContent().isNull()) {
27661 try {
27662 this.delegations_.wireDecode(this.getContent());
27663 this.getMetaInfo().setType(ContentType.LINK);
27664 }
27665 catch (ex) {
27666 this.delegations_.clear();
27667 }
27668 }
27669 }
27670 else {
27671 if (value != undefined)
27672 // value is a Name.
27673 Data.call(this, value);
27674 else
27675 Data.call(this);
27676
27677 this.getMetaInfo().setType(ContentType.LINK);
27678 }
27679};
27680
27681Link.prototype = new Data();
27682Link.prototype.name = "Link";
27683
27684exports.Link = Link;
27685
27686/**
27687 * Override to call the base class wireDecode then populate the list of
27688 * delegations from the content.
27689 * @param {Blob|Buffer} input The buffer with the bytes to decode.
27690 * @param {WireFormat} wireFormat (optional) A WireFormat object used to decode
27691 * this object. If omitted, use WireFormat.getDefaultWireFormat().
27692 */
27693Link.prototype.wireDecode = function(input, wireFormat)
27694{
27695 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
27696
27697 Data.prototype.wireDecode.call(this, input, wireFormat);
27698 if (this.getMetaInfo().getType() != ContentType.LINK)
27699 throw new Error
27700 ("Link.wireDecode: MetaInfo ContentType is not LINK.");
27701
27702 this.delegations_.wireDecode(this.getContent());
27703};
27704
27705/**
27706 * Add a new delegation to the list of delegations, sorted by preference number
27707 * then by name. Re-encode this object's content using the optional wireFormat.
27708 * @param {number} preference The preference number.
27709 * @param {Name} name The delegation name. This makes a copy of the name. If
27710 * there is already a delegation with the same name, this updates its preference.
27711 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
27712 * the DelegationSet. If omitted, use WireFormat.getDefaultWireFormat().
27713 * @return {Link} This Link so that you can chain calls to update values.
27714 */
27715Link.prototype.addDelegation = function(preference, name, wireFormat)
27716{
27717 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
27718
27719 this.delegations_.add(preference, name);
27720 this.encodeContent(wireFormat);
27721
27722 return this;
27723};
27724
27725/**
27726 * Remove every delegation with the given name. Re-encode this object's content
27727 * using the optional wireFormat.
27728 * @param {Name} name Then name to match the name of the delegation(s) to be
27729 * removed.
27730 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
27731 * the DelegationSet. If omitted, use WireFormat.getDefaultWireFormat().
27732 * @return {boolean} True if a delegation was removed, otherwise false.
27733 */
27734Link.prototype.removeDelegation = function(name, wireFormat)
27735{
27736 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
27737
27738 var wasRemoved = this.delegations_.remove(name);
27739 if (wasRemoved)
27740 this.encodeContent(wireFormat);
27741
27742 return wasRemoved;
27743};
27744
27745/**
27746 * Get the list of delegation for read only.
27747 * @return {DelegationSet} The list of delegation, which you should treat as
27748 * read-only. To modify it, call Link.addDelegation, etc.
27749 */
27750Link.prototype.getDelegations = function() { return this.delegations_; };
27751
27752/**
27753 * A private method to encode the delegations_ and set this object's content.
27754 * Also set the meta info content type to LINK.
27755 * @param {WireFormat} wireFormat A WireFormat object used to encode the
27756 * DelegationSet.
27757 */
27758Link.prototype.encodeContent = function(wireFormat)
27759{
27760 this.setContent(this.delegations_.wireEncode(wireFormat));
27761 this.getMetaInfo().setType(ContentType.LINK);
27762};
27763/**
27764 * Copyright (C) 2016 Regents of the University of California.
27765 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
27766 * @author: From ndn-cxx nack.hpp https://github.com/named-data/ndn-cxx/blob/master/src/lp/nack.hpp
27767 *
27768 * This program is free software: you can redistribute it and/or modify
27769 * it under the terms of the GNU Lesser General Public License as published by
27770 * the Free Software Foundation, either version 3 of the License, or
27771 * (at your option) any later version.
27772 *
27773 * This program is distributed in the hope that it will be useful,
27774 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27775 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27776 * GNU Lesser General Public License for more details.
27777 *
27778 * You should have received a copy of the GNU Lesser General Public License
27779 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27780 * A copy of the GNU Lesser General Public License is in the file COPYING.
27781 */
27782
27783/**
27784 * NetworkNack represents a network Nack packet and includes a Nack reason.
27785 * @constructor
27786 */
27787var NetworkNack = function NetworkNack()
27788{
27789 this.reason_ = NetworkNack.Reason.NONE;
27790 this.otherReasonCode_ = -1;
27791};
27792
27793exports.NetworkNack = NetworkNack;
27794
27795/**
27796 * A NetworkNack.Reason specifies the reason in a NetworkNack packet. If the
27797 * reason code in the packet is not a recognized enum value, then we use
27798 * Reason.OTHER_CODE and you can call getOtherReasonCode(). We do this to keep
27799 * the recognized reason values independent of packet encoding formats.
27800 */
27801NetworkNack.Reason = {
27802 NONE: 0,
27803 CONGESTION: 50,
27804 DUPLICATE: 100,
27805 NO_ROUTE: 150,
27806 OTHER_CODE: 0x7fff
27807};
27808
27809/**
27810 * Get the network Nack reason.
27811 * @return {number} The reason enum value from NetworkNack.Reason. If this is
27812 * Reason.OTHER_CODE, then call getOtherReasonCode() to get the unrecognized
27813 * reason code.
27814 */
27815NetworkNack.prototype.getReason = function() { return this.reason_; };
27816
27817/**
27818 * Get the reason code from the packet which is other than a recognized
27819 * Reason enum value. This is only meaningful if getReason() is
27820 * Reason.OTHER_CODE.
27821 * @return {number} The reason code.
27822 */
27823NetworkNack.prototype.getOtherReasonCode = function()
27824{
27825 return this.otherReasonCode_;
27826};
27827
27828/**
27829 * Set the network Nack reason.
27830 * @param {number} reason The network Nack reason enum value from
27831 * NetworkNack.Reason. If the packet's reason code is not a recognized Reason
27832 * enum value, use Reason.OTHER_CODE and call setOtherReasonCode().
27833 */
27834NetworkNack.prototype.setReason = function(reason) { this.reason_ = reason; };
27835
27836/**
27837 * Set the packet's reason code to use when the reason enum is
27838 * Reason.OTHER_CODE. If the packet's reason code is a recognized enum value,
27839 * just call setReason().
27840 * @param {number} otherReasonCode The packet's unrecognized reason code, which
27841 * must be non-negative.
27842 */
27843NetworkNack.prototype.setOtherReasonCode = function(otherReasonCode)
27844{
27845 if (otherReasonCode < 0)
27846 throw new Error("NetworkNack other reason code must be non-negative");
27847 this.otherReasonCode_ = otherReasonCode;
27848};
27849
27850/**
27851 * Get the first header field in lpPacket which is a NetworkNack. This is
27852 * an internal method which the application normally would not use.
27853 * @param {LpPacket} lpPacket The LpPacket with the header fields to search.
27854 * @return {NetworkNack} The first NetworkNack header field, or null if not
27855 * found.
27856 */
27857NetworkNack.getFirstHeader = function(lpPacket)
27858{
27859 for (var i = 0; i < lpPacket.countHeaderFields(); ++i) {
27860 var field = lpPacket.getHeaderField(i);
27861 if (field instanceof NetworkNack)
27862 return field;
27863 }
27864
27865 return null;
27866};
27867/**
27868 * Copyright (C) 2013-2016 Regents of the University of California.
27869 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
27870 *
27871 * This program is free software: you can redistribute it and/or modify
27872 * it under the terms of the GNU Lesser General Public License as published by
27873 * the Free Software Foundation, either version 3 of the License, or
27874 * (at your option) any later version.
27875 *
27876 * This program is distributed in the hope that it will be useful,
27877 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27878 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27879 * GNU Lesser General Public License for more details.
27880 *
27881 * You should have received a copy of the GNU Lesser General Public License
27882 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27883 * A copy of the GNU Lesser General Public License is in the file COPYING.
27884 */
27885
27886/** @ignore */
27887var Crypto = require('../crypto.js'); /** @ignore */
27888var Blob = require('../util/blob.js').Blob; /** @ignore */
27889var Name = require('../name.js').Name; /** @ignore */
27890var ForwardingFlags = require('../forwarding-flags').ForwardingFlags; /** @ignore */
27891var Tlv = require('./tlv/tlv.js').Tlv; /** @ignore */
27892var TlvEncoder = require('./tlv/tlv-encoder.js').TlvEncoder; /** @ignore */
27893var TlvDecoder = require('./tlv/tlv-decoder.js').TlvDecoder; /** @ignore */
27894var WireFormat = require('./wire-format.js').WireFormat; /** @ignore */
27895var Exclude = require('../exclude.js').Exclude; /** @ignore */
27896var ContentType = require('../meta-info.js').ContentType; /** @ignore */
27897var KeyLocatorType = require('../key-locator.js').KeyLocatorType; /** @ignore */
27898var Sha256WithRsaSignature = require('../sha256-with-rsa-signature.js').Sha256WithRsaSignature; /** @ignore */
27899var Sha256WithEcdsaSignature = require('../sha256-with-ecdsa-signature.js').Sha256WithEcdsaSignature; /** @ignore */
27900var GenericSignature = require('../generic-signature.js').GenericSignature; /** @ignore */
27901var HmacWithSha256Signature = require('../hmac-with-sha256-signature.js').HmacWithSha256Signature; /** @ignore */
27902var DigestSha256Signature = require('../digest-sha256-signature.js').DigestSha256Signature; /** @ignore */
27903var ControlParameters = require('../control-parameters.js').ControlParameters; /** @ignore */
27904var ForwardingFlags = require('../forwarding-flags.js').ForwardingFlags; /** @ignore */
27905var NetworkNack = require('../network-nack.js').NetworkNack; /** @ignore */
27906var IncomingFaceId = require('../lp/incoming-face-id.js').IncomingFaceId; /** @ignore */
27907var DecodingException = require('./decoding-exception.js').DecodingException;
27908
27909/**
27910 * A Tlv0_2WireFormat implements the WireFormat interface for encoding and
27911 * decoding with the NDN-TLV wire format, version 0.2.
27912 * @constructor
27913 */
27914var Tlv0_2WireFormat = function Tlv0_2WireFormat()
27915{
27916 // Inherit from WireFormat.
27917 WireFormat.call(this);
27918};
27919
27920Tlv0_2WireFormat.prototype = new WireFormat();
27921Tlv0_2WireFormat.prototype.name = "Tlv0_2WireFormat";
27922
27923exports.Tlv0_2WireFormat = Tlv0_2WireFormat;
27924
27925// Default object.
27926Tlv0_2WireFormat.instance = null;
27927
27928/**
27929 * Encode name as an NDN-TLV Name and return the encoding.
27930 * @param {Name} name The Name to encode.
27931 * @return {Blobl} A Blob containing the encoding.
27932 */
27933Tlv0_2WireFormat.prototype.encodeName = function(name)
27934{
27935 var encoder = new TlvEncoder();
27936 Tlv0_2WireFormat.encodeName(name, encoder);
27937 return new Blob(encoder.getOutput(), false);
27938};
27939
27940/**
27941 * Decode input as a NDN-TLV name and set the fields of the Name object.
27942 * @param {Name} name The Name object whose fields are updated.
27943 * @param {Buffer} input The buffer with the bytes to decode.
27944 * @param {boolean} copy (optional) If true, copy from the input when making new
27945 * Blob values. If false, then Blob values share memory with the input, which
27946 * must remain unchanged while the Blob values are used. If omitted, use true.
27947 */
27948Tlv0_2WireFormat.prototype.decodeName = function(name, input, copy)
27949{
27950 if (copy == null)
27951 copy = true;
27952
27953 var decoder = new TlvDecoder(input);
27954 Tlv0_2WireFormat.decodeName(name, decoder, copy);
27955};
27956
27957/**
27958 * Encode the interest using NDN-TLV and return a Buffer.
27959 * @param {Interest} interest The Interest object to encode.
27960 * @return {object} An associative array with fields
27961 * (encoding, signedPortionBeginOffset, signedPortionEndOffset) where encoding
27962 * is a Blob containing the encoding, signedPortionBeginOffset is the offset in
27963 * the encoding of the beginning of the signed portion, and
27964 * signedPortionEndOffset is the offset in the encoding of the end of the signed
27965 * portion. The signed portion starts from the first name component and ends
27966 * just before the final name component (which is assumed to be a signature for
27967 * a signed interest).
27968 */
27969Tlv0_2WireFormat.prototype.encodeInterest = function(interest)
27970{
27971 var encoder = new TlvEncoder(256);
27972 var saveLength = encoder.getLength();
27973
27974 // Encode backwards.
27975 encoder.writeOptionalNonNegativeIntegerTlv
27976 (Tlv.SelectedDelegation, interest.getSelectedDelegationIndex());
27977 var linkWireEncoding = interest.getLinkWireEncoding(this);
27978 if (!linkWireEncoding.isNull())
27979 // Encode the entire link as is.
27980 encoder.writeBuffer(linkWireEncoding.buf());
27981
27982 encoder.writeOptionalNonNegativeIntegerTlv
27983 (Tlv.InterestLifetime, interest.getInterestLifetimeMilliseconds());
27984
27985 // Encode the Nonce as 4 bytes.
27986 if (interest.getNonce().isNull() || interest.getNonce().size() == 0)
27987 // This is the most common case. Generate a nonce.
27988 encoder.writeBlobTlv(Tlv.Nonce, Crypto.randomBytes(4));
27989 else if (interest.getNonce().size() < 4) {
27990 var nonce = Buffer(4);
27991 // Copy existing nonce bytes.
27992 interest.getNonce().buf().copy(nonce);
27993
27994 // Generate random bytes for remaining bytes in the nonce.
27995 for (var i = interest.getNonce().size(); i < 4; ++i)
27996 nonce[i] = Crypto.randomBytes(1)[0];
27997
27998 encoder.writeBlobTlv(Tlv.Nonce, nonce);
27999 }
28000 else if (interest.getNonce().size() == 4)
28001 // Use the nonce as-is.
28002 encoder.writeBlobTlv(Tlv.Nonce, interest.getNonce().buf());
28003 else
28004 // Truncate.
28005 encoder.writeBlobTlv(Tlv.Nonce, interest.getNonce().buf().slice(0, 4));
28006
28007 Tlv0_2WireFormat.encodeSelectors(interest, encoder);
28008 var tempOffsets = Tlv0_2WireFormat.encodeName(interest.getName(), encoder);
28009 var signedPortionBeginOffsetFromBack =
28010 encoder.getLength() - tempOffsets.signedPortionBeginOffset;
28011 var signedPortionEndOffsetFromBack =
28012 encoder.getLength() - tempOffsets.signedPortionEndOffset;
28013
28014 encoder.writeTypeAndLength(Tlv.Interest, encoder.getLength() - saveLength);
28015 var signedPortionBeginOffset =
28016 encoder.getLength() - signedPortionBeginOffsetFromBack;
28017 var signedPortionEndOffset =
28018 encoder.getLength() - signedPortionEndOffsetFromBack;
28019
28020 return { encoding: new Blob(encoder.getOutput(), false),
28021 signedPortionBeginOffset: signedPortionBeginOffset,
28022 signedPortionEndOffset: signedPortionEndOffset };
28023};
28024
28025/**
28026 * Decode input as an NDN-TLV interest and set the fields of the interest
28027 * object.
28028 * @param {Interest} interest The Interest object whose fields are updated.
28029 * @param {Buffer} input The buffer with the bytes to decode.
28030 * @param {boolean} copy (optional) If true, copy from the input when making new
28031 * Blob values. If false, then Blob values share memory with the input, which
28032 * must remain unchanged while the Blob values are used. If omitted, use true.
28033 * @return {object} An associative array with fields
28034 * (signedPortionBeginOffset, signedPortionEndOffset) where
28035 * signedPortionBeginOffset is the offset in the encoding of the beginning of
28036 * the signed portion, and signedPortionEndOffset is the offset in the encoding
28037 * of the end of the signed portion. The signed portion starts from the first
28038 * name component and ends just before the final name component (which is
28039 * assumed to be a signature for a signed interest).
28040 */
28041Tlv0_2WireFormat.prototype.decodeInterest = function(interest, input, copy)
28042{
28043 if (copy == null)
28044 copy = true;
28045
28046 var decoder = new TlvDecoder(input);
28047
28048 var endOffset = decoder.readNestedTlvsStart(Tlv.Interest);
28049 var offsets = Tlv0_2WireFormat.decodeName(interest.getName(), decoder, copy);
28050 if (decoder.peekType(Tlv.Selectors, endOffset))
28051 Tlv0_2WireFormat.decodeSelectors(interest, decoder, copy);
28052 // Require a Nonce, but don't force it to be 4 bytes.
28053 var nonce = decoder.readBlobTlv(Tlv.Nonce);
28054 interest.setInterestLifetimeMilliseconds
28055 (decoder.readOptionalNonNegativeIntegerTlv(Tlv.InterestLifetime, endOffset));
28056
28057 if (decoder.peekType(Tlv.Data, endOffset)) {
28058 // Get the bytes of the Link TLV.
28059 var linkBeginOffset = decoder.getOffset();
28060 var linkEndOffset = decoder.readNestedTlvsStart(Tlv.Data);
28061 decoder.seek(linkEndOffset);
28062
28063 interest.setLinkWireEncoding
28064 (new Blob(decoder.getSlice(linkBeginOffset, linkEndOffset), copy), this);
28065 }
28066 else
28067 interest.unsetLink();
28068 interest.setSelectedDelegationIndex
28069 (decoder.readOptionalNonNegativeIntegerTlv(Tlv.SelectedDelegation, endOffset));
28070 if (interest.getSelectedDelegationIndex() != null &&
28071 interest.getSelectedDelegationIndex() >= 0 && !interest.hasLink())
28072 throw new Error("Interest has a selected delegation, but no link object");
28073
28074 // Set the nonce last because setting other interest fields clears it.
28075 interest.setNonce(new Blob(nonce, copy));
28076
28077 decoder.finishNestedTlvs(endOffset);
28078 return offsets;
28079};
28080
28081/**
28082 * Encode data as NDN-TLV and return the encoding and signed offsets.
28083 * @param {Data} data The Data object to encode.
28084 * @return {object} An associative array with fields
28085 * (encoding, signedPortionBeginOffset, signedPortionEndOffset) where encoding
28086 * is a Blob containing the encoding, signedPortionBeginOffset is the offset in
28087 * the encoding of the beginning of the signed portion, and
28088 * signedPortionEndOffset is the offset in the encoding of the end of the
28089 * signed portion.
28090 */
28091Tlv0_2WireFormat.prototype.encodeData = function(data)
28092{
28093 var encoder = new TlvEncoder(1500);
28094 var saveLength = encoder.getLength();
28095
28096 // Encode backwards.
28097 encoder.writeBlobTlv(Tlv.SignatureValue, data.getSignature().getSignature().buf());
28098 var signedPortionEndOffsetFromBack = encoder.getLength();
28099
28100 Tlv0_2WireFormat.encodeSignatureInfo_(data.getSignature(), encoder);
28101 encoder.writeBlobTlv(Tlv.Content, data.getContent().buf());
28102 Tlv0_2WireFormat.encodeMetaInfo(data.getMetaInfo(), encoder);
28103 Tlv0_2WireFormat.encodeName(data.getName(), encoder);
28104 var signedPortionBeginOffsetFromBack = encoder.getLength();
28105
28106 encoder.writeTypeAndLength(Tlv.Data, encoder.getLength() - saveLength);
28107 var signedPortionBeginOffset =
28108 encoder.getLength() - signedPortionBeginOffsetFromBack;
28109 var signedPortionEndOffset = encoder.getLength() - signedPortionEndOffsetFromBack;
28110
28111 return { encoding: new Blob(encoder.getOutput(), false),
28112 signedPortionBeginOffset: signedPortionBeginOffset,
28113 signedPortionEndOffset: signedPortionEndOffset };
28114};
28115
28116/**
28117 * Decode input as an NDN-TLV data packet, set the fields in the data object,
28118 * and return the signed offsets.
28119 * @param {Data} data The Data object whose fields are updated.
28120 * @param {Buffer} input The buffer with the bytes to decode.
28121 * @param {boolean} copy (optional) If true, copy from the input when making new
28122 * Blob values. If false, then Blob values share memory with the input, which
28123 * must remain unchanged while the Blob values are used. If omitted, use true.
28124 * @return {object} An associative array with fields
28125 * (signedPortionBeginOffset, signedPortionEndOffset) where
28126 * signedPortionBeginOffset is the offset in the encoding of the beginning of
28127 * the signed portion, and signedPortionEndOffset is the offset in the encoding
28128 * of the end of the signed portion.
28129 */
28130Tlv0_2WireFormat.prototype.decodeData = function(data, input, copy)
28131{
28132 if (copy == null)
28133 copy = true;
28134
28135 var decoder = new TlvDecoder(input);
28136
28137 var endOffset = decoder.readNestedTlvsStart(Tlv.Data);
28138 var signedPortionBeginOffset = decoder.getOffset();
28139
28140 Tlv0_2WireFormat.decodeName(data.getName(), decoder, copy);
28141 Tlv0_2WireFormat.decodeMetaInfo(data.getMetaInfo(), decoder, copy);
28142 data.setContent(new Blob(decoder.readBlobTlv(Tlv.Content), copy));
28143 Tlv0_2WireFormat.decodeSignatureInfo(data, decoder, copy);
28144
28145 var signedPortionEndOffset = decoder.getOffset();
28146 data.getSignature().setSignature
28147 (new Blob(decoder.readBlobTlv(Tlv.SignatureValue), copy));
28148
28149 decoder.finishNestedTlvs(endOffset);
28150 return { signedPortionBeginOffset: signedPortionBeginOffset,
28151 signedPortionEndOffset: signedPortionEndOffset };
28152};
28153
28154/**
28155 * Encode controlParameters as NDN-TLV and return the encoding.
28156 * @param {ControlParameters} controlParameters The ControlParameters object to
28157 * encode.
28158 * @return {Blob} A Blob containing the encoding.
28159 */
28160Tlv0_2WireFormat.prototype.encodeControlParameters = function(controlParameters)
28161{
28162 var encoder = new TlvEncoder(256);
28163 Tlv0_2WireFormat.encodeControlParameters(controlParameters, encoder);
28164 return new Blob(encoder.getOutput(), false);
28165};
28166
28167/**
28168 * Decode controlParameters in NDN-TLV and return the encoding.
28169 * @param {ControlParameters} controlParameters The ControlParameters object to
28170 * encode.
28171 * @param {Buffer} input The buffer with the bytes to decode.
28172 * @param {boolean} copy (optional) If true, copy from the input when making new
28173 * Blob values. If false, then Blob values share memory with the input, which
28174 * must remain unchanged while the Blob values are used. If omitted, use true.
28175 * @throws DecodingException For invalid encoding
28176 */
28177Tlv0_2WireFormat.prototype.decodeControlParameters = function
28178 (controlParameters, input, copy)
28179{
28180 if (copy == null)
28181 copy = true;
28182
28183 var decoder = new TlvDecoder(input);
28184 Tlv0_2WireFormat.decodeControlParameters(controlParameters, decoder, copy);
28185};
28186
28187/**
28188 * Encode controlResponse as NDN-TLV and return the encoding.
28189 * @param {ControlResponse} controlResponse The ControlResponse object to
28190 * encode.
28191 * @return {Blob} A Blob containing the encoding.
28192 */
28193Tlv0_2WireFormat.prototype.encodeControlResponse = function(controlResponse)
28194{
28195 var encoder = new TlvEncoder(256);
28196 var saveLength = encoder.getLength();
28197
28198 // Encode backwards.
28199
28200 // Encode the body.
28201 if (controlResponse.getBodyAsControlParameters() != null)
28202 Tlv0_2WireFormat.encodeControlParameters
28203 (controlResponse.getBodyAsControlParameters(), encoder);
28204
28205 encoder.writeBlobTlv
28206 (Tlv.NfdCommand_StatusText, new Blob(controlResponse.getStatusText()).buf());
28207 encoder.writeNonNegativeIntegerTlv
28208 (Tlv.NfdCommand_StatusCode, controlResponse.getStatusCode());
28209
28210 encoder.writeTypeAndLength
28211 (Tlv.NfdCommand_ControlResponse, encoder.getLength() - saveLength);
28212
28213 return new Blob(encoder.getOutput(), false);
28214};
28215
28216/**
28217 * Decode controlResponse in NDN-TLV and return the encoding.
28218 * @param {ControlResponse} controlResponse The ControlResponse object to
28219 * encode.
28220 * @param {Buffer} input The buffer with the bytes to decode.
28221 * @param {boolean} copy (optional) If true, copy from the input when making new
28222 * Blob values. If false, then Blob values share memory with the input, which
28223 * must remain unchanged while the Blob values are used. If omitted, use true.
28224 * @throws DecodingException For invalid encoding
28225 */
28226Tlv0_2WireFormat.prototype.decodeControlResponse = function
28227 (controlResponse, input, copy)
28228{
28229 if (copy == null)
28230 copy = true;
28231
28232 var decoder = new TlvDecoder(input);
28233 var endOffset = decoder.readNestedTlvsStart(Tlv.NfdCommand_ControlResponse);
28234
28235 controlResponse.setStatusCode(decoder.readNonNegativeIntegerTlv
28236 (Tlv.NfdCommand_StatusCode));
28237 // Set copy false since we just immediately get a string.
28238 var statusText = new Blob
28239 (decoder.readBlobTlv(Tlv.NfdCommand_StatusText), false);
28240 controlResponse.setStatusText(statusText.toString());
28241
28242 // Decode the body.
28243 if (decoder.peekType(Tlv.ControlParameters_ControlParameters, endOffset)) {
28244 controlResponse.setBodyAsControlParameters(new ControlParameters());
28245 // Decode into the existing ControlParameters to avoid copying.
28246 Tlv0_2WireFormat.decodeControlParameters
28247 (controlResponse.getBodyAsControlParameters(), decoder, copy);
28248 }
28249 else
28250 controlResponse.setBodyAsControlParameters(null);
28251
28252 decoder.finishNestedTlvs(endOffset);
28253};
28254
28255/**
28256 * Encode signature as an NDN-TLV SignatureInfo and return the encoding.
28257 * @param {Signature} signature An object of a subclass of Signature to encode.
28258 * @return {Blob} A Blob containing the encoding.
28259 */
28260Tlv0_2WireFormat.prototype.encodeSignatureInfo = function(signature)
28261{
28262 var encoder = new TlvEncoder(256);
28263 Tlv0_2WireFormat.encodeSignatureInfo_(signature, encoder);
28264
28265 return new Blob(encoder.getOutput(), false);
28266};
28267
28268// SignatureHolder is used by decodeSignatureInfoAndValue.
28269Tlv0_2WireFormat.SignatureHolder = function Tlv0_2WireFormatSignatureHolder()
28270{
28271};
28272
28273Tlv0_2WireFormat.SignatureHolder.prototype.setSignature = function(signature)
28274{
28275 this.signature = signature;
28276};
28277
28278Tlv0_2WireFormat.SignatureHolder.prototype.getSignature = function()
28279{
28280 return this.signature;
28281};
28282
28283/**
28284 * Decode signatureInfo as an NDN-TLV SignatureInfo and signatureValue as the
28285 * related SignatureValue, and return a new object which is a subclass of Signature.
28286 * @param {Buffer} signatureInfo The buffer with the signature info bytes to
28287 * decode.
28288 * @param {Buffer} signatureValue The buffer with the signature value to decode.
28289 * @param {boolean} copy (optional) If true, copy from the input when making new
28290 * Blob values. If false, then Blob values share memory with the input, which
28291 * must remain unchanged while the Blob values are used. If omitted, use true.
28292 * @return {Signature} A new object which is a subclass of Signature.
28293 */
28294Tlv0_2WireFormat.prototype.decodeSignatureInfoAndValue = function
28295 (signatureInfo, signatureValue, copy)
28296{
28297 if (copy == null)
28298 copy = true;
28299
28300 // Use a SignatureHolder to imitate a Data object for decodeSignatureInfo.
28301 var signatureHolder = new Tlv0_2WireFormat.SignatureHolder();
28302 var decoder = new TlvDecoder(signatureInfo);
28303 Tlv0_2WireFormat.decodeSignatureInfo(signatureHolder, decoder, copy);
28304
28305 decoder = new TlvDecoder(signatureValue);
28306 signatureHolder.getSignature().setSignature
28307 (new Blob(decoder.readBlobTlv(Tlv.SignatureValue), copy));
28308
28309 return signatureHolder.getSignature();
28310};
28311
28312/**
28313 * Encode the signatureValue in the Signature object as an NDN-TLV
28314 * SignatureValue (the signature bits) and return the encoding.
28315 * @param {Signature} signature An object of a subclass of Signature with the
28316 * signature value to encode.
28317 * @return {Blob} A Blob containing the encoding.
28318 */
28319Tlv0_2WireFormat.prototype.encodeSignatureValue = function(signature)
28320{
28321 var encoder = new TlvEncoder(256);
28322 encoder.writeBlobTlv(Tlv.SignatureValue, signature.getSignature().buf());
28323
28324 return new Blob(encoder.getOutput(), false);
28325};
28326
28327/**
28328 * Decode input as an NDN-TLV LpPacket and set the fields of the lpPacket object.
28329 * @param {LpPacket} lpPacket The LpPacket object whose fields are updated.
28330 * @param {Buffer} input The buffer with the bytes to decode.
28331 * @param {boolean} copy (optional) If true, copy from the input when making new
28332 * Blob values. If false, then Blob values share memory with the input, which
28333 * must remain unchanged while the Blob values are used. If omitted, use true.
28334 */
28335Tlv0_2WireFormat.prototype.decodeLpPacket = function(lpPacket, input, copy)
28336{
28337 if (copy == null)
28338 copy = true;
28339
28340 lpPacket.clear();
28341
28342 var decoder = new TlvDecoder(input);
28343 var endOffset = decoder.readNestedTlvsStart(Tlv.LpPacket_LpPacket);
28344
28345 while (decoder.getOffset() < endOffset) {
28346 // Imitate TlvDecoder.readTypeAndLength.
28347 var fieldType = decoder.readVarNumber();
28348 var fieldLength = decoder.readVarNumber();
28349 var fieldEndOffset = decoder.getOffset() + fieldLength;
28350 if (fieldEndOffset > input.length)
28351 throw new DecodingException(new Error("TLV length exceeds the buffer length"));
28352
28353 if (fieldType == Tlv.LpPacket_Fragment) {
28354 // Set the fragment to the bytes of the TLV value.
28355 lpPacket.setFragmentWireEncoding
28356 (new Blob(decoder.getSlice(decoder.getOffset(), fieldEndOffset), copy));
28357 decoder.seek(fieldEndOffset);
28358
28359 // The fragment is supposed to be the last field.
28360 break;
28361 }
28362 else if (fieldType == Tlv.LpPacket_Nack) {
28363 var networkNack = new NetworkNack();
28364 var code = decoder.readOptionalNonNegativeIntegerTlv
28365 (Tlv.LpPacket_NackReason, fieldEndOffset);
28366 var reason;
28367 // The enum numeric values are the same as this wire format, so use as is.
28368 if (code < 0 || code == NetworkNack.Reason.NONE)
28369 // This includes an omitted NackReason.
28370 networkNack.setReason(NetworkNack.Reason.NONE);
28371 else if (code == NetworkNack.Reason.CONGESTION ||
28372 code == NetworkNack.Reason.DUPLICATE ||
28373 code == NetworkNack.Reason.NO_ROUTE)
28374 networkNack.setReason(code);
28375 else {
28376 // Unrecognized reason.
28377 networkNack.setReason(NetworkNack.Reason.OTHER_CODE);
28378 networkNack.setOtherReasonCode(code);
28379 }
28380
28381 lpPacket.addHeaderField(networkNack);
28382 }
28383 else if (fieldType == Tlv.LpPacket_IncomingFaceId) {
28384 var incomingFaceId = new IncomingFaceId();
28385 incomingFaceId.setFaceId(decoder.readNonNegativeInteger(fieldLength));
28386 lpPacket.addHeaderField(incomingFaceId);
28387 }
28388 else {
28389 // Unrecognized field type. The conditions for ignoring are here:
28390 // http://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
28391 var canIgnore =
28392 (fieldType >= Tlv.LpPacket_IGNORE_MIN &&
28393 fieldType <= Tlv.LpPacket_IGNORE_MAX &&
28394 (fieldType & 0x01) === 1);
28395 if (!canIgnore)
28396 throw new DecodingException(new Error("Did not get the expected TLV type"));
28397
28398 // Ignore.
28399 decoder.seek(fieldEndOffset);
28400 }
28401
28402 decoder.finishNestedTlvs(fieldEndOffset);
28403 }
28404
28405 decoder.finishNestedTlvs(endOffset);
28406};
28407
28408/**
28409 * Encode delegationSet as a sequence of NDN-TLV Delegation, and return the
28410 * encoding. Note that the sequence of Delegation does not have an outer TLV
28411 * type and length because it is intended to use the type and length of a Data
28412 * packet's Content.
28413 * @param {DelegationSet} delegationSet The DelegationSet object to encode.
28414 * @return {Blob} A Blob containing the encoding.
28415 */
28416Tlv0_2WireFormat.prototype.encodeDelegationSet = function(delegationSet)
28417{
28418 var encoder = new TlvEncoder(256);
28419
28420 // Encode backwards.
28421 for (var i = delegationSet.size() - 1; i >= 0; --i) {
28422 var saveLength = encoder.getLength();
28423
28424 Tlv0_2WireFormat.encodeName(delegationSet.get(i).getName(), encoder);
28425 encoder.writeNonNegativeIntegerTlv
28426 (Tlv.Link_Preference, delegationSet.get(i).getPreference());
28427
28428 encoder.writeTypeAndLength
28429 (Tlv.Link_Delegation, encoder.getLength() - saveLength);
28430 }
28431
28432 return new Blob(encoder.getOutput(), false);
28433};
28434
28435/**
28436 * Decode input as a sequence of NDN-TLV Delegation and set the fields of the
28437 * delegationSet object. Note that the sequence of Delegation does not have an
28438 * outer TLV type and length because it is intended to use the type and length
28439 * of a Data packet's Content. This ignores any elements after the sequence
28440 * of Delegation.
28441 * @param {DelegationSet} delegationSet The DelegationSet object
28442 * whose fields are updated.
28443 * @param {Buffer} input The buffer with the bytes to decode.
28444 * @param {boolean} copy (optional) If true, copy from the input when making new
28445 * Blob values. If false, then Blob values share memory with the input, which
28446 * must remain unchanged while the Blob values are used. If omitted, use true.
28447 */
28448Tlv0_2WireFormat.prototype.decodeDelegationSet = function
28449 (delegationSet, input, copy)
28450{
28451 if (copy == null)
28452 copy = true;
28453
28454 var decoder = new TlvDecoder(input);
28455 var endOffset = input.length;
28456
28457 delegationSet.clear();
28458 while (decoder.getOffset() < endOffset) {
28459 decoder.readTypeAndLength(Tlv.Link_Delegation);
28460 var preference = decoder.readNonNegativeIntegerTlv(Tlv.Link_Preference);
28461 var name = new Name();
28462 Tlv0_2WireFormat.decodeName(name, decoder, copy);
28463
28464 // Add unsorted to preserve the order so that Interest selected delegation
28465 // index will work.
28466 delegationSet.addUnsorted(preference, name);
28467 }
28468};
28469
28470/**
28471 * Encode the EncryptedContent in NDN-TLV and return the encoding.
28472 * @param {EncryptedContent} encryptedContent The EncryptedContent object to
28473 * encode.
28474 * @return {Blob} A Blob containing the encoding.
28475 */
28476Tlv0_2WireFormat.prototype.encodeEncryptedContent = function(encryptedContent)
28477{
28478 var encoder = new TlvEncoder(256);
28479 var saveLength = encoder.getLength();
28480
28481 // Encode backwards.
28482 encoder.writeBlobTlv
28483 (Tlv.Encrypt_EncryptedPayload, encryptedContent.getPayload().buf());
28484 encoder.writeOptionalBlobTlv
28485 (Tlv.Encrypt_InitialVector, encryptedContent.getInitialVector().buf());
28486 // Assume the algorithmType value is the same as the TLV type.
28487 encoder.writeNonNegativeIntegerTlv
28488 (Tlv.Encrypt_EncryptionAlgorithm, encryptedContent.getAlgorithmType());
28489 Tlv0_2WireFormat.encodeKeyLocator
28490 (Tlv.KeyLocator, encryptedContent.getKeyLocator(), encoder);
28491
28492 encoder.writeTypeAndLength
28493 (Tlv.Encrypt_EncryptedContent, encoder.getLength() - saveLength);
28494
28495 return new Blob(encoder.getOutput(), false);
28496};
28497
28498/**
28499 * Decode input as an EncryptedContent in NDN-TLV and set the fields of the
28500 * encryptedContent object.
28501 * @param {EncryptedContent} encryptedContent The EncryptedContent object
28502 * whose fields are updated.
28503 * @param {Buffer} input The buffer with the bytes to decode.
28504 * @param {boolean} copy (optional) If true, copy from the input when making new
28505 * Blob values. If false, then Blob values share memory with the input, which
28506 * must remain unchanged while the Blob values are used. If omitted, use true.
28507 */
28508Tlv0_2WireFormat.prototype.decodeEncryptedContent = function
28509 (encryptedContent, input, copy)
28510{
28511 if (copy == null)
28512 copy = true;
28513
28514 var decoder = new TlvDecoder(input);
28515 var endOffset = decoder.
28516 readNestedTlvsStart(Tlv.Encrypt_EncryptedContent);
28517
28518 Tlv0_2WireFormat.decodeKeyLocator
28519 (Tlv.KeyLocator, encryptedContent.getKeyLocator(), decoder, copy);
28520 encryptedContent.setAlgorithmType
28521 (decoder.readNonNegativeIntegerTlv(Tlv.Encrypt_EncryptionAlgorithm));
28522 encryptedContent.setInitialVector
28523 (new Blob(decoder.readOptionalBlobTlv
28524 (Tlv.Encrypt_InitialVector, endOffset), copy));
28525 encryptedContent.setPayload
28526 (new Blob(decoder.readBlobTlv(Tlv.Encrypt_EncryptedPayload), copy));
28527
28528 decoder.finishNestedTlvs(endOffset);
28529};
28530
28531/**
28532 * Get a singleton instance of a Tlv0_2WireFormat. To always use the
28533 * preferred version NDN-TLV, you should use TlvWireFormat.get().
28534 * @return {Tlv0_2WireFormat} The singleton instance.
28535 */
28536Tlv0_2WireFormat.get = function()
28537{
28538 if (Tlv0_2WireFormat.instance === null)
28539 Tlv0_2WireFormat.instance = new Tlv0_2WireFormat();
28540 return Tlv0_2WireFormat.instance;
28541};
28542
28543/**
28544 * Encode the name component to the encoder as NDN-TLV. This handles different
28545 * component types such as ImplicitSha256DigestComponent.
28546 * @param {Name.Component} component The name component to encode.
28547 * @param {TlvEncoder} encoder The encoder to receive the encoding.
28548 */
28549Tlv0_2WireFormat.encodeNameComponent = function(component, encoder)
28550{
28551 var type = component.isImplicitSha256Digest() ?
28552 Tlv.ImplicitSha256DigestComponent : Tlv.NameComponent;
28553 encoder.writeBlobTlv(type, component.getValue().buf());
28554};
28555
28556/**
28557 * Decode the name component as NDN-TLV and return the component. This handles
28558 * different component types such as ImplicitSha256DigestComponent.
28559 * @param {TlvDecoder} decoder The decoder with the input.
28560 * @param {boolean} copy (optional) If true, copy from the input when making new
28561 * Blob values. If false, then Blob values share memory with the input, which
28562 * must remain unchanged while the Blob values are used. If omitted, use true.
28563 * @return {Name.Component} A new Name.Component.
28564 */
28565Tlv0_2WireFormat.decodeNameComponent = function(decoder, copy)
28566{
28567 if (copy == null)
28568 copy = true;
28569
28570 var savePosition = decoder.getOffset();
28571 var type = decoder.readVarNumber();
28572 // Restore the position.
28573 decoder.seek(savePosition);
28574
28575 var value = new Blob(decoder.readBlobTlv(type), copy);
28576 if (type === Tlv.ImplicitSha256DigestComponent)
28577 return Name.Component.fromImplicitSha256Digest(value);
28578 else
28579 return new Name.Component(value);
28580};
28581
28582/**
28583 * Encode the name to the encoder.
28584 * @param {Name} name The name to encode.
28585 * @param {TlvEncoder} encoder The encoder to receive the encoding.
28586 * @return {object} An associative array with fields
28587 * (signedPortionBeginOffset, signedPortionEndOffset) where
28588 * signedPortionBeginOffset is the offset in the encoding of the beginning of
28589 * the signed portion, and signedPortionEndOffset is the offset in the encoding
28590 * of the end of the signed portion. The signed portion starts from the first
28591 * name component and ends just before the final name component (which is
28592 * assumed to be a signature for a signed interest).
28593 */
28594Tlv0_2WireFormat.encodeName = function(name, encoder)
28595{
28596 var saveLength = encoder.getLength();
28597
28598 // Encode the components backwards.
28599 var signedPortionEndOffsetFromBack;
28600 for (var i = name.size() - 1; i >= 0; --i) {
28601 Tlv0_2WireFormat.encodeNameComponent(name.get(i), encoder);
28602 if (i == name.size() - 1)
28603 signedPortionEndOffsetFromBack = encoder.getLength();
28604 }
28605
28606 var signedPortionBeginOffsetFromBack = encoder.getLength();
28607 encoder.writeTypeAndLength(Tlv.Name, encoder.getLength() - saveLength);
28608
28609 var signedPortionBeginOffset =
28610 encoder.getLength() - signedPortionBeginOffsetFromBack;
28611 var signedPortionEndOffset;
28612 if (name.size() == 0)
28613 // There is no "final component", so set signedPortionEndOffset arbitrarily.
28614 signedPortionEndOffset = signedPortionBeginOffset;
28615 else
28616 signedPortionEndOffset = encoder.getLength() - signedPortionEndOffsetFromBack;
28617
28618 return { signedPortionBeginOffset: signedPortionBeginOffset,
28619 signedPortionEndOffset: signedPortionEndOffset };
28620};
28621
28622/**
28623 * Clear the name, decode a Name from the decoder and set the fields of the name
28624 * object.
28625 * @param {Name} name The name object whose fields are updated.
28626 * @param {TlvDecoder} decoder The decoder with the input.
28627 * @return {object} An associative array with fields
28628 * (signedPortionBeginOffset, signedPortionEndOffset) where
28629 * signedPortionBeginOffset is the offset in the encoding of the beginning of
28630 * the signed portion, and signedPortionEndOffset is the offset in the encoding
28631 * of the end of the signed portion. The signed portion starts from the first
28632 * name component and ends just before the final name component (which is
28633 * assumed to be a signature for a signed interest).
28634 */
28635Tlv0_2WireFormat.decodeName = function(name, decoder, copy)
28636{
28637 name.clear();
28638
28639 var endOffset = decoder.readNestedTlvsStart(Tlv.Name);
28640 var signedPortionBeginOffset = decoder.getOffset();
28641 // In case there are no components, set signedPortionEndOffset arbitrarily.
28642 var signedPortionEndOffset = signedPortionBeginOffset;
28643
28644 while (decoder.getOffset() < endOffset) {
28645 signedPortionEndOffset = decoder.getOffset();
28646 name.append(Tlv0_2WireFormat.decodeNameComponent(decoder, copy));
28647 }
28648
28649 decoder.finishNestedTlvs(endOffset);
28650
28651 return { signedPortionBeginOffset: signedPortionBeginOffset,
28652 signedPortionEndOffset: signedPortionEndOffset };
28653};
28654
28655/**
28656 * Encode the interest selectors. If no selectors are written, do not output a
28657 * Selectors TLV.
28658 */
28659Tlv0_2WireFormat.encodeSelectors = function(interest, encoder)
28660{
28661 var saveLength = encoder.getLength();
28662
28663 // Encode backwards.
28664 if (interest.getMustBeFresh())
28665 encoder.writeTypeAndLength(Tlv.MustBeFresh, 0);
28666 encoder.writeOptionalNonNegativeIntegerTlv(
28667 Tlv.ChildSelector, interest.getChildSelector());
28668 if (interest.getExclude().size() > 0)
28669 Tlv0_2WireFormat.encodeExclude(interest.getExclude(), encoder);
28670
28671 if (interest.getKeyLocator().getType() != null)
28672 Tlv0_2WireFormat.encodeKeyLocator
28673 (Tlv.PublisherPublicKeyLocator, interest.getKeyLocator(), encoder);
28674
28675 encoder.writeOptionalNonNegativeIntegerTlv(
28676 Tlv.MaxSuffixComponents, interest.getMaxSuffixComponents());
28677 encoder.writeOptionalNonNegativeIntegerTlv(
28678 Tlv.MinSuffixComponents, interest.getMinSuffixComponents());
28679
28680 // Only output the type and length if values were written.
28681 if (encoder.getLength() != saveLength)
28682 encoder.writeTypeAndLength(Tlv.Selectors, encoder.getLength() - saveLength);
28683};
28684
28685Tlv0_2WireFormat.decodeSelectors = function(interest, decoder, copy)
28686{
28687 if (copy == null)
28688 copy = true;
28689
28690 var endOffset = decoder.readNestedTlvsStart(Tlv.Selectors);
28691
28692 interest.setMinSuffixComponents(decoder.readOptionalNonNegativeIntegerTlv
28693 (Tlv.MinSuffixComponents, endOffset));
28694 interest.setMaxSuffixComponents(decoder.readOptionalNonNegativeIntegerTlv
28695 (Tlv.MaxSuffixComponents, endOffset));
28696
28697 if (decoder.peekType(Tlv.PublisherPublicKeyLocator, endOffset))
28698 Tlv0_2WireFormat.decodeKeyLocator
28699 (Tlv.PublisherPublicKeyLocator, interest.getKeyLocator(), decoder, copy);
28700 else
28701 interest.getKeyLocator().clear();
28702
28703 if (decoder.peekType(Tlv.Exclude, endOffset))
28704 Tlv0_2WireFormat.decodeExclude(interest.getExclude(), decoder, copy);
28705 else
28706 interest.getExclude().clear();
28707
28708 interest.setChildSelector(decoder.readOptionalNonNegativeIntegerTlv
28709 (Tlv.ChildSelector, endOffset));
28710 interest.setMustBeFresh(decoder.readBooleanTlv(Tlv.MustBeFresh, endOffset));
28711
28712 decoder.finishNestedTlvs(endOffset);
28713};
28714
28715Tlv0_2WireFormat.encodeExclude = function(exclude, encoder)
28716{
28717 var saveLength = encoder.getLength();
28718
28719 // TODO: Do we want to order the components (except for ANY)?
28720 // Encode the entries backwards.
28721 for (var i = exclude.size() - 1; i >= 0; --i) {
28722 var entry = exclude.get(i);
28723
28724 if (entry == Exclude.ANY)
28725 encoder.writeTypeAndLength(Tlv.Any, 0);
28726 else
28727 Tlv0_2WireFormat.encodeNameComponent(entry, encoder);
28728 }
28729
28730 encoder.writeTypeAndLength(Tlv.Exclude, encoder.getLength() - saveLength);
28731};
28732
28733Tlv0_2WireFormat.decodeExclude = function(exclude, decoder, copy)
28734{
28735 if (copy == null)
28736 copy = true;
28737
28738 var endOffset = decoder.readNestedTlvsStart(Tlv.Exclude);
28739
28740 exclude.clear();
28741 while (decoder.getOffset() < endOffset) {
28742 if (decoder.peekType(Tlv.Any, endOffset)) {
28743 // Read past the Any TLV.
28744 decoder.readBooleanTlv(Tlv.Any, endOffset);
28745 exclude.appendAny();
28746 }
28747 else
28748 exclude.appendComponent(Tlv0_2WireFormat.decodeNameComponent(decoder, copy));
28749 }
28750
28751 decoder.finishNestedTlvs(endOffset);
28752};
28753
28754Tlv0_2WireFormat.encodeKeyLocator = function(type, keyLocator, encoder)
28755{
28756 var saveLength = encoder.getLength();
28757
28758 // Encode backwards.
28759 if (keyLocator.getType() != null) {
28760 if (keyLocator.getType() == KeyLocatorType.KEYNAME)
28761 Tlv0_2WireFormat.encodeName(keyLocator.getKeyName(), encoder);
28762 else if (keyLocator.getType() == KeyLocatorType.KEY_LOCATOR_DIGEST &&
28763 keyLocator.getKeyData().size() > 0)
28764 encoder.writeBlobTlv(Tlv.KeyLocatorDigest, keyLocator.getKeyData().buf());
28765 else
28766 throw new Error("Unrecognized KeyLocatorType " + keyLocator.getType());
28767 }
28768
28769 encoder.writeTypeAndLength(type, encoder.getLength() - saveLength);
28770};
28771
28772Tlv0_2WireFormat.decodeKeyLocator = function
28773 (expectedType, keyLocator, decoder, copy)
28774{
28775 if (copy == null)
28776 copy = true;
28777
28778 var endOffset = decoder.readNestedTlvsStart(expectedType);
28779
28780 keyLocator.clear();
28781
28782 if (decoder.getOffset() == endOffset)
28783 // The KeyLocator is omitted, so leave the fields as none.
28784 return;
28785
28786 if (decoder.peekType(Tlv.Name, endOffset)) {
28787 // KeyLocator is a Name.
28788 keyLocator.setType(KeyLocatorType.KEYNAME);
28789 Tlv0_2WireFormat.decodeName(keyLocator.getKeyName(), decoder, copy);
28790 }
28791 else if (decoder.peekType(Tlv.KeyLocatorDigest, endOffset)) {
28792 // KeyLocator is a KeyLocatorDigest.
28793 keyLocator.setType(KeyLocatorType.KEY_LOCATOR_DIGEST);
28794 keyLocator.setKeyData
28795 (new Blob(decoder.readBlobTlv(Tlv.KeyLocatorDigest), copy));
28796 }
28797 else
28798 throw new DecodingException(new Error
28799 ("decodeKeyLocator: Unrecognized key locator type"));
28800
28801 decoder.finishNestedTlvs(endOffset);
28802};
28803
28804/**
28805 * An internal method to encode signature as the appropriate form of
28806 * SignatureInfo in NDN-TLV.
28807 * @param {Signature} signature An object of a subclass of Signature to encode.
28808 * @param {TlvEncoder} encoder The encoder.
28809 */
28810Tlv0_2WireFormat.encodeSignatureInfo_ = function(signature, encoder)
28811{
28812 if (signature instanceof GenericSignature) {
28813 // Handle GenericSignature separately since it has the entire encoding.
28814 var encoding = signature.getSignatureInfoEncoding();
28815
28816 // Do a test decoding to sanity check that it is valid TLV.
28817 try {
28818 var decoder = new TlvDecoder(encoding.buf());
28819 var endOffset = decoder.readNestedTlvsStart(Tlv.SignatureInfo);
28820 decoder.readNonNegativeIntegerTlv(Tlv.SignatureType);
28821 decoder.finishNestedTlvs(endOffset);
28822 } catch (ex) {
28823 throw new Error
28824 ("The GenericSignature encoding is not a valid NDN-TLV SignatureInfo: " +
28825 ex.message);
28826 }
28827
28828 encoder.writeBuffer(encoding.buf());
28829 return;
28830 }
28831
28832 var saveLength = encoder.getLength();
28833
28834 // Encode backwards.
28835 if (signature instanceof Sha256WithRsaSignature) {
28836 Tlv0_2WireFormat.encodeKeyLocator
28837 (Tlv.KeyLocator, signature.getKeyLocator(), encoder);
28838 encoder.writeNonNegativeIntegerTlv
28839 (Tlv.SignatureType, Tlv.SignatureType_SignatureSha256WithRsa);
28840 }
28841 else if (signature instanceof Sha256WithEcdsaSignature) {
28842 Tlv0_2WireFormat.encodeKeyLocator
28843 (Tlv.KeyLocator, signature.getKeyLocator(), encoder);
28844 encoder.writeNonNegativeIntegerTlv
28845 (Tlv.SignatureType, Tlv.SignatureType_SignatureSha256WithEcdsa);
28846 }
28847 else if (signature instanceof HmacWithSha256Signature) {
28848 Tlv0_2WireFormat.encodeKeyLocator
28849 (Tlv.KeyLocator, signature.getKeyLocator(), encoder);
28850 encoder.writeNonNegativeIntegerTlv
28851 (Tlv.SignatureType, Tlv.SignatureType_SignatureHmacWithSha256);
28852 }
28853 else if (signature instanceof DigestSha256Signature)
28854 encoder.writeNonNegativeIntegerTlv
28855 (Tlv.SignatureType, Tlv.SignatureType_DigestSha256);
28856 else
28857 throw new Error("encodeSignatureInfo: Unrecognized Signature object type");
28858
28859 encoder.writeTypeAndLength(Tlv.SignatureInfo, encoder.getLength() - saveLength);
28860};
28861
28862Tlv0_2WireFormat.decodeSignatureInfo = function(data, decoder, copy)
28863{
28864 if (copy == null)
28865 copy = true;
28866
28867 var beginOffset = decoder.getOffset();
28868 var endOffset = decoder.readNestedTlvsStart(Tlv.SignatureInfo);
28869
28870 var signatureType = decoder.readNonNegativeIntegerTlv(Tlv.SignatureType);
28871 if (signatureType == Tlv.SignatureType_SignatureSha256WithRsa) {
28872 data.setSignature(new Sha256WithRsaSignature());
28873 // Modify data's signature object because if we create an object
28874 // and set it, then data will have to copy all the fields.
28875 var signatureInfo = data.getSignature();
28876 Tlv0_2WireFormat.decodeKeyLocator
28877 (Tlv.KeyLocator, signatureInfo.getKeyLocator(), decoder, copy);
28878 }
28879 else if (signatureType == Tlv.SignatureType_SignatureSha256WithEcdsa) {
28880 data.setSignature(new Sha256WithEcdsaSignature());
28881 var signatureInfo = data.getSignature();
28882 Tlv0_2WireFormat.decodeKeyLocator
28883 (Tlv.KeyLocator, signatureInfo.getKeyLocator(), decoder, copy);
28884 }
28885 else if (signatureType == Tlv.SignatureType_SignatureHmacWithSha256) {
28886 data.setSignature(new HmacWithSha256Signature());
28887 var signatureInfo = data.getSignature();
28888 Tlv0_2WireFormat.decodeKeyLocator
28889 (Tlv.KeyLocator, signatureInfo.getKeyLocator(), decoder, copy);
28890 }
28891 else if (signatureType == Tlv.SignatureType_DigestSha256)
28892 data.setSignature(new DigestSha256Signature());
28893 else {
28894 data.setSignature(new GenericSignature());
28895 var signatureInfo = data.getSignature();
28896
28897 // Get the bytes of the SignatureInfo TLV.
28898 signatureInfo.setSignatureInfoEncoding
28899 (new Blob(decoder.getSlice(beginOffset, endOffset), copy), signatureType);
28900 }
28901
28902 decoder.finishNestedTlvs(endOffset);
28903};
28904
28905Tlv0_2WireFormat.encodeMetaInfo = function(metaInfo, encoder)
28906{
28907 var saveLength = encoder.getLength();
28908
28909 // Encode backwards.
28910 var finalBlockIdBuf = metaInfo.getFinalBlockId().getValue().buf();
28911 if (finalBlockIdBuf != null && finalBlockIdBuf.length > 0) {
28912 // FinalBlockId has an inner NameComponent.
28913 var finalBlockIdSaveLength = encoder.getLength();
28914 Tlv0_2WireFormat.encodeNameComponent(metaInfo.getFinalBlockId(), encoder);
28915 encoder.writeTypeAndLength
28916 (Tlv.FinalBlockId, encoder.getLength() - finalBlockIdSaveLength);
28917 }
28918
28919 encoder.writeOptionalNonNegativeIntegerTlv
28920 (Tlv.FreshnessPeriod, metaInfo.getFreshnessPeriod());
28921 if (metaInfo.getType() != ContentType.BLOB) {
28922 // Not the default, so we need to encode the type.
28923 if (metaInfo.getType() == ContentType.LINK ||
28924 metaInfo.getType() == ContentType.KEY ||
28925 metaInfo.getType() == ContentType.NACK)
28926 // The ContentType enum is set up with the correct integer for
28927 // each NDN-TLV ContentType.
28928 encoder.writeNonNegativeIntegerTlv(Tlv.ContentType, metaInfo.getType());
28929 else if (metaInfo.getType() == ContentType.OTHER_CODE)
28930 encoder.writeNonNegativeIntegerTlv
28931 (Tlv.ContentType, metaInfo.getOtherTypeCode());
28932 else
28933 // We don't expect this to happen.
28934 throw new Error("unrecognized TLV ContentType");
28935 }
28936
28937 encoder.writeTypeAndLength(Tlv.MetaInfo, encoder.getLength() - saveLength);
28938};
28939
28940Tlv0_2WireFormat.decodeMetaInfo = function(metaInfo, decoder, copy)
28941{
28942 if (copy == null)
28943 copy = true;
28944
28945 var endOffset = decoder.readNestedTlvsStart(Tlv.MetaInfo);
28946
28947 var type = decoder.readOptionalNonNegativeIntegerTlv
28948 (Tlv.ContentType, endOffset);
28949 if (type == null || type < 0 || type === ContentType.BLOB)
28950 metaInfo.setType(ContentType.BLOB);
28951 else if (type === ContentType.LINK ||
28952 type === ContentType.KEY ||
28953 type === ContentType.NACK)
28954 // The ContentType enum is set up with the correct integer for each NDN-TLV
28955 // ContentType.
28956 metaInfo.setType(type);
28957 else {
28958 // Unrecognized content type.
28959 metaInfo.setType(ContentType.OTHER_CODE);
28960 metaInfo.setOtherTypeCode(type);
28961 }
28962
28963 metaInfo.setFreshnessPeriod
28964 (decoder.readOptionalNonNegativeIntegerTlv(Tlv.FreshnessPeriod, endOffset));
28965 if (decoder.peekType(Tlv.FinalBlockId, endOffset)) {
28966 var finalBlockIdEndOffset = decoder.readNestedTlvsStart(Tlv.FinalBlockId);
28967 metaInfo.setFinalBlockId(Tlv0_2WireFormat.decodeNameComponent(decoder, copy));
28968 decoder.finishNestedTlvs(finalBlockIdEndOffset);
28969 }
28970 else
28971 metaInfo.setFinalBlockId(null);
28972
28973 decoder.finishNestedTlvs(endOffset);
28974};
28975
28976Tlv0_2WireFormat.encodeControlParameters = function(controlParameters, encoder)
28977{
28978 var saveLength = encoder.getLength();
28979
28980 // Encode backwards.
28981 encoder.writeOptionalNonNegativeIntegerTlv
28982 (Tlv.ControlParameters_ExpirationPeriod,
28983 controlParameters.getExpirationPeriod());
28984
28985 if (controlParameters.getStrategy().size() > 0){
28986 var strategySaveLength = encoder.getLength();
28987 Tlv0_2WireFormat.encodeName(controlParameters.getStrategy(), encoder);
28988 encoder.writeTypeAndLength(Tlv.ControlParameters_Strategy,
28989 encoder.getLength() - strategySaveLength);
28990 }
28991
28992 var flags = controlParameters.getForwardingFlags().getNfdForwardingFlags();
28993 if (flags != new ForwardingFlags().getNfdForwardingFlags())
28994 // The flags are not the default value.
28995 encoder.writeNonNegativeIntegerTlv
28996 (Tlv.ControlParameters_Flags, flags);
28997
28998 encoder.writeOptionalNonNegativeIntegerTlv
28999 (Tlv.ControlParameters_Cost, controlParameters.getCost());
29000 encoder.writeOptionalNonNegativeIntegerTlv
29001 (Tlv.ControlParameters_Origin, controlParameters.getOrigin());
29002 encoder.writeOptionalNonNegativeIntegerTlv
29003 (Tlv.ControlParameters_LocalControlFeature,
29004 controlParameters.getLocalControlFeature());
29005
29006 if (controlParameters.getUri().length != 0)
29007 encoder.writeBlobTlv
29008 (Tlv.ControlParameters_Uri, new Blob(controlParameters.getUri()).buf());
29009
29010 encoder.writeOptionalNonNegativeIntegerTlv
29011 (Tlv.ControlParameters_FaceId, controlParameters.getFaceId());
29012 if (controlParameters.getName() != null)
29013 Tlv0_2WireFormat.encodeName(controlParameters.getName(), encoder);
29014
29015 encoder.writeTypeAndLength
29016 (Tlv.ControlParameters_ControlParameters, encoder.getLength() - saveLength);
29017};
29018
29019Tlv0_2WireFormat.decodeControlParameters = function
29020 (controlParameters, decoder, copy)
29021{
29022 if (copy == null)
29023 copy = true;
29024
29025 controlParameters.clear();
29026 var endOffset = decoder.
29027 readNestedTlvsStart(Tlv.ControlParameters_ControlParameters);
29028
29029 // decode name
29030 if (decoder.peekType(Tlv.Name, endOffset)) {
29031 var name = new Name();
29032 Tlv0_2WireFormat.decodeName(name, decoder, copy);
29033 controlParameters.setName(name);
29034 }
29035
29036 // decode face ID
29037 controlParameters.setFaceId(decoder.readOptionalNonNegativeIntegerTlv
29038 (Tlv.ControlParameters_FaceId, endOffset));
29039
29040 // decode URI
29041 if (decoder.peekType(Tlv.ControlParameters_Uri, endOffset)) {
29042 // Set copy false since we just immediately get the string.
29043 var uri = new Blob
29044 (decoder.readOptionalBlobTlv(Tlv.ControlParameters_Uri, endOffset), false);
29045 controlParameters.setUri(uri.toString());
29046 }
29047
29048 // decode integers
29049 controlParameters.setLocalControlFeature(decoder.
29050 readOptionalNonNegativeIntegerTlv(
29051 Tlv.ControlParameters_LocalControlFeature, endOffset));
29052 controlParameters.setOrigin(decoder.
29053 readOptionalNonNegativeIntegerTlv(Tlv.ControlParameters_Origin,
29054 endOffset));
29055 controlParameters.setCost(decoder.readOptionalNonNegativeIntegerTlv(
29056 Tlv.ControlParameters_Cost, endOffset));
29057
29058 // set forwarding flags
29059 if (decoder.peekType(Tlv.ControlParameters_Flags, endOffset)) {
29060 var flags = new ForwardingFlags();
29061 flags.setNfdForwardingFlags(decoder.
29062 readNonNegativeIntegerTlv(Tlv.ControlParameters_Flags, endOffset));
29063 controlParameters.setForwardingFlags(flags);
29064 }
29065
29066 // decode strategy
29067 if (decoder.peekType(Tlv.ControlParameters_Strategy, endOffset)) {
29068 var strategyEndOffset = decoder.readNestedTlvsStart(Tlv.ControlParameters_Strategy);
29069 Tlv0_2WireFormat.decodeName(controlParameters.getStrategy(), decoder, copy);
29070 decoder.finishNestedTlvs(strategyEndOffset);
29071 }
29072
29073 // decode expiration period
29074 controlParameters.setExpirationPeriod(
29075 decoder.readOptionalNonNegativeIntegerTlv(
29076 Tlv.ControlParameters_ExpirationPeriod, endOffset));
29077
29078 decoder.finishNestedTlvs(endOffset);
29079};
29080/**
29081 * Copyright (C) 2013-2016 Regents of the University of California.
29082 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
29083 *
29084 * This program is free software: you can redistribute it and/or modify
29085 * it under the terms of the GNU Lesser General Public License as published by
29086 * the Free Software Foundation, either version 3 of the License, or
29087 * (at your option) any later version.
29088 *
29089 * This program is distributed in the hope that it will be useful,
29090 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29091 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29092 * GNU Lesser General Public License for more details.
29093 *
29094 * You should have received a copy of the GNU Lesser General Public License
29095 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29096 * A copy of the GNU Lesser General Public License is in the file COPYING.
29097 */
29098
29099/** @ignore */
29100var Tlv0_2WireFormat = require('./tlv-0_2-wire-format.js').Tlv0_2WireFormat;
29101
29102/**
29103 * A Tlv0_1_1WireFormat extends Tlv0_2WireFormat so that it is an alias in case
29104 * any applications use Tlv0_1_1WireFormat directly. These two wire formats are
29105 * the same except that Tlv0_2WireFormat adds support for the name component
29106 * type ImplicitSha256Digest.
29107 * @constructor
29108 */
29109var Tlv0_1_1WireFormat = function Tlv0_1_1WireFormat()
29110{
29111 // Inherit from Tlv0_2WireFormat.
29112 Tlv0_2WireFormat.call(this);
29113};
29114
29115Tlv0_1_1WireFormat.prototype = new Tlv0_2WireFormat();
29116Tlv0_1_1WireFormat.prototype.name = "Tlv0_1_1WireFormat";
29117
29118exports.Tlv0_1_1WireFormat = Tlv0_1_1WireFormat;
29119
29120// Default object.
29121Tlv0_1_1WireFormat.instance = null;
29122
29123/**
29124 * Get a singleton instance of a Tlv0_1_1WireFormat.
29125 * @return {Tlv0_1_1WireFormat} The singleton instance.
29126 */
29127Tlv0_1_1WireFormat.get = function()
29128{
29129 if (Tlv0_1_1WireFormat.instance === null)
29130 Tlv0_1_1WireFormat.instance = new Tlv0_1_1WireFormat();
29131 return Tlv0_1_1WireFormat.instance;
29132};
29133/**
29134 * Copyright (C) 2013-2016 Regents of the University of California.
29135 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
29136 *
29137 * This program is free software: you can redistribute it and/or modify
29138 * it under the terms of the GNU Lesser General Public License as published by
29139 * the Free Software Foundation, either version 3 of the License, or
29140 * (at your option) any later version.
29141 *
29142 * This program is distributed in the hope that it will be useful,
29143 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29144 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29145 * GNU Lesser General Public License for more details.
29146 *
29147 * You should have received a copy of the GNU Lesser General Public License
29148 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29149 * A copy of the GNU Lesser General Public License is in the file COPYING.
29150 */
29151
29152/** @ignore */
29153var WireFormat = require('./wire-format.js').WireFormat; /** @ignore */
29154var Tlv0_1_1WireFormat = require('./tlv-0_1_1-wire-format.js').Tlv0_1_1WireFormat;
29155
29156/**
29157 * A Tlv0_1WireFormat extends Tlv0_1_1WireFormat so that it is an alias in case
29158 * any applications use Tlv0_1WireFormat directly. These two wire formats are
29159 * the same except that Tlv0_1_1WireFormat adds support for
29160 * Sha256WithEcdsaSignature.
29161 * @constructor
29162 */
29163var Tlv0_1WireFormat = function Tlv0_1WireFormat()
29164{
29165 // Inherit from Tlv0_1_1WireFormat.
29166 Tlv0_1_1WireFormat.call(this);
29167};
29168
29169Tlv0_1WireFormat.prototype = new Tlv0_1_1WireFormat();
29170Tlv0_1WireFormat.prototype.name = "Tlv0_1WireFormat";
29171
29172exports.Tlv0_1WireFormat = Tlv0_1WireFormat;
29173
29174// Default object.
29175Tlv0_1WireFormat.instance = null;
29176
29177/**
29178 * Get a singleton instance of a Tlv0_1WireFormat.
29179 * @return {Tlv0_1WireFormat} The singleton instance.
29180 */
29181Tlv0_1WireFormat.get = function()
29182{
29183 if (Tlv0_1WireFormat.instance === null)
29184 Tlv0_1WireFormat.instance = new Tlv0_1WireFormat();
29185 return Tlv0_1WireFormat.instance;
29186};
29187/**
29188 * Copyright (C) 2013-2016 Regents of the University of California.
29189 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
29190 *
29191 * This program is free software: you can redistribute it and/or modify
29192 * it under the terms of the GNU Lesser General Public License as published by
29193 * the Free Software Foundation, either version 3 of the License, or
29194 * (at your option) any later version.
29195 *
29196 * This program is distributed in the hope that it will be useful,
29197 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29198 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29199 * GNU Lesser General Public License for more details.
29200 *
29201 * You should have received a copy of the GNU Lesser General Public License
29202 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29203 * A copy of the GNU Lesser General Public License is in the file COPYING.
29204 */
29205
29206/** @ignore */
29207var WireFormat = require('./wire-format.js').WireFormat; /** @ignore */
29208var Tlv0_2WireFormat = require('./tlv-0_2-wire-format.js').Tlv0_2WireFormat;
29209
29210/**
29211 * A TlvWireFormat extends WireFormat to override its methods to
29212 * implement encoding and decoding using the preferred implementation of NDN-TLV.
29213 * @constructor
29214 */
29215var TlvWireFormat = function TlvWireFormat()
29216{
29217 // Inherit from Tlv0_2WireFormat.
29218 Tlv0_2WireFormat.call(this);
29219};
29220
29221TlvWireFormat.prototype = new Tlv0_2WireFormat();
29222TlvWireFormat.prototype.name = "TlvWireFormat";
29223
29224exports.TlvWireFormat = TlvWireFormat;
29225
29226// Default object.
29227TlvWireFormat.instance = null;
29228
29229/**
29230 * Get a singleton instance of a TlvWireFormat. Assuming that the default
29231 * wire format was set with WireFormat.setDefaultWireFormat(TlvWireFormat.get()),
29232 * you can check if this is the default wire encoding with
29233 * if WireFormat.getDefaultWireFormat() == TlvWireFormat.get().
29234 * @return {TlvWireFormat} The singleton instance.
29235 */
29236TlvWireFormat.get = function()
29237{
29238 if (TlvWireFormat.instance === null)
29239 TlvWireFormat.instance = new TlvWireFormat();
29240 return TlvWireFormat.instance;
29241};
29242
29243// On loading this module, make this the default wire format.
29244// This module will be loaded because WireFormat loads it.
29245WireFormat.setDefaultWireFormat(TlvWireFormat.get());
29246/**
29247 * This file contains utilities to help encode and decode NDN objects.
29248 * Copyright (C) 2013-2016 Regents of the University of California.
29249 * author: Meki Cheraoui
29250 *
29251 * This program is free software: you can redistribute it and/or modify
29252 * it under the terms of the GNU Lesser General Public License as published by
29253 * the Free Software Foundation, either version 3 of the License, or
29254 * (at your option) any later version.
29255 *
29256 * This program is distributed in the hope that it will be useful,
29257 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29258 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29259 * GNU Lesser General Public License for more details.
29260 *
29261 * You should have received a copy of the GNU Lesser General Public License
29262 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29263 * A copy of the GNU Lesser General Public License is in the file COPYING.
29264 */
29265
29266/** @ignore */
29267var DataUtils = require('./data-utils.js').DataUtils; /** @ignore */
29268var KeyLocatorType = require('../key-locator.js').KeyLocatorType; /** @ignore */
29269var Interest = require('../interest.js').Interest; /** @ignore */
29270var Data = require('../data.js').Data; /** @ignore */
29271var Sha256WithRsaSignature = require('../sha256-with-rsa-signature.js').Sha256WithRsaSignature; /** @ignore */
29272var Sha256WithEcdsaSignature = require('../sha256-with-ecdsa-signature.js').Sha256WithEcdsaSignature; /** @ignore */
29273var HmacWithSha256Signature = require('../hmac-with-sha256-signature.js').HmacWithSha256Signature; /** @ignore */
29274var DigestSha256Signature = require('../digest-sha256-signature.js').DigestSha256Signature; /** @ignore */
29275var ContentType = require('../meta-info.js').ContentType; /** @ignore */
29276var WireFormat = require('./wire-format.js').WireFormat;
29277
29278/**
29279 * An EncodingUtils has static methods for encoding data.
29280 * @constructor
29281 */
29282var EncodingUtils = function EncodingUtils()
29283{
29284};
29285
29286exports.EncodingUtils = EncodingUtils;
29287
29288EncodingUtils.encodeToHexInterest = function(interest, wireFormat)
29289{
29290 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
29291 return DataUtils.toHex(interest.wireEncode(wireFormat).buf());
29292};
29293
29294EncodingUtils.encodeToHexData = function(data, wireFormat)
29295{
29296 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
29297 return DataUtils.toHex(data.wireEncode(wireFormat).buf());
29298};
29299
29300EncodingUtils.decodeHexInterest = function(input, wireFormat)
29301{
29302 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
29303 var interest = new Interest();
29304 interest.wireDecode(DataUtils.toNumbers(input), wireFormat);
29305 return interest;
29306};
29307
29308EncodingUtils.decodeHexData = function(input, wireFormat)
29309{
29310 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
29311 var data = new Data();
29312 data.wireDecode(DataUtils.toNumbers(input), wireFormat);
29313 return data;
29314};
29315
29316/**
29317 * Decode the Buffer array which holds SubjectPublicKeyInfo and return an RSAKey.
29318 */
29319EncodingUtils.decodeSubjectPublicKeyInfo = function(array)
29320{
29321 var hex = DataUtils.toHex(array).toLowerCase();
29322 var a = _x509_getPublicKeyHexArrayFromCertHex(hex, _x509_getSubjectPublicKeyPosFromCertHex(hex, 0));
29323 var rsaKey = new RSAKey();
29324 rsaKey.setPublic(a[0], a[1]);
29325 return rsaKey;
29326}
29327
29328/**
29329 * Return a user friendly HTML string with the contents of data.
29330 */
29331EncodingUtils.dataToHtml = function(/* Data */ data)
29332{
29333 if (data == -1)
29334 return "NO CONTENT FOUND";
29335 if (data == -2)
29336 return "CONTENT NAME IS EMPTY";
29337
29338 var output = "";
29339 function append(message) {
29340 message = message.replace(/&/g, "&amp;");
29341 message = message.replace(/</g, "&lt;");
29342
29343 output += message;
29344 output += "<br/>";
29345 }
29346
29347 // Imitate dumpData in examples/node/test-encode-decode-data.js
29348
29349 append("name: " + data.getName().toUri());
29350 if (data.getContent().size() > 0) {
29351 append("content (raw): " + data.getContent().buf().toString('binary'));
29352 append("content (hex): " + data.getContent().toHex());
29353 }
29354 else
29355 append("content: <empty>");
29356
29357 if (!(data.getMetaInfo().getType() == ContentType.BLOB)) {
29358 if (data.getMetaInfo().getType() == ContentType.KEY)
29359 append("metaInfo.type: KEY");
29360 else if (data.getMetaInfo().getType() == ContentType.LINK)
29361 append("metaInfo.type: LINK");
29362 else if (data.getMetaInfo().getType() == ContentType.NACK)
29363 append("metaInfo.type: NACK");
29364 else if (data.getMetaInfo().getType() == ContentType.OTHER_CODE)
29365 append("metaInfo.type: other code " + data.getMetaInfo().getOtherTypeCode());
29366 }
29367 append("metaInfo.freshnessPeriod (milliseconds): " +
29368 (data.getMetaInfo().getFreshnessPeriod() >= 0 ?
29369 "" + data.getMetaInfo().getFreshnessPeriod() : "<none>"));
29370 append("metaInfo.finalBlockId: " +
29371 (data.getMetaInfo().getFinalBlockId().getValue().size() > 0 ?
29372 data.getMetaInfo().getFinalBlockId().getValue().toHex() : "<none>"));
29373
29374 var keyLocator = null;
29375 var signature = data.getSignature();
29376 if (signature instanceof Sha256WithRsaSignature) {
29377 var signature = data.getSignature();
29378 append("Sha256WithRsa signature.signature: " +
29379 (signature.getSignature().size() > 0 ?
29380 signature.getSignature().toHex() : "<none>"));
29381 keyLocator = signature.getKeyLocator();
29382 }
29383 else if (signature instanceof Sha256WithEcdsaSignature) {
29384 var signature = data.getSignature();
29385 append("Sha256WithEcdsa signature.signature: " +
29386 (signature.getSignature().size() > 0 ?
29387 signature.getSignature().toHex() : "<none>"));
29388 keyLocator = signature.getKeyLocator();
29389 }
29390 else if (signature instanceof HmacWithSha256Signature) {
29391 var signature = data.getSignature();
29392 append("HmacWithSha256 signature.signature: " +
29393 (signature.getSignature().size() > 0 ?
29394 signature.getSignature().toHex() : "<none>"));
29395 keyLocator = signature.getKeyLocator();
29396 }
29397 else if (signature instanceof DigestSha256Signature) {
29398 var signature = data.getSignature();
29399 append("DigestSha256 signature.signature: " +
29400 (signature.getSignature().size() > 0 ?
29401 signature.getSignature().toHex() : "<none>"));
29402 }
29403 if (keyLocator !== null) {
29404 if (keyLocator.getType() == null)
29405 append("signature.keyLocator: <none>");
29406 else if (keyLocator.getType() == KeyLocatorType.KEY_LOCATOR_DIGEST)
29407 append("signature.keyLocator: KeyLocatorDigest: " + keyLocator.getKeyData().toHex());
29408 else if (keyLocator.getType() == KeyLocatorType.KEYNAME)
29409 append("signature.keyLocator: KeyName: " + keyLocator.getKeyName().toUri());
29410 else
29411 append("signature.keyLocator: <unrecognized ndn_KeyLocatorType>");
29412 }
29413
29414 return output;
29415};
29416
29417//
29418// Deprecated: For the browser, define these in the global scope. Applications should access as member of EncodingUtils.
29419//
29420
29421var encodeToHexInterest = function(interest) { return EncodingUtils.encodeToHexInterest(interest); }
29422var decodeHexInterest = function(input) { return EncodingUtils.decodeHexInterest(input); }
29423var decodeSubjectPublicKeyInfo = function(input) { return EncodingUtils.decodeSubjectPublicKeyInfo(input); }
29424
29425/**
29426 * @deprecated Use interest.wireEncode().
29427 */
29428function encodeToBinaryInterest(interest) { return interest.wireEncode().buf(); }
29429/**
29430 * Copyright (C) 2015-2016 Regents of the University of California.
29431 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
29432 * @author: From ndn-group-encrypt src/algo/aes https://github.com/named-data/ndn-group-encrypt
29433 *
29434 * This program is free software: you can redistribute it and/or modify
29435 * it under the terms of the GNU Lesser General Public License as published by
29436 * the Free Software Foundation, either version 3 of the License, or
29437 * (at your option) any later version.
29438 *
29439 * This program is distributed in the hope that it will be useful,
29440 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29441 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29442 * GNU Lesser General Public License for more details.
29443 *
29444 * You should have received a copy of the GNU Lesser General Public License
29445 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29446 * A copy of the GNU Lesser General Public License is in the file COPYING.
29447 */
29448
29449// (This is ported from ndn::gep::algo::Aes, and named AesAlgorithm because
29450// "Aes" is very short and not all the Common Client Libraries have namespaces.)
29451
29452/** @ignore */
29453var Crypto = require('../../crypto.js'); /** @ignore */
29454var Blob = require('../../util/blob.js').Blob; /** @ignore */
29455var DecryptKey = require('../decrypt-key.js').DecryptKey; /** @ignore */
29456var EncryptKey = require('../encrypt-key.js').EncryptKey; /** @ignore */
29457var EncryptAlgorithmType = require('./encrypt-params.js').EncryptAlgorithmType; /** @ignore */
29458var UseSubtleCrypto = require('../../use-subtle-crypto-node.js').UseSubtleCrypto; /** @ignore */
29459var SyncPromise = require('../../util/sync-promise.js').SyncPromise;
29460
29461/**
29462 * The AesAlgorithm class provides static methods to manipulate keys, encrypt
29463 * and decrypt using the AES symmetric key cipher.
29464 * @note This class is an experimental feature. The API may change.
29465 * @constructor
29466 */
29467var AesAlgorithm = function AesAlgorithm()
29468{
29469};
29470
29471exports.AesAlgorithm = AesAlgorithm;
29472
29473/**
29474 * Generate a new random decrypt key for AES based on the given params.
29475 * @param {AesKeyParams} params The key params with the key size (in bits).
29476 * @return {DecryptKey} The new decrypt key.
29477 */
29478AesAlgorithm.generateKey = function(params)
29479{
29480 // Convert the key bit size to bytes.
29481 var key = Crypto.randomBytes(params.getKeySize() / 8);
29482
29483 var decryptKey = new DecryptKey(new Blob(key, false));
29484 return decryptKey;
29485};
29486
29487/**
29488 * Derive a new encrypt key from the given decrypt key value.
29489 * @param {Blob} keyBits The key value of the decrypt key.
29490 * @return {EncryptKey} The new encrypt key.
29491 */
29492AesAlgorithm.deriveEncryptKey = function(keyBits)
29493{
29494 return new EncryptKey(keyBits);
29495};
29496
29497/**
29498 * Decrypt the encryptedData using the keyBits according the encrypt params.
29499 * @param {Blob} keyBits The key value.
29500 * @param {Blob} encryptedData The data to decrypt.
29501 * @param {EncryptParams} params This decrypts according to
29502 * params.getAlgorithmType() and other params as needed such as
29503 * params.getInitialVector().
29504 * @param {boolean} useSync (optional) If true then return a SyncPromise which
29505 * is already fulfilled. If omitted or false, this may return a SyncPromise or
29506 * an async Promise.
29507 * @return {Promise|SyncPromise} A promise which returns the decrypted Blob.
29508 */
29509AesAlgorithm.decryptPromise = function(keyBits, encryptedData, params, useSync)
29510{
29511 if (UseSubtleCrypto() && !useSync &&
29512 // Crypto.subtle doesn't implement ECB.
29513 params.getAlgorithmType() != EncryptAlgorithmType.AesEcb) {
29514 if (params.getAlgorithmType() == EncryptAlgorithmType.AesCbc) {
29515 return crypto.subtle.importKey
29516 ("raw", keyBits.buf(), { name: "AES-CBC" }, false,
29517 ["encrypt", "decrypt"])
29518 .then(function(key) {
29519 return crypto.subtle.decrypt
29520 ({ name: "AES-CBC", iv: params.getInitialVector().buf() },
29521 key, encryptedData.buf());
29522 })
29523 .then(function(result) {
29524 return Promise.resolve(new Blob(new Uint8Array(result), false));
29525 });
29526 }
29527 else
29528 return Promise.reject(new Error("unsupported encryption mode"));
29529 }
29530 else {
29531 if (params.getAlgorithmType() == EncryptAlgorithmType.AesEcb) {
29532 try {
29533 // ECB ignores the initial vector.
29534 var cipher = Crypto.createDecipheriv("aes-128-ecb", keyBits.buf(), "");
29535 return SyncPromise.resolve(new Blob
29536 (Buffer.concat([cipher.update(encryptedData.buf()), cipher.final()]),
29537 false));
29538 } catch (err) {
29539 return SyncPromise.reject(err);
29540 }
29541 }
29542 else if (params.getAlgorithmType() == EncryptAlgorithmType.AesCbc) {
29543 try {
29544 var cipher = Crypto.createDecipheriv
29545 ("aes-128-cbc", keyBits.buf(), params.getInitialVector().buf());
29546 return SyncPromise.resolve(new Blob
29547 (Buffer.concat([cipher.update(encryptedData.buf()), cipher.final()]),
29548 false));
29549 } catch (err) {
29550 return SyncPromise.reject(err);
29551 }
29552 }
29553 else
29554 return SyncPromise.reject(new Error("unsupported encryption mode"));
29555 }
29556};
29557
29558/**
29559 * Decrypt the encryptedData using the keyBits according the encrypt params.
29560 * @param {Blob} keyBits The key value.
29561 * @param {Blob} encryptedData The data to decrypt.
29562 * @param {EncryptParams} params This decrypts according to
29563 * params.getAlgorithmType() and other params as needed such as
29564 * params.getInitialVector().
29565 * @return {Blob} The decrypted data.
29566 * @throws Error If decryptPromise doesn't return a SyncPromise which is
29567 * already fulfilled.
29568 */
29569AesAlgorithm.decrypt = function(keyBits, encryptedData, params)
29570{
29571 return SyncPromise.getValue(this.decryptPromise
29572 (keyBits, encryptedData, params, true));
29573};
29574
29575/**
29576 * Encrypt the plainData using the keyBits according the encrypt params.
29577 * @param {Blob} keyBits The key value.
29578 * @param {Blob} plainData The data to encrypt.
29579 * @param {EncryptParams} params This encrypts according to
29580 * params.getAlgorithmType() and other params as needed such as
29581 * params.getInitialVector().
29582 * @param {boolean} useSync (optional) If true then return a SyncPromise which
29583 * is already fulfilled. If omitted or false, this may return a SyncPromise or
29584 * an async Promise.
29585 * @return {Promise|SyncPromise} A promise which returns the encrypted Blob.
29586 */
29587AesAlgorithm.encryptPromise = function(keyBits, plainData, params, useSync)
29588{
29589 if (params.getAlgorithmType() == EncryptAlgorithmType.AesCbc) {
29590 if (params.getInitialVector().size() != AesAlgorithm.BLOCK_SIZE)
29591 return SyncPromise.reject(new Error("incorrect initial vector size"));
29592 }
29593
29594 if (UseSubtleCrypto() && !useSync &&
29595 // Crypto.subtle doesn't implement ECB.
29596 params.getAlgorithmType() != EncryptAlgorithmType.AesEcb) {
29597 if (params.getAlgorithmType() == EncryptAlgorithmType.AesCbc) {
29598 return crypto.subtle.importKey
29599 ("raw", keyBits.buf(), { name: "AES-CBC" }, false,
29600 ["encrypt", "decrypt"])
29601 .then(function(key) {
29602 return crypto.subtle.encrypt
29603 ({ name: "AES-CBC", iv: params.getInitialVector().buf() },
29604 key, plainData.buf());
29605 })
29606 .then(function(result) {
29607 return Promise.resolve(new Blob(new Uint8Array(result), false));
29608 });
29609 }
29610 else
29611 return Promise.reject(new Error("unsupported encryption mode"));
29612 }
29613 else {
29614 if (params.getAlgorithmType() == EncryptAlgorithmType.AesEcb) {
29615 // ECB ignores the initial vector.
29616 var cipher = Crypto.createCipheriv("aes-128-ecb", keyBits.buf(), "");
29617 return SyncPromise.resolve(new Blob
29618 (Buffer.concat([cipher.update(plainData.buf()), cipher.final()]),
29619 false));
29620 }
29621 else if (params.getAlgorithmType() == EncryptAlgorithmType.AesCbc) {
29622 var cipher = Crypto.createCipheriv
29623 ("aes-128-cbc", keyBits.buf(), params.getInitialVector().buf());
29624 return SyncPromise.resolve(new Blob
29625 (Buffer.concat([cipher.update(plainData.buf()), cipher.final()]),
29626 false));
29627 }
29628 else
29629 return SyncPromise.reject(new Error("unsupported encryption mode"));
29630 }
29631};
29632
29633/**
29634 * Encrypt the plainData using the keyBits according the encrypt params.
29635 * @param {Blob} keyBits The key value.
29636 * @param {Blob} plainData The data to encrypt.
29637 * @param {EncryptParams} params This encrypts according to
29638 * params.getAlgorithmType() and other params as needed such as
29639 * params.getInitialVector().
29640 * @return {Blob} The encrypted data.
29641 * @throws Error If encryptPromise doesn't return a SyncPromise which is
29642 * already fulfilled.
29643 */
29644AesAlgorithm.encrypt = function(keyBits, plainData, params)
29645{
29646 return SyncPromise.getValue(this.encryptPromise
29647 (keyBits, plainData, params, true));
29648};
29649
29650AesAlgorithm.BLOCK_SIZE = 16;
29651/**
29652 * Copyright (C) 2014-2016 Regents of the University of California.
29653 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
29654 * @author: From ndn-group-encrypt src/encrypt-params https://github.com/named-data/ndn-group-encrypt
29655 *
29656 * This program is free software: you can redistribute it and/or modify
29657 * it under the terms of the GNU Lesser General Public License as published by
29658 * the Free Software Foundation, either version 3 of the License, or
29659 * (at your option) any later version.
29660 *
29661 * This program is distributed in the hope that it will be useful,
29662 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29663 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29664 * GNU Lesser General Public License for more details.
29665 *
29666 * You should have received a copy of the GNU Lesser General Public License
29667 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29668 * A copy of the GNU Lesser General Public License is in the file COPYING.
29669 */
29670
29671/** @ignore */
29672var Crypto = require('../../crypto.js'); /** @ignore */
29673var Blob = require('../../util/blob.js').Blob;
29674
29675var EncryptAlgorithmType = function EncryptAlgorithmType()
29676{
29677}
29678
29679exports.EncryptAlgorithmType = EncryptAlgorithmType;
29680
29681// These correspond to the TLV codes.
29682EncryptAlgorithmType.AesEcb = 0;
29683EncryptAlgorithmType.AesCbc = 1;
29684EncryptAlgorithmType.RsaPkcs = 2;
29685EncryptAlgorithmType.RsaOaep = 3;
29686
29687/**
29688 * An EncryptParams holds an algorithm type and other parameters used to
29689 * encrypt and decrypt. Create an EncryptParams with the given parameters.
29690 * @param {number} algorithmType The algorithm type from EncryptAlgorithmType,
29691 * or null if not specified.
29692 * @param {number} initialVectorLength (optional) The initial vector length, or
29693 * 0 if the initial vector is not specified. If ommitted, the initial vector is
29694 * not specified.
29695 * @note This class is an experimental feature. The API may change.
29696 * @constructor
29697 */
29698var EncryptParams = function EncryptParams(algorithmType, initialVectorLength)
29699{
29700 this.algorithmType_ = algorithmType;
29701
29702 if (initialVectorLength != null && initialVectorLength > 0) {
29703 var initialVector = Crypto.randomBytes(initialVectorLength);
29704 this.initialVector_ = new Blob(initialVector, false);
29705 }
29706 else
29707 this.initialVector_ = new Blob();
29708};
29709
29710exports.EncryptParams = EncryptParams;
29711
29712/**
29713 * Get the algorithmType.
29714 * @return {number} The algorithm type from EncryptAlgorithmType, or null if not
29715 * specified.
29716 */
29717EncryptParams.prototype.getAlgorithmType = function()
29718{
29719 return this.algorithmType_;
29720};
29721
29722/**
29723 * Get the initial vector.
29724 * @return {Blob} The initial vector. If not specified, isNull() is true.
29725 */
29726EncryptParams.prototype.getInitialVector = function()
29727{
29728 return this.initialVector_;
29729};
29730
29731/**
29732 * Set the algorithm type.
29733 * @param {number} algorithmType The algorithm type from EncryptAlgorithmType.
29734 * If not specified, set to null.
29735 * @return {EncryptParams} This EncryptParams so that you can chain calls to
29736 * update values.
29737 */
29738EncryptParams.prototype.setAlgorithmType = function(algorithmType)
29739{
29740 this.algorithmType_ = algorithmType;
29741 return this;
29742};
29743
29744/**
29745 * Set the initial vector.
29746 * @param {Blob} initialVector The initial vector. If not specified, set to the
29747 * default Blob() where isNull() is true.
29748 * @return {EncryptParams} This EncryptParams so that you can chain calls to
29749 * update values.
29750 */
29751EncryptParams.prototype.setInitialVector = function(initialVector)
29752{
29753 this.initialVector_ =
29754 typeof initialVector === 'object' && initialVector instanceof Blob ?
29755 initialVector : new Blob(initialVector);
29756 return this;
29757};
29758/**
29759 * Copyright (C) 2015-2016 Regents of the University of California.
29760 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
29761 * @author: From ndn-group-encrypt src/encryptor https://github.com/named-data/ndn-group-encrypt
29762 *
29763 * This program is free software: you can redistribute it and/or modify
29764 * it under the terms of the GNU Lesser General Public License as published by
29765 * the Free Software Foundation, either version 3 of the License, or
29766 * (at your option) any later version.
29767 *
29768 * This program is distributed in the hope that it will be useful,
29769 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29770 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29771 * GNU Lesser General Public License for more details.
29772 *
29773 * You should have received a copy of the GNU Lesser General Public License
29774 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29775 * A copy of the GNU Lesser General Public License is in the file COPYING.
29776 */
29777
29778/** @ignore */
29779var Crypto = require('../../crypto.js'); /** @ignore */
29780var Name = require('../../name.js').Name; /** @ignore */
29781var KeyLocator = require('../../key-locator.js').KeyLocator; /** @ignore */
29782var KeyLocatorType = require('../../key-locator.js').KeyLocatorType; /** @ignore */
29783var TlvWireFormat = require('../../encoding/tlv-wire-format.js').TlvWireFormat; /** @ignore */
29784var Blob = require('../../util/blob.js').Blob; /** @ignore */
29785var AesAlgorithm = require('./aes-algorithm.js').AesAlgorithm; /** @ignore */
29786var RsaAlgorithm = require('./rsa-algorithm.js').RsaAlgorithm; /** @ignore */
29787var EncryptParams = require('./encrypt-params.js').EncryptParams; /** @ignore */
29788var EncryptAlgorithmType = require('./encrypt-params.js').EncryptAlgorithmType; /** @ignore */
29789var EncryptedContent = require('../encrypted-content.js').EncryptedContent; /** @ignore */
29790var SyncPromise = require('../../util/sync-promise.js').SyncPromise;
29791
29792/**
29793 * Encryptor has static constants and utility methods for encryption, such as
29794 * encryptData.
29795 * @constructor
29796 */
29797var Encryptor = function Encryptor(value)
29798{
29799};
29800
29801exports.Encryptor = Encryptor;
29802
29803Encryptor.NAME_COMPONENT_FOR = new Name.Component("FOR");
29804Encryptor.NAME_COMPONENT_READ = new Name.Component("READ");
29805Encryptor.NAME_COMPONENT_SAMPLE = new Name.Component("SAMPLE");
29806Encryptor.NAME_COMPONENT_ACCESS = new Name.Component("ACCESS");
29807Encryptor.NAME_COMPONENT_E_KEY = new Name.Component("E-KEY");
29808Encryptor.NAME_COMPONENT_D_KEY = new Name.Component("D-KEY");
29809Encryptor.NAME_COMPONENT_C_KEY = new Name.Component("C-KEY");
29810
29811/**
29812 * Prepare an encrypted data packet by encrypting the payload using the key
29813 * according to the params. In addition, this prepares the encoded
29814 * EncryptedContent with the encryption result using keyName and params. The
29815 * encoding is set as the content of the data packet. If params defines an
29816 * asymmetric encryption algorithm and the payload is larger than the maximum
29817 * plaintext size, this encrypts the payload with a symmetric key that is
29818 * asymmetrically encrypted and provided as a nonce in the content of the data
29819 * packet. The packet's /<dataName>/ is updated to be <dataName>/FOR/<keyName>.
29820 * @param {Data} data The data packet which is updated.
29821 * @param {Blob} payload The payload to encrypt.
29822 * @param {Name} keyName The key name for the EncryptedContent.
29823 * @param {Blob} key The encryption key value.
29824 * @param {EncryptParams} params The parameters for encryption.
29825 * @param {boolean} useSync (optional) If true then return a SyncPromise which
29826 * is already fulfilled. If omitted or false, this may return a SyncPromise or
29827 * an async Promise.
29828 * @return {Promise|SyncPromise} A promise which fulfills when the data packet
29829 * is updated.
29830 */
29831Encryptor.encryptDataPromise = function
29832 (data, payload, keyName, key, params, useSync)
29833{
29834 data.getName().append(Encryptor.NAME_COMPONENT_FOR).append(keyName);
29835
29836 var algorithmType = params.getAlgorithmType();
29837
29838 if (algorithmType == EncryptAlgorithmType.AesCbc ||
29839 algorithmType == EncryptAlgorithmType.AesEcb) {
29840 return Encryptor.encryptSymmetricPromise_
29841 (payload, key, keyName, params, useSync)
29842 .then(function(content) {
29843 data.setContent(content.wireEncode(TlvWireFormat.get()));
29844 return SyncPromise.resolve();
29845 });
29846 }
29847 else if (algorithmType == EncryptAlgorithmType.RsaPkcs ||
29848 algorithmType == EncryptAlgorithmType.RsaOaep) {
29849 // Node.js doesn't have a direct way to get the maximum plain text size, so
29850 // try to encrypt the payload first and catch the error if it is too big.
29851 return Encryptor.encryptAsymmetricPromise_
29852 (payload, key, keyName, params, useSync)
29853 .then(function(content) {
29854 data.setContent(content.wireEncode(TlvWireFormat.get()));
29855 return SyncPromise.resolve();
29856 }, function(err) {
29857 if (err.message.indexOf("data too large for key size") < 0)
29858 // Not the expected error.
29859 throw err;
29860
29861 // The payload is larger than the maximum plaintext size.
29862 // 128-bit nonce.
29863 var nonceKeyBuffer = Crypto.randomBytes(16);
29864 var nonceKey = new Blob(nonceKeyBuffer, false);
29865
29866 var nonceKeyName = new Name(keyName);
29867 nonceKeyName.append("nonce");
29868
29869 var symmetricParams = new EncryptParams
29870 (EncryptAlgorithmType.AesCbc, AesAlgorithm.BLOCK_SIZE);
29871
29872 var nonceContent;
29873 return Encryptor.encryptSymmetricPromise_
29874 (payload, nonceKey, nonceKeyName, symmetricParams, useSync)
29875 .then(function(localNonceContent) {
29876 nonceContent = localNonceContent;
29877 return Encryptor.encryptAsymmetricPromise_
29878 (nonceKey, key, keyName, params, useSync);
29879 })
29880 .then(function(payloadContent) {
29881 var nonceContentEncoding = nonceContent.wireEncode();
29882 var payloadContentEncoding = payloadContent.wireEncode();
29883 var content = new Buffer
29884 (nonceContentEncoding.size() + payloadContentEncoding.size());
29885 payloadContentEncoding.buf().copy(content, 0);
29886 nonceContentEncoding.buf().copy(content, payloadContentEncoding.size());
29887
29888 data.setContent(new Blob(content, false));
29889 return SyncPromise.resolve();
29890 });
29891 });
29892 }
29893 else
29894 return SyncPromise.reject(new Error("Unsupported encryption method"));
29895};
29896
29897/**
29898 * Prepare an encrypted data packet by encrypting the payload using the key
29899 * according to the params. In addition, this prepares the encoded
29900 * EncryptedContent with the encryption result using keyName and params. The
29901 * encoding is set as the content of the data packet. If params defines an
29902 * asymmetric encryption algorithm and the payload is larger than the maximum
29903 * plaintext size, this encrypts the payload with a symmetric key that is
29904 * asymmetrically encrypted and provided as a nonce in the content of the data
29905 * packet.
29906 * @param {Data} data The data packet which is updated.
29907 * @param {Blob} payload The payload to encrypt.
29908 * @param {Name} keyName The key name for the EncryptedContent.
29909 * @param {Blob} key The encryption key value.
29910 * @param {EncryptParams} params The parameters for encryption.
29911 * @throws Error If encryptPromise doesn't return a SyncPromise which is
29912 * already fulfilled.
29913 */
29914Encryptor.encryptData = function(data, payload, keyName, key, params)
29915{
29916 return SyncPromise.getValue(Encryptor.encryptDataPromise
29917 (data, payload, keyName, key, params, true));
29918};
29919
29920/**
29921 * Encrypt the payload using the symmetric key according to params, and return
29922 * an EncryptedContent.
29923 * @param {Blob} payload The data to encrypt.
29924 * @param {Blob} key The key value.
29925 * @param {Name} keyName The key name for the EncryptedContent key locator.
29926 * @param {EncryptParams} params The parameters for encryption.
29927 * @param {boolean} useSync (optional) If true then return a SyncPromise which
29928 * is already fulfilled. If omitted or false, this may return a SyncPromise or
29929 * an async Promise.
29930 * @return {Promise|SyncPromise} A promise which returns a new EncryptedContent.
29931 */
29932Encryptor.encryptSymmetricPromise_ = function
29933 (payload, key, keyName, params, useSync)
29934{
29935 var algorithmType = params.getAlgorithmType();
29936 var initialVector = params.getInitialVector();
29937 var keyLocator = new KeyLocator();
29938 keyLocator.setType(KeyLocatorType.KEYNAME);
29939 keyLocator.setKeyName(keyName);
29940
29941 if (algorithmType == EncryptAlgorithmType.AesCbc ||
29942 algorithmType == EncryptAlgorithmType.AesEcb) {
29943 if (algorithmType == EncryptAlgorithmType.AesCbc) {
29944 if (initialVector.size() != AesAlgorithm.BLOCK_SIZE)
29945 return SyncPromise.reject(new Error("incorrect initial vector size"));
29946 }
29947
29948 return AesAlgorithm.encryptPromise(key, payload, params, useSync)
29949 .then(function(encryptedPayload) {
29950 var result = new EncryptedContent();
29951 result.setAlgorithmType(algorithmType);
29952 result.setKeyLocator(keyLocator);
29953 result.setPayload(encryptedPayload);
29954 result.setInitialVector(initialVector);
29955 return SyncPromise.resolve(result);
29956 });
29957 }
29958 else
29959 return SyncPromise.reject(new Error("Unsupported encryption method"));
29960};
29961
29962/**
29963 * Encrypt the payload using the asymmetric key according to params, and
29964 * return an EncryptedContent.
29965 * @param {Blob} payload The data to encrypt. The size should be within range of
29966 * the key.
29967 * @param {Blob} key The key value.
29968 * @param {Name} keyName The key name for the EncryptedContent key locator.
29969 * @param {EncryptParams} params The parameters for encryption.
29970 * @param {boolean} useSync (optional) If true then return a SyncPromise which
29971 * is already fulfilled. If omitted or false, this may return a SyncPromise or
29972 * an async Promise.
29973 * @return {Promise|SyncPromise} A promise which returns a new EncryptedContent.
29974 */
29975Encryptor.encryptAsymmetricPromise_ = function
29976 (payload, key, keyName, params, useSync)
29977{
29978 var algorithmType = params.getAlgorithmType();
29979 var keyLocator = new KeyLocator();
29980 keyLocator.setType(KeyLocatorType.KEYNAME);
29981 keyLocator.setKeyName(keyName);
29982
29983 if (algorithmType == EncryptAlgorithmType.RsaPkcs ||
29984 algorithmType == EncryptAlgorithmType.RsaOaep) {
29985 return RsaAlgorithm.encryptPromise(key, payload, params, useSync)
29986 .then(function(encryptedPayload) {
29987 var result = new EncryptedContent();
29988 result.setAlgorithmType(algorithmType);
29989 result.setKeyLocator(keyLocator);
29990 result.setPayload(encryptedPayload);
29991 return SyncPromise.resolve(result);
29992 });
29993 }
29994 else
29995 return SyncPromise.reject(new Error("Unsupported encryption method"));
29996};
29997/**
29998 * Copyright (C) 2015-2016 Regents of the University of California.
29999 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
30000 * @author: From ndn-group-encrypt src/algo/rsa https://github.com/named-data/ndn-group-encrypt
30001 *
30002 * This program is free software: you can redistribute it and/or modify
30003 * it under the terms of the GNU Lesser General Public License as published by
30004 * the Free Software Foundation, either version 3 of the License, or
30005 * (at your option) any later version.
30006 *
30007 * This program is distributed in the hope that it will be useful,
30008 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30009 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30010 * GNU Lesser General Public License for more details.
30011 *
30012 * You should have received a copy of the GNU Lesser General Public License
30013 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30014 * A copy of the GNU Lesser General Public License is in the file COPYING.
30015 */
30016
30017// (This is ported from ndn::gep::algo::Rsa, and named RsaAlgorithm because
30018// "Rsa" is very short and not all the Common Client Libraries have namespaces.)
30019
30020/** @ignore */
30021var constants = require('constants'); /** @ignore */
30022var Crypto = require('../../crypto.js'); /** @ignore */
30023var Blob = require('../../util/blob.js').Blob; /** @ignore */
30024var DecryptKey = require('../decrypt-key.js').DecryptKey; /** @ignore */
30025var EncryptKey = require('../encrypt-key.js').EncryptKey; /** @ignore */
30026var EncryptAlgorithmType = require('./encrypt-params.js').EncryptAlgorithmType; /** @ignore */
30027var DerNode = require('../../encoding/der/der-node.js').DerNode; /** @ignore */
30028var OID = require('../../encoding/oid.js').OID; /** @ignore */
30029var PrivateKeyStorage = require('../../security/identity/private-key-storage.js').PrivateKeyStorage; /** @ignore */
30030var UseSubtleCrypto = require('../../use-subtle-crypto-node.js').UseSubtleCrypto; /** @ignore */
30031var SyncPromise = require('../../util/sync-promise.js').SyncPromise; /** @ignore */
30032var rsaKeygen = null;
30033try {
30034 // This should be installed with: sudo npm install rsa-keygen
30035 rsaKeygen = require('rsa-keygen');
30036}
30037catch (e) {}
30038
30039/**
30040 * The RsaAlgorithm class provides static methods to manipulate keys, encrypt
30041 * and decrypt using RSA.
30042 * @note This class is an experimental feature. The API may change.
30043 * @constructor
30044 */
30045var RsaAlgorithm = function RsaAlgorithm()
30046{
30047};
30048
30049exports.RsaAlgorithm = RsaAlgorithm;
30050
30051/**
30052 * Generate a new random decrypt key for RSA based on the given params.
30053 * @param {RsaKeyParams} params The key params with the key size (in bits).
30054 * @param {boolean} useSync (optional) If true then return a SyncPromise which
30055 * is already fulfilled. If omitted or false, this may return a SyncPromise or
30056 * an async Promise.
30057 * @return {Promise|SyncPromise} A promise which returns the new DecryptKey
30058 * (containing a PKCS8-encoded private key).
30059 */
30060RsaAlgorithm.generateKeyPromise = function(params, useSync)
30061{
30062 if (UseSubtleCrypto() && !useSync) {
30063 return crypto.subtle.generateKey
30064 ({ name: "RSASSA-PKCS1-v1_5", modulusLength: params.getKeySize(),
30065 publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
30066 hash: {name: "SHA-256"} },
30067 true, ["sign", "verify"])
30068 .then(function(key) {
30069 // Export the private key to DER.
30070 return crypto.subtle.exportKey("pkcs8", key.privateKey);
30071 })
30072 .then(function(pkcs8Der) {
30073 return Promise.resolve(new DecryptKey
30074 (new Blob(new Uint8Array(pkcs8Der), false)));
30075 });
30076 }
30077 else {
30078 if (!rsaKeygen)
30079 return SyncPromise.reject(new Error
30080 ("Need to install rsa-keygen: sudo npm install rsa-keygen"));
30081
30082 try {
30083 var keyPair = rsaKeygen.generate(params.getKeySize());
30084 // Get the PKCS1 private key DER from the PEM string and encode as PKCS8.
30085 var privateKeyBase64 = keyPair.private_key.toString().replace
30086 ("-----BEGIN RSA PRIVATE KEY-----", "").replace
30087 ("-----END RSA PRIVATE KEY-----", "");
30088 var pkcs1PrivateKeyDer = new Buffer(privateKeyBase64, 'base64');
30089 var privateKey = PrivateKeyStorage.encodePkcs8PrivateKey
30090 (pkcs1PrivateKeyDer, new OID(PrivateKeyStorage.RSA_ENCRYPTION_OID),
30091 new DerNode.DerNull()).buf();
30092
30093 return SyncPromise.resolve(new DecryptKey(privateKey));
30094 } catch (err) {
30095 return SyncPromise.reject(err);
30096 }
30097 }
30098};
30099
30100/**
30101 * Generate a new random decrypt key for RSA based on the given params.
30102 * @param {RsaKeyParams} params The key params with the key size (in bits).
30103 * @return {DecryptKey} The new decrypt key (containing a PKCS8-encoded private
30104 * key).
30105 * @throws Error If generateKeyPromise doesn't return a SyncPromise which is
30106 * already fulfilled.
30107 */
30108RsaAlgorithm.generateKey = function(params)
30109{
30110 return SyncPromise.getValue(this.generateKeyPromise(params, true));
30111};
30112
30113/**
30114 * Derive a new encrypt key from the given decrypt key value.
30115 * @param {Blob} keyBits The key value of the decrypt key (PKCS8-encoded private
30116 * key).
30117 * @return {EncryptKey} The new encrypt key (DER-encoded public key).
30118 */
30119RsaAlgorithm.deriveEncryptKey = function(keyBits)
30120{
30121 var rsaPrivateKeyDer = RsaAlgorithm.getRsaPrivateKeyDer(keyBits);
30122
30123 // Decode the PKCS #1 RSAPrivateKey.
30124 var parsedNode = DerNode.parse(rsaPrivateKeyDer.buf(), 0);
30125 var rsaPrivateKeyChildren = parsedNode.getChildren();
30126 var modulus = rsaPrivateKeyChildren[1];
30127 var publicExponent = rsaPrivateKeyChildren[2];
30128
30129 // Encode the PKCS #1 RSAPublicKey.
30130 var rsaPublicKey = new DerNode.DerSequence();
30131 rsaPublicKey.addChild(modulus);
30132 rsaPublicKey.addChild(publicExponent);
30133 var rsaPublicKeyDer = rsaPublicKey.encode();
30134
30135 // Encode the SubjectPublicKeyInfo.
30136 var algorithmIdentifier = new DerNode.DerSequence();
30137 algorithmIdentifier.addChild(new DerNode.DerOid(new OID
30138 (PrivateKeyStorage.RSA_ENCRYPTION_OID)));
30139 algorithmIdentifier.addChild(new DerNode.DerNull());
30140 var publicKey = new DerNode.DerSequence();
30141 publicKey.addChild(algorithmIdentifier);
30142 publicKey.addChild(new DerNode.DerBitString(rsaPublicKeyDer.buf(), 0));
30143
30144 return new EncryptKey(publicKey.encode());
30145};
30146
30147/**
30148 * Decrypt the encryptedData using the keyBits according the encrypt params.
30149 * @param {Blob} keyBits The key value (PKCS8-encoded private key).
30150 * @param {Blob} encryptedData The data to decrypt.
30151 * @param {EncryptParams} params This decrypts according to
30152 * params.getAlgorithmType().
30153 * @param {boolean} useSync (optional) If true then return a SyncPromise which
30154 * is already fulfilled. If omitted or false, this may return a SyncPromise or
30155 * an async Promise.
30156 * @return {Promise|SyncPromise} A promise which returns the decrypted Blob.
30157 */
30158RsaAlgorithm.decryptPromise = function(keyBits, encryptedData, params, useSync)
30159{
30160 if (UseSubtleCrypto() && !useSync &&
30161 // Crypto.subtle doesn't implement PKCS1 padding.
30162 params.getAlgorithmType() != EncryptAlgorithmType.RsaPkcs) {
30163 if (params.getAlgorithmType() == EncryptAlgorithmType.RsaOaep) {
30164 return crypto.subtle.importKey
30165 ("pkcs8", keyBits.buf(), { name: "RSA-OAEP", hash: {name: "SHA-1"} },
30166 false, ["decrypt"])
30167 .then(function(privateKey) {
30168 return crypto.subtle.decrypt
30169 ({ name: "RSA-OAEP" }, privateKey, encryptedData.buf());
30170 })
30171 .then(function(result) {
30172 return Promise.resolve(new Blob(new Uint8Array(result), false));
30173 });
30174 }
30175 else
30176 return Promise.reject(new Error("unsupported padding scheme"));
30177 }
30178 else {
30179 // keyBits is PKCS #8 but we need the inner RSAPrivateKey.
30180 var rsaPrivateKeyDer = RsaAlgorithm.getRsaPrivateKeyDer(keyBits);
30181
30182 // Encode the key DER as a PEM private key as needed by Crypto.
30183 var keyBase64 = rsaPrivateKeyDer.buf().toString('base64');
30184 var keyPem = "-----BEGIN RSA PRIVATE KEY-----\n";
30185 for (var i = 0; i < keyBase64.length; i += 64)
30186 keyPem += (keyBase64.substr(i, 64) + "\n");
30187 keyPem += "-----END RSA PRIVATE KEY-----";
30188
30189 var padding;
30190 if (params.getAlgorithmType() == EncryptAlgorithmType.RsaPkcs)
30191 padding = constants.RSA_PKCS1_PADDING;
30192 else if (params.getAlgorithmType() == EncryptAlgorithmType.RsaOaep)
30193 padding = constants.RSA_PKCS1_OAEP_PADDING;
30194 else
30195 return SyncPromise.reject(new Error("unsupported padding scheme"));
30196
30197 try {
30198 // In Node.js, privateDecrypt requires version v0.12.
30199 return SyncPromise.resolve(new Blob
30200 (Crypto.privateDecrypt({ key: keyPem, padding: padding }, encryptedData.buf()),
30201 false));
30202 } catch (err) {
30203 return SyncPromise.reject(err);
30204 }
30205 }
30206};
30207
30208/**
30209 * Decrypt the encryptedData using the keyBits according the encrypt params.
30210 * @param {Blob} keyBits The key value (PKCS8-encoded private key).
30211 * @param {Blob} encryptedData The data to decrypt.
30212 * @param {EncryptParams} params This decrypts according to
30213 * params.getAlgorithmType().
30214 * @return {Blob} The decrypted data.
30215 * @throws Error If decryptPromise doesn't return a SyncPromise which is
30216 * already fulfilled.
30217 */
30218RsaAlgorithm.decrypt = function(keyBits, encryptedData, params)
30219{
30220 return SyncPromise.getValue(this.decryptPromise
30221 (keyBits, encryptedData, params, true));
30222};
30223
30224/**
30225 * Encrypt the plainData using the keyBits according the encrypt params.
30226 * @param {Blob} keyBits The key value (DER-encoded public key).
30227 * @param {Blob} plainData The data to encrypt.
30228 * @param {EncryptParams} params This encrypts according to
30229 * params.getAlgorithmType().
30230 * @param {boolean} useSync (optional) If true then return a SyncPromise which
30231 * is already fulfilled. If omitted or false, this may return a SyncPromise or
30232 * an async Promise.
30233 * @return {Promise|SyncPromise} A promise which returns the encrypted Blob.
30234 */
30235RsaAlgorithm.encryptPromise = function(keyBits, plainData, params, useSync)
30236{
30237 if (UseSubtleCrypto() && !useSync &&
30238 // Crypto.subtle doesn't implement PKCS1 padding.
30239 params.getAlgorithmType() != EncryptAlgorithmType.RsaPkcs) {
30240 if (params.getAlgorithmType() == EncryptAlgorithmType.RsaOaep) {
30241 return crypto.subtle.importKey
30242 ("spki", keyBits.buf(), { name: "RSA-OAEP", hash: {name: "SHA-1"} },
30243 false, ["encrypt"])
30244 .then(function(publicKey) {
30245 return crypto.subtle.encrypt
30246 ({ name: "RSA-OAEP" }, publicKey, plainData.buf());
30247 })
30248 .then(function(result) {
30249 return Promise.resolve(new Blob(new Uint8Array(result), false));
30250 });
30251 }
30252 else
30253 return Promise.reject(new Error("unsupported padding scheme"));
30254 }
30255 else {
30256 // Encode the key DER as a PEM public key as needed by Crypto.
30257 var keyBase64 = keyBits.buf().toString('base64');
30258 var keyPem = "-----BEGIN PUBLIC KEY-----\n";
30259 for (var i = 0; i < keyBase64.length; i += 64)
30260 keyPem += (keyBase64.substr(i, 64) + "\n");
30261 keyPem += "-----END PUBLIC KEY-----";
30262
30263 var padding;
30264 if (params.getAlgorithmType() == EncryptAlgorithmType.RsaPkcs)
30265 padding = constants.RSA_PKCS1_PADDING;
30266 else if (params.getAlgorithmType() == EncryptAlgorithmType.RsaOaep)
30267 padding = constants.RSA_PKCS1_OAEP_PADDING;
30268 else
30269 return SyncPromise.reject(new Error("unsupported padding scheme"));
30270
30271 try {
30272 // In Node.js, publicEncrypt requires version v0.12.
30273 return SyncPromise.resolve(new Blob
30274 (Crypto.publicEncrypt({ key: keyPem, padding: padding }, plainData.buf()),
30275 false));
30276 } catch (err) {
30277 return SyncPromise.reject(err);
30278 }
30279 }
30280};
30281
30282/**
30283 * Encrypt the plainData using the keyBits according the encrypt params.
30284 * @param {Blob} keyBits The key value (DER-encoded public key).
30285 * @param {Blob} plainData The data to encrypt.
30286 * @param {EncryptParams} params This encrypts according to
30287 * params.getAlgorithmType().
30288 * @return {Blob} The encrypted data.
30289 * @throws Error If encryptPromise doesn't return a SyncPromise which is
30290 * already fulfilled.
30291 */
30292RsaAlgorithm.encrypt = function(keyBits, plainData, params)
30293{
30294 return SyncPromise.getValue(this.encryptPromise
30295 (keyBits, plainData, params, true));
30296};
30297
30298/**
30299 * Decode the PKCS #8 private key, check that the algorithm is RSA, and return
30300 * the inner RSAPrivateKey DER.
30301 * @param {Blob} The DER-encoded PKCS #8 private key.
30302 * @param {Blob} The DER-encoded RSAPrivateKey.
30303 */
30304RsaAlgorithm.getRsaPrivateKeyDer = function(pkcs8PrivateKeyDer)
30305{
30306 var parsedNode = DerNode.parse(pkcs8PrivateKeyDer.buf(), 0);
30307 var pkcs8Children = parsedNode.getChildren();
30308 var algorithmIdChildren = DerNode.getSequence(pkcs8Children, 1).getChildren();
30309 var oidString = algorithmIdChildren[0].toVal();
30310
30311 if (oidString != PrivateKeyStorage.RSA_ENCRYPTION_OID)
30312 throw new Error("The PKCS #8 private key is not RSA_ENCRYPTION");
30313
30314 return pkcs8Children[2].getPayload();
30315};
30316/**
30317 * Copyright (C) 2015-2016 Regents of the University of California.
30318 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
30319 * @author: From ndn-group-encrypt src/consumer-db https://github.com/named-data/ndn-group-encrypt
30320 *
30321 * This program is free software: you can redistribute it and/or modify
30322 * it under the terms of the GNU Lesser General Public License as published by
30323 * the Free Software Foundation, either version 3 of the License, or
30324 * (at your option) any later version.
30325 *
30326 * This program is distributed in the hope that it will be useful,
30327 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30328 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30329 * GNU Lesser General Public License for more details.
30330 *
30331 * You should have received a copy of the GNU Lesser General Public License
30332 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30333 * A copy of the GNU Lesser General Public License is in the file COPYING.
30334 */
30335
30336/** @ignore */
30337var SyncPromise = require('../util/sync-promise.js').SyncPromise;
30338
30339/**
30340 * ConsumerDb is a base class the storage of decryption keys for the consumer. A
30341 * subclass must implement the methods. For example, see Sqlite3ConsumerDb (for
30342 * Nodejs) or IndexedDbConsumerDb (for the browser).
30343 * @note This class is an experimental feature. The API may change.
30344 * @constructor
30345 */
30346var ConsumerDb = function ConsumerDb()
30347{
30348};
30349
30350exports.ConsumerDb = ConsumerDb;
30351
30352/**
30353 * Create a new ConsumerDb.Error to report an error using ConsumerDb
30354 * methods, wrapping the given error object.
30355 * Call with: throw new ConsumerDb.Error(new Error("message")).
30356 * @constructor
30357 * @param {Error} error The exception created with new Error.
30358 */
30359ConsumerDb.Error = function ConsumerDbError(error)
30360{
30361 if (error) {
30362 error.__proto__ = ConsumerDb.Error.prototype;
30363 return error;
30364 }
30365}
30366
30367ConsumerDb.Error.prototype = new Error();
30368ConsumerDb.Error.prototype.name = "ConsumerDbError";
30369
30370/**
30371 * Get the key with keyName from the database.
30372 * @param {Name} keyName The key name.
30373 * @param {boolean} useSync (optional) If true then return a SyncPromise which
30374 * is already fulfilled. If omitted or false, this may return a SyncPromise or
30375 * an async Promise.
30376 * @return {Promise|SyncPromise} A promise that returns a Blob with the encoded
30377 * key (or an isNull Blob if cannot find the key with keyName), or that is
30378 * rejected with ConsumerDb.Error for a database error.
30379 */
30380ConsumerDb.prototype.getKeyPromise = function(keyName, useSync)
30381{
30382 return SyncPromise.reject(new Error
30383 ("ConsumerDb.getKeyPromise is not implemented"));
30384};
30385
30386/**
30387 * Add the key with keyName and keyBlob to the database.
30388 * @param {Name} keyName The key name.
30389 * @param {Blob} keyBlob The encoded key.
30390 * @param {boolean} useSync (optional) If true then return a SyncPromise which
30391 * is already fulfilled. If omitted or false, this may return a SyncPromise or
30392 * an async Promise.
30393 * @return {Promise|SyncPromise} A promise that fulfills when the key is added,
30394 * or that is rejected with ConsumerDb.Error if a key with the same keyName
30395 * already exists, or other database error.
30396 */
30397ConsumerDb.prototype.addKeyPromise = function(keyName, keyBlob, useSync)
30398{
30399 return SyncPromise.reject(new Error
30400 ("ConsumerDb.addKeyPromise is not implemented"));
30401};
30402
30403/**
30404 * Delete the key with keyName from the database. If there is no key with
30405 * keyName, do nothing.
30406 * @param {Name} keyName The key name.
30407 * @param {boolean} useSync (optional) If true then return a SyncPromise which
30408 * is already fulfilled. If omitted or false, this may return a SyncPromise or
30409 * an async Promise.
30410 * @return {Promise|SyncPromise} A promise that fulfills when the key is deleted
30411 * (or there is no such key), or that is rejected with ConsumerDb.Error for a
30412 * database error.
30413 */
30414ConsumerDb.prototype.deleteKeyPromise = function(keyName, useSync)
30415{
30416 return SyncPromise.reject(new Error
30417 ("ConsumerDb.addKeyPromise is not implemented"));
30418};
30419/**
30420 * Copyright (C) 2015-2016 Regents of the University of California.
30421 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
30422 * @author: From ndn-group-encrypt src/consumer https://github.com/named-data/ndn-group-encrypt
30423 *
30424 * This program is free software: you can redistribute it and/or modify
30425 * it under the terms of the GNU Lesser General Public License as published by
30426 * the Free Software Foundation, either version 3 of the License, or
30427 * (at your option) any later version.
30428 *
30429 * This program is distributed in the hope that it will be useful,
30430 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30431 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30432 * GNU Lesser General Public License for more details.
30433 *
30434 * You should have received a copy of the GNU Lesser General Public License
30435 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30436 * A copy of the GNU Lesser General Public License is in the file COPYING.
30437 */
30438
30439/** @ignore */
30440var Blob = require('../util/blob.js').Blob; /** @ignore */
30441var Name = require('../name.js').Name; /** @ignore */
30442var Interest = require('../interest.js').Interest; /** @ignore */
30443var NetworkNack = require('../network-nack.js').NetworkNack; /** @ignore */
30444var Link = require('../link.js').Link; /** @ignore */
30445var EncryptedContent = require('./encrypted-content.js').EncryptedContent; /** @ignore */
30446var EncryptError = require('./encrypt-error.js').EncryptError; /** @ignore */
30447var EncryptParams = require('./algo/encrypt-params.js').EncryptParams; /** @ignore */
30448var EncryptAlgorithmType = require('./algo/encrypt-params.js').EncryptAlgorithmType; /** @ignore */
30449var RsaAlgorithm = require('./algo/rsa-algorithm.js').RsaAlgorithm; /** @ignore */
30450var AesAlgorithm = require('./algo/aes-algorithm.js').AesAlgorithm; /** @ignore */
30451var Encryptor = require('./algo/encryptor.js').Encryptor; /** @ignore */
30452var SyncPromise = require('../util/sync-promise.js').SyncPromise; /** @ignore */
30453var NdnCommon = require('../util/ndn-common.js').NdnCommon;
30454
30455/**
30456 * A Consumer manages fetched group keys used to decrypt a data packet in the
30457 * group-based encryption protocol.
30458 * Create a Consumer to use the given ConsumerDb, Face and other values.
30459 * @param {Face} face The face used for data packet and key fetching.
30460 * @param {KeyChain} keyChain The keyChain used to verify data packets.
30461 * @param {Name} groupName The reading group name that the consumer belongs to.
30462 * This makes a copy of the Name.
30463 * @param {Name} consumerName The identity of the consumer. This makes a copy of
30464 * the Name.
30465 * @param {ConsumerDb} database The ConsumerDb database for storing decryption
30466 * keys.
30467 * @param {Link} cKeyLink (optional) The Link object to use in Interests for
30468 * C-KEY retrieval. This makes a copy of the Link object. If the Link object's
30469 * getDelegations().size() is zero, don't use it. If omitted, don't use a Link
30470 * object.
30471 * @param {Link} dKeyLink (optional) The Link object to use in Interests for
30472 * D-KEY retrieval. This makes a copy of the Link object. If the Link object's
30473 * getDelegations().size() is zero, don't use it. If omitted, don't use a Link
30474 * object.
30475 * @note This class is an experimental feature. The API may change.
30476 * @constructor
30477 */
30478var Consumer = function Consumer
30479 (face, keyChain, groupName, consumerName, database, cKeyLink, dKeyLink)
30480{
30481 this.database_ = database;
30482 this.keyChain_ = keyChain;
30483 this.face_ = face;
30484 this.groupName_ = new Name(groupName);
30485 this.consumerName_ = new Name(consumerName);
30486 this.cKeyLink_ =
30487 (cKeyLink == undefined ? Consumer.NO_LINK : new Link(cKeyLink));
30488 this.dKeyLink_ =
30489 (dKeyLink == undefined ? Consumer.NO_LINK : new Link(dKeyLink));
30490
30491 // The map key is the C-KEY name URI string. The value is the encoded key Blob.
30492 // (Use a string because we can't use the Name object as the key in JavaScript.)
30493 this.cKeyMap_ = {};
30494 // The map key is the D-KEY name URI string. The value is the encoded key Blob.
30495 this.dKeyMap_ = {};
30496};
30497
30498exports.Consumer = Consumer;
30499
30500/**
30501 * Express an Interest to fetch the content packet with contentName, and
30502 * decrypt it, fetching keys as needed.
30503 * @param {Name} contentName The name of the content packet.
30504 * @param {function} onConsumeComplete When the content packet is fetched and
30505 * decrypted, this calls onConsumeComplete(contentData, result) where
30506 * contentData is the fetched Data packet and result is the decrypted plain
30507 * text Blob.
30508 * NOTE: The library will log any exceptions thrown by this callback, but for
30509 * better error handling the callback should catch and properly handle any
30510 * exceptions.
30511 * @param {function} onError This calls onError(errorCode, message) for an error,
30512 * where errorCode is an error code from EncryptError.ErrorCode.
30513 * NOTE: The library will log any exceptions thrown by this callback, but for
30514 * better error handling the callback should catch and properly handle any
30515 * exceptions.
30516 * @param link {Link} (optional) The Link object to use in Interests for data
30517 * retrieval. This makes a copy of the Link object. If the Link object's
30518 * getDelegations().size() is zero, don't use it. If omitted, don't use a Link
30519 * object.
30520 */
30521Consumer.prototype.consume = function
30522 (contentName, onConsumeComplete, onError, link)
30523{
30524 if (link == undefined)
30525 link = Consumer.NO_LINK;
30526
30527 var interest = new Interest(contentName);
30528 var thisConsumer = this;
30529 // Copy the Link object since the passed link may become invalid.
30530 this.sendInterest_
30531 (interest, 1, new Link(link),
30532 function(validData) {
30533 // Decrypt the content.
30534 thisConsumer.decryptContent_(validData, function(plainText) {
30535 try {
30536 onConsumeComplete(validData, plainText);
30537 } catch (ex) {
30538 console.log("Error in onConsumeComplete: " + NdnCommon.getErrorWithStackTrace(ex));
30539 }
30540 }, onError);
30541 },
30542 onError);
30543};
30544
30545/**
30546 * Set the group name.
30547 * @param {Name} groupName The reading group name that the consumer belongs to.
30548 * This makes a copy of the Name.
30549 */
30550Consumer.prototype.setGroup = function(groupName)
30551{
30552 this.groupName_ = new Name(groupName);
30553};
30554
30555/**
30556 * Add a new decryption key with keyName and keyBlob to the database.
30557 * @param {Name} keyName The key name.
30558 * @param {Blob} keyBlob The encoded key.
30559 * @param {boolean} useSync (optional) If true then return a SyncPromise which
30560 * is already fulfilled. If omitted or false, this may return a SyncPromise or
30561 * an async Promise.
30562 * @return {Promise|SyncPromise} A promise that fulfills when the key is added,
30563 * or that is rejected with Error if the consumer name is not a prefix of the
30564 * key name, or ConsumerDb.Error if a key with the same keyName already exists,
30565 * or other database error.
30566 */
30567Consumer.prototype.addDecryptionKeyPromise = function(keyName, keyBlob, useSync)
30568{
30569 if (!(this.consumerName_.match(keyName)))
30570 return SyncPromise.reject(new Error
30571 ("addDecryptionKey: The consumer name must be a prefix of the key name"));
30572
30573 return this.database_.addKeyPromise(keyName, keyBlob, useSync);
30574};
30575
30576/**
30577 * Add a new decryption key with keyName and keyBlob to the database.
30578 * @param {Name} keyName The key name.
30579 * @param {Blob} keyBlob The encoded key.
30580 * @param {function} onComplete (optional) This calls onComplete() when the key
30581 * is added. (Some database libraries only use a callback, so onComplete is
30582 * required to use these.)
30583 * @param {function} onError (optional) If defined, then onComplete must be
30584 * defined and if there is an exception, then this calls onError(exception)
30585 * where exception is Error if the consumer name is not a prefix of the key
30586 * name, or ConsumerDb.Error if a key with the same keyName already exists,
30587 * or other database error. If onComplete is defined but onError is undefined,
30588 * then this will log any thrown exception. (Some database libraries only use a
30589 * callback, so onError is required to be notified of an exception.)
30590 */
30591Consumer.prototype.addDecryptionKey = function
30592 (keyName, keyBlob, onComplete, onError)
30593{
30594 return SyncPromise.complete(onComplete, onError,
30595 this.addDecryptionKeyPromise(keyName, keyBlob, !onComplete));
30596};
30597
30598/**
30599 * Consume.Error is used internally from promised-based methods to reject with
30600 * an error object that has the errorCode and message returned through the
30601 * onError callback.
30602 * @param {number} errorCode An error code from EncryptError.ErrorCode.
30603 * @param {string} message The error message.
30604 */
30605Consumer.Error = function ConsumerError(errorCode, message)
30606{
30607 this.errorCode = errorCode;
30608 this.message = message;
30609};
30610
30611/**
30612 * If exception is a ConsumerError, then call onError with the errorCode and
30613 * message, otherwise call onError with ErrorCode.General.
30614 */
30615Consumer.Error.callOnError = function(onError, exception, messagePrefix)
30616{
30617 if (!messagePrefix)
30618 messagePrefix = "";
30619
30620 if (exception instanceof Consumer.Error) {
30621 try {
30622 onError(exception.errorCode, exception.message);
30623 } catch (ex) {
30624 console.log("Error in onError: " + NdnCommon.getErrorWithStackTrace(ex));
30625 }
30626 }
30627 else {
30628 try {
30629 onError(EncryptError.ErrorCode.General, messagePrefix + exception);
30630 } catch (ex) {
30631 console.log("Error in onError: " + NdnCommon.getErrorWithStackTrace(ex));
30632 }
30633 }
30634}
30635
30636/**
30637 * Decrypt encryptedContent using keyBits.
30638 * @param {Blob|EncryptedContent} encryptedContent The EncryptedContent to
30639 * decrypt, or a Blob which is first decoded as an EncryptedContent.
30640 * @param {Blob} keyBits The key value.
30641 * @return {Promise|SyncPromise} A promise that returns the decrypted Blob, or
30642 * that is rejected with Consumer.Error or other error.
30643 */
30644Consumer.decryptPromise_ = function(encryptedContent, keyBits)
30645{
30646 return SyncPromise.resolve()
30647 .then(function() {
30648 if (typeof encryptedContent == 'object' && encryptedContent instanceof Blob) {
30649 // Decode as EncryptedContent.
30650 var encryptedBlob = encryptedContent;
30651 encryptedContent = new EncryptedContent();
30652 encryptedContent.wireDecode(encryptedBlob);
30653 }
30654
30655 var payload = encryptedContent.getPayload();
30656
30657 if (encryptedContent.getAlgorithmType() == EncryptAlgorithmType.AesCbc) {
30658 // Prepare the parameters.
30659 var decryptParams = new EncryptParams(EncryptAlgorithmType.AesCbc);
30660 decryptParams.setInitialVector(encryptedContent.getInitialVector());
30661
30662 // Decrypt the content.
30663 return AesAlgorithm.decryptPromise(keyBits, payload, decryptParams);
30664 }
30665 else if (encryptedContent.getAlgorithmType() == EncryptAlgorithmType.RsaOaep) {
30666 // Prepare the parameters.
30667 var decryptParams = new EncryptParams(EncryptAlgorithmType.RsaOaep);
30668
30669 // Decrypt the content.
30670 return RsaAlgorithm.decryptPromise(keyBits, payload, decryptParams);
30671 }
30672 else
30673 return SyncPromise.reject(new Consumer.Error
30674 (EncryptError.ErrorCode.UnsupportedEncryptionScheme,
30675 "" + encryptedContent.getAlgorithmType()));
30676 });
30677};
30678
30679/**
30680 * Decrypt encryptedContent using keyBits.
30681 * @param {Blob|EncryptedContent} encryptedContent The EncryptedContent to
30682 * decrypt, or a Blob which is first decoded as an EncryptedContent.
30683 * @param {Blob} keyBits The key value.
30684 * @param {function} onPlainText When the data packet is decrypted, this calls
30685 * onPlainText(decryptedBlob) with the decrypted Blob.
30686 * @param {function} onError This calls onError(errorCode, message) for an error,
30687 * where errorCode is an error code from EncryptError.ErrorCode.
30688 */
30689Consumer.decrypt_ = function(encryptedContent, keyBits, onPlainText, onError)
30690{
30691 Consumer.decryptPromise_(encryptedContent, keyBits)
30692 .then(function(decryptedBlob) {
30693 onPlainText(decryptedBlob);
30694 }, function(ex) {
30695 Consumer.Error.callOnError(onError, ex);
30696 });
30697};
30698
30699/**
30700 * Decrypt the data packet.
30701 * @param {Data} data The data packet. This does not verify the packet.
30702 * @param {function} onPlainText When the data packet is decrypted, this calls
30703 * onPlainText(decryptedBlob) with the decrypted Blob.
30704 * @param {function} onError This calls onError(errorCode, message) for an error,
30705 * where errorCode is an error code from EncryptError.ErrorCode.
30706 */
30707Consumer.prototype.decryptContent_ = function(data, onPlainText, onError)
30708{
30709 // Get the encrypted content.
30710 var dataEncryptedContent = new EncryptedContent();
30711 try {
30712 dataEncryptedContent.wireDecode(data.getContent());
30713 } catch (ex) {
30714 Consumer.Error.callOnError(onError, ex, "Error decoding EncryptedContent: ");
30715 return;
30716 }
30717 var cKeyName = dataEncryptedContent.getKeyLocator().getKeyName();
30718
30719 // Check if the content key is already in the store.
30720 var cKey = this.cKeyMap_[cKeyName.toUri()];
30721 if (cKey)
30722 this.decrypt_(dataEncryptedContent, cKey, onPlainText, onError);
30723 else {
30724 // Retrieve the C-KEY Data from the network.
30725 var interestName = new Name(cKeyName);
30726 interestName.append(Encryptor.NAME_COMPONENT_FOR).append(this.groupName_);
30727 var interest = new Interest(interestName);
30728 var thisConsumer = this;
30729 this.sendInterest_
30730 (interest, 1, this.cKeyLink_,
30731 function(validCKeyData) {
30732 thisConsumer.decryptCKey_(validCKeyData, function(cKeyBits) {
30733 thisConsumer.cKeyMap_[cKeyName.toUri()] = cKeyBits;
30734 Consumer.decrypt_
30735 (dataEncryptedContent, cKeyBits, onPlainText, onError);
30736 }, onError);
30737 },
30738 onError);
30739 }
30740};
30741
30742/**
30743 * Decrypt cKeyData.
30744 * @param {Data} cKeyData The C-KEY data packet.
30745 * @param {function} onPlainText When the data packet is decrypted, this calls
30746 * onPlainText(decryptedBlob) with the decrypted Blob.
30747 * @param {function} onError This calls onError(errorCode, message) for an error,
30748 * where errorCode is an error code from EncryptError.ErrorCode.
30749 */
30750Consumer.prototype.decryptCKey_ = function(cKeyData, onPlainText, onError)
30751{
30752 // Get the encrypted content.
30753 var cKeyContent = cKeyData.getContent();
30754 var cKeyEncryptedContent = new EncryptedContent();
30755 try {
30756 cKeyEncryptedContent.wireDecode(cKeyContent);
30757 } catch (ex) {
30758 Consumer.Error.callOnError(onError, ex, "Error decoding EncryptedContent: ");
30759 return;
30760 }
30761 var eKeyName = cKeyEncryptedContent.getKeyLocator().getKeyName();
30762 var dKeyName = eKeyName.getPrefix(-3);
30763 dKeyName.append(Encryptor.NAME_COMPONENT_D_KEY).append(eKeyName.getSubName(-2));
30764
30765 // Check if the decryption key is already in the store.
30766 var dKey = this.dKeyMap_[dKeyName.toUri()];
30767 if (dKey)
30768 this.decrypt_(cKeyEncryptedContent, dKey, onPlainText, onError);
30769 else {
30770 // Get the D-Key Data.
30771 var interestName = new Name(dKeyName);
30772 interestName.append(Encryptor.NAME_COMPONENT_FOR).append(this.consumerName_);
30773 var interest = new Interest(interestName);
30774 var thisConsumer = this;
30775 this.sendInterest_
30776 (interest, 1, this.dKeyLink_,
30777 function(validDKeyData) {
30778 thisConsumer.decryptDKeyPromise_(validDKeyData)
30779 .then(function(dKeyBits) {
30780 thisConsumer.dKeyMap_[dKeyName.toUri()] = dKeyBits;
30781 Consumer.decrypt_
30782 (cKeyEncryptedContent, dKeyBits, onPlainText, onError);
30783 }, function(ex) {
30784 Consumer.Error.callOnError(onError, ex, "decryptDKey error: ");
30785 });
30786 },
30787 onError);
30788 }
30789};
30790
30791/**
30792 * Decrypt dKeyData.
30793 * @param {Data} dKeyData The D-KEY data packet.
30794 * @return {Promise|SyncPromise} A promise that returns the decrypted Blob, or
30795 * that is rejected with Consumer.Error or other error.
30796 */
30797Consumer.prototype.decryptDKeyPromise_ = function(dKeyData)
30798{
30799 var dataContent;
30800 var encryptedNonce;
30801 var encryptedPayloadBlob;
30802 var thisConsumer = this;
30803
30804 return SyncPromise.resolve()
30805 .then(function() {
30806 // Get the encrypted content.
30807 dataContent = dKeyData.getContent();
30808
30809 // Process the nonce.
30810 // dataContent is a sequence of the two EncryptedContent.
30811 encryptedNonce = new EncryptedContent();
30812 encryptedNonce.wireDecode(dataContent);
30813 var consumerKeyName = encryptedNonce.getKeyLocator().getKeyName();
30814
30815 // Get consumer decryption key.
30816 return thisConsumer.getDecryptionKeyPromise_(consumerKeyName);
30817 })
30818 .then(function(consumerKeyBlob) {
30819 if (consumerKeyBlob.size() == 0)
30820 return SyncPromise.reject(new Consumer.Error
30821 (EncryptError.ErrorCode.NoDecryptKey,
30822 "The desired consumer decryption key in not in the database"));
30823
30824 // Process the D-KEY.
30825 // Use the size of encryptedNonce to find the start of encryptedPayload.
30826 var encryptedPayloadBuffer = dataContent.buf().slice
30827 (encryptedNonce.wireEncode().size());
30828 encryptedPayloadBlob = new Blob(encryptedPayloadBuffer, false);
30829 if (encryptedPayloadBlob.size() == 0)
30830 return SyncPromise.reject(new Consumer.Error
30831 (EncryptError.ErrorCode.InvalidEncryptedFormat,
30832 "The data packet does not satisfy the D-KEY packet format"));
30833
30834 // Decrypt the D-KEY.
30835 return Consumer.decryptPromise_(encryptedNonce, consumerKeyBlob);
30836 })
30837 .then(function(nonceKeyBits) {
30838 return Consumer.decryptPromise_(encryptedPayloadBlob, nonceKeyBits);
30839 });
30840};
30841
30842/**
30843 * Express the interest, call verifyData for the fetched Data packet and call
30844 * onVerified if verify succeeds. If verify fails, call
30845 * onError(EncryptError.ErrorCode.Validation, "verifyData failed"). If the
30846 * interest times out, re-express nRetrials times. If the interest times out
30847 * nRetrials times, or for a network Nack, call
30848 * onError(EncryptError.ErrorCode.DataRetrievalFailure, interest.getName().toUri()).
30849 * @param {Interest} interest The Interest to express.
30850 * @param {number} nRetrials The number of retrials left after a timeout.
30851 * @param {Link} link The Link object to use in the Interest. This does not make
30852 * a copy of the Link object. If the Link object's getDelegations().size() is
30853 * zero, don't use it.
30854 * @param {function} onVerified When the fetched Data packet validation
30855 * succeeds, this calls onVerified(data).
30856 * @param {function} onError This calls onError(errorCode, message) for an error,
30857 * where errorCode is an error code from EncryptError.ErrorCode.
30858 */
30859Consumer.prototype.sendInterest_ = function
30860 (interest, nRetrials, link, onVerified, onError)
30861{
30862 // Prepare the callback functions.
30863 var thisConsumer = this;
30864 var onData = function(contentInterest, contentData) {
30865 try {
30866 thisConsumer.keyChain_.verifyData
30867 (contentData, onVerified,
30868 function(d, reason) {
30869 try {
30870 onError
30871 (EncryptError.ErrorCode.Validation, "verifyData failed. Reason: " +
30872 reason);
30873 } catch (ex) {
30874 console.log("Error in onError: " + NdnCommon.getErrorWithStackTrace(ex));
30875 }
30876 });
30877 } catch (ex) {
30878 Consumer.Error.callOnError(onError, ex, "verifyData error: ");
30879 }
30880 };
30881
30882 function onNetworkNack(interest, networkNack) {
30883 // We have run out of options. Report a retrieval failure.
30884 try {
30885 onError(EncryptError.ErrorCode.DataRetrievalFailure,
30886 interest.getName().toUri());
30887 } catch (ex) {
30888 console.log("Error in onError: " + NdnCommon.getErrorWithStackTrace(ex));
30889 }
30890 }
30891
30892 var onTimeout = function(interest) {
30893 if (nRetrials > 0)
30894 thisConsumer.sendInterest_(interest, nRetrials - 1, link, onVerified, onError);
30895 else
30896 onNetworkNack(interest, new NetworkNack());
30897 };
30898
30899 var request;
30900 if (link.getDelegations().size() === 0)
30901 // We can use the supplied interest without copying.
30902 request = interest;
30903 else {
30904 // Copy the supplied interest and add the Link.
30905 request = new Interest(interest);
30906 // This will use a cached encoding if available.
30907 request.setLinkWireEncoding(link.wireEncode());
30908 }
30909
30910 try {
30911 this.face_.expressInterest(request, onData, onTimeout, onNetworkNack);
30912 } catch (ex) {
30913 Consumer.Error.callOnError(onError, ex, "expressInterest error: ");
30914 }
30915};
30916
30917/**
30918 * Get the encoded blob of the decryption key with decryptionKeyName from the
30919 * database.
30920 * @param {Name} decryptionKeyName The key name.
30921 * @return {Promise|SyncPromise} A promise that returns a Blob with the encoded
30922 * key (or an isNull Blob if cannot find the key with decryptionKeyName), or
30923 * that is rejected with ConsumerDb.Error for a database error.
30924 */
30925Consumer.prototype.getDecryptionKeyPromise_ = function(decryptionKeyName)
30926{
30927 return this.database_.getKeyPromise(decryptionKeyName);
30928};
30929
30930Consumer.NO_LINK = new Link();
30931/**
30932 * Copyright (C) 2015-2016 Regents of the University of California.
30933 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
30934 * @author: From ndn-group-encrypt src/decrypt-key https://github.com/named-data/ndn-group-encrypt
30935 *
30936 * This program is free software: you can redistribute it and/or modify
30937 * it under the terms of the GNU Lesser General Public License as published by
30938 * the Free Software Foundation, either version 3 of the License, or
30939 * (at your option) any later version.
30940 *
30941 * This program is distributed in the hope that it will be useful,
30942 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30943 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30944 * GNU Lesser General Public License for more details.
30945 *
30946 * You should have received a copy of the GNU Lesser General Public License
30947 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30948 * A copy of the GNU Lesser General Public License is in the file COPYING.
30949 */
30950
30951/** @ignore */
30952var Blob = require('../util/blob.js').Blob;
30953
30954/**
30955 * A DecryptKey supplies the key for decrypt.
30956 * Create a DecryptKey with the given key value.
30957 * @param {Blob|DecryptKey} value If value is another DecryptKey then copy it.
30958 * Otherwise, value is the key value.
30959 * @note This class is an experimental feature. The API may change.
30960 * @constructor
30961 */
30962var DecryptKey = function DecryptKey(value)
30963{
30964 if (typeof value === 'object' && value instanceof DecryptKey) {
30965 // Make a deep copy.
30966 this.keyBits_ = value.keyBits_;
30967 }
30968 else {
30969 var keyBits = value;
30970 this.keyBits_ = typeof keyBits === 'object' && keyBits instanceof Blob ?
30971 keyBits : new Blob(keyBits);
30972 }
30973};
30974
30975exports.DecryptKey = DecryptKey;
30976
30977/**
30978 * Get the key value.
30979 * @return {Blob} The key value.
30980 */
30981DecryptKey.prototype.getKeyBits = function() { return this.keyBits_; };
30982/**
30983 * Copyright (C) 2015-2016 Regents of the University of California.
30984 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
30985 * @author: From ndn-group-encrypt src/error-code https://github.com/named-data/ndn-group-encrypt
30986 *
30987 * This program is free software: you can redistribute it and/or modify
30988 * it under the terms of the GNU Lesser General Public License as published by
30989 * the Free Software Foundation, either version 3 of the License, or
30990 * (at your option) any later version.
30991 *
30992 * This program is distributed in the hope that it will be useful,
30993 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30994 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30995 * GNU Lesser General Public License for more details.
30996 *
30997 * You should have received a copy of the GNU Lesser General Public License
30998 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30999 * A copy of the GNU Lesser General Public License is in the file COPYING.
31000 */
31001
31002/**
31003 * EncryptError holds the ErrorCode enum for errors from the encrypt library.
31004 */
31005var EncryptError = function EncryptError()
31006{
31007};
31008
31009exports.EncryptError = EncryptError;
31010
31011EncryptError.ErrorCode = {
31012 Timeout: 1,
31013 Validation: 2,
31014 UnsupportedEncryptionScheme: 32,
31015 InvalidEncryptedFormat: 33,
31016 NoDecryptKey: 34,
31017 EncryptionFailure: 35,
31018 DataRetrievalFailure: 36,
31019 General: 100
31020};
31021/**
31022 * Copyright (C) 2015-2016 Regents of the University of California.
31023 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
31024 * @author: From ndn-group-encrypt src/encrypt-key https://github.com/named-data/ndn-group-encrypt
31025 *
31026 * This program is free software: you can redistribute it and/or modify
31027 * it under the terms of the GNU Lesser General Public License as published by
31028 * the Free Software Foundation, either version 3 of the License, or
31029 * (at your option) any later version.
31030 *
31031 * This program is distributed in the hope that it will be useful,
31032 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31033 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31034 * GNU Lesser General Public License for more details.
31035 *
31036 * You should have received a copy of the GNU Lesser General Public License
31037 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31038 * A copy of the GNU Lesser General Public License is in the file COPYING.
31039 */
31040
31041/** @ignore */
31042var Blob = require('../util/blob.js').Blob;
31043
31044/**
31045 * An EncryptKey supplies the key for encrypt.
31046 * Create an EncryptKey with the given key value.
31047 * @param {Blob|EncryptKey} value If value is another EncryptKey then copy it.
31048 * Otherwise, value is the key value.
31049 * @note This class is an experimental feature. The API may change.
31050 * @constructor
31051 */
31052var EncryptKey = function EncryptKey(value)
31053{
31054 if (typeof value === 'object' && value instanceof EncryptKey) {
31055 // Make a deep copy.
31056 this.keyBits_ = value.keyBits_;
31057 }
31058 else {
31059 var keyBits = value;
31060 this.keyBits_ = typeof keyBits === 'object' && keyBits instanceof Blob ?
31061 keyBits : new Blob(keyBits);
31062 }
31063};
31064
31065exports.EncryptKey = EncryptKey;
31066
31067/**
31068 * Get the key value.
31069 * @return {Blob} The key value.
31070 */
31071EncryptKey.prototype.getKeyBits = function() { return this.keyBits_; };
31072/**
31073 * Copyright (C) 2015-2016 Regents of the University of California.
31074 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
31075 * @author: From ndn-group-encrypt src/encrypted-content https://github.com/named-data/ndn-group-encrypt
31076 *
31077 * This program is free software: you can redistribute it and/or modify
31078 * it under the terms of the GNU Lesser General Public License as published by
31079 * the Free Software Foundation, either version 3 of the License, or
31080 * (at your option) any later version.
31081 *
31082 * This program is distributed in the hope that it will be useful,
31083 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31084 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31085 * GNU Lesser General Public License for more details.
31086 *
31087 * You should have received a copy of the GNU Lesser General Public License
31088 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31089 * A copy of the GNU Lesser General Public License is in the file COPYING.
31090 */
31091
31092/** @ignore */
31093var KeyLocator = require('../key-locator.js').KeyLocator; /** @ignore */
31094var WireFormat = require('../encoding/wire-format.js').WireFormat; /** @ignore */
31095var Blob = require('../util/blob.js').Blob;
31096
31097/**
31098 * An EncryptedContent holds an encryption type, a payload and other fields
31099 * representing encrypted content.
31100 * @param {EncryptedContent} (optional) If value is another EncryptedContent
31101 * then copy it. If value is omitted then create an EncryptedContent with
31102 * unspecified values.
31103 * @note This class is an experimental feature. The API may change.
31104 * @constructor
31105 */
31106var EncryptedContent = function EncryptedContent(value)
31107{
31108 if (typeof value === 'object' && value instanceof EncryptedContent) {
31109 // Make a deep copy.
31110 this.algorithmType_ = value.algorithmType_;
31111 this.keyLocator_ = new KeyLocator(value.keyLocator_);
31112 this.initialVector_ = value.initialVector_;
31113 this.payload_ = value.payload_;
31114 }
31115 else {
31116 this.algorithmType_ = null;
31117 this.keyLocator_ = new KeyLocator();
31118 this.initialVector_ = new Blob();
31119 this.payload_ = new Blob();
31120 }
31121};
31122
31123exports.EncryptedContent = EncryptedContent;
31124
31125/**
31126 * Get the algorithm type from EncryptAlgorithmType.
31127 * @return {number} The algorithm type from EncryptAlgorithmType, or null if
31128 * not specified.
31129 */
31130EncryptedContent.prototype.getAlgorithmType = function()
31131{
31132 return this.algorithmType_;
31133};
31134
31135/**
31136 * Get the key locator.
31137 * @return {KeyLocator} The key locator. If not specified, getType() is null.
31138 */
31139EncryptedContent.prototype.getKeyLocator = function()
31140{
31141 return this.keyLocator_;
31142};
31143
31144/**
31145 * Get the initial vector.
31146 * @return {Blob} The initial vector. If not specified, isNull() is true.
31147 */
31148EncryptedContent.prototype.getInitialVector = function()
31149{
31150 return this.initialVector_;
31151};
31152
31153/**
31154 * Get the payload.
31155 * @return {Blob} The payload. If not specified, isNull() is true.
31156 */
31157EncryptedContent.prototype.getPayload = function()
31158{
31159 return this.payload_;
31160};
31161
31162/**
31163 * Set the algorithm type.
31164 * @param {number} algorithmType The algorithm type from EncryptAlgorithmType.
31165 * If not specified, set to null.
31166 * @return {EncryptedContent} This EncryptedContent so that you can chain calls
31167 * to update values.
31168 */
31169EncryptedContent.prototype.setAlgorithmType = function(algorithmType)
31170{
31171 this.algorithmType_ = algorithmType;
31172 return this;
31173};
31174
31175/**
31176 * Set the key locator.
31177 * @param {KeyLocator} keyLocator The key locator. This makes a copy of the
31178 * object. If not specified, set to the default KeyLocator().
31179 * @return {EncryptedContent} This EncryptedContent so that you can chain calls
31180 * to update values.
31181 */
31182EncryptedContent.prototype.setKeyLocator = function(keyLocator)
31183{
31184 this.keyLocator_ = typeof keyLocator === 'object' &&
31185 keyLocator instanceof KeyLocator ?
31186 new KeyLocator(keyLocator) : new KeyLocator();
31187 return this;
31188};
31189
31190/**
31191 * Set the initial vector.
31192 * @param {Blob} initialVector The initial vector. If not specified, set to the
31193 * default Blob() where isNull() is true.
31194 * @return {EncryptedContent} This EncryptedContent so that you can chain calls
31195 * to update values.
31196 */
31197EncryptedContent.prototype.setInitialVector = function(initialVector)
31198{
31199 this.initialVector_ =
31200 typeof initialVector === 'object' && initialVector instanceof Blob ?
31201 initialVector : new Blob(initialVector);
31202 return this;
31203};
31204
31205/**
31206 * Set the encrypted payload.
31207 * @param {Blob} payload The payload. If not specified, set to the default Blob()
31208 * where isNull() is true.
31209 * @return {EncryptedContent} This EncryptedContent so that you can chain calls
31210 * to update values.
31211 */
31212EncryptedContent.prototype.setPayload = function(payload)
31213{
31214 this.payload_ = typeof payload === 'object' && payload instanceof Blob ?
31215 payload : new Blob(payload);
31216 return this;
31217};
31218
31219/**
31220 * Encode this EncryptedContent for a particular wire format.
31221 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
31222 * this object. If omitted, use WireFormat.getDefaultWireFormat().
31223 * @return {Blob} The encoded buffer in a Blob object.
31224 */
31225EncryptedContent.prototype.wireEncode = function(wireFormat)
31226{
31227 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
31228 return wireFormat.encodeEncryptedContent(this);
31229};
31230
31231/**
31232 * Decode the input using a particular wire format and update this
31233 * EncryptedContent.
31234 * @param {Blob|Buffer} input The buffer with the bytes to decode.
31235 * @param {WireFormat} wireFormat (optional) A WireFormat object used to decode
31236 * this object. If omitted, use WireFormat.getDefaultWireFormat().
31237 */
31238EncryptedContent.prototype.wireDecode = function(input, wireFormat)
31239{
31240 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
31241 if (typeof input === 'object' && input instanceof Blob)
31242 // Input is a blob, so get its buf() and set copy false.
31243 wireFormat.decodeEncryptedContent(this, input.buf(), false);
31244 else
31245 wireFormat.decodeEncryptedContent(this, input, true);
31246};
31247/**
31248 * Copyright (C) 2015-2016 Regents of the University of California.
31249 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
31250 * @author: From ndn-group-encrypt src/group-manager-db https://github.com/named-data/ndn-group-encrypt
31251 *
31252 * This program is free software: you can redistribute it and/or modify
31253 * it under the terms of the GNU Lesser General Public License as published by
31254 * the Free Software Foundation, either version 3 of the License, or
31255 * (at your option) any later version.
31256 *
31257 * This program is distributed in the hope that it will be useful,
31258 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31259 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31260 * GNU Lesser General Public License for more details.
31261 *
31262 * You should have received a copy of the GNU Lesser General Public License
31263 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31264 * A copy of the GNU Lesser General Public License is in the file COPYING.
31265 */
31266
31267/** @ignore */
31268var SyncPromise = require('../util/sync-promise.js').SyncPromise;
31269
31270/**
31271 * GroupManagerDb is a base class for the storage of data used by the
31272 * GroupManager. It contains two tables to store Schedules and Members.
31273 * This is an abstract base class. A subclass must implement the methods.
31274 * For example, see Sqlite3GroupManagerDb (for Nodejs) or IndexedDbGroupManagerDb
31275 * (for the browser).
31276 * @note This class is an experimental feature. The API may change.
31277 * @constructor
31278 */
31279var GroupManagerDb = function GroupManagerDb()
31280{
31281};
31282
31283exports.GroupManagerDb = GroupManagerDb;
31284
31285/**
31286 * Create a new GroupManagerDb.Error to report an error using GroupManagerDb
31287 * methods, wrapping the given error object.
31288 * Call with: throw new GroupManagerDb.Error(new Error("message")).
31289 * @constructor
31290 * @param {Error} error The exception created with new Error.
31291 */
31292GroupManagerDb.Error = function GroupManagerDbError(error)
31293{
31294 if (error) {
31295 error.__proto__ = GroupManagerDb.Error.prototype;
31296 return error;
31297 }
31298}
31299
31300GroupManagerDb.Error.prototype = new Error();
31301GroupManagerDb.Error.prototype.name = "GroupManagerDbError";
31302
31303////////////////////////////////////////////////////// Schedule management.
31304
31305/**
31306 * Check if there is a schedule with the given name.
31307 * @param {string} name The name of the schedule.
31308 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31309 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31310 * an async Promise.
31311 * @return {Promise|SyncPromise} A promise that returns true if there is a
31312 * schedule (else false), or that is rejected with GroupManagerDb.Error for a
31313 * database error.
31314 */
31315GroupManagerDb.prototype.hasSchedulePromise = function(name, useSync)
31316{
31317 return SyncPromise.reject(new Error
31318 ("GroupManagerDb.hasSchedulePromise is not implemented"));
31319};
31320
31321/**
31322 * List all the names of the schedules.
31323 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31324 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31325 * an async Promise.
31326 * @return {Promise|SyncPromise} A promise that returns a new array of string
31327 * with the names of all schedules, or that is rejected with
31328 * GroupManagerDb.Error for a database error.
31329 */
31330GroupManagerDb.prototype.listAllScheduleNamesPromise = function(useSync)
31331{
31332 return SyncPromise.reject(new Error
31333 ("GroupManagerDb.listAllScheduleNamesPromise is not implemented"));
31334};
31335
31336/**
31337 * Get a schedule with the given name.
31338 * @param {string} name The name of the schedule.
31339 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31340 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31341 * an async Promise.
31342 * @return {Promise|SyncPromise} A promise that returns a new Schedule object,
31343 * or that is rejected with GroupManagerDb.Error if the schedule does not exist
31344 * or other database error.
31345 */
31346GroupManagerDb.prototype.getSchedulePromise = function(name, useSync)
31347{
31348 return SyncPromise.reject(new Error
31349 ("GroupManagerDb.getSchedulePromise is not implemented"));
31350};
31351
31352/**
31353 * For each member using the given schedule, get the name and public key DER
31354 * of the member's key.
31355 * @param {string} name The name of the schedule.
31356 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31357 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31358 * an async Promise.
31359 * @return {Promise|SyncPromise} A promise that returns a new array of object
31360 * (where "keyName" is the Name of the public key and "publicKey" is the Blob of
31361 * the public key DER), or that is rejected with GroupManagerDb.Error for a
31362 * database error. Note that the member's identity name is keyName.getPrefix(-1).
31363 * If the schedule name is not found, the list is empty.
31364 */
31365GroupManagerDb.prototype.getScheduleMembersPromise = function
31366 (name, useSync)
31367{
31368 return SyncPromise.reject(new Error
31369 ("GroupManagerDb.getScheduleMembersPromise is not implemented"));
31370};
31371
31372/**
31373 * Add a schedule with the given name.
31374 * @param {string} name The name of the schedule. The name cannot be empty.
31375 * @param {Schedule} schedule The Schedule to add.
31376 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31377 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31378 * an async Promise.
31379 * @return {Promise|SyncPromise} A promise that fulfills when the schedule is
31380 * added, or that is rejected with GroupManagerDb.Error if a schedule with the
31381 * same name already exists, if the name is empty, or other database error.
31382 */
31383GroupManagerDb.prototype.addSchedulePromise = function(name, schedule, useSync)
31384{
31385 return SyncPromise.reject(new Error
31386 ("GroupManagerDb.addSchedulePromise is not implemented"));
31387};
31388
31389/**
31390 * Delete the schedule with the given name. Also delete members which use this
31391 * schedule. If there is no schedule with the name, then do nothing.
31392 * @param {string} name The name of the schedule.
31393 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31394 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31395 * an async Promise.
31396 * @return {Promise|SyncPromise} A promise that fulfills when the schedule is
31397 * deleted (or there is no such schedule), or that is rejected with
31398 * GroupManagerDb.Error for a database error.
31399 */
31400GroupManagerDb.prototype.deleteSchedulePromise = function(name, useSync)
31401{
31402 return SyncPromise.reject(new Error
31403 ("GroupManagerDb.deleteSchedulePromise is not implemented"));
31404};
31405
31406/**
31407 * Rename a schedule with oldName to newName.
31408 * @param {string} oldName The name of the schedule to be renamed.
31409 * @param {string} newName The new name of the schedule. The name cannot be empty.
31410 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31411 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31412 * an async Promise.
31413 * @return {Promise|SyncPromise} A promise that fulfills when the schedule is
31414 * renamed, or that is rejected with GroupManagerDb.Error if a schedule with
31415 * newName already exists, if the schedule with oldName does not exist, if
31416 * newName is empty, or other database error.
31417 */
31418GroupManagerDb.prototype.renameSchedulePromise = function
31419 (oldName, newName, useSync)
31420{
31421 return SyncPromise.reject(new Error
31422 ("GroupManagerDb.renameSchedulePromise is not implemented"));
31423};
31424
31425/**
31426 * Update the schedule with name and replace the old object with the given
31427 * schedule. Otherwise, if no schedule with name exists, a new schedule
31428 * with name and the given schedule will be added to database.
31429 * @param {string} name The name of the schedule. The name cannot be empty.
31430 * @param {Schedule} schedule The Schedule to update or add.
31431 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31432 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31433 * an async Promise.
31434 * @return {Promise|SyncPromise} A promise that fulfills when the schedule is
31435 * updated, or that is rejected with GroupManagerDb.Error if the name is empty,
31436 * or other database error.
31437 */
31438GroupManagerDb.prototype.updateSchedulePromise = function
31439 (name, schedule, useSync)
31440{
31441 return SyncPromise.reject(new Error
31442 ("GroupManagerDb.updateSchedulePromise is not implemented"));
31443};
31444
31445////////////////////////////////////////////////////// Member management.
31446
31447/**
31448 * Check if there is a member with the given identity name.
31449 * @param {Name} identity The member's identity name.
31450 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31451 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31452 * an async Promise.
31453 * @return {Promise|SyncPromise} A promise that returns true if there is a
31454 * member (else false), or that is rejected with GroupManagerDb.Error for a
31455 * database error.
31456 */
31457GroupManagerDb.prototype.hasMemberPromise = function(identity, useSync)
31458{
31459 return SyncPromise.reject(new Error
31460 ("GroupManagerDb.hasMemberPromise is not implemented"));
31461};
31462
31463/**
31464 * List all the members.
31465 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31466 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31467 * an async Promise.
31468 * @return {Promise|SyncPromise} A promise that returns a new array of Name with
31469 * the names of all members, or that is rejected with GroupManagerDb.Error for a
31470 * database error.
31471 */
31472GroupManagerDb.prototype.listAllMembersPromise = function(useSync)
31473{
31474 return SyncPromise.reject(new Error
31475 ("GroupManagerDb.listAllMembersPromise is not implemented"));
31476};
31477
31478/**
31479 * Get the name of the schedule for the given member's identity name.
31480 * @param {Name} identity The member's identity name.
31481 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31482 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31483 * an async Promise.
31484 * @return {Promise|SyncPromise} A promise that returns the string schedule name,
31485 * or that is rejected with GroupManagerDb.Error if there's no member with the
31486 * given identity name in the database, or other database error.
31487 */
31488GroupManagerDb.prototype.getMemberSchedulePromise = function(identity, useSync)
31489{
31490 return SyncPromise.reject(new Error
31491 ("GroupManagerDb.getMemberSchedulePromise is not implemented"));
31492};
31493
31494/**
31495 * Add a new member with the given key named keyName into a schedule named
31496 * scheduleName. The member's identity name is keyName.getPrefix(-1).
31497 * @param {string} scheduleName The schedule name.
31498 * @param {Name} keyName The name of the key.
31499 * @param {Blob} key A Blob of the public key DER.
31500 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31501 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31502 * an async Promise.
31503 * @return {Promise|SyncPromise} A promise that fulfills when the member is
31504 * added, or that is rejected with GroupManagerDb.Error if there's no schedule
31505 * named scheduleName, if the member's identity name already exists, or other
31506 * database error.
31507 */
31508GroupManagerDb.prototype.addMemberPromise = function
31509 (scheduleName, keyName, key, useSync)
31510{
31511 return SyncPromise.reject(new Error
31512 ("GroupManagerDb.addMemberPromise is not implemented"));
31513};
31514
31515/**
31516 * Change the name of the schedule for the given member's identity name.
31517 * @param {Name} identity The member's identity name.
31518 * @param {string} scheduleName The new schedule name.
31519 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31520 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31521 * an async Promise.
31522 * @return {Promise|SyncPromise} A promise that fulfills when the member is
31523 * updated, or that is rejected with GroupManagerDb.Error if there's no member
31524 * with the given identity name in the database, or there's no schedule named
31525 * scheduleName, or other database error.
31526 */
31527GroupManagerDb.prototype.updateMemberSchedulePromise = function
31528 (identity, scheduleName, useSync)
31529{
31530 return SyncPromise.reject(new Error
31531 ("GroupManagerDb.updateMemberSchedulePromise is not implemented"));
31532};
31533
31534/**
31535 * Delete a member with the given identity name. If there is no member with
31536 * the identity name, then do nothing.
31537 * @param {Name} identity The member's identity name.
31538 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31539 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31540 * an async Promise.
31541 * @return {Promise|SyncPromise} A promise that fulfills when the member is
31542 * deleted (or there is no such member), or that is rejected with
31543 * GroupManagerDb.Error for a database error.
31544 */
31545GroupManagerDb.prototype.deleteMemberPromise = function(identity, useSync)
31546{
31547 return SyncPromise.reject(new Error
31548 ("GroupManagerDb.deleteMemberPromise is not implemented"));
31549};
31550/**
31551 * Copyright (C) 2015-2016 Regents of the University of California.
31552 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
31553 * @author: From ndn-group-encrypt src/group-manager https://github.com/named-data/ndn-group-encrypt
31554 *
31555 * This program is free software: you can redistribute it and/or modify
31556 * it under the terms of the GNU Lesser General Public License as published by
31557 * the Free Software Foundation, either version 3 of the License, or
31558 * (at your option) any later version.
31559 *
31560 * This program is distributed in the hope that it will be useful,
31561 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31562 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31563 * GNU Lesser General Public License for more details.
31564 *
31565 * You should have received a copy of the GNU Lesser General Public License
31566 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31567 * A copy of the GNU Lesser General Public License is in the file COPYING.
31568 */
31569
31570/** @ignore */
31571var Name = require('../name.js').Name; /** @ignore */
31572var Data = require('../data.js').Data; /** @ignore */
31573var SyncPromise = require('../util/sync-promise.js').SyncPromise; /** @ignore */
31574var IdentityCertificate = require('../security/certificate/identity-certificate.js').IdentityCertificate; /** @ignore */
31575var SecurityException = require('../security/security-exception.js').SecurityException; /** @ignore */
31576var RsaKeyParams = require('../security/key-params.js').RsaKeyParams; /** @ignore */
31577var EncryptParams = require('./algo/encrypt-params.js').EncryptParams; /** @ignore */
31578var EncryptAlgorithmType = require('./algo/encrypt-params.js').EncryptAlgorithmType; /** @ignore */
31579var Encryptor = require('./algo/encryptor.js').Encryptor; /** @ignore */
31580var RsaAlgorithm = require('./algo/rsa-algorithm.js').RsaAlgorithm; /** @ignore */
31581var Interval = require('./interval.js').Interval; /** @ignore */
31582var Schedule = require('./schedule.js').Schedule;
31583
31584/**
31585 * A GroupManager manages keys and schedules for group members in a particular
31586 * namespace.
31587 * Create a group manager with the given values. The group manager namespace
31588 * is <prefix>/read/<dataType> .
31589 * @param {Name} prefix The prefix for the group manager namespace.
31590 * @param {Name} dataType The data type for the group manager namespace.
31591 * @param {GroupManagerDb} database The GroupManagerDb for storing the group
31592 * management information (including user public keys and schedules).
31593 * @param {number} keySize The group key will be an RSA key with keySize bits.
31594 * @param {number} freshnessHours The number of hours of the freshness period of
31595 * data packets carrying the keys.
31596 * @param {KeyChain} keyChain The KeyChain to use for signing data packets. This
31597 * signs with the default identity.
31598 * @note This class is an experimental feature. The API may change.
31599 * @constructor
31600 */
31601var GroupManager = function GroupManager
31602 (prefix, dataType, database, keySize, freshnessHours, keyChain)
31603{
31604 this.namespace_ = new Name(prefix).append(Encryptor.NAME_COMPONENT_READ)
31605 .append(dataType);
31606 this.database_ = database;
31607 this.keySize_ = keySize;
31608 this.freshnessHours_ = freshnessHours;
31609
31610 this.keyChain_ = keyChain;
31611};
31612
31613exports.GroupManager = GroupManager;
31614
31615/**
31616 * Create a group key for the interval into which timeSlot falls. This creates
31617 * a group key if it doesn't exist, and encrypts the key using the public key of
31618 * each eligible member.
31619 * @param {number} timeSlot The time slot to cover as milliseconds since
31620 * Jan 1, 1970 UTC.
31621 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31622 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31623 * an async Promise.
31624 * @return {Promise|SyncPromise} A promise that returns a List of Data packets
31625 * (where the first is the E-KEY data packet with the group's public key and the
31626 * rest are the D-KEY data packets with the group's private key encrypted with
31627 * the public key of each eligible member), or that is rejected with
31628 * GroupManagerDb.Error for a database error or SecurityException for an error
31629 * using the security KeyChain.
31630 */
31631GroupManager.prototype.getGroupKeyPromise = function(timeSlot, useSync)
31632{
31633 var memberKeys = [];
31634 var result = [];
31635 var thisManager = this;
31636 var privateKeyBlob;
31637 var publicKeyBlob;
31638 var startTimeStamp;
31639 var endTimeStamp;
31640
31641 // Get the time interval.
31642 return this.calculateIntervalPromise_(timeSlot, memberKeys, useSync)
31643 .then(function(finalInterval) {
31644 if (finalInterval.isValid() == false)
31645 return SyncPromise.resolve(result);
31646
31647 startTimeStamp = Schedule.toIsoString(finalInterval.getStartTime());
31648 endTimeStamp = Schedule.toIsoString(finalInterval.getEndTime());
31649
31650 // Generate the private and public keys.
31651 return thisManager.generateKeyPairPromise_(useSync)
31652 .then(function(keyPair) {
31653 privateKeyBlob = keyPair.privateKeyBlob;
31654 publicKeyBlob = keyPair.publicKeyBlob;
31655
31656 // Add the first element to the result.
31657 // The E-KEY (public key) data packet name convention is:
31658 // /<data_type>/E-KEY/[start-ts]/[end-ts]
31659 return thisManager.createEKeyDataPromise_
31660 (startTimeStamp, endTimeStamp, publicKeyBlob, useSync);
31661 })
31662 .then(function(data) {
31663 result.push(data);
31664
31665 // Encrypt the private key with the public key from each member's certificate.
31666
31667 // Process the memberKeys entry at i, and recursively call to process the
31668 // next entry. Return a promise which is resolved when all are processed.
31669 // (We have to make a recursive function to use Promises.)
31670 function processMemberKey(i) {
31671 if (i >= memberKeys.length)
31672 // Finished.
31673 return SyncPromise.resolve();
31674
31675 var keyName = memberKeys[i].keyName;
31676 var certificateKey = memberKeys[i].publicKey;
31677
31678 return thisManager.createDKeyDataPromise_
31679 (startTimeStamp, endTimeStamp, keyName, privateKeyBlob, certificateKey,
31680 useSync)
31681 .then(function(data) {
31682 result.push(data);
31683
31684 return processMemberKey(i + 1);
31685 });
31686 }
31687
31688 return processMemberKey(0);
31689 })
31690 .then(function() {
31691 return SyncPromise.resolve(result);
31692 });
31693 });
31694};
31695
31696/**
31697 * Add a schedule with the given scheduleName.
31698 * @param {string} scheduleName The name of the schedule. The name cannot be
31699 * empty.
31700 * @param {Schedule} schedule The Schedule to add.
31701 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31702 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31703 * an async Promise.
31704 * @return {Promise|SyncPromise} A promise that fulfills when the schedule is
31705 * added, or that is rejected with GroupManagerDb.Error if a schedule with the
31706 * same name already exists, if the name is empty, or other database error.
31707 */
31708GroupManager.prototype.addSchedulePromise = function
31709 (scheduleName, schedule, useSync)
31710{
31711 return this.database_.addSchedulePromise(scheduleName, schedule, useSync);
31712};
31713
31714/**
31715 * Delete the schedule with the given scheduleName. Also delete members which
31716 * use this schedule. If there is no schedule with the name, then do nothing.
31717 * @param {string} scheduleName The name of the schedule.
31718 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31719 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31720 * an async Promise.
31721 * @return {Promise|SyncPromise} A promise that fulfills when the schedule is
31722 * deleted (or there is no such schedule), or that is rejected with
31723 * GroupManagerDb.Error for a database error.
31724 */
31725GroupManager.prototype.deleteSchedulePromise = function(scheduleName, useSync)
31726{
31727 return this.database_.deleteSchedulePromise(scheduleName, useSync);
31728};
31729
31730/**
31731 * Update the schedule with scheduleName and replace the old object with the
31732 * given schedule. Otherwise, if no schedule with name exists, a new schedule
31733 * with name and the given schedule will be added to database.
31734 * @param {string} scheduleName The name of the schedule. The name cannot be
31735 * empty.
31736 * @param {Schedule} schedule The Schedule to update or add.
31737 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31738 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31739 * an async Promise.
31740 * @return {Promise|SyncPromise} A promise that fulfills when the schedule is
31741 * updated, or that is rejected with GroupManagerDb.Error if the name is empty,
31742 * or other database error.
31743 */
31744GroupManager.prototype.updateSchedulePromise = function
31745 (name, scheduleName, useSync)
31746{
31747 return this.database_.updateSchedulePromise(scheduleName, schedule, useSync);
31748};
31749
31750/**
31751 * Add a new member with the given memberCertificate into a schedule named
31752 * scheduleName. If cert is an IdentityCertificate made from memberCertificate,
31753 * then the member's identity name is cert.getPublicKeyName().getPrefix(-1).
31754 * @param {string} scheduleName The schedule name.
31755 * @param {Data} memberCertificate The member's certificate.
31756 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31757 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31758 * an async Promise.
31759 * @return {Promise|SyncPromise} A promise that fulfills when the member is
31760 * added, or that is rejected with GroupManagerDb.Error if there's no schedule
31761 * named scheduleName, if the member's identity name already exists, or other
31762 * database error. Or a promise that is rejected with DerDecodingException for
31763 * an error decoding memberCertificate as a certificate.
31764 */
31765GroupManager.prototype.addMemberPromise = function
31766 (scheduleName, memberCertificate, useSync)
31767{
31768 var cert = new IdentityCertificate(memberCertificate);
31769 return this.database_.addMemberPromise
31770 (scheduleName, cert.getPublicKeyName(), cert.getPublicKeyInfo().getKeyDer(),
31771 useSync);
31772};
31773
31774/**
31775 * Remove a member with the given identity name. If there is no member with
31776 * the identity name, then do nothing.
31777 * @param {Name} identity The member's identity name.
31778 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31779 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31780 * an async Promise.
31781 * @return {Promise|SyncPromise} A promise that fulfills when the member is
31782 * removed (or there is no such member), or that is rejected with
31783 * GroupManagerDb.Error for a database error.
31784 */
31785GroupManager.prototype.removeMemberPromise = function(identity, useSync)
31786{
31787 return this.database_.deleteMemberPromise(identity, useSync);
31788};
31789
31790/**
31791 * Change the name of the schedule for the given member's identity name.
31792 * @param {Name} identity The member's identity name.
31793 * @param {string} scheduleName The new schedule name.
31794 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31795 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31796 * an async Promise.
31797 * @return {Promise|SyncPromise} A promise that fulfills when the member is
31798 * updated, or that is rejected with GroupManagerDb.Error if there's no member
31799 * with the given identity name in the database, or there's no schedule named
31800 * scheduleName.
31801 */
31802GroupManager.prototype.updateMemberSchedulePromise = function
31803 (identity, scheduleName, useSync)
31804{
31805 return this.database_.updateMemberSchedulePromise
31806 (identity, scheduleName, useSync);
31807};
31808
31809/**
31810 * Calculate an Interval that covers the timeSlot.
31811 * @param {number} timeSlot The time slot to cover as milliseconds since
31812 * Jan 1, 1970 UTC.
31813 * @param {Array<object>} memberKeys First clear memberKeys then fill it with
31814 * the info of members who are allowed to access the interval. memberKeys is an
31815 * array of object where "keyName" is the Name of the public key and "publicKey"
31816 * is the Blob of the public key DER. The memberKeys entries are sorted by
31817 * the entry keyName.
31818 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31819 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31820 * an async Promise.
31821 * @return {Promise|SyncPromise} A promise that returns a new nterval covering
31822 * the time slot, or that is rejected with GroupManagerDb.Error for a database
31823 * error.
31824 */
31825GroupManager.prototype.calculateIntervalPromise_ = function
31826 (timeSlot, memberKeys, useSync)
31827{
31828 // Prepare.
31829 var positiveResult = new Interval();
31830 var negativeResult = new Interval();
31831 // Clear memberKeys.
31832 memberKeys.splice(0, memberKeys.length);
31833 var thisManager = this;
31834
31835 // Get the all intervals from the schedules.
31836 return this.database_.listAllScheduleNamesPromise(useSync)
31837 .then(function(scheduleNames) {
31838 // Process the scheduleNames entry at i, and recursively call to process the
31839 // next entry. Return a promise which is resolved when all are processed.
31840 // (We have to make a recursive function to use Promises.)
31841 function processSchedule(i) {
31842 if (i >= scheduleNames.length)
31843 // Finished.
31844 return SyncPromise.resolve();
31845
31846 var scheduleName = scheduleNames[i];
31847
31848 return thisManager.database_.getSchedulePromise(scheduleName, useSync)
31849 .then(function(schedule) {
31850 var result = schedule.getCoveringInterval(timeSlot);
31851 var tempInterval = result.interval;
31852
31853 if (result.isPositive) {
31854 if (!positiveResult.isValid())
31855 positiveResult = tempInterval;
31856 positiveResult.intersectWith(tempInterval);
31857
31858 return thisManager.database_.getScheduleMembersPromise
31859 (scheduleName, useSync)
31860 .then(function(map) {
31861 // Add each entry in map to memberKeys.
31862 for (var iMap = 0; iMap < map.length; ++iMap)
31863 GroupManager.memberKeysAdd_(memberKeys, map[iMap]);
31864
31865 return processSchedule(i + 1);
31866 });
31867 }
31868 else {
31869 if (!negativeResult.isValid())
31870 negativeResult = tempInterval;
31871 negativeResult.intersectWith(tempInterval);
31872
31873 return processSchedule(i + 1);
31874 }
31875 });
31876 }
31877
31878 return processSchedule(0);
31879 })
31880 .then(function() {
31881 if (!positiveResult.isValid())
31882 // Return an invalid interval when there is no member which has an
31883 // interval covering the time slot.
31884 return SyncPromise.resolve(new Interval(false));
31885
31886 // Get the final interval result.
31887 var finalInterval;
31888 if (negativeResult.isValid())
31889 finalInterval = positiveResult.intersectWith(negativeResult);
31890 else
31891 finalInterval = positiveResult;
31892
31893 return SyncPromise.resolve(finalInterval);
31894 });
31895};
31896
31897/**
31898 * Add entry to memberKeys, sorted by entry.keyName. If there is already an
31899 * entry with keyName, then don't add.
31900 */
31901GroupManager.memberKeysAdd_ = function(memberKeys, entry)
31902{
31903 // Find the index of the first node where the keyName is not less than
31904 // entry.keyName.
31905 var i = 0;
31906 while (i < memberKeys.length) {
31907 var comparison = memberKeys[i].keyName.compare(entry.keyName);
31908 if (comparison == 0)
31909 // A duplicate, so don't add.
31910 return;
31911
31912 if (comparison > 0)
31913 break;
31914 i += 1;
31915 }
31916
31917 memberKeys.splice(i, 0, entry);
31918};
31919
31920/**
31921 * Generate an RSA key pair according to keySize_.
31922 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31923 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31924 * an async Promise.
31925 * @return {Promise|SyncPromise} A promise that returns an object where
31926 * "privateKeyBlob" is the encoding Blob of the private key and "publicKeyBlob"
31927 * is the encoding Blob of the public key.
31928 */
31929GroupManager.prototype.generateKeyPairPromise_ = function(useSync)
31930{
31931 var params = new RsaKeyParams(this.keySize_);
31932
31933 return RsaAlgorithm.generateKeyPromise(params)
31934 .then(function(privateKey) {
31935 var privateKeyBlob = privateKey.getKeyBits();
31936 var publicKey = RsaAlgorithm.deriveEncryptKey(privateKeyBlob);
31937 var publicKeyBlob = publicKey.getKeyBits();
31938
31939 return SyncPromise.resolve
31940 ({ privateKeyBlob: privateKeyBlob, publicKeyBlob: publicKeyBlob });
31941 });
31942};
31943
31944/**
31945 * Create an E-KEY Data packet for the given public key.
31946 * @param {string} startTimeStamp The start time stamp string to put in the name.
31947 * @param {string} endTimeStamp The end time stamp string to put in the name.
31948 * @param {Blob} publicKeyBlob A Blob of the public key DER.
31949 * @return The Data packet.
31950 * @throws SecurityException for an error using the security KeyChain.
31951 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31952 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31953 * an async Promise.
31954 * @return {Promise|SyncPromise} A promise that returns the Data packet, or that
31955 * is rejected with SecurityException for an error using the security KeyChain.
31956 */
31957GroupManager.prototype.createEKeyDataPromise_ = function
31958 (startTimeStamp, endTimeStamp, publicKeyBlob, useSync)
31959{
31960 var name = new Name(this.namespace_);
31961 name.append(Encryptor.NAME_COMPONENT_E_KEY).append(startTimeStamp)
31962 .append(endTimeStamp);
31963
31964 var data = new Data(name);
31965 data.getMetaInfo().setFreshnessPeriod
31966 (this.freshnessHours_ * GroupManager.MILLISECONDS_IN_HOUR);
31967 data.setContent(publicKeyBlob);
31968
31969 return this.keyChain_.signPromise(data);
31970};
31971
31972/**
31973 * Create a D-KEY Data packet with an EncryptedContent for the given private
31974 * key, encrypted with the certificate key.
31975 * @param {string} startTimeStamp The start time stamp string to put in the name.
31976 * @param {string} endTimeStamp The end time stamp string to put in the name.
31977 * @param {Name} keyName The key name to put in the data packet name and the
31978 * EncryptedContent key locator.
31979 * @param {Blob} privateKeyBlob A Blob of the encoded private key.
31980 * @param {Blob} certificateKey The certificate key encoding, used to encrypt
31981 * the private key.
31982 * @param {boolean} useSync (optional) If true then return a SyncPromise which
31983 * is already fulfilled. If omitted or false, this may return a SyncPromise or
31984 * an async Promise.
31985 * @return {Promise|SyncPromise} A promise that returns the Data packet, or that
31986 * is rejected with SecurityException for an error using the security KeyChain.
31987 */
31988GroupManager.prototype.createDKeyDataPromise_ = function
31989 (startTimeStamp, endTimeStamp, keyName, privateKeyBlob, certificateKey,
31990 useSync)
31991{
31992 var name = new Name(this.namespace_);
31993 name.append(Encryptor.NAME_COMPONENT_D_KEY);
31994 name.append(startTimeStamp).append(endTimeStamp);
31995 var data = new Data(name);
31996 data.getMetaInfo().setFreshnessPeriod
31997 (this.freshnessHours_ * GroupManager.MILLISECONDS_IN_HOUR);
31998 var encryptParams = new EncryptParams(EncryptAlgorithmType.RsaOaep);
31999 var thisManager = this;
32000
32001 return Encryptor.encryptDataPromise
32002 (data, privateKeyBlob, keyName, certificateKey, encryptParams, useSync)
32003 .catch(function(ex) {
32004 // Consolidate errors such as InvalidKeyException.
32005 return SyncPromise.reject(SecurityException(new Error
32006 ("createDKeyData: Error in encryptData: " + ex)));
32007 })
32008 .then(function() {
32009 return thisManager.keyChain_.signPromise(data);
32010 });
32011};
32012
32013GroupManager.MILLISECONDS_IN_HOUR = 3600 * 1000;
32014/**
32015 * Copyright (C) 2015-2016 Regents of the University of California.
32016 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
32017 * @author: From ndn-group-encrypt src/interval https://github.com/named-data/ndn-group-encrypt
32018 *
32019 * This program is free software: you can redistribute it and/or modify
32020 * it under the terms of the GNU Lesser General Public License as published by
32021 * the Free Software Foundation, either version 3 of the License, or
32022 * (at your option) any later version.
32023 *
32024 * This program is distributed in the hope that it will be useful,
32025 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32026 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32027 * GNU Lesser General Public License for more details.
32028 *
32029 * You should have received a copy of the GNU Lesser General Public License
32030 * along with this program. If not, see <http://www.gnu.org/licenses/>.
32031 * A copy of the GNU Lesser General Public License is in the file COPYING.
32032 */
32033
32034/**
32035 * An Interval defines a time duration which contains a start timestamp and an
32036 * end timestamp. Create an Interval with one of these forms:
32037 * Interval(isValid).
32038 * Interval(startTime, endTime).
32039 * Interval(interval).
32040 * @param {boolean} isValid True to create a valid empty interval, false to
32041 * create an invalid interval.
32042 * @param {number} startTime The start time as milliseconds since Jan 1, 1970 UTC.
32043 * The start time must be less than the end time. To create an empty interval
32044 * (start time equals end time), use the constructor Interval(true).
32045 * @param {number} endTime The end time as milliseconds since Jan 1, 1970 UTC.
32046 * @param {Interval} interval The other interval with values to copy.
32047 * @note This class is an experimental feature. The API may change.
32048 * @constructor
32049 */
32050var Interval = function Interval(value, endTime)
32051{
32052 if (typeof value === 'object' && value instanceof Interval) {
32053 // Make a copy.
32054 this.startTime_ = value.startTime_;
32055 this.endTime_ = value.endTime_;
32056 this.isValid_ = value.isValid_;
32057 }
32058 else if (typeof value === 'number') {
32059 var startTime = value;
32060
32061 if (!(startTime < endTime))
32062 throw new Error("Interval start time must be less than the end time");
32063
32064 this.startTime_ = startTime;
32065 this.endTime_ = endTime;
32066 this.isValid_ = true;
32067 }
32068 else {
32069 var isValid = (value ? true : false);
32070
32071 this.startTime_ = -Number.MAX_VALUE;
32072 this.endTime_ = -Number.MAX_VALUE;
32073 this.isValid_ = isValid;
32074 }
32075};
32076
32077exports.Interval = Interval;
32078
32079/**
32080 * Set this interval to have the same values as the other interval.
32081 * @param {Interval} other The other Interval with values to copy.
32082 */
32083Interval.prototype.set = function(other)
32084{
32085 this.startTime_ = other.startTime_;
32086 this.endTime_ = other.endTime_;
32087 this.isValid_ = other.isValid_;
32088};
32089
32090/**
32091 * Check if the time point is in this interval.
32092 * @param {number} timePoint The time point to check as milliseconds since
32093 * Jan 1, 1970 UTC.
32094 * @return {boolean} True if timePoint is in this interval.
32095 * @throws Error if this Interval is invalid.
32096 */
32097Interval.prototype.covers = function(timePoint)
32098{
32099 if (!this.isValid_)
32100 throw new Error("Interval.covers: This Interval is invalid");
32101
32102 if (this.isEmpty())
32103 return false;
32104 else
32105 return this.startTime_ <= timePoint && timePoint < this.endTime_;
32106};
32107
32108/**
32109 * Set this Interval to the intersection of this and the other interval.
32110 * This and the other interval should be valid but either can be empty.
32111 * @param {Interval} interval The other Interval to intersect with.
32112 * @return {Interval} This Interval.
32113 * @throws Error if this Interval or the other interval is invalid.
32114 */
32115Interval.prototype.intersectWith = function(interval)
32116{
32117 if (!this.isValid_)
32118 throw new Error("Interval.intersectWith: This Interval is invalid");
32119 if (!interval.isValid_)
32120 throw new Error("Interval.intersectWith: The other Interval is invalid");
32121
32122 if (this.isEmpty() || interval.isEmpty()) {
32123 // If either is empty, the result is empty.
32124 this.startTime_ = this.endTime_;
32125 return this;
32126 }
32127
32128 if (this.startTime_ >= interval.endTime_ || this.endTime_ <= interval.startTime_) {
32129 // The two intervals don't have an intersection, so the result is empty.
32130 this.startTime_ = this.endTime_;
32131 return this;
32132 }
32133
32134 // Get the start time.
32135 if (this.startTime_ <= interval.startTime_)
32136 this.startTime_ = interval.startTime_;
32137
32138 // Get the end time.
32139 if (this.endTime_ > interval.endTime_)
32140 this.endTime_ = interval.endTime_;
32141
32142 return this;
32143};
32144
32145/**
32146 * Set this Interval to the union of this and the other interval.
32147 * This and the other interval should be valid but either can be empty.
32148 * This and the other interval should have an intersection. (Contiguous
32149 * intervals are not allowed.)
32150 * @param {Interval} interval The other Interval to union with.
32151 * @return {Interval} This Interval.
32152 * @throws Error if this Interval or the other interval is invalid, or if the
32153 * two intervals do not have an intersection.
32154 */
32155Interval.prototype.unionWith = function(interval)
32156{
32157 if (!this.isValid_)
32158 throw new Error("Interval.intersectWith: This Interval is invalid");
32159 if (!interval.isValid_)
32160 throw new Error("Interval.intersectWith: The other Interval is invalid");
32161
32162 if (this.isEmpty()) {
32163 // This interval is empty, so use the other.
32164 this.startTime_ = interval.startTime_;
32165 this.endTime_ = interval.endTime_;
32166 return this;
32167 }
32168
32169 if (interval.isEmpty())
32170 // The other interval is empty, so keep using this one.
32171 return this;
32172
32173 if (this.startTime_ >= interval.endTime_ || this.endTime_ <= interval.startTime_)
32174 throw new Error
32175 ("Interval.unionWith: The two intervals do not have an intersection");
32176
32177 // Get the start time.
32178 if (this.startTime_ > interval.startTime_)
32179 this.startTime_ = interval.startTime_;
32180
32181 // Get the end time.
32182 if (this.endTime_ < interval.endTime_)
32183 this.endTime_ = interval.endTime_;
32184
32185 return this;
32186};
32187
32188/**
32189 * Get the start time.
32190 * @return {number} The start time as milliseconds since Jan 1, 1970 UTC.
32191 * @throws Error if this Interval is invalid.
32192 */
32193Interval.prototype.getStartTime = function()
32194{
32195 if (!this.isValid_)
32196 throw new Error("Interval.getStartTime: This Interval is invalid");
32197 return this.startTime_;
32198};
32199
32200/**
32201 * Get the end time.
32202 * @return {number} The end time as milliseconds since Jan 1, 1970 UTC.
32203 * @throws Error if this Interval is invalid.
32204 */
32205Interval.prototype.getEndTime = function()
32206{
32207 if (!this.isValid_)
32208 throw new Error("Interval.getEndTime: This Interval is invalid");
32209 return this.endTime_;
32210};
32211
32212/**
32213 * Check if this Interval is valid.
32214 * @return {boolean} True if this interval is valid, false if invalid.
32215 */
32216Interval.prototype.isValid = function() { return this.isValid_; };
32217
32218/**
32219 * Check if this Interval is empty.
32220 * @return {boolean} True if this Interval is empty (start time equals end time),
32221 * false if not.
32222 * @throws Error if this Interval is invalid.
32223 */
32224Interval.prototype.isEmpty = function()
32225{
32226 if (!this.isValid_)
32227 throw new Error("Interval.isEmpty: This Interval is invalid");
32228 return this.startTime_ == this.endTime_;
32229};
32230/**
32231 * Copyright (C) 2015-2016 Regents of the University of California.
32232 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
32233 * @author: From ndn-group-encrypt src/producer-db https://github.com/named-data/ndn-group-encrypt
32234 *
32235 * This program is free software: you can redistribute it and/or modify
32236 * it under the terms of the GNU Lesser General Public License as published by
32237 * the Free Software Foundation, either version 3 of the License, or
32238 * (at your option) any later version.
32239 *
32240 * This program is distributed in the hope that it will be useful,
32241 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32242 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32243 * GNU Lesser General Public License for more details.
32244 *
32245 * You should have received a copy of the GNU Lesser General Public License
32246 * along with this program. If not, see <http://www.gnu.org/licenses/>.
32247 * A copy of the GNU Lesser General Public License is in the file COPYING.
32248 */
32249
32250/** @ignore */
32251var SyncPromise = require('../util/sync-promise.js').SyncPromise;
32252
32253/**
32254 * ProducerDb is a base class for the storage of keys for the producer. It contains
32255 * one table that maps time slots (to the nearest hour) to the content key
32256 * created for that time slot. A subclass must implement the methods. For
32257 * example, see Sqlite3ProducerDb (for Nodejs) or IndexedDbProducerDb (for the
32258 * browser).
32259 * @note This class is an experimental feature. The API may change.
32260 * @constructor
32261 */
32262var ProducerDb = function ProducerDb()
32263{
32264};
32265
32266exports.ProducerDb = ProducerDb;
32267
32268/**
32269 * Create a new ProducerDb.Error to report an error using ProducerDb
32270 * methods, wrapping the given error object.
32271 * Call with: throw new ProducerDb.Error(new Error("message")).
32272 * @constructor
32273 * @param {Error} error The exception created with new Error.
32274 */
32275ProducerDb.Error = function ProducerDbError(error)
32276{
32277 if (error) {
32278 error.__proto__ = ProducerDb.Error.prototype;
32279 return error;
32280 }
32281}
32282
32283ProducerDb.Error.prototype = new Error();
32284ProducerDb.Error.prototype.name = "ProducerDbError";
32285
32286/**
32287 * Check if a content key exists for the hour covering timeSlot.
32288 * @param {number} timeSlot The time slot as milliseconds since Jan 1, 1970 UTC.
32289 * @param {boolean} useSync (optional) If true then return a SyncPromise which
32290 * is already fulfilled. If omitted or false, this may return a SyncPromise or
32291 * an async Promise.
32292 * @return {Promise|SyncPromise} A promise that returns true if there is a
32293 * content key for timeSlot (else false), or that is rejected with
32294 * ProducerDb.Error for a database error.
32295 */
32296ProducerDb.prototype.hasContentKeyPromise = function(timeSlot, useSync)
32297{
32298 return SyncPromise.reject(new Error
32299 ("ProducerDb.hasContentKeyPromise is not implemented"));
32300};
32301
32302/**
32303 * Get the content key for the hour covering timeSlot.
32304 * @param {number} timeSlot The time slot as milliseconds since Jan 1, 1970 UTC.
32305 * @param {boolean} useSync (optional) If true then return a SyncPromise which
32306 * is already fulfilled. If omitted or false, this may return a SyncPromise or
32307 * an async Promise.
32308 * @return {Promise|SyncPromise} A promise that returns a Blob with the encoded
32309 * key, or that is rejected with ProducerDb.Error if there is no key covering
32310 * timeSlot, or other database error
32311 */
32312ProducerDb.prototype.getContentKeyPromise = function(timeSlot, useSync)
32313{
32314 return SyncPromise.reject(new Error
32315 ("ProducerDb.getContentKeyPromise is not implemented"));
32316};
32317
32318/**
32319 * Add key as the content key for the hour covering timeSlot.
32320 * @param {number} timeSlot The time slot as milliseconds since Jan 1, 1970 UTC.
32321 * @param {Blob} key The encoded key.
32322 * @param {boolean} useSync (optional) If true then return a SyncPromise which
32323 * is already fulfilled. If omitted or false, this may return a SyncPromise or
32324 * an async Promise.
32325 * @return {Promise|SyncPromise} A promise that fulfills when the key is added,
32326 * or that is rejected with ProducerDb.Error if a key for the same hour already
32327 * exists in the database, or other database error.
32328 */
32329ProducerDb.prototype.addContentKeyPromise = function
32330 (timeSlot, key, useSync)
32331{
32332 return SyncPromise.reject(new Error
32333 ("ProducerDb.addContentKeyPromise is not implemented"));
32334};
32335
32336/**
32337 * Delete the content key for the hour covering timeSlot. If there is no key for
32338 * the time slot, do nothing.
32339 * @param {number} timeSlot The time slot as milliseconds since Jan 1, 1970 UTC.
32340 * @param {boolean} useSync (optional) If true then return a SyncPromise which
32341 * is already fulfilled. If omitted or false, this may return a SyncPromise or
32342 * an async Promise.
32343 * @return {Promise|SyncPromise} A promise that fulfills when the key is deleted
32344 * (or there is no such key), or that is rejected with ProducerDb.Error for a
32345 * database error.
32346 */
32347ProducerDb.prototype.deleteContentKeyPromise = function(timeSlot, useSync)
32348{
32349 return SyncPromise.reject(new Error
32350 ("ProducerDb.deleteContentKeyPromise is not implemented"));
32351};
32352
32353/**
32354 * Get the hour-based time slot.
32355 * @param {number} timeSlot The time slot as milliseconds since Jan 1, 1970 UTC.
32356 * @return {number} The hour-based time slot as hours since Jan 1, 1970 UTC.
32357 */
32358ProducerDb.getFixedTimeSlot = function(timeSlot)
32359{
32360 return Math.floor(Math.round(timeSlot) / 3600000.0);
32361};
32362/**
32363 * Copyright (C) 2015-2016 Regents of the University of California.
32364 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
32365 * @author: From ndn-group-encrypt src/producer https://github.com/named-data/ndn-group-encrypt
32366 *
32367 * This program is free software: you can redistribute it and/or modify
32368 * it under the terms of the GNU Lesser General Public License as published by
32369 * the Free Software Foundation, either version 3 of the License, or
32370 * (at your option) any later version.
32371 *
32372 * This program is distributed in the hope that it will be useful,
32373 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32374 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32375 * GNU Lesser General Public License for more details.
32376 *
32377 * You should have received a copy of the GNU Lesser General Public License
32378 * along with this program. If not, see <http://www.gnu.org/licenses/>.
32379 * A copy of the GNU Lesser General Public License is in the file COPYING.
32380 */
32381
32382/** @ignore */
32383var Name = require('../name.js').Name; /** @ignore */
32384var Interest = require('../interest.js').Interest; /** @ignore */
32385var Data = require('../data.js').Data; /** @ignore */
32386var Link = require('../link.js').Link; /** @ignore */
32387var NetworkNack = require('../network-nack.js').NetworkNack; /** @ignore */
32388var Exclude = require('../exclude.js').Exclude; /** @ignore */
32389var Encryptor = require('./algo/encryptor.js').Encryptor; /** @ignore */
32390var EncryptParams = require('./algo/encrypt-params.js').EncryptParams; /** @ignore */
32391var EncryptAlgorithmType = require('./algo/encrypt-params.js').EncryptAlgorithmType; /** @ignore */
32392var AesKeyParams = require('../security/key-params.js').AesKeyParams; /** @ignore */
32393var AesAlgorithm = require('./algo/aes-algorithm.js').AesAlgorithm; /** @ignore */
32394var Schedule = require('./schedule.js').Schedule; /** @ignore */
32395var EncryptError = require('./encrypt-error.js').EncryptError; /** @ignore */
32396var NdnCommon = require('../util/ndn-common.js').NdnCommon; /** @ignore */
32397var SyncPromise = require('../util/sync-promise.js').SyncPromise;
32398
32399/**
32400 * A Producer manages content keys used to encrypt a data packet in the
32401 * group-based encryption protocol.
32402 * Create a Producer to use the given ProducerDb, Face and other values.
32403 *
32404 * A producer can produce data with a naming convention:
32405 * /<prefix>/SAMPLE/<dataType>/[timestamp]
32406 *
32407 * The produced data packet is encrypted with a content key,
32408 * which is stored in the ProducerDb database.
32409 *
32410 * A producer also needs to produce data containing a content key
32411 * encrypted with E-KEYs. A producer can retrieve E-KEYs through the face,
32412 * and will re-try for at most repeatAttemps times when E-KEY retrieval fails.
32413 *
32414 * @param {Name} prefix The producer name prefix. This makes a copy of the Name.
32415 * @param {Name} dataType The dataType portion of the producer name. This makes
32416 * a copy of the Name.
32417 * @param {Face} face The face used to retrieve keys.
32418 * @param {KeyChain} keyChain The keyChain used to sign data packets.
32419 * @param {ProducerDb} database The ProducerDb database for storing keys.
32420 * @param {number} repeatAttempts (optional) The maximum retry for retrieving
32421 * keys. If omitted, use a default value of 3.
32422 * @param {Link} keyRetrievalLink (optional) The Link object to use in Interests
32423 * for key retrieval. This makes a copy of the Link object. If the Link object's
32424 * getDelegations().size() is zero, don't use it. If omitted, don't use a Link
32425 * object.
32426 * @note This class is an experimental feature. The API may change.
32427 * @constructor
32428 */
32429var Producer = function Producer
32430 (prefix, dataType, face, keyChain, database, repeatAttempts, keyRetrievalLink)
32431{
32432 this.face_ = face;
32433 this.keyChain_ = keyChain;
32434 this.database_ = database;
32435 this.maxRepeatAttempts_ = (repeatAttempts == undefined ? 3 : repeatAttempts);
32436 this.keyRetrievalLink_ =
32437 (keyRetrievalLink == undefined ? Producer.NO_LINK : new Link(keyRetrievalLink));
32438
32439 // The map key is the key name URI string. The value is an object with fields
32440 // "keyName" and "keyInfo" where "keyName" is the same Name used for the key
32441 // name URI string, and "keyInfo" is the Producer.KeyInfo_.
32442 // (Use a string because we can't use the Name object as the key in JavaScript.)
32443 // (Also put the original Name in the value because we need to iterate over
32444 // eKeyInfo_ and we don't want to rebuild the Name from the name URI string.)
32445 this.eKeyInfo_ = {};
32446 // The map key is the time stamp. The value is a Producer.KeyRequest_.
32447 this.keyRequests_ = {};
32448
32449 var fixedPrefix = new Name(prefix);
32450 var fixedDataType = new Name(dataType);
32451
32452 // Fill ekeyInfo_ with all permutations of dataType, including the 'E-KEY'
32453 // component of the name. This will be used in createContentKey to send
32454 // interests without reconstructing names every time.
32455 fixedPrefix.append(Encryptor.NAME_COMPONENT_READ);
32456 while (fixedDataType.size() > 0) {
32457 var nodeName = new Name(fixedPrefix);
32458 nodeName.append(fixedDataType);
32459 nodeName.append(Encryptor.NAME_COMPONENT_E_KEY);
32460
32461 this.eKeyInfo_[nodeName.toUri()] =
32462 { keyName: nodeName, keyInfo: new Producer.KeyInfo_() };
32463 fixedDataType = fixedDataType.getPrefix(-1);
32464 }
32465 fixedPrefix.append(dataType);
32466 this.namespace_ = new Name(prefix);
32467 this.namespace_.append(Encryptor.NAME_COMPONENT_SAMPLE);
32468 this.namespace_.append(dataType);
32469};
32470
32471exports.Producer = Producer;
32472
32473/**
32474 * Create the content key corresponding to the timeSlot. This first checks if
32475 * the content key exists. For an existing content key, this returns the
32476 * content key name directly. If the key does not exist, this creates one and
32477 * encrypts it using the corresponding E-KEYs. The encrypted content keys are
32478 * passed to the onEncryptedKeys callback.
32479 * @param {number} timeSlot The time slot as milliseconds since Jan 1, 1970 UTC.
32480 * @param {function} onEncryptedKeys If this creates a content key, then this
32481 * calls onEncryptedKeys(keys) where keys is a list of encrypted content key
32482 * Data packets. If onEncryptedKeys is null, this does not use it.
32483 * NOTE: The library will log any exceptions thrown by this callback, but for
32484 * better error handling the callback should catch and properly handle any
32485 * exceptions.
32486 * @param {function} onContentKeyName This calls onContentKeyName(contentKeyName)
32487 * with the content key name for the time slot. If onContentKeyName is null,
32488 * this does not use it. (A callback is needed because of async database
32489 * operations.)
32490 * NOTE: The library will log any exceptions thrown by this callback, but for
32491 * better error handling the callback should catch and properly handle any
32492 * exceptions.
32493 * @param {function} onError (optional) This calls onError(errorCode, message)
32494 * for an error, where errorCode is from EncryptError.ErrorCode and message is a
32495 * string. If omitted, use a default callback which does nothing.
32496 * NOTE: The library will log any exceptions thrown by this callback, but for
32497 * better error handling the callback should catch and properly handle any
32498 * exceptions.
32499 */
32500Producer.prototype.createContentKey = function
32501 (timeSlot, onEncryptedKeys, onContentKeyName, onError)
32502{
32503 if (!onError)
32504 onError = Producer.defaultOnError;
32505
32506 var hourSlot = Producer.getRoundedTimeSlot_(timeSlot);
32507
32508 // Create the content key name.
32509 var contentKeyName = new Name(this.namespace_);
32510 contentKeyName.append(Encryptor.NAME_COMPONENT_C_KEY);
32511 contentKeyName.append(Schedule.toIsoString(hourSlot));
32512
32513 var contentKeyBits;
32514 var thisProducer = this;
32515
32516 // Check if we have created the content key before.
32517 this.database_.hasContentKeyPromise(timeSlot)
32518 .then(function(exists) {
32519 if (exists) {
32520 if (onContentKeyName != null)
32521 onContentKeyName(contentKeyName);
32522 return;
32523 }
32524
32525 // We haven't created the content key. Create one and add it into the database.
32526 var aesParams = new AesKeyParams(128);
32527 contentKeyBits = AesAlgorithm.generateKey(aesParams).getKeyBits();
32528 thisProducer.database_.addContentKeyPromise(timeSlot, contentKeyBits)
32529 .then(function() {
32530 // Now we need to retrieve the E-KEYs for content key encryption.
32531 var timeCount = Math.round(timeSlot);
32532 thisProducer.keyRequests_[timeCount] =
32533 new Producer.KeyRequest_(thisProducer.getEKeyInfoSize_());
32534 var keyRequest = thisProducer.keyRequests_[timeCount];
32535
32536 // Check if the current E-KEYs can cover the content key.
32537 var timeRange = new Exclude();
32538 Producer.excludeAfter
32539 (timeRange, new Name.Component(Schedule.toIsoString(timeSlot)));
32540 for (var keyNameUri in thisProducer.eKeyInfo_) {
32541 // For each current E-KEY.
32542 var entry = thisProducer.eKeyInfo_[keyNameUri];
32543 var keyInfo = entry.keyInfo;
32544 if (timeSlot < keyInfo.beginTimeSlot || timeSlot >= keyInfo.endTimeSlot) {
32545 // The current E-KEY cannot cover the content key, so retrieve one.
32546 keyRequest.repeatAttempts[keyNameUri] = 0;
32547 thisProducer.sendKeyInterest_
32548 (new Interest(entry.keyName).setExclude(timeRange).setChildSelector(1),
32549 timeSlot, onEncryptedKeys, onError);
32550 }
32551 else {
32552 // The current E-KEY can cover the content key.
32553 // Encrypt the content key directly.
32554 var eKeyName = new Name(entry.keyName);
32555 eKeyName.append(Schedule.toIsoString(keyInfo.beginTimeSlot));
32556 eKeyName.append(Schedule.toIsoString(keyInfo.endTimeSlot));
32557 thisProducer.encryptContentKeyPromise_
32558 (keyInfo.keyBits, eKeyName, timeSlot, onEncryptedKeys, onError);
32559 }
32560 }
32561
32562 if (onContentKeyName != null)
32563 onContentKeyName(contentKeyName);
32564 });
32565 });
32566};
32567
32568/**
32569 * Encrypt the given content with the content key that covers timeSlot, and
32570 * update the data packet with the encrypted content and an appropriate data
32571 * name.
32572 * @param {Data} data An empty Data object which is updated.
32573 * @param {number} timeSlot The time slot as milliseconds since Jan 1, 1970 UTC.
32574 * @param {Blob} content The content to encrypt.
32575 * @param {function} onComplete This calls onComplete() when the data packet has
32576 * been updated.
32577 * NOTE: The library will log any exceptions thrown by this callback, but for
32578 * better error handling the callback should catch and properly handle any
32579 * exceptions.
32580 * @param {function} onError (optional) This calls onError(errorCode, message)
32581 * for an error, where errorCode is from EncryptError.ErrorCode and message is a
32582 * string. If omitted, use a default callback which does nothing.
32583 * NOTE: The library will log any exceptions thrown by this callback, but for
32584 * better error handling the callback should catch and properly handle any
32585 * exceptions.
32586 */
32587Producer.prototype.produce = function
32588 (data, timeSlot, content, onComplete, onError)
32589{
32590 if (!onError)
32591 onError = Producer.defaultOnError;
32592
32593 var thisProducer = this;
32594
32595 // Get a content key.
32596 this.createContentKey(timeSlot, null, function(contentKeyName) {
32597 thisProducer.database_.getContentKeyPromise(timeSlot)
32598 .then(function(contentKey) {
32599 // Produce data.
32600 var dataName = new Name(thisProducer.namespace_);
32601 dataName.append(Schedule.toIsoString(timeSlot));
32602
32603 data.setName(dataName);
32604 var params = new EncryptParams(EncryptAlgorithmType.AesCbc, 16);
32605 return Encryptor.encryptData
32606 (data, content, contentKeyName, contentKey, params);
32607 })
32608 .then(function() {
32609 return thisProducer.keyChain_.signPromise(data);
32610 })
32611 .then(function() {
32612 try {
32613 onComplete();
32614 } catch (ex) {
32615 console.log("Error in onComplete: " + NdnCommon.getErrorWithStackTrace(ex));
32616 }
32617 }, function(error) {
32618 try {
32619 onError(EncryptError.ErrorCode.General, "" + error);
32620 } catch (ex) {
32621 console.log("Error in onError: " + NdnCommon.getErrorWithStackTrace(ex));
32622 }
32623 });
32624 }, onError);
32625};
32626
32627/**
32628 * The default onError callback which does nothing.
32629 */
32630Producer.defaultOnError = function(errorCode, message)
32631{
32632 // Do nothing.
32633};
32634
32635Producer.KeyInfo_ = function ProducerKeyInfo()
32636{
32637 this.beginTimeSlot = 0.0;
32638 this.endTimeSlot = 0.0;
32639 this.keyBits = null; // Blob
32640};
32641
32642Producer.KeyRequest_ = function ProducerKeyRequest(interests)
32643{
32644 this.interestCount = interests; // number
32645 // The map key is the name URI string. The value is an int count.
32646 // (Use a string because we can't use the Name object as the key in JavaScript.)
32647 this.repeatAttempts = {};
32648 this.encryptedKeys = []; // of Data
32649};
32650
32651/**
32652 * Round timeSlot to the nearest whole hour, so that we can store content keys
32653 * uniformly (by start of the hour).
32654 * @param {number} timeSlot The time slot as milliseconds since Jan 1, 1970 UTC.
32655 * @return {number} The start of the hour as milliseconds since Jan 1, 1970 UTC.
32656 */
32657Producer.getRoundedTimeSlot_ = function(timeSlot)
32658{
32659 return Math.round(Math.floor(Math.round(timeSlot) / 3600000.0) * 3600000.0);
32660}
32661
32662/**
32663 * Send an interest with the given name through the face with callbacks to
32664 * handleCoveringKey_, handleTimeout_ and handleNetworkNack_.
32665 * @param {Interest} interest The interest to send.
32666 * @param {number} timeSlot The time slot, passed to handleCoveringKey_,
32667 * handleTimeout_ and handleNetworkNack_.
32668 * @param {function} onEncryptedKeys The OnEncryptedKeys callback, passed to
32669 * handleCoveringKey_, handleTimeout_ and handleNetworkNack_.
32670 * @param {function} onError This calls onError(errorCode, message) for an error.
32671 */
32672Producer.prototype.sendKeyInterest_ = function
32673 (interest, timeSlot, onEncryptedKeys, onError)
32674{
32675 var thisProducer = this;
32676
32677 function onKey(interest, data) {
32678 thisProducer.handleCoveringKey_
32679 (interest, data, timeSlot, onEncryptedKeys, onError);
32680 }
32681
32682 function onTimeout(interest) {
32683 thisProducer.handleTimeout_(interest, timeSlot, onEncryptedKeys, onError);
32684 }
32685
32686 function onNetworkNack(interest, networkNack) {
32687 thisProducer.handleNetworkNack_
32688 (interest, networkNack, timeSlot, onEncryptedKeys, onError);
32689 }
32690
32691 var request;
32692 if (this.keyRetrievalLink_.getDelegations().size() === 0)
32693 // We can use the supplied interest without copying.
32694 request = interest;
32695 else {
32696 // Copy the supplied interest and add the Link.
32697 request = new Interest(interest);
32698 // This will use a cached encoding if available.
32699 request.setLinkWireEncoding(this.keyRetrievalLink_.wireEncode());
32700 }
32701
32702 this.face_.expressInterest(request, onKey, onTimeout, onNetworkNack);
32703};
32704
32705/**
32706 * This is called from an expressInterest timeout to update the state of
32707 * keyRequest. Re-express the interest if the number of retrials is less than
32708 * the max limit.
32709 * @param {Interest} interest The timed-out interest.
32710 * @param {number} timeSlot The time slot as milliseconds since Jan 1, 1970 UTC.
32711 * @param {function} onEncryptedKeys When there are no more interests to process,
32712 * this calls onEncryptedKeys(keys) where keys is a list of encrypted content
32713 * key Data packets. If onEncryptedKeys is null, this does not use it.
32714 * @param {function} onError This calls onError(errorCode, message) for an error.
32715 */
32716Producer.prototype.handleTimeout_ = function
32717 (interest, timeSlot, onEncryptedKeys, onError)
32718{
32719 var timeCount = Math.round(timeSlot);
32720 var keyRequest = this.keyRequests_[timeCount];
32721
32722 var interestName = interest.getName();
32723 var interestNameUri = interestName.toUri();
32724
32725 if (keyRequest.repeatAttempts[interestNameUri] < this.maxRepeatAttempts_) {
32726 // Increase the retrial count.
32727 ++keyRequest.repeatAttempts[interestNameUri];
32728 this.sendKeyInterest_(interest, timeSlot, onEncryptedKeys, onError);
32729 }
32730 else
32731 // Treat an eventual timeout as a network Nack.
32732 this.handleNetworkNack_
32733 (interest, new NetworkNack(), timeSlot, onEncryptedKeys, onError);
32734};
32735
32736/**
32737 * This is called from an expressInterest OnNetworkNack to handle a network
32738 * Nack for the E-KEY requested through the Interest. Decrease the outstanding
32739 * E-KEY interest count for the C-KEY corresponding to the timeSlot.
32740 * @param {Interest} interest The interest given to expressInterest.
32741 * @param {NetworkNack} networkNack The returned NetworkNack (unused).
32742 * @param {number} timeSlot The time slot as milliseconds since Jan 1, 1970 UTC.
32743 * @param {function} onEncryptedKeys When there are no more interests to process,
32744 * this calls onEncryptedKeys(keys) where keys is a list of encrypted content
32745 * key Data packets. If onEncryptedKeys is null, this does not use it.
32746 */
32747Producer.prototype.handleNetworkNack_ = function
32748 (interest, networkNack, timeSlot, onEncryptedKeys, onError)
32749{
32750 // We have run out of options....
32751 var timeCount = Math.round(timeSlot);
32752 this.updateKeyRequest_
32753 (this.keyRequests_[timeCount], timeCount, onEncryptedKeys);
32754};
32755
32756/**
32757 * Decrease the count of outstanding E-KEY interests for the C-KEY for
32758 * timeCount. If the count decreases to 0, invoke onEncryptedKeys.
32759 * @param {Producer.KeyRequest_} keyRequest The KeyRequest with the
32760 * interestCount to update.
32761 * @param {number} timeCount The time count for indexing keyRequests_.
32762 * @param {function} onEncryptedKeys When there are no more interests to
32763 * process, this calls onEncryptedKeys(keys) where keys is a list of encrypted
32764 * content key Data packets. If onEncryptedKeys is null, this does not use it.
32765 */
32766Producer.prototype.updateKeyRequest_ = function
32767 (keyRequest, timeCount, onEncryptedKeys)
32768{
32769 --keyRequest.interestCount;
32770 if (keyRequest.interestCount == 0 && onEncryptedKeys != null) {
32771 try {
32772 onEncryptedKeys(keyRequest.encryptedKeys);
32773 } catch (ex) {
32774 console.log("Error in onEncryptedKeys: " + NdnCommon.getErrorWithStackTrace(ex));
32775 }
32776 delete this.keyRequests_[timeCount];
32777 }
32778};
32779
32780/**
32781 * This is called from an expressInterest OnData to check that the encryption
32782 * key contained in data fits the timeSlot. This sends a refined interest if
32783 * required.
32784 * @param {Interest} interest The interest given to expressInterest.
32785 * @param {Data} data The fetched Data packet.
32786 * @param {number} timeSlot The time slot as milliseconds since Jan 1, 1970 UTC.
32787 * @param {function} onEncryptedKeys When there are no more interests to process,
32788 * this calls onEncryptedKeys(keys) where keys is a list of encrypted content
32789 * key Data packets. If onEncryptedKeys is null, this does not use it.
32790 * @param {function} onError This calls onError(errorCode, message) for an error.
32791 */
32792Producer.prototype.handleCoveringKey_ = function
32793 (interest, data, timeSlot, onEncryptedKeys, onError)
32794{
32795 var timeCount = Math.round(timeSlot);
32796 var keyRequest = this.keyRequests_[timeCount];
32797
32798 var interestName = interest.getName();
32799 var interestNameUrl = interestName.toUri();
32800 var keyName = data.getName();
32801
32802 var begin = Schedule.fromIsoString
32803 (keyName.get(Producer.START_TIME_STAMP_INDEX).getValue().toString());
32804 var end = Schedule.fromIsoString
32805 (keyName.get(Producer.END_TIME_STAMP_INDEX).getValue().toString());
32806
32807 if (timeSlot >= end) {
32808 // If the received E-KEY covers some earlier period, try to retrieve an
32809 // E-KEY covering a later one.
32810 var timeRange = new Exclude(interest.getExclude());
32811 Producer.excludeBefore(timeRange, keyName.get(Producer.START_TIME_STAMP_INDEX));
32812 keyRequest.repeatAttempts[interestNameUrl] = 0;
32813 this.sendKeyInterest_
32814 (new Interest(interestName).setExclude(timeRange).setChildSelector(1),
32815 timeSlot, onEncryptedKeys, onError);
32816 }
32817 else {
32818 // If the received E-KEY covers the content key, encrypt the content.
32819 var encryptionKey = data.getContent();
32820 var thisProducer = this;
32821 this.encryptContentKeyPromise_
32822 (encryptionKey, keyName, timeSlot, onEncryptedKeys, onError)
32823 .then(function(success) {
32824 if (success) {
32825 var keyInfo = thisProducer.eKeyInfo_[interestNameUrl].keyInfo;
32826 keyInfo.beginTimeSlot = begin;
32827 keyInfo.endTimeSlot = end;
32828 keyInfo.keyBits = encryptionKey;
32829 }
32830 });
32831 }
32832};
32833
32834/**
32835 * Get the content key from the database_ and encrypt it for the timeSlot
32836 * using encryptionKey.
32837 * @param {Blob} encryptionKey The encryption key value.
32838 * @param {Name} eKeyName The key name for the EncryptedContent.
32839 * @param {number} timeSlot The time slot as milliseconds since Jan 1, 1970 UTC.
32840 * @param {function} onEncryptedKeys When there are no more interests to process,
32841 * this calls onEncryptedKeys(keys) where keys is a list of encrypted content
32842 * key Data packets. If onEncryptedKeys is null, this does not use it.
32843 * @param {function} onError This calls onError(errorCode, message) for an error.
32844 * @return {Promise} A promise that returns true if encryption succeeds,
32845 * otherwise false.
32846 */
32847Producer.prototype.encryptContentKeyPromise_ = function
32848 (encryptionKey, eKeyName, timeSlot, onEncryptedKeys, onError)
32849{
32850 var timeCount = Math.round(timeSlot);
32851 var keyRequest = this.keyRequests_[timeCount];
32852
32853 var keyName = new Name(this.namespace_);
32854 keyName.append(Encryptor.NAME_COMPONENT_C_KEY);
32855 keyName.append(Schedule.toIsoString(Producer.getRoundedTimeSlot_(timeSlot)));
32856
32857 var cKeyData;
32858 var thisProducer = this;
32859
32860 return this.database_.getContentKeyPromise(timeSlot)
32861 .then(function(contentKey) {
32862 cKeyData = new Data();
32863 cKeyData.setName(keyName);
32864 var params = new EncryptParams(EncryptAlgorithmType.RsaOaep);
32865 return Encryptor.encryptDataPromise
32866 (cKeyData, contentKey, eKeyName, encryptionKey, params);
32867 })
32868 .then(function() {
32869 return SyncPromise.resolve(true);
32870 }, function(error) {
32871 try {
32872 onError(EncryptError.ErrorCode.EncryptionFailure,
32873 "encryptData failed: " + error);
32874 } catch (ex) {
32875 console.log("Error in onError: " + NdnCommon.getErrorWithStackTrace(ex));
32876 }
32877 return SyncPromise.resolve(false);
32878 })
32879 .then(function(success) {
32880 if (success) {
32881 return thisProducer.keyChain_.signPromise(cKeyData)
32882 .then(function() {
32883 keyRequest.encryptedKeys.push(cKeyData);
32884 thisProducer.updateKeyRequest_(keyRequest, timeCount, onEncryptedKeys);
32885 return SyncPromise.resolve(true);
32886 });
32887 }
32888 else
32889 return SyncPromise.resolve(false);
32890 });
32891};
32892
32893Producer.prototype.getEKeyInfoSize_ = function()
32894{
32895 // Note: This is really a method to find the key count in any object, but we
32896 // don't want to claim that it is a tested and general utility method.
32897 var size = 0;
32898 for (key in this.eKeyInfo_) {
32899 if (this.eKeyInfo_.hasOwnProperty(key))
32900 ++size;
32901 }
32902
32903 return size;
32904};
32905
32906// TODO: Move this to be the main representation inside the Exclude object.
32907/**
32908 * Create a new ExcludeEntry.
32909 * @param {Name.Component} component
32910 * @param {boolean} anyFollowsComponent
32911 */
32912Producer.ExcludeEntry = function ExcludeEntry(component, anyFollowsComponent)
32913{
32914 this.component_ = component;
32915 this.anyFollowsComponent_ = anyFollowsComponent;
32916};
32917
32918/**
32919 * Create a list of ExcludeEntry from the Exclude object.
32920 * @param {Exclude} exclude The Exclude object to read.
32921 * @return {Array<ExcludeEntry>} A new array of ExcludeEntry.
32922 */
32923Producer.getExcludeEntries = function(exclude)
32924{
32925 var entries = [];
32926
32927 for (var i = 0; i < exclude.size(); ++i) {
32928 if (exclude.get(i) == Exclude.ANY) {
32929 if (entries.length == 0)
32930 // Add a "beginning ANY".
32931 entries.push(new Producer.ExcludeEntry(new Name.Component(), true));
32932 else
32933 // Set anyFollowsComponent of the final component.
32934 entries[entries.length - 1].anyFollowsComponent_ = true;
32935 }
32936 else
32937 entries.push(new Producer.ExcludeEntry(exclude.get(i), false));
32938 }
32939
32940 return entries;
32941};
32942
32943/**
32944 * Set the Exclude object from the array of ExcludeEntry.
32945 * @param {Exclude} exclude The Exclude object to update.
32946 * @param {Array<ExcludeEntry>} entries The array of ExcludeEntry.
32947 */
32948Producer.setExcludeEntries = function(exclude, entries)
32949{
32950 exclude.clear();
32951
32952 for (var i = 0; i < entries.length; ++i) {
32953 var entry = entries[i];
32954
32955 if (i == 0 && entry.component_.getValue().size() == 0 &&
32956 entry.anyFollowsComponent_)
32957 // This is a "beginning ANY".
32958 exclude.appendAny();
32959 else {
32960 exclude.appendComponent(entry.component_);
32961 if (entry.anyFollowsComponent_)
32962 exclude.appendAny();
32963 }
32964 }
32965};
32966
32967/**
32968 * Get the latest entry in the array whose component_ is less than or equal to
32969 * component.
32970 * @param {Array<ExcludeEntry>} entries The array of ExcludeEntry.
32971 * @param {Name.Component} component The component to compare.
32972 * @return {number} The index of the found entry, or -1 if not found.
32973 */
32974Producer.findEntryBeforeOrAt = function(entries, component)
32975{
32976 var i = entries.length - 1;
32977 while (i >= 0) {
32978 if (entries[i].component_.compare(component) <= 0)
32979 break;
32980 --i;
32981 }
32982
32983 return i;
32984};
32985
32986/**
32987 * Exclude all components in the range beginning at "from".
32988 * @param {Exclude} exclude The Exclude object to update.
32989 * @param {Name.Component} from The first component in the exclude range.
32990 */
32991Producer.excludeAfter = function(exclude, from)
32992{
32993 var entries = Producer.getExcludeEntries(exclude);
32994
32995 var iNewFrom;
32996 var iFoundFrom = Producer.findEntryBeforeOrAt(entries, from);
32997 if (iFoundFrom < 0) {
32998 // There is no entry before "from" so insert at the beginning.
32999 entries.splice(0, 0, new Producer.ExcludeEntry(from, true));
33000 iNewFrom = 0;
33001 }
33002 else {
33003 var foundFrom = entries[iFoundFrom];
33004
33005 if (!foundFrom.anyFollowsComponent_) {
33006 if (foundFrom.component_.equals(from)) {
33007 // There is already an entry with "from", so just set the "ANY" flag.
33008 foundFrom.anyFollowsComponent_ = true;
33009 iNewFrom = iFoundFrom;
33010 }
33011 else {
33012 // Insert following the entry before "from".
33013 entries.splice(iFoundFrom + 1, 0, new Producer.ExcludeEntry(from, true));
33014 iNewFrom = iFoundFrom + 1;
33015 }
33016 }
33017 else
33018 // The entry before "from" already has an "ANY" flag, so do nothing.
33019 iNewFrom = iFoundFrom;
33020 }
33021
33022 // Remove intermediate entries since they are inside the range.
33023 var iRemoveBegin = iNewFrom + 1;
33024 var nRemoveNeeded = entries.length - iRemoveBegin;
33025 entries.splice(iRemoveBegin, nRemoveNeeded);
33026
33027 Producer.setExcludeEntries(exclude, entries);
33028};
33029
33030/**
33031 * Exclude all components in the range ending at "to".
33032 * @param {Exclude} exclude The Exclude object to update.
33033 * @param {Name.Component} to The last component in the exclude range.
33034 */
33035Producer.excludeBefore = function(exclude, to)
33036{
33037 Producer.excludeRange(exclude, new Name.Component(), to);
33038};
33039
33040/**
33041 * Exclude all components in the range beginning at "from" and ending at "to".
33042 * @param {Exclude} exclude The Exclude object to update.
33043 * @param {Name.Component} from The first component in the exclude range.
33044 * @param {Name.Component} to The last component in the exclude range.
33045 */
33046Producer.excludeRange = function(exclude, from, to)
33047{
33048 if (from.compare(to) >= 0) {
33049 if (from.compare(to) == 0)
33050 throw new Error
33051 ("excludeRange: from == to. To exclude a single component, sue excludeOne.");
33052 else
33053 throw new Error
33054 ("excludeRange: from must be less than to. Invalid range: [" +
33055 from.toEscapedString() + ", " + to.toEscapedString() + "]");
33056 }
33057
33058 var entries = Producer.getExcludeEntries(exclude);
33059
33060 var iNewFrom;
33061 var iFoundFrom = Producer.findEntryBeforeOrAt(entries, from);
33062 if (iFoundFrom < 0) {
33063 // There is no entry before "from" so insert at the beginning.
33064 entries.splice(0, 0, new Producer.ExcludeEntry(from, true));
33065 iNewFrom = 0;
33066 }
33067 else {
33068 var foundFrom = entries[iFoundFrom];
33069
33070 if (!foundFrom.anyFollowsComponent_) {
33071 if (foundFrom.component_.equals(from)) {
33072 // There is already an entry with "from", so just set the "ANY" flag.
33073 foundFrom.anyFollowsComponent_ = true;
33074 iNewFrom = iFoundFrom;
33075 }
33076 else {
33077 // Insert following the entry before "from".
33078 entries.splice(iFoundFrom + 1, 0, new Producer.ExcludeEntry(from, true));
33079 iNewFrom = iFoundFrom + 1;
33080 }
33081 }
33082 else
33083 // The entry before "from" already has an "ANY" flag, so do nothing.
33084 iNewFrom = iFoundFrom;
33085 }
33086
33087 // We have at least one "from" before "to", so we know this will find an entry.
33088 var iFoundTo = Producer.findEntryBeforeOrAt(entries, to);
33089 var foundTo = entries[iFoundTo];
33090 if (iFoundTo == iNewFrom)
33091 // Insert the "to" immediately after the "from".
33092 entries.splice(iNewFrom + 1, 0, new Producer.ExcludeEntry(to, false));
33093 else {
33094 var iRemoveEnd;
33095 if (!foundTo.anyFollowsComponent_) {
33096 if (foundTo.component_.equals(to))
33097 // The "to" entry already exists. Remove up to it.
33098 iRemoveEnd = iFoundTo;
33099 else {
33100 // Insert following the previous entry, which will be removed.
33101 entries.splice(iFoundTo + 1, 0, new Producer.ExcludeEntry(to, false));
33102 iRemoveEnd = iFoundTo + 1;
33103 }
33104 }
33105 else
33106 // "to" follows a component which is already followed by "ANY", meaning
33107 // the new range now encompasses it, so remove the component.
33108 iRemoveEnd = iFoundTo + 1;
33109
33110 // Remove intermediate entries since they are inside the range.
33111 var iRemoveBegin = iNewFrom + 1;
33112 var nRemoveNeeded = iRemoveEnd - iRemoveBegin;
33113 entries.splice(iRemoveBegin, nRemoveNeeded);
33114 }
33115
33116 Producer.setExcludeEntries(exclude, entries);
33117};
33118
33119Producer.START_TIME_STAMP_INDEX = -2;
33120Producer.END_TIME_STAMP_INDEX = -1;
33121Producer.NO_LINK = new Link();
33122/**
33123 * Copyright (C) 2015-2016 Regents of the University of California.
33124 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
33125 * @author: From ndn-group-encrypt src/repetitive-interval https://github.com/named-data/ndn-group-encrypt
33126 *
33127 * This program is free software: you can redistribute it and/or modify
33128 * it under the terms of the GNU Lesser General Public License as published by
33129 * the Free Software Foundation, either version 3 of the License, or
33130 * (at your option) any later version.
33131 *
33132 * This program is distributed in the hope that it will be useful,
33133 * but WITHOUT ANY WARRANTY; without even the implied warranty of
33134 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33135 * GNU Lesser General Public License for more details.
33136 *
33137 * You should have received a copy of the GNU Lesser General Public License
33138 * along with this program. If not, see <http://www.gnu.org/licenses/>.
33139 * A copy of the GNU Lesser General Public License is in the file COPYING.
33140 */
33141
33142/** @ignore */
33143var Interval = require('./interval.js').Interval;
33144
33145/**
33146 * A RepetitiveInterval is an advanced interval which can repeat and can be used
33147 * to find a simple Interval that a time point falls in. Create a
33148 * RepetitiveInterval with one of these forms:
33149 * RepetitiveInterval() A RepetitiveInterval with one day duration, non-repeating..
33150 * RepetitiveInterval(startDate, endDate, intervalStartHour, intervalEndHour, nRepeats, repeatUnit).
33151 * RepetitiveInterval(repetitiveInterval).
33152 * @param {number} startDate The start date as milliseconds since Jan 1, 1970 UTC.
33153 * startDate must be earlier than or same as endDate. Or if repeatUnit is
33154 * RepetitiveInterval.RepeatUnit.NONE, then it must equal endDate.
33155 * @param {number} endDate The end date as milliseconds since Jan 1, 1970 UTC.
33156 * @param {number} intervalStartHour The start hour in the day, from 0 to 23.
33157 * intervalStartHour must be less than intervalEndHour.
33158 * @param {number} intervalEndHour The end hour in the day from 1 to 24.
33159 * @param {number} nRepeats (optional) Repeat the interval nRepeats repetitions,
33160 * every unit, until endDate. If ommitted, use 0.
33161 * @param {number} repeatUnit (optional) The unit of the repetition, from
33162 * RepetitiveInterval.RepeatUnit. If ommitted, use NONE. If this is NONE or
33163 * ommitted, then startDate must equal endDate.
33164 * @note This class is an experimental feature. The API may change.
33165 * @constructor
33166 */
33167var RepetitiveInterval = function RepetitiveInterval
33168 (startDate, endDate, intervalStartHour, intervalEndHour, nRepeats, repeatUnit)
33169{
33170 if (typeof startDate === 'object' && startDate instanceof RepetitiveInterval) {
33171 // Make a copy.
33172 repetitiveInterval = startDate;
33173
33174 this.startDate_ = repetitiveInterval.startDate_;
33175 this.endDate_ = repetitiveInterval.endDate_;
33176 this.intervalStartHour_ = repetitiveInterval.intervalStartHour_;
33177 this.intervalEndHour_ = repetitiveInterval.intervalEndHour_;
33178 this.nRepeats_ = repetitiveInterval.nRepeats_;
33179 this.repeatUnit_ = repetitiveInterval.repeatUnit_;
33180 }
33181 else if (typeof startDate === 'number') {
33182 if (nRepeats == undefined)
33183 nRepeats = 0;
33184 if (repeatUnit == undefined)
33185 repeatUnit = RepetitiveInterval.RepeatUnit.NONE;
33186
33187 this.startDate_ = RepetitiveInterval.toDateOnlyMilliseconds_(startDate);
33188 this.endDate_ = RepetitiveInterval.toDateOnlyMilliseconds_(endDate);
33189 this.intervalStartHour_ = Math.round(intervalStartHour);
33190 this.intervalEndHour_ = Math.round(intervalEndHour);
33191 this.nRepeats_ = Math.round(nRepeats);
33192 this.repeatUnit_ = repeatUnit;
33193
33194 // Validate.
33195 if (!(this.intervalStartHour_ < this.intervalEndHour_))
33196 throw new Error("ReptitiveInterval: startHour must be less than endHour");
33197 if (!(this.startDate_ <= this.endDate_))
33198 throw new Error
33199 ("ReptitiveInterval: startDate must be earlier than or same as endDate");
33200 if (!(this.intervalStartHour_ >= 0))
33201 throw new Error("ReptitiveInterval: intervalStartHour must be non-negative");
33202 if (!(this.intervalEndHour_ >= 1 && this.intervalEndHour_ <= 24))
33203 throw new Error("ReptitiveInterval: intervalEndHour must be from 1 to 24");
33204 if (this.repeatUnit_ == RepetitiveInterval.RepeatUnit.NONE) {
33205 if (!(this.startDate_ == this.endDate_))
33206 throw new Error
33207 ("ReptitiveInterval: With RepeatUnit.NONE, startDate must equal endDate");
33208 }
33209 }
33210 else {
33211 // The default constructor.
33212 this.startDate_ = -Number.MAX_VALUE;
33213 this.endDate_ = -Number.MAX_VALUE;
33214 this.intervalStartHour_ = 0;
33215 this.intervalEndHour_ = 24;
33216 this.nRepeats_ = 0;
33217 this.repeatUnit_ = RepetitiveInterval.RepeatUnit.NONE;
33218 }
33219};
33220
33221exports.RepetitiveInterval = RepetitiveInterval;
33222
33223RepetitiveInterval.RepeatUnit = {
33224 NONE: 0,
33225 DAY: 1,
33226 MONTH: 2,
33227 YEAR: 3
33228};
33229
33230/**
33231 * Get an interval that covers the time point. If there is no interval
33232 * covering the time point, this returns false for isPositive and returns a
33233 * negative interval.
33234 * @param {number} timePoint The time point as milliseconds since Jan 1, 1970 UTC.
33235 * @return {object} An associative array with fields
33236 * (isPositive, interval) where
33237 * isPositive is true if the returned interval is
33238 * positive or false if negative, and interval is the Interval covering the time
33239 * point or a negative interval if not found.
33240 */
33241RepetitiveInterval.prototype.getInterval = function(timePoint)
33242{
33243 var isPositive;
33244 var startTime;
33245 var endTime;
33246
33247 if (!this.hasIntervalOnDate_(timePoint)) {
33248 // There is no interval on the date of timePoint.
33249 startTime = RepetitiveInterval.toDateOnlyMilliseconds_(timePoint);
33250 endTime = RepetitiveInterval.toDateOnlyMilliseconds_(timePoint) +
33251 24 * RepetitiveInterval.MILLISECONDS_IN_HOUR;
33252 isPositive = false;
33253 }
33254 else {
33255 // There is an interval on the date of timePoint.
33256 startTime = RepetitiveInterval.toDateOnlyMilliseconds_(timePoint) +
33257 this.intervalStartHour_ * RepetitiveInterval.MILLISECONDS_IN_HOUR;
33258 endTime = RepetitiveInterval.toDateOnlyMilliseconds_(timePoint) +
33259 this.intervalEndHour_ * RepetitiveInterval.MILLISECONDS_IN_HOUR;
33260
33261 // check if in the time duration
33262 if (timePoint < startTime) {
33263 endTime = startTime;
33264 startTime = RepetitiveInterval.toDateOnlyMilliseconds_(timePoint);
33265 isPositive = false;
33266 }
33267 else if (timePoint > endTime) {
33268 startTime = endTime;
33269 endTime = RepetitiveInterval.toDateOnlyMilliseconds_(timePoint) +
33270 RepetitiveInterval.MILLISECONDS_IN_DAY;
33271 isPositive = false;
33272 }
33273 else
33274 isPositive = true;
33275 }
33276
33277 return { isPositive: isPositive, interval: new Interval(startTime, endTime) };
33278};
33279
33280/**
33281 * Compare this to the other RepetitiveInterval.
33282 * @param {RepetitiveInterval} other The other RepetitiveInterval to compare to.
33283 * @return {number} -1 if this is less than the other, 1 if greater and 0 if equal.
33284 */
33285RepetitiveInterval.prototype.compare = function(other)
33286{
33287 if (this.startDate_ < other.startDate_)
33288 return -1;
33289 if (this.startDate_ > other.startDate_)
33290 return 1;
33291
33292 if (this.endDate_ < other.endDate_)
33293 return -1;
33294 if (this.endDate_ > other.endDate_)
33295 return 1;
33296
33297 if (this.intervalStartHour_ < other.intervalStartHour_)
33298 return -1;
33299 if (this.intervalStartHour_ > other.intervalStartHour_)
33300 return 1;
33301
33302 if (this.intervalEndHour_ < other.intervalEndHour_)
33303 return -1;
33304 if (this.intervalEndHour_ > other.intervalEndHour_)
33305 return 1;
33306
33307 if (this.nRepeats_ < other.nRepeats_)
33308 return -1;
33309 if (this.nRepeats_ > other.nRepeats_)
33310 return 1;
33311
33312 if (this.repeatUnit_ < other.repeatUnit_)
33313 return -1;
33314 if (this.repeatUnit_ > other.repeatUnit_)
33315 return 1;
33316
33317 return 0;
33318};
33319
33320/**
33321 * Get the start date.
33322 * @return {number} The start date as milliseconds since Jan 1, 1970 UTC.
33323 */
33324RepetitiveInterval.prototype.getStartDate = function()
33325{
33326 return this.startDate_;
33327};
33328
33329/**
33330 * Get the end date.
33331 * @return {number} The end date as milliseconds since Jan 1, 1970 UTC.
33332 */
33333RepetitiveInterval.prototype.getEndDate = function()
33334{
33335 return this.endDate_;
33336};
33337
33338/**
33339 * Get the interval start hour.
33340 * @return {number} The interval start hour.
33341 */
33342RepetitiveInterval.prototype.getIntervalStartHour = function()
33343{
33344 return this.intervalStartHour_;
33345}
33346
33347/**
33348 * Get the interval end hour.
33349 * @return {number} The interval end hour.
33350 */
33351RepetitiveInterval.prototype.getIntervalEndHour = function()
33352{
33353 return this.intervalEndHour_;
33354};
33355
33356/**
33357 * Get the number of repeats.
33358 * @return {number} The number of repeats.
33359 */
33360RepetitiveInterval.prototype.getNRepeats = function()
33361{
33362 return this.nRepeats_;
33363};
33364
33365/**
33366 * Get the repeat unit.
33367 * @return {number} The repeat unit, from RepetitiveInterval.RepeatUnit.
33368 */
33369RepetitiveInterval.prototype.getRepeatUnit = function()
33370{
33371 return this.repeatUnit_;
33372};
33373
33374/**
33375 * Check if the date of the time point is in any interval.
33376 * @param {number} timePoint The time point as milliseconds since Jan 1, 1970 UTC.
33377 * @return {boolean} True if the date of the time point is in any interval.
33378 */
33379RepetitiveInterval.prototype.hasIntervalOnDate_ = function(timePoint)
33380{
33381 var timePointDateMilliseconds = RepetitiveInterval.toDateOnlyMilliseconds_(timePoint);
33382
33383 if (timePointDateMilliseconds < this.startDate_ ||
33384 timePointDateMilliseconds > this.endDate_)
33385 return false;
33386
33387 if (this.repeatUnit_ == RepetitiveInterval.RepeatUnit.NONE)
33388 return true;
33389 else if (this.repeatUnit_ == RepetitiveInterval.RepeatUnit.DAY) {
33390 var durationDays = (timePointDateMilliseconds - this.startDate_) /
33391 RepetitiveInterval.MILLISECONDS_IN_DAY;
33392 if (durationDays % this.nRepeats_ == 0)
33393 return true;
33394 }
33395 else {
33396 var timePointDate = new Date(timePointDateMilliseconds);
33397 var startDate = new Date(this.startDate_);
33398
33399 if (this.repeatUnit_ == RepetitiveInterval.RepeatUnit.MONTH &&
33400 timePointDate.getUTCDate() == startDate.getUTCDate()) {
33401 var yearDifference =
33402 timePointDate.getUTCFullYear() - startDate.getUTCFullYear();
33403 var monthDifference = 12 * yearDifference +
33404 timePointDate.getUTCMonth() - startDate.getUTCMonth();
33405 if (monthDifference % this.nRepeats_ == 0)
33406 return true;
33407 }
33408 else if (this.repeatUnit_ == RepetitiveInterval.RepeatUnit.YEAR &&
33409 timePointDate.getUTCDate() == startDate.getUTCDate() &&
33410 timePointDate.getUTCMonth() == startDate.getUTCMonth()) {
33411 var difference = timePointDate.getUTCFullYear() - startDate.getUTCFullYear();
33412 if (difference % this.nRepeats_ == 0)
33413 return true;
33414 }
33415 }
33416
33417 return false;
33418};
33419
33420/**
33421 * Return a time point on the beginning of the date (without hours, minutes, etc.)
33422 * @param {number} timePoint The time point as milliseconds since Jan 1, 1970 UTC.
33423 * @return {number} A time point as milliseconds since Jan 1, 1970 UTC.
33424 */
33425RepetitiveInterval.toDateOnlyMilliseconds_ = function(timePoint)
33426{
33427 var result = Math.round(timePoint);
33428 result -= result % RepetitiveInterval.MILLISECONDS_IN_DAY;
33429 return result;
33430};
33431
33432RepetitiveInterval.MILLISECONDS_IN_HOUR = 3600 * 1000;
33433RepetitiveInterval.MILLISECONDS_IN_DAY = 24 * 3600 * 1000;
33434/**
33435 * Copyright (C) 2015-2016 Regents of the University of California.
33436 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
33437 * @author: From ndn-group-encrypt src/schedule https://github.com/named-data/ndn-group-encrypt
33438 *
33439 * This program is free software: you can redistribute it and/or modify
33440 * it under the terms of the GNU Lesser General Public License as published by
33441 * the Free Software Foundation, either version 3 of the License, or
33442 * (at your option) any later version.
33443 *
33444 * This program is distributed in the hope that it will be useful,
33445 * but WITHOUT ANY WARRANTY; without even the implied warranty of
33446 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33447 * GNU Lesser General Public License for more details.
33448 *
33449 * You should have received a copy of the GNU Lesser General Public License
33450 * along with this program. If not, see <http://www.gnu.org/licenses/>.
33451 * A copy of the GNU Lesser General Public License is in the file COPYING.
33452 */
33453
33454/** @ignore */
33455var Interval = require('./interval.js').Interval; /** @ignore */
33456var RepetitiveInterval = require('./repetitive-interval.js').RepetitiveInterval; /** @ignore */
33457var Tlv = require('../encoding/tlv/tlv.js').Tlv; /** @ignore */
33458var TlvEncoder = require('../encoding/tlv/tlv-encoder.js').TlvEncoder; /** @ignore */
33459var TlvDecoder = require('../encoding/tlv/tlv-decoder.js').TlvDecoder; /** @ignore */
33460var Blob = require('../util/blob.js').Blob;
33461
33462/**
33463 * Schedule is used to manage the times when a member can access data using two
33464 * sets of RepetitiveInterval as follows. whiteIntervalList is an ordered
33465 * set for the times a member is allowed to access to data, and
33466 * blackIntervalList is for the times a member is not allowed.
33467 * Create a Schedule with one of these forms:
33468 * Schedule() A Schedule with empty whiteIntervalList and blackIntervalList.
33469 * Schedule(schedule). A copy of the given schedule.
33470 * @note This class is an experimental feature. The API may change.
33471 * @constructor
33472 */
33473var Schedule = function Schedule(value)
33474{
33475 if (typeof value === 'object' && value instanceof Schedule) {
33476 // Make a copy.
33477 var schedule = value;
33478
33479 // RepetitiveInterval is immutable, so we don't need to make a deep copy.
33480 this.whiteIntervalList_ = schedule.whiteIntervalList_.slice(0);
33481 this.blackIntervalList_ = schedule.blackIntervalList_.slice(0);
33482 }
33483 else {
33484 // The default constructor.
33485 this.whiteIntervalList_ = [];
33486 this.blackIntervalList_ = [];
33487 }
33488};
33489
33490exports.Schedule = Schedule;
33491
33492/**
33493 * Add the repetitiveInterval to the whiteIntervalList.
33494 * @param {RepetitiveInterval} repetitiveInterval The RepetitiveInterval to add.
33495 * If the list already contains the same RepetitiveInterval, this does nothing.
33496 * @return {Schedule} This Schedule so you can chain calls to add.
33497 */
33498Schedule.prototype.addWhiteInterval = function(repetitiveInterval)
33499{
33500 // RepetitiveInterval is immutable, so we don't need to make a copy.
33501 Schedule.sortedSetAdd_(this.whiteIntervalList_, repetitiveInterval);
33502 return this;
33503};
33504
33505/**
33506 * Add the repetitiveInterval to the blackIntervalList.
33507 * @param {RepetitiveInterval} repetitiveInterval The RepetitiveInterval to add.
33508 * If the list already contains the same RepetitiveInterval, this does nothing.
33509 * @return {Schedule} This Schedule so you can chain calls to add.
33510 */
33511Schedule.prototype.addBlackInterval = function(repetitiveInterval)
33512{
33513 // RepetitiveInterval is immutable, so we don't need to make a copy.
33514 Schedule.sortedSetAdd_(this.blackIntervalList_, repetitiveInterval);
33515 return this;
33516};
33517
33518/**
33519 * Get the interval that covers the time stamp. This iterates over the two
33520 * repetitive interval sets and find the shortest interval that allows a group
33521 * member to access the data. If there is no interval covering the time stamp,
33522 * this returns false for isPositive and a negative interval.
33523 * @param {number} timeStamp The time stamp as milliseconds since Jan 1, 1970 UTC.
33524 * @return {object} An associative array with fields
33525 * (isPositive, interval) where
33526 * isPositive is true if the returned interval is positive or false if negative,
33527 * and interval is the Interval covering the time stamp, or a negative interval
33528 * if not found.
33529 */
33530Schedule.prototype.getCoveringInterval = function(timeStamp)
33531{
33532 var blackPositiveResult = new Interval(true);
33533 var whitePositiveResult = new Interval(true);
33534
33535 var blackNegativeResult = new Interval();
33536 var whiteNegativeResult = new Interval();
33537
33538 // Get the black result.
33539 Schedule.calculateIntervalResult_
33540 (this.blackIntervalList_, timeStamp, blackPositiveResult, blackNegativeResult);
33541
33542 // If the black positive result is not empty, then isPositive must be false.
33543 if (!blackPositiveResult.isEmpty())
33544 return { isPositive: false, interval: blackPositiveResult };
33545
33546 // Get the whiteResult.
33547 Schedule.calculateIntervalResult_
33548 (this.whiteIntervalList_, timeStamp, whitePositiveResult, whiteNegativeResult);
33549
33550 if (whitePositiveResult.isEmpty() && !whiteNegativeResult.isValid()) {
33551 // There is no white interval covering the time stamp.
33552 // Return false and a 24-hour interval.
33553 var timeStampDateOnly =
33554 RepetitiveInterval.toDateOnlyMilliseconds_(timeStamp);
33555 return { isPositive: false,
33556 interval: new Interval
33557 (timeStampDateOnly,
33558 timeStampDateOnly + RepetitiveInterval.MILLISECONDS_IN_DAY) };
33559 }
33560
33561 if (!whitePositiveResult.isEmpty()) {
33562 // There is white interval covering the time stamp.
33563 // Return true and calculate the intersection.
33564 if (blackNegativeResult.isValid())
33565 return { isPositive: true,
33566 interval: whitePositiveResult.intersectWith(blackNegativeResult) };
33567 else
33568 return { isPositive: true, interval: whitePositiveResult };
33569 }
33570 else
33571 // There is no white interval covering the time stamp.
33572 // Return false.
33573 return { isPositive: false, interval: whiteNegativeResult };
33574};
33575
33576/**
33577 * Encode this Schedule.
33578 * @return {Blob} The encoded buffer.
33579 */
33580Schedule.prototype.wireEncode = function()
33581{
33582 // For now, don't use WireFormat and hardcode to use TLV since the encoding
33583 // doesn't go out over the wire, only into the local SQL database.
33584 var encoder = new TlvEncoder(256);
33585 var saveLength = encoder.getLength();
33586
33587 // Encode backwards.
33588 // Encode the blackIntervalList.
33589 var saveLengthForList = encoder.getLength();
33590 for (var i = this.blackIntervalList_.length - 1; i >= 0; i--)
33591 Schedule.encodeRepetitiveInterval_(this.blackIntervalList_[i], encoder);
33592 encoder.writeTypeAndLength
33593 (Tlv.Encrypt_BlackIntervalList, encoder.getLength() - saveLengthForList);
33594
33595 // Encode the whiteIntervalList.
33596 saveLengthForList = encoder.getLength();
33597 for (var i = this.whiteIntervalList_.length - 1; i >= 0; i--)
33598 Schedule.encodeRepetitiveInterval_(this.whiteIntervalList_[i], encoder);
33599 encoder.writeTypeAndLength
33600 (Tlv.Encrypt_WhiteIntervalList, encoder.getLength() - saveLengthForList);
33601
33602 encoder.writeTypeAndLength
33603 (Tlv.Encrypt_Schedule, encoder.getLength() - saveLength);
33604
33605 return new Blob(encoder.getOutput(), false);
33606};
33607
33608/**
33609 * Decode the input and update this Schedule object.
33610 * @param {Blob|Buffer} input The input buffer to decode. For Buffer, this reads
33611 * from position() to limit(), but does not change the position.
33612 * @throws DecodingException For invalid encoding.
33613 */
33614Schedule.prototype.wireDecode = function(input)
33615{
33616 // If input is a blob, get its buf().
33617 var decodeBuffer = typeof input === 'object' && input instanceof Blob ?
33618 input.buf() : input;
33619
33620 // For now, don't use WireFormat and hardcode to use TLV since the encoding
33621 // doesn't go out over the wire, only into the local SQL database.
33622 var decoder = new TlvDecoder(decodeBuffer);
33623
33624 var endOffset = decoder.readNestedTlvsStart(Tlv.Encrypt_Schedule);
33625
33626 // Decode the whiteIntervalList.
33627 this.whiteIntervalList_ = [];
33628 var listEndOffset = decoder.readNestedTlvsStart(Tlv.Encrypt_WhiteIntervalList);
33629 while (decoder.getOffset() < listEndOffset)
33630 Schedule.sortedSetAdd_
33631 (this.whiteIntervalList_, Schedule.decodeRepetitiveInterval_(decoder));
33632 decoder.finishNestedTlvs(listEndOffset);
33633
33634 // Decode the blackIntervalList.
33635 this.blackIntervalList_ = [];
33636 listEndOffset = decoder.readNestedTlvsStart(Tlv.Encrypt_BlackIntervalList);
33637 while (decoder.getOffset() < listEndOffset)
33638 Schedule.sortedSetAdd_
33639 (this.blackIntervalList_, Schedule.decodeRepetitiveInterval_(decoder));
33640 decoder.finishNestedTlvs(listEndOffset);
33641
33642 decoder.finishNestedTlvs(endOffset);
33643};
33644
33645/**
33646 * Insert element into the list, sorted using element.compare(). If it is a
33647 * duplicate of an existing list element, don't add it.
33648 */
33649Schedule.sortedSetAdd_ = function(list, element)
33650{
33651 // Find the index of the first element where it is not less than element.
33652 var i = 0;
33653 while (i < list.length) {
33654 var comparison = list[i].compare(element);
33655 if (comparison == 0)
33656 // Don't add a duplicate.
33657 return;
33658 if (!(comparison < 0))
33659 break;
33660
33661 ++i;
33662 }
33663
33664 list.splice(i, 0, element);
33665};
33666
33667/**
33668 * Encode the RepetitiveInterval as NDN-TLV to the encoder.
33669 * @param {RepetitiveInterval} repetitiveInterval The RepetitiveInterval to encode.
33670 * @param {TlvEncoder} encoder The TlvEncoder to receive the encoding.
33671 */
33672Schedule.encodeRepetitiveInterval_ = function(repetitiveInterval, encoder)
33673{
33674 var saveLength = encoder.getLength();
33675
33676 // Encode backwards.
33677 // The RepeatUnit enum has the same values as the encoding.
33678 encoder.writeNonNegativeIntegerTlv
33679 (Tlv.Encrypt_RepeatUnit, repetitiveInterval.getRepeatUnit());
33680 encoder.writeNonNegativeIntegerTlv
33681 (Tlv.Encrypt_NRepeats, repetitiveInterval.getNRepeats());
33682 encoder.writeNonNegativeIntegerTlv
33683 (Tlv.Encrypt_IntervalEndHour, repetitiveInterval.getIntervalEndHour());
33684 encoder.writeNonNegativeIntegerTlv
33685 (Tlv.Encrypt_IntervalStartHour, repetitiveInterval.getIntervalStartHour());
33686 // Use Blob to convert the string to UTF8 encoding.
33687 encoder.writeBlobTlv(Tlv.Encrypt_EndDate,
33688 new Blob(Schedule.toIsoString(repetitiveInterval.getEndDate())).buf());
33689 encoder.writeBlobTlv(Tlv.Encrypt_StartDate,
33690 new Blob(Schedule.toIsoString(repetitiveInterval.getStartDate())).buf());
33691
33692 encoder.writeTypeAndLength
33693 (Tlv.Encrypt_RepetitiveInterval, encoder.getLength() - saveLength);
33694};
33695
33696/**
33697 * Decode the input as an NDN-TLV RepetitiveInterval.
33698 * @param {TlvDecoder} decoder The decoder with the input to decode.
33699 * @return {RepetitiveInterval} A new RepetitiveInterval with the decoded result.
33700 */
33701Schedule.decodeRepetitiveInterval_ = function(decoder)
33702{
33703 var endOffset = decoder.readNestedTlvsStart(Tlv.Encrypt_RepetitiveInterval);
33704
33705 // Use Blob to convert UTF8 to a string.
33706 var startDate = Schedule.fromIsoString
33707 (new Blob(decoder.readBlobTlv(Tlv.Encrypt_StartDate), true).toString());
33708 var endDate = Schedule.fromIsoString
33709 (new Blob(decoder.readBlobTlv(Tlv.Encrypt_EndDate), true).toString());
33710 var startHour = decoder.readNonNegativeIntegerTlv(Tlv.Encrypt_IntervalStartHour);
33711 var endHour = decoder.readNonNegativeIntegerTlv(Tlv.Encrypt_IntervalEndHour);
33712 var nRepeats = decoder.readNonNegativeIntegerTlv(Tlv.Encrypt_NRepeats);
33713
33714 // The RepeatUnit enum has the same values as the encoding.
33715 var repeatUnit = decoder.readNonNegativeIntegerTlv(Tlv.Encrypt_RepeatUnit);
33716
33717 decoder.finishNestedTlvs(endOffset);
33718 return new RepetitiveInterval
33719 (startDate, endDate, startHour, endHour, nRepeats, repeatUnit);
33720};
33721
33722/**
33723 * A helper function to calculate black interval results or white interval
33724 * results.
33725 * @param {Array} list The set of RepetitiveInterval, which can be the white
33726 * list or the black list.
33727 * @param {number} timeStamp The time stamp as milliseconds since Jan 1, 1970 UTC.
33728 * @param {Interval} positiveResult The positive result which is updated.
33729 * @param {Interval} negativeResult The negative result which is updated.
33730 */
33731Schedule.calculateIntervalResult_ = function
33732 (list, timeStamp, positiveResult, negativeResult)
33733{
33734 for (var i = 0; i < list.length; ++i) {
33735 var element = list[i];
33736
33737 var result = element.getInterval(timeStamp);
33738 var tempInterval = result.interval;
33739 if (result.isPositive == true)
33740 positiveResult.unionWith(tempInterval);
33741 else {
33742 if (!negativeResult.isValid())
33743 negativeResult.set(tempInterval);
33744 else
33745 negativeResult.intersectWith(tempInterval);
33746 }
33747 }
33748};
33749
33750/**
33751 * Convert a UNIX timestamp to ISO time representation with the "T" in the middle.
33752 * @param {number} msSince1970 Timestamp as milliseconds since Jan 1, 1970 UTC.
33753 * @return {string} The string representation.
33754 */
33755Schedule.toIsoString = function(msSince1970)
33756{
33757 var utcTime = new Date(Math.round(msSince1970));
33758 return utcTime.getUTCFullYear() +
33759 Schedule.to2DigitString(utcTime.getUTCMonth() + 1) +
33760 Schedule.to2DigitString(utcTime.getUTCDate()) +
33761 "T" +
33762 Schedule.to2DigitString(utcTime.getUTCHours()) +
33763 Schedule.to2DigitString(utcTime.getUTCMinutes()) +
33764 Schedule.to2DigitString(utcTime.getUTCSeconds());
33765};
33766
33767/**
33768 * A private method to zero pad an integer to 2 digits.
33769 * @param {number} x The number to pad. Assume it is a non-negative integer.
33770 * @return {string} The padded string.
33771 */
33772Schedule.to2DigitString = function(x)
33773{
33774 var result = x.toString();
33775 return result.length === 1 ? "0" + result : result;
33776};
33777
33778/**
33779 * Convert an ISO time representation with the "T" in the middle to a UNIX
33780 * timestamp.
33781 * @param {string} timeString The ISO time representation.
33782 * @return {number} The timestamp as milliseconds since Jan 1, 1970 UTC.
33783 */
33784Schedule.fromIsoString = function(timeString)
33785{
33786 if (timeString.length != 15 || timeString.substr(8, 1) != 'T')
33787 throw new Error("fromIsoString: Format is not the expected yyyymmddThhmmss");
33788
33789 return Date.UTC
33790 (parseInt(timeString.substr(0, 4)),
33791 parseInt(timeString.substr(4, 2) - 1),
33792 parseInt(timeString.substr(6, 2)),
33793 parseInt(timeString.substr(9, 2)),
33794 parseInt(timeString.substr(11, 2)),
33795 parseInt(timeString.substr(13, 2)));
33796};
33797/**
33798 * Copyright (C) 2015-2016 Regents of the University of California.
33799 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
33800 *
33801 * This program is free software: you can redistribute it and/or modify
33802 * it under the terms of the GNU Lesser General Public License as published by
33803 * the Free Software Foundation, either version 3 of the License, or
33804 * (at your option) any later version.
33805 *
33806 * This program is distributed in the hope that it will be useful,
33807 * but WITHOUT ANY WARRANTY; without even the implied warranty of
33808 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33809 * GNU Lesser General Public License for more details.
33810 *
33811 * You should have received a copy of the GNU Lesser General Public License
33812 * along with this program. If not, see <http://www.gnu.org/licenses/>.
33813 * A copy of the GNU Lesser General Public License is in the file COPYING.
33814 */
33815
33816// Don't require modules since this is meant for the browser, not Node.js.
33817
33818/**
33819 * IndexedDbConsumerDb extends ConsumerDb to implement the storage of decryption
33820 * keys for the consumer using the browser's IndexedDB service.
33821 * Create an IndexedDbConsumerDb to use the given IndexedDB database name.
33822 * @param {string} databaseName IndexedDB database name.
33823 * @note This class is an experimental feature. The API may change.
33824 * @constructor
33825 */
33826var IndexedDbConsumerDb = function IndexedDbConsumerDb(databaseName)
33827{
33828 ConsumerDb.call(this);
33829
33830 this.database = new Dexie(databaseName);
33831 this.database.version(1).stores({
33832 // "keyName" is the key name URI // string
33833 // (Note: In SQLite3, the key name is the TLV encoded bytes, but we can't
33834 // index on a byte array in IndexedDb.)
33835 // "key" is the key bytes // Uint8Array
33836 decryptionKeys: "keyName"
33837 });
33838 this.database.open();
33839};
33840
33841IndexedDbConsumerDb.prototype = new ConsumerDb();
33842IndexedDbConsumerDb.prototype.name = "IndexedDbConsumerDb";
33843
33844/**
33845 * Get the key with keyName from the database.
33846 * @param {Name} keyName The key name.
33847 * @param {boolean} useSync (optional) If true then return a rejected promise
33848 * since this only supports async code.
33849 * @return {Promise} A promise that returns a Blob with the encoded key (or an
33850 * isNull Blob if cannot find the key with keyName), or that is
33851 * rejected with ConsumerDb.Error for a database error.
33852 */
33853IndexedDbConsumerDb.prototype.getKeyPromise = function(keyName, useSync)
33854{
33855 if (useSync)
33856 return Promise.reject(new ConsumerDb.Error(new Error
33857 ("IndexedDbConsumerDb.getKeyPromise is only supported for async")));
33858
33859 return this.database.decryptionKeys.get(keyName.toUri())
33860 .then(function(decryptionKeysEntry) {
33861 if (decryptionKeysEntry)
33862 return Promise.resolve(new Blob(decryptionKeysEntry.key));
33863 else
33864 return Promise.resolve(new Blob());
33865 })
33866 .catch(function(ex) {
33867 return Promise.reject(new ConsumerDb.Error(new Error
33868 ("IndexedDbConsumerDb.getKeyPromise: Error: " + ex)));
33869 });
33870};
33871
33872/**
33873 * Add the key with keyName and keyBlob to the database.
33874 * @param {Name} keyName The key name.
33875 * @param {Blob} keyBlob The encoded key.
33876 * @param {boolean} useSync (optional) If true then return a rejected promise
33877 * since this only supports async code.
33878 * @return {Promise} A promise that fulfills when the key is added, or that
33879 * is rejected with ConsumerDb.Error if a key with the same keyName already
33880 * exists, or other database error.
33881 */
33882IndexedDbConsumerDb.prototype.addKeyPromise = function(keyName, keyBlob, useSync)
33883{
33884 if (useSync)
33885 return Promise.reject(new ConsumerDb.Error(new Error
33886 ("IndexedDbConsumerDb.addKeyPromise is only supported for async")));
33887
33888 // Add rejects if the primary key already exists.
33889 return this.database.decryptionKeys.add
33890 ({ keyName: keyName.toUri(), key: keyBlob.buf() })
33891 .catch(function(ex) {
33892 return Promise.reject(new ConsumerDb.Error(new Error
33893 ("IndexedDbConsumerDb.addKeyPromise: Error: " + ex)));
33894 });
33895};
33896
33897/**
33898 * Delete the key with keyName from the database. If there is no key with
33899 * keyName, do nothing.
33900 * @param {Name} keyName The key name.
33901 * @param {boolean} useSync (optional) If true then return a rejected promise
33902 * since this only supports async code.
33903 * @return {Promise} A promise that fulfills when the key is deleted (or there
33904 * is no such key), or that is rejected with ConsumerDb.Error for a database
33905 * error.
33906 */
33907IndexedDbConsumerDb.prototype.deleteKeyPromise = function(keyName, useSync)
33908{
33909 if (useSync)
33910 return Promise.reject(new ConsumerDb.Error(new Error
33911 ("IndexedDbConsumerDb.deleteKeyPromise is only supported for async")));
33912
33913 return this.database.decryptionKeys.delete(keyName.toUri())
33914 .catch(function(ex) {
33915 return Promise.reject(new ConsumerDb.Error(new Error
33916 ("IndexedDbConsumerDb.deleteKeyPromise: Error: " + ex)));
33917 });
33918};
33919/**
33920 * Copyright (C) 2015-2016 Regents of the University of California.
33921 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
33922 *
33923 * This program is free software: you can redistribute it and/or modify
33924 * it under the terms of the GNU Lesser General Public License as published by
33925 * the Free Software Foundation, either version 3 of the License, or
33926 * (at your option) any later version.
33927 *
33928 * This program is distributed in the hope that it will be useful,
33929 * but WITHOUT ANY WARRANTY; without even the implied warranty of
33930 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33931 * GNU Lesser General Public License for more details.
33932 *
33933 * You should have received a copy of the GNU Lesser General Public License
33934 * along with this program. If not, see <http://www.gnu.org/licenses/>.
33935 * A copy of the GNU Lesser General Public License is in the file COPYING.
33936 */
33937
33938// Don't require modules since this is meant for the browser, not Node.js.
33939
33940/**
33941 * IndexedDbGroupManagerDb extends GroupManagerDb to implement the storage of
33942 * data used by the GroupManager using the browser's IndexedDB service.
33943 * Create an IndexedDbGroupManagerDb to use the given IndexedDB database name.
33944 * @param {string} databaseName IndexedDB database name.
33945 * @note This class is an experimental feature. The API may change.
33946 * @constructor
33947 */
33948var IndexedDbGroupManagerDb = function IndexedDbGroupManagerDb(databaseName)
33949{
33950 GroupManagerDb.call(this);
33951
33952 this.database = new Dexie(databaseName);
33953 this.database.version(1).stores({
33954 // "scheduleId" is the schedule ID, auto incremented // number
33955 // "scheduleName" is the schedule name, unique // string
33956 // "schedule" is the TLV-encoded schedule // Uint8Array
33957 schedules: "++scheduleId, &scheduleName",
33958
33959 // "memberNameUri" is the member name URI // string
33960 // (Note: In SQLite3, the member name index is the TLV encoded bytes, but
33961 // we can't index on a byte array in IndexedDb.)
33962 // (Note: The SQLite3 table also has an auto-incremented member ID primary
33963 // key, but is not used so we omit it to simplify.)
33964 // "memberName" is the TLV-encoded member name (same as memberNameUri // Uint8Array
33965 // "scheduleId" is the schedule ID, linked to the schedules table // number
33966 // (Note: The SQLite3 table has a foreign key to the schedules table with
33967 // cascade update and delete, but we have to handle it manually.)
33968 // "keyName" is the TLV-encoded key name // Uint8Array
33969 // "publicKey" is the encoded key bytes // Uint8Array
33970 members: "memberNameUri, scheduleId"
33971 });
33972 this.database.open();
33973};
33974
33975IndexedDbGroupManagerDb.prototype = new GroupManagerDb();
33976IndexedDbGroupManagerDb.prototype.name = "IndexedDbGroupManagerDb";
33977
33978////////////////////////////////////////////////////// Schedule management.
33979
33980/**
33981 * Check if there is a schedule with the given name.
33982 * @param {string} name The name of the schedule.
33983 * @param {boolean} useSync (optional) If true then return a rejected promise
33984 * since this only supports async code.
33985 * @return {Promise} A promise that returns true if there is a schedule (else
33986 * false), or that is rejected with GroupManagerDb.Error for a database error.
33987 */
33988IndexedDbGroupManagerDb.prototype.hasSchedulePromise = function(name, useSync)
33989{
33990 if (useSync)
33991 return Promise.reject(new GroupManagerDb.Error(new Error
33992 ("IndexedDbGroupManagerDb.hasSchedulePromise is only supported for async")));
33993
33994 return this.getScheduleIdPromise_(name)
33995 .then(function(scheduleId) {
33996 return Promise.resolve(scheduleId != -1);
33997 });
33998};
33999
34000/**
34001 * List all the names of the schedules.
34002 * @param {boolean} useSync (optional) If true then return a rejected promise
34003 * since this only supports async code.
34004 * @return {Promise} A promise that returns a new array of string with the names
34005 * of all schedules, or that is rejected with GroupManagerDb.Error for a
34006 * database error.
34007 */
34008IndexedDbGroupManagerDb.prototype.listAllScheduleNamesPromise = function(useSync)
34009{
34010 if (useSync)
34011 return Promise.reject(new GroupManagerDb.Error(new Error
34012 ("IndexedDbGroupManagerDb.listAllScheduleNamesPromise is only supported for async")));
34013
34014 var list = [];
34015 return this.database.schedules.each(function(entry) {
34016 list.push(entry.scheduleName);
34017 })
34018 .then(function() {
34019 return Promise.resolve(list);
34020 })
34021 .catch(function(ex) {
34022 return Promise.reject(new GroupManagerDb.Error(new Error
34023 ("IndexedDbGroupManagerDb.listAllScheduleNamesPromise: Error: " + ex)));
34024 });
34025};
34026
34027/**
34028 * Get a schedule with the given name.
34029 * @param {string} name The name of the schedule.
34030 * @param {boolean} useSync (optional) If true then return a rejected promise
34031 * since this only supports async code.
34032 * @return {Promise} A promise that returns a new Schedule object, or that is
34033 * rejected with GroupManagerDb.Error if the schedule does not exist or other
34034 * database error.
34035 */
34036IndexedDbGroupManagerDb.prototype.getSchedulePromise = function(name, useSync)
34037{
34038 if (useSync)
34039 return Promise.reject(new GroupManagerDb.Error(new Error
34040 ("IndexedDbGroupManagerDb.getSchedulePromise is only supported for async")));
34041
34042 var thisManager = this;
34043 // Use getScheduleIdPromise_ to handle the search on the non-primary key.
34044 return this.getScheduleIdPromise_(name)
34045 .then(function(scheduleId) {
34046 if (scheduleId != -1) {
34047 return thisManager.database.schedules.get(scheduleId)
34048 .then(function(entry) {
34049 // We expect entry to be found, and don't expect an error decoding.
34050 var schedule = new Schedule();
34051 schedule.wireDecode(new Blob(entry.schedule, false));
34052 return Promise.resolve(schedule);
34053 })
34054 .catch(function(ex) {
34055 return Promise.reject(new GroupManagerDb.Error(new Error
34056 ("IndexedDbGroupManagerDb.getSchedulePromise: Error: " + ex)));
34057 });
34058 }
34059 else
34060 return Promise.reject(new GroupManagerDb.Error(new Error
34061 ("IndexedDbGroupManagerDb.getSchedulePromise: Cannot get the result from the database")));
34062 });
34063};
34064
34065/**
34066 * For each member using the given schedule, get the name and public key DER
34067 * of the member's key.
34068 * @param {string} name The name of the schedule.
34069 * @param {boolean} useSync (optional) If true then return a rejected promise
34070 * since this only supports async code.
34071 * @return {Promise} A promise that returns a new array of object (where
34072 * "keyName" is the Name of the public key and "publicKey" is the Blob of the
34073 * public key DER), or that is rejected with GroupManagerDb.Error for a database
34074 * error. Note that the member's identity name is keyName.getPrefix(-1). If the
34075 * schedule name is not found, the list is empty.
34076 */
34077IndexedDbGroupManagerDb.prototype.getScheduleMembersPromise = function
34078 (name, useSync)
34079{
34080 if (useSync)
34081 return Promise.reject(new GroupManagerDb.Error(new Error
34082 ("IndexedDbGroupManagerDb.getScheduleMembersPromise is only supported for async")));
34083
34084 var list = [];
34085 var thisManager = this;
34086 // There is only one matching schedule ID, so we can just look it up instead
34087 // of doing a more complicated join.
34088 return this.getScheduleIdPromise_(name)
34089 .then(function(scheduleId) {
34090 if (scheduleId == -1)
34091 // Return the empty list.
34092 return Promise.resolve(list);
34093
34094 var onEntryError = null;
34095 return thisManager.database.members.where("scheduleId").equals(scheduleId)
34096 .each(function(entry) {
34097 try {
34098 var keyName = new Name();
34099 keyName.wireDecode(new Blob(entry.keyName, false), TlvWireFormat.get());
34100
34101 list.push({ keyName: keyName, publicKey: new Blob(entry.publicKey, false) });
34102 } catch (ex) {
34103 // We don't expect this to happen.
34104 onEntryError = new GroupManagerDb.Error(new Error
34105 ("IndexedDbGroupManagerDb.getScheduleMembersPromise: Error decoding name: " + ex));
34106 }
34107 })
34108 .then(function() {
34109 if (onEntryError)
34110 // We got an error decoding.
34111 return Promise.reject(onEntryError);
34112 else
34113 return Promise.resolve(list);
34114 }, function(ex) {
34115 return Promise.reject(new GroupManagerDb.Error(new Error
34116 ("IndexedDbGroupManagerDb.getScheduleMembersPromise: Error: " + ex)));
34117 });
34118 });
34119};
34120
34121/**
34122 * Add a schedule with the given name.
34123 * @param {string} name The name of the schedule. The name cannot be empty.
34124 * @param {Schedule} schedule The Schedule to add.
34125 * @param {boolean} useSync (optional) If true then return a rejected promise
34126 * since this only supports async code.
34127 * @return {Promise} A promise that fulfills when the schedule is added, or that
34128 * is rejected with GroupManagerDb.Error if a schedule with the same name
34129 * already exists, if the name is empty, or other database error.
34130 */
34131IndexedDbGroupManagerDb.prototype.addSchedulePromise = function
34132 (name, schedule, useSync)
34133{
34134 if (useSync)
34135 return Promise.reject(new GroupManagerDb.Error(new Error
34136 ("IndexedDbGroupManagerDb.addSchedulePromise is only supported for async")));
34137
34138 if (name.length == 0)
34139 return Promise.reject(new GroupManagerDb.Error
34140 ("IndexedDbGroupManagerDb.addSchedulePromise: The schedule name cannot be empty"));
34141
34142 // Add rejects if the primary key already exists.
34143 return this.database.schedules.add
34144 ({ scheduleName: name, schedule: schedule.wireEncode().buf() })
34145 .catch(function(ex) {
34146 return Promise.reject(new GroupManagerDb.Error(new Error
34147 ("IndexedDbGroupManagerDb.addContentKeyPromise: Error: " + ex)));
34148 });
34149};
34150
34151/**
34152 * Delete the schedule with the given name. Also delete members which use this
34153 * schedule. If there is no schedule with the name, then do nothing.
34154 * @param {string} name The name of the schedule.
34155 * @param {boolean} useSync (optional) If true then return a rejected promise
34156 * since this only supports async code.
34157 * @return {Promise} A promise that fulfills when the schedule is deleted (or
34158 * there is no such schedule), or that is rejected with GroupManagerDb.Error for
34159 * a database error.
34160 */
34161IndexedDbGroupManagerDb.prototype.deleteSchedulePromise = function
34162 (name, useSync)
34163{
34164 if (useSync)
34165 return Promise.reject(new GroupManagerDb.Error(new Error
34166 ("IndexedDbGroupManagerDb.deleteSchedulePromise is only supported for async")));
34167
34168 var scheduleId;
34169 var thisManager = this;
34170 return this.getScheduleIdPromise_(name)
34171 .then(function(localScheduleId) {
34172 scheduleId = localScheduleId;
34173
34174 // Get the members which use this schedule.
34175 return thisManager.database.members.where("scheduleId").equals(scheduleId).toArray();
34176 })
34177 .then(function(membersEntries) {
34178 // Delete the members.
34179 var promises = membersEntries.map(function(entry) {
34180 return thisManager.database.members.delete(entry.memberNameUri);
34181 });
34182 return Promise.all(promises);
34183 })
34184 .then(function() {
34185 // Now delete the schedule.
34186 return thisManager.database.schedules.delete(scheduleId);
34187 })
34188 .catch(function(ex) {
34189 return Promise.reject(new GroupManagerDb.Error(new Error
34190 ("IndexedDbGroupManagerDb.deleteSchedulePromise: Error: " + ex)));
34191 });
34192};
34193
34194/**
34195 * Rename a schedule with oldName to newName.
34196 * @param {string} oldName The name of the schedule to be renamed.
34197 * @param {string} newName The new name of the schedule. The name cannot be empty.
34198 * @param {boolean} useSync (optional) If true then return a rejected promise
34199 * since this only supports async code.
34200 * @return {Promise} A promise that fulfills when the schedule is renamed, or
34201 * that is rejected with GroupManagerDb.Error if a schedule with newName already
34202 * exists, if the schedule with oldName does not exist, if newName is empty, or
34203 * other database error.
34204 */
34205IndexedDbGroupManagerDb.prototype.renameSchedulePromise = function
34206 (oldName, newName, useSync)
34207{
34208 if (useSync)
34209 return Promise.reject(new GroupManagerDb.Error(new Error
34210 ("IndexedDbGroupManagerDb.renameSchedulePromise is only supported for async")));
34211
34212 if (newName.length == 0)
34213 return Promise.reject(new GroupManagerDb.Error(new Error
34214 ("IndexedDbGroupManagerDb.renameSchedule: The schedule newName cannot be empty")));
34215
34216 var thisManager = this;
34217 return this.getScheduleIdPromise_(oldName)
34218 .then(function(scheduleId) {
34219 if (scheduleId == -1)
34220 return Promise.reject(new GroupManagerDb.Error(new Error
34221 ("IndexedDbGroupManagerDb.renameSchedule: The schedule oldName does not exist")));
34222
34223 return thisManager.database.schedules.update
34224 (scheduleId, { scheduleName: newName })
34225 .catch(function(ex) {
34226 return Promise.reject(new GroupManagerDb.Error(new Error
34227 ("IndexedDbGroupManagerDb.renameSchedulePromise: Error: " + ex)));
34228 });
34229 });
34230};
34231
34232/**
34233 * Update the schedule with name and replace the old object with the given
34234 * schedule. Otherwise, if no schedule with name exists, a new schedule
34235 * with name and the given schedule will be added to database.
34236 * @param {string} name The name of the schedule. The name cannot be empty.
34237 * @param {Schedule} schedule The Schedule to update or add.
34238 * @param {boolean} useSync (optional) If true then return a rejected promise
34239 * since this only supports async code.
34240 * @return {Promise} A promise that fulfills when the schedule is updated, or
34241 * that is rejected with GroupManagerDb.Error if the name is empty, or other
34242 * database error.
34243 */
34244IndexedDbGroupManagerDb.prototype.updateSchedulePromise = function
34245 (name, schedule, useSync)
34246{
34247 if (useSync)
34248 return Promise.reject(new GroupManagerDb.Error(new Error
34249 ("IndexedDbGroupManagerDb.updateSchedulePromise is only supported for async")));
34250
34251 var thisManager = this;
34252 return this.getScheduleIdPromise_(name)
34253 .then(function(scheduleId) {
34254 if (scheduleId == -1)
34255 return thisManager.addSchedulePromise(name, schedule);
34256
34257 return thisManager.database.schedules.update
34258 (scheduleId, { schedule: schedule.wireEncode().buf() })
34259 .catch(function(ex) {
34260 return Promise.reject(new GroupManagerDb.Error(new Error
34261 ("IndexedDbGroupManagerDb.updateSchedulePromise: Error: " + ex)));
34262 });
34263 });
34264};
34265
34266////////////////////////////////////////////////////// Member management.
34267
34268/**
34269 * Check if there is a member with the given identity name.
34270 * @param {Name} identity The member's identity name.
34271 * @param {boolean} useSync (optional) If true then return a rejected promise
34272 * since this only supports async code.
34273 * @return {Promise} A promise that returns true if there is a member (else
34274 * false), or that is rejected with GroupManagerDb.Error for a database error.
34275 */
34276IndexedDbGroupManagerDb.prototype.hasMemberPromise = function(identity, useSync)
34277{
34278 if (useSync)
34279 return Promise.reject(new GroupManagerDb.Error(new Error
34280 ("IndexedDbGroupManagerDb.hasMemberPromise is only supported for async")));
34281
34282 return this.database.members.get(identity.toUri())
34283 .then(function(entry) {
34284 return Promise.resolve(entry != undefined);
34285 })
34286 .catch(function(ex) {
34287 return Promise.reject(new GroupManagerDb.Error(new Error
34288 ("IndexedDbGroupManagerDb.hasMemberPromise: Error: " + ex)));
34289 });
34290};
34291
34292/**
34293 * List all the members.
34294 * @param {boolean} useSync (optional) If true then return a rejected promise
34295 * since this only supports async code.
34296 * @return {Promise} A promise that returns a new array of Name with the names
34297 * of all members, or that is rejected with GroupManagerDb.Error for a
34298 * database error.
34299 */
34300IndexedDbGroupManagerDb.prototype.listAllMembersPromise = function(useSync)
34301{
34302 if (useSync)
34303 return Promise.reject(new GroupManagerDb.Error(new Error
34304 ("IndexedDbGroupManagerDb.listAllMembersPromise is only supported for async")));
34305
34306 var list = [];
34307 var onEntryError = null;
34308 return this.database.members.each(function(entry) {
34309 try {
34310 var identity = new Name();
34311 identity.wireDecode(new Blob(entry.memberName, false), TlvWireFormat.get());
34312 list.push(identity);
34313 } catch (ex) {
34314 // We don't expect this to happen.
34315 onEntryError = new GroupManagerDb.Error(new Error
34316 ("IndexedDbGroupManagerDb.listAllMembersPromise: Error decoding name: " + ex));
34317 }
34318 })
34319 .then(function() {
34320 if (onEntryError)
34321 // We got an error decoding.
34322 return Promise.reject(onEntryError);
34323 else
34324 return Promise.resolve(list);
34325 }, function(ex) {
34326 return Promise.reject(new GroupManagerDb.Error(new Error
34327 ("IndexedDbGroupManagerDb.listAllMembersPromise: Error: " + ex)));
34328 });
34329};
34330
34331/**
34332 * Get the name of the schedule for the given member's identity name.
34333 * @param {Name} identity The member's identity name.
34334 * @param {boolean} useSync (optional) If true then return a rejected promise
34335 * since this only supports async code.
34336 * @return {Promise} A promise that returns the string schedule name, or that is
34337 * rejected with GroupManagerDb.Error if there's no member with the given
34338 * identity name in the database, or other database error.
34339 */
34340IndexedDbGroupManagerDb.prototype.getMemberSchedulePromise = function
34341 (identity, useSync)
34342{
34343 if (useSync)
34344 return Promise.reject(new GroupManagerDb.Error(new Error
34345 ("IndexedDbGroupManagerDb.getMemberSchedulePromise is only supported for async")));
34346
34347 var thisManager = this;
34348 return this.database.members.get(identity.toUri())
34349 .then(function(membersEntry) {
34350 if (!membersEntry)
34351 throw new Error("The member identity name does not exist in the database");
34352
34353 return thisManager.database.schedules.get(membersEntry.scheduleId);
34354 })
34355 .then(function(schedulesEntry) {
34356 if (!schedulesEntry)
34357 throw new Error
34358 ("The schedule ID for the member identity name does not exist in the database");
34359
34360 return Promise.resolve(schedulesEntry.scheduleName);
34361 })
34362 .catch(function(ex) {
34363 return Promise.reject(new GroupManagerDb.Error(new Error
34364 ("IndexedDbGroupManagerDb.getScheduleIdPromise_: Error: " + ex)));
34365 });
34366};
34367
34368/**
34369 * Add a new member with the given key named keyName into a schedule named
34370 * scheduleName. The member's identity name is keyName.getPrefix(-1).
34371 * @param {string} scheduleName The schedule name.
34372 * @param {Name} keyName The name of the key.
34373 * @param {Blob} key A Blob of the public key DER.
34374 * @param {boolean} useSync (optional) If true then return a rejected promise
34375 * since this only supports async code.
34376 * @return {Promise} A promise that fulfills when the member is added, or that
34377 * is rejected with GroupManagerDb.Error if there's no schedule named
34378 * scheduleName, if the member's identity name already exists, or other database
34379 * error.
34380 */
34381IndexedDbGroupManagerDb.prototype.addMemberPromise = function
34382 (scheduleName, keyName, key, useSync)
34383{
34384 if (useSync)
34385 return Promise.reject(new GroupManagerDb.Error(new Error
34386 ("IndexedDbGroupManagerDb.addMemberPromise is only supported for async")));
34387
34388 var thisManager = this;
34389 return this.getScheduleIdPromise_(scheduleName)
34390 .then(function(scheduleId) {
34391 if (scheduleId == -1)
34392 return Promise.reject(new GroupManagerDb.Error(new Error
34393 ("IndexedDbGroupManagerDb.addMemberPromise: The schedule does not exist")));
34394
34395 // Needs to be changed in the future.
34396 var memberName = keyName.getPrefix(-1);
34397
34398 // Add rejects if the primary key already exists.
34399 return thisManager.database.members.add
34400 ({ memberNameUri: memberName.toUri(),
34401 memberName: memberName.wireEncode(TlvWireFormat.get()).buf(),
34402 scheduleId: scheduleId,
34403 keyName: keyName.wireEncode(TlvWireFormat.get()).buf(),
34404 publicKey: key.buf() })
34405 .catch(function(ex) {
34406 return Promise.reject(new GroupManagerDb.Error(new Error
34407 ("IndexedDbGroupManagerDb.addMemberPromise: Error: " + ex)));
34408 });
34409 });
34410};
34411
34412/**
34413 * Change the name of the schedule for the given member's identity name.
34414 * @param {Name} identity The member's identity name.
34415 * @param {string} scheduleName The new schedule name.
34416 * @param {boolean} useSync (optional) If true then return a rejected promise
34417 * since this only supports async code.
34418 * @return {Promise} A promise that fulfills when the member is updated, or that
34419 * is rejected with GroupManagerDb.Error if there's no member with the given
34420 * identity name in the database, or there's no schedule named scheduleName, or
34421 * other database error.
34422 */
34423IndexedDbGroupManagerDb.prototype.updateMemberSchedulePromise = function
34424 (identity, scheduleName, useSync)
34425{
34426 if (useSync)
34427 return Promise.reject(new GroupManagerDb.Error(new Error
34428 ("IndexedDbGroupManagerDb.updateMemberSchedulePromise is only supported for async")));
34429
34430 var thisManager = this;
34431 return this.getScheduleIdPromise_(scheduleName)
34432 .then(function(scheduleId) {
34433 if (scheduleId == -1)
34434 return Promise.reject(new GroupManagerDb.Error(new Error
34435 ("IndexedDbGroupManagerDb.updateMemberSchedulePromise: The schedule does not exist")));
34436
34437 return thisManager.database.members.update
34438 (identity.toUri(), { scheduleId: scheduleId })
34439 .catch(function(ex) {
34440 return Promise.reject(new GroupManagerDb.Error(new Error
34441 ("IndexedDbGroupManagerDb.updateMemberSchedulePromise: Error: " + ex)));
34442 });
34443 });
34444};
34445
34446/**
34447 * Delete a member with the given identity name. If there is no member with
34448 * the identity name, then do nothing.
34449 * @param {Name} identity The member's identity name.
34450 * @param {boolean} useSync (optional) If true then return a rejected promise
34451 * since this only supports async code.
34452 * @return {Promise} A promise that fulfills when the member is deleted (or
34453 * there is no such member), or that is rejected with GroupManagerDb.Error for a
34454 * database error.
34455 */
34456IndexedDbGroupManagerDb.prototype.deleteMemberPromise = function
34457 (identity, useSync)
34458{
34459 if (useSync)
34460 return Promise.reject(new GroupManagerDb.Error(new Error
34461 ("IndexedDbGroupManagerDb.deleteMemberPromise is only supported for async")));
34462
34463 return this.database.members.delete(identity.toUri())
34464 .catch(function(ex) {
34465 return Promise.reject(new GroupManagerDb.Error(new Error
34466 ("IndexedDbGroupManagerDb.deleteMemberPromise: Error: " + ex)));
34467 });
34468};
34469
34470/**
34471 * Get the ID for the schedule.
34472 * @param {string} name The schedule name.
34473 * @return {Promise} A promise that returns the ID (or -1 if not found), or that
34474 * is rejected with GroupManagerDb.Error for a database error.
34475 */
34476IndexedDbGroupManagerDb.prototype.getScheduleIdPromise_ = function(name)
34477{
34478 // The scheduleName is not the primary key, so use 'where' instead of 'get'.
34479 var id = -1;
34480 return this.database.schedules.where("scheduleName").equals(name)
34481 .each(function(entry) {
34482 id = entry.scheduleId;
34483 })
34484 .then(function() {
34485 return Promise.resolve(id);
34486 })
34487 .catch(function(ex) {
34488 return Promise.reject(new GroupManagerDb.Error(new Error
34489 ("IndexedDbGroupManagerDb.getScheduleIdPromise_: Error: " + ex)));
34490 });
34491};
34492/**
34493 * Copyright (C) 2015-2016 Regents of the University of California.
34494 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
34495 *
34496 * This program is free software: you can redistribute it and/or modify
34497 * it under the terms of the GNU Lesser General Public License as published by
34498 * the Free Software Foundation, either version 3 of the License, or
34499 * (at your option) any later version.
34500 *
34501 * This program is distributed in the hope that it will be useful,
34502 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34503 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34504 * GNU Lesser General Public License for more details.
34505 *
34506 * You should have received a copy of the GNU Lesser General Public License
34507 * along with this program. If not, see <http://www.gnu.org/licenses/>.
34508 * A copy of the GNU Lesser General Public License is in the file COPYING.
34509 */
34510
34511// Don't require modules since this is meant for the browser, not Node.js.
34512
34513/**
34514 * IndexedDbProducerDb extends ProducerDb to implement storage of keys for the
34515 * producer using the browser's IndexedDB service. It contains one table that
34516 * maps time slots (to the nearest hour) to the content key created for that
34517 * time slot.
34518 * Create an IndexedDbProducerDb to use the given IndexedDB database name.
34519 * @param {string} databaseName IndexedDB database name.
34520 * @note This class is an experimental feature. The API may change.
34521 * @constructor
34522 */
34523var IndexedDbProducerDb = function IndexedDbProducerDb(databaseName)
34524{
34525 ProducerDb.call(this);
34526
34527 this.database = new Dexie(databaseName);
34528 this.database.version(1).stores({
34529 // "timeSlot" is the hour-based time slot as hours since Jan 1, 1970 UTC. // number
34530 // "key" is the encoded key // Uint8Array
34531 contentKeys: "timeSlot"
34532 });
34533 this.database.open();
34534};
34535
34536IndexedDbProducerDb.prototype = new ProducerDb();
34537IndexedDbProducerDb.prototype.name = "IndexedDbProducerDb";
34538
34539/**
34540 * Check if a content key exists for the hour covering timeSlot.
34541 * @param {number} timeSlot The time slot as milliseconds since Jan 1, 1970 UTC.
34542 * @param {boolean} useSync (optional) If true then return a rejected promise
34543 * since this only supports async code.
34544 * @return {Promise} A promise that returns true if there is a content key for
34545 * timeSlot (else false), or that is rejected with ProducerDb.Error for a
34546 * database error.
34547 */
34548IndexedDbProducerDb.prototype.hasContentKeyPromise = function(timeSlot, useSync)
34549{
34550 if (useSync)
34551 return Promise.reject(new ProducerDb.Error(new Error
34552 ("IndexedDbProducerDb.hasContentKeyPromise is only supported for async")));
34553
34554 var fixedTimeSlot = ProducerDb.getFixedTimeSlot(timeSlot);
34555
34556 return this.database.contentKeys.get(fixedTimeSlot)
34557 .then(function(contentKeysEntry) {
34558 return Promise.resolve(contentKeysEntry != undefined);
34559 })
34560 .catch(function(ex) {
34561 return Promise.reject(new ProducerDb.Error(new Error
34562 ("IndexedDbProducerDb.hasContentKeyPromise: Error: " + ex)));
34563 });
34564};
34565
34566/**
34567 * Get the content key for the hour covering timeSlot.
34568 * @param {number} timeSlot The time slot as milliseconds since Jan 1, 1970 UTC.
34569 * @param {boolean} useSync (optional) If true then return a rejected promise
34570 * since this only supports async code.
34571 * @return {Promise} A promise that returns a Blob with the encoded key, or that
34572 * is rejected with ProducerDb.Error if there is no key covering timeSlot, or
34573 * other database error
34574 */
34575IndexedDbProducerDb.prototype.getContentKeyPromise = function(timeSlot, useSync)
34576{
34577 if (useSync)
34578 return Promise.reject(new ProducerDb.Error(new Error
34579 ("IndexedDbProducerDb.getContentKeyPromise is only supported for async")));
34580
34581 var fixedTimeSlot = ProducerDb.getFixedTimeSlot(timeSlot);
34582
34583 return this.database.contentKeys.get(fixedTimeSlot)
34584 .then(function(contentKeysEntry) {
34585 if (contentKeysEntry)
34586 return Promise.resolve(new Blob(contentKeysEntry.key));
34587 else
34588 return Promise.reject(new ProducerDb.Error(new Error
34589 ("IndexedDbProducerDb.getContentKeyPromise: Cannot get the key from the database")));
34590 }, function(ex) {
34591 return Promise.reject(new ProducerDb.Error(new Error
34592 ("IndexedDbProducerDb.getContentKeyPromise: Error: " + ex)));
34593 });
34594};
34595
34596/**
34597 * Add key as the content key for the hour covering timeSlot.
34598 * @param {number} timeSlot The time slot as milliseconds since Jan 1, 1970 UTC.
34599 * @param {Blob} key The encoded key.
34600 * @param {boolean} useSync (optional) If true then return a rejected promise
34601 * since this only supports async code.
34602 * @return {Promise} A promise that fulfills when the key is added, or that
34603 * is rejected with ProducerDb.Error if a key for the same hour already exists
34604 * in the database, or other database error.
34605 */
34606IndexedDbProducerDb.prototype.addContentKeyPromise = function
34607 (timeSlot, key, useSync)
34608{
34609 if (useSync)
34610 return Promise.reject(new ProducerDb.Error(new Error
34611 ("IndexedDbProducerDb.addContentKeyPromise is only supported for async")));
34612
34613 var fixedTimeSlot = ProducerDb.getFixedTimeSlot(timeSlot);
34614
34615 // Add rejects if the primary key already exists.
34616 return this.database.contentKeys.add
34617 ({ timeSlot: fixedTimeSlot, key: key.buf() })
34618 .catch(function(ex) {
34619 return Promise.reject(new ProducerDb.Error(new Error
34620 ("IndexedDbProducerDb.addContentKeyPromise: Error: " + ex)));
34621 });
34622};
34623
34624/**
34625 * Delete the content key for the hour covering timeSlot. If there is no key for
34626 * the time slot, do nothing.
34627 * @param {number} timeSlot The time slot as milliseconds since Jan 1, 1970 UTC.
34628 * @param {boolean} useSync (optional) If true then return a rejected promise
34629 * since this only supports async code.
34630 * @return {Promise} A promise that fulfills when the key is deleted (or there
34631 * is no such key), or that is rejected with ProducerDb.Error for a database
34632 * error.
34633 */
34634IndexedDbProducerDb.prototype.deleteContentKeyPromise = function(timeSlot, useSync)
34635{
34636 if (useSync)
34637 return Promise.reject(new ProducerDb.Error(new Error
34638 ("IndexedDbProducerDb.deleteContentKeyPromise is only supported for async")));
34639
34640 var fixedTimeSlot = ProducerDb.getFixedTimeSlot(timeSlot);
34641
34642 return this.database.contentKeys.delete(fixedTimeSlot)
34643 .catch(function(ex) {
34644 return Promise.reject(new ProducerDb.Error(new Error
34645 ("IndexedDbProducerDb.deleteContentKeyPromise: Error: " + ex)));
34646 });
34647};
34648/**
34649 * This class represents the digest tree for chrono-sync2013.
34650 * Copyright (C) 2014-2016 Regents of the University of California.
34651 * @author: Zhehao Wang, based on Jeff T.'s implementation in ndn-cpp
34652 *
34653 * This program is free software: you can redistribute it and/or modify
34654 * it under the terms of the GNU Lesser General Public License as published by
34655 * the Free Software Foundation, either version 3 of the License, or
34656 * (at your option) any later version.
34657 *
34658 * This program is distributed in the hope that it will be useful,
34659 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34660 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34661 * GNU Lesser General Public License for more details.
34662 *
34663 * You should have received a copy of the GNU Lesser General Public License
34664 * along with this program. If not, see <http://www.gnu.org/licenses/>.
34665 * A copy of the GNU Lesser General Public License is in the file COPYING.
34666 */
34667
34668/** @ignore */
34669var DigestTree = require('./digest-tree.js').DigestTree; /** @ignore */
34670var Interest = require('../interest.js').Interest; /** @ignore */
34671var Data = require('../data.js').Data; /** @ignore */
34672var Name = require('../name.js').Name; /** @ignore */
34673var Blob = require('../util/blob.js').Blob; /** @ignore */
34674var MemoryContentCache = require('../util/memory-content-cache.js').MemoryContentCache; /** @ignore */
34675var SyncStateProto = require('./sync-state.js').SyncStateProto; /** @ignore */
34676var NdnCommon = require('../util/ndn-common.js').NdnCommon;
34677
34678/**
34679 * ChronoSync2013 implements the NDN ChronoSync protocol as described in the
34680 * 2013 paper "Let's ChronoSync: Decentralized Dataset State Synchronization in
34681 * Named Data Networking". http://named-data.net/publications/chronosync .
34682 * @note The support for ChronoSync is experimental and the API is not finalized.
34683 * See the API docs for more detail at
34684 * http://named-data.net/doc/ndn-ccl-api/chrono-sync2013.html .
34685 *
34686 * Create a new ChronoSync2013 to communicate using the given face. Initialize
34687 * the digest log with a digest of "00" and and empty content. Register the
34688 * applicationBroadcastPrefix to receive interests for sync state messages and
34689 * express an interest for the initial root digest "00".
34690 * @param {function} onReceivedSyncState When ChronoSync receives a sync state message,
34691 * this calls onReceivedSyncState(syncStates, isRecovery) where syncStates is the
34692 * list of SyncState messages and isRecovery is true if this is the initial
34693 * list of SyncState messages or from a recovery interest. (For example, if
34694 * isRecovery is true, a chat application would not want to re-display all
34695 * the associated chat messages.) The callback should send interests to fetch
34696 * the application data for the sequence numbers in the sync state.
34697 * NOTE: The library will log any exceptions thrown by this callback, but for
34698 * better error handling the callback should catch and properly handle any
34699 * exceptions.
34700 * @param {function} onInitialized This calls onInitialized() when the first sync data
34701 * is received (or the interest times out because there are no other
34702 * publishers yet).
34703 * NOTE: The library will log any exceptions thrown by this callback, but for
34704 * better error handling the callback should catch and properly handle any
34705 * exceptions.
34706 * @param {Name} applicationDataPrefix The prefix used by this application instance
34707 * for application data. For example, "/my/local/prefix/ndnchat4/0K4wChff2v".
34708 * This is used when sending a sync message for a new sequence number.
34709 * In the sync message, this uses applicationDataPrefix.toUri().
34710 * @param {Name} applicationBroadcastPrefix The broadcast name prefix including the
34711 * application name. For example, "/ndn/broadcast/ChronoChat-0.3/ndnchat1".
34712 * This makes a copy of the name.
34713 * @param {int} sessionNo The session number used with the applicationDataPrefix in
34714 * sync state messages.
34715 * @param {Face} face The Face for calling registerPrefix and expressInterest. The
34716 * Face object must remain valid for the life of this ChronoSync2013 object.
34717 * @param {KeyChain} keyChain To sign a data packet containing a sync state message, this
34718 * calls keyChain.sign(data, certificateName).
34719 * @param {Name} certificateName The certificate name of the key to use for signing a
34720 * data packet containing a sync state message.
34721 * @param {Milliseconds} syncLifetime The interest lifetime in milliseconds for sending
34722 * sync interests.
34723 * @param {function} onRegisterFailed If failed to register the prefix to receive
34724 * interests for the applicationBroadcastPrefix, this calls
34725 * onRegisterFailed(applicationBroadcastPrefix).
34726 * NOTE: The library will log any exceptions thrown by this callback, but for
34727 * better error handling the callback should catch and properly handle any
34728 * exceptions.
34729 * @constructor
34730 */
34731var ChronoSync2013 = function ChronoSync2013
34732 (onReceivedSyncState, onInitialized, applicationDataPrefix,
34733 applicationBroadcastPrefix, sessionNo, face, keyChain, certificateName,
34734 syncLifetime, onRegisterFailed)
34735{
34736 // assigning function pointers
34737 this.onReceivedSyncState = onReceivedSyncState;
34738 this.onInitialized = onInitialized;
34739 this.applicationDataPrefixUri = applicationDataPrefix.toUri();
34740 this.applicationBroadcastPrefix = applicationBroadcastPrefix;
34741 this.session = sessionNo;
34742 this.face = face;
34743 this.keyChain = keyChain;
34744 this.certificateName = certificateName;
34745 this.sync_lifetime = syncLifetime;
34746 this.usrseq = -1;
34747
34748 this.digest_tree = new DigestTree();
34749 this.contentCache = new MemoryContentCache(face);
34750
34751 this.digest_log = new Array();
34752 this.digest_log.push(new ChronoSync2013.DigestLogEntry("00",[]));
34753
34754 this.contentCache.registerPrefix
34755 (this.applicationBroadcastPrefix, onRegisterFailed,
34756 this.onInterest.bind(this));
34757 this.enabled = true;
34758
34759 var interest = new Interest(this.applicationBroadcastPrefix);
34760 interest.getName().append("00");
34761
34762 interest.setInterestLifetimeMilliseconds(1000);
34763
34764 var Sync;
34765 try {
34766 // Using protobuf.min.js in the browser.
34767 Sync = dcodeIO.ProtoBuf.newBuilder().import(SyncStateProto).build("Sync");
34768 }
34769 catch (ex) {
34770 // Using protobufjs in node.
34771 Sync = require("protobufjs").newBuilder().import(SyncStateProto).build("Sync");
34772 }
34773 this.SyncStateMsg = Sync.SyncStateMsg;
34774 this.SyncState = Sync.SyncState;
34775
34776 this.face.expressInterest(interest, this.onData.bind(this), this.initialTimeOut.bind(this));
34777};
34778
34779exports.ChronoSync2013 = ChronoSync2013;
34780
34781ChronoSync2013.prototype.getProducerSequenceNo = function(dataPrefix, sessionNo)
34782{
34783 var index = this.digest_tree.find(dataPrefix, sessionNo);
34784 if (index < 0)
34785 return -1;
34786 else
34787 return this.digest_tree.get(index).getSequenceNo();
34788};
34789
34790/**
34791 * Increment the sequence number, create a sync message with the new sequence number,
34792 * and publish a data packet where the name is applicationBroadcastPrefix + root
34793 * digest of current digest tree. Then add the sync message to digest tree and digest
34794 * log which creates a new root digest. Finally, express an interest for the next sync
34795 * update with the name applicationBroadcastPrefix + the new root digest.
34796 * After this, application should publish the content for the new sequence number.
34797 * Get the new sequence number with getSequenceNo().
34798 */
34799ChronoSync2013.prototype.publishNextSequenceNo = function()
34800{
34801 this.usrseq ++;
34802 var content = [new this.SyncState({ name:this.applicationDataPrefixUri,
34803 type:'UPDATE',
34804 seqno:{
34805 seq:this.usrseq,
34806 session:this.session
34807 }
34808 })];
34809 var content_t = new this.SyncStateMsg({ss:content});
34810 this.broadcastSyncState(this.digest_tree.getRoot(), content_t);
34811
34812 if (!this.update(content))
34813 console.log("Warning: ChronoSync: update did not create a new digest log entry");
34814
34815 var interest = new Interest(this.applicationBroadcastPrefix);
34816 interest.getName().append(this.digest_tree.getRoot());
34817 interest.setInterestLifetimeMilliseconds(this.sync_lifetime);
34818
34819 this.face.expressInterest(interest, this.onData.bind(this), this.syncTimeout.bind(this));
34820};
34821
34822/**
34823 * Get the sequence number of the latest data published by this application instance.
34824 * @return {int} the sequence number
34825 */
34826ChronoSync2013.prototype.getSequenceNo = function()
34827{
34828 return this.usrseq;
34829};
34830
34831// DigestLogEntry class
34832
34833ChronoSync2013.DigestLogEntry = function ChronoSync2013DisgestLogEntry(digest, data)
34834{
34835 this.digest = digest;
34836 this.data = data;
34837};
34838
34839ChronoSync2013.DigestLogEntry.prototype.getDigest = function()
34840{
34841 return this.digest;
34842};
34843
34844ChronoSync2013.DigestLogEntry.prototype.getData = function()
34845{
34846 return this.data;
34847};
34848
34849/**
34850 * Unregister callbacks so that this does not respond to interests anymore.
34851 * If you will dispose this ChronoSync2013 object while your application is
34852 * still running, you should call shutdown() first. After calling this, you
34853 * should not call publishNextSequenceNo() again since the behavior will be
34854 * undefined.
34855 */
34856ChronoSync2013.prototype.shutdown = function()
34857{
34858 this.enabled = false;
34859 this.contentCache.unregisterAll();
34860};
34861
34862// SyncState class
34863/**
34864 * A SyncState holds the values of a sync state message which is passed to the
34865 * onReceivedSyncState callback which was given to the ChronoSyn2013
34866 * constructor. Note: this has the same info as the Protobuf class
34867 * Sync::SyncState, but we make a separate class so that we don't need the
34868 * Protobuf definition in the ChronoSync API.
34869 */
34870ChronoSync2013.SyncState = function ChronoSync2013SyncState(dataPrefixUri, sessionNo, sequenceNo)
34871{
34872 this.dataPrefixUri_ = dataPrefixUri;
34873 this.sessionNo_ = sessionNo;
34874 this.sequenceNo_ = sequenceNo;
34875};
34876
34877/**
34878 * Get the application data prefix for this sync state message.
34879 * @return The application data prefix as a Name URI string.
34880 */
34881ChronoSync2013.SyncState.prototype.getDataPrefix = function()
34882{
34883 return this.dataPrefixUri_;
34884}
34885
34886/**
34887 * Get the session number associated with the application data prefix for
34888 * this sync state message.
34889 * @return The session number.
34890 */
34891ChronoSync2013.SyncState.prototype.getSessionNo = function()
34892{
34893 return this.sessionNo_;
34894}
34895
34896/**
34897 * Get the sequence number for this sync state message.
34898 * @return The sequence number.
34899 */
34900ChronoSync2013.SyncState.prototype.getSequenceNo = function()
34901{
34902 return this.sequenceNo_;
34903}
34904
34905// Private methods for ChronoSync2013 class,
34906/**
34907 * Make a data packet with the syncMessage and with name applicationBroadcastPrefix_ + digest.
34908 * Sign and send.
34909 * @param {string} The root digest as a hex string for the data packet name.
34910 * @param {SyncStateMsg} The syncMessage updates the digest tree state with the given digest.
34911 */
34912ChronoSync2013.prototype.broadcastSyncState = function(digest, syncMessage)
34913{
34914 var array = new Uint8Array(syncMessage.toArrayBuffer());
34915 var data = new Data(this.applicationBroadcastPrefix);
34916 data.getName().append(digest);
34917 data.setContent(new Blob(array, false));
34918 var thisChronoSync = this;
34919 this.keyChain.sign(data, this.certificateName, function() {
34920 thisChronoSync.contentCache.add(data);
34921 });
34922};
34923
34924/**
34925 * Update the digest tree with the messages in content. If the digest tree root is not in
34926 * the digest log, also add a log entry with the content.
34927 * @param {SyncStates[]} The sync state messages
34928 * @return {bool} True if added a digest log entry (because the updated digest tree root
34929 * was not in the log), false if didn't add a log entry.
34930 */
34931 // Whatever's received by ondata, is pushed into digest log as its data directly
34932ChronoSync2013.prototype.update = function(content)
34933{
34934 for (var i = 0; i < content.length; i++) {
34935 if (content[i].type == 0) {
34936 if (this.digest_tree.update(content[i].name, content[i].seqno.session, content[i].seqno.seq)) {
34937 if (this.applicationDataPrefixUri == content[i].name)
34938 this.usrseq = content[i].seqno.seq;
34939 }
34940 }
34941 }
34942
34943 if (this.logfind(this.digest_tree.getRoot()) == -1) {
34944 var newlog = new ChronoSync2013.DigestLogEntry(this.digest_tree.getRoot(), content);
34945 this.digest_log.push(newlog);
34946 return true;
34947 }
34948 else
34949 return false;
34950};
34951
34952ChronoSync2013.prototype.logfind = function(digest)
34953{
34954 for (var i = 0; i < this.digest_log.length; i++) {
34955 if(digest == this.digest_log[i].digest)
34956 return i;
34957 }
34958 return -1;
34959};
34960
34961/**
34962 * Process the sync interest from the applicationBroadcastPrefix. If we can't
34963 * satisfy the interest, add it to the pending interest table in
34964 * this.contentCache so that a future call to contentCacheAdd may satisfy it.
34965 */
34966ChronoSync2013.prototype.onInterest = function
34967 (prefix, interest, face, interestFilterId, filter)
34968{
34969 if (!this.enabled)
34970 // Ignore callbacks after the application calls shutdown().
34971 return;
34972
34973 //search if the digest is already exist in the digest log
34974
34975 var syncdigest = interest.getName().get(this.applicationBroadcastPrefix.size()).toEscapedString();
34976 if (interest.getName().size() == this.applicationBroadcastPrefix.size() + 2) {
34977 syncdigest = interest.getName().get(this.applicationBroadcastPrefix.size() + 1).toEscapedString();
34978 }
34979 if (interest.getName().size() == this.applicationBroadcastPrefix.size() + 2 || syncdigest == "00") {
34980 this.processRecoveryInst(interest, syncdigest, face);
34981 }
34982 else {
34983 this.contentCache.storePendingInterest(interest, face);
34984
34985 if (syncdigest != this.digest_tree.getRoot()) {
34986 var index = this.logfind(syncdigest);
34987 var content = [];
34988 if(index == -1) {
34989 var self = this;
34990 // Are we sure that using a "/local/timeout" interest is the best future call approach?
34991 var timeout = new Interest(new Name("/local/timeout"));
34992 timeout.setInterestLifetimeMilliseconds(2000);
34993 this.face.expressInterest
34994 (timeout, this.dummyOnData,
34995 this.judgeRecovery.bind(this, timeout, syncdigest, face));
34996 }
34997 else {
34998 //common interest processing
34999 this.processSyncInst(index, syncdigest, face);
35000 }
35001 }
35002 }
35003};
35004
35005/**
35006 * Process sync/recovery data.
35007 * @param {Interest}
35008 * @param {Data}
35009 */
35010ChronoSync2013.prototype.onData = function(interest, co)
35011{
35012 if (!this.enabled)
35013 // Ignore callbacks after the application calls shutdown().
35014 return;
35015
35016 var arr = new Uint8Array(co.getContent().size());
35017 arr.set(co.getContent().buf());
35018 var content_t = this.SyncStateMsg.decode(arr.buffer);
35019 var content = content_t.ss;
35020
35021 var isRecovery = false;
35022
35023 if (this.digest_tree.getRoot() == "00") {
35024 isRecovery = true;
35025 this.initialOndata(content);
35026 }
35027 else {
35028 this.update(content);
35029 if (interest.getName().size() == this.applicationBroadcastPrefix.size() + 2)
35030 // Assume this is a recovery interest.
35031 isRecovery = true;
35032 else
35033 isRecovery = false;
35034 }
35035
35036 var syncStates = [];
35037
35038 for (var i = 0; i < content.length; i++) {
35039 if (content[i].type == 0) {
35040 syncStates.push(new ChronoSync2013.SyncState
35041 (content[i].name, content[i].seqno.session, content[i].seqno.seq));
35042 }
35043 }
35044
35045 // Instead of using Protobuf, use our own definition of SyncStates to pass to onReceivedSyncState.
35046 try {
35047 this.onReceivedSyncState(syncStates, isRecovery);
35048 } catch (ex) {
35049 console.log("Error in onReceivedSyncState: " + NdnCommon.getErrorWithStackTrace(ex));
35050 }
35051
35052 var n = new Name(this.applicationBroadcastPrefix);
35053 n.append(this.digest_tree.getRoot());
35054
35055 var interest = new Interest(n);
35056 interest.setInterestLifetimeMilliseconds(this.sync_lifetime);
35057
35058 this.face.expressInterest(interest, this.onData.bind(this), this.syncTimeout.bind(this));
35059};
35060
35061/**
35062 * Interest variable not actually in use here
35063 */
35064ChronoSync2013.prototype.initialTimeOut = function(interest)
35065{
35066 if (!this.enabled)
35067 // Ignore callbacks after the application calls shutdown().
35068 return;
35069
35070 console.log("no other people");
35071
35072 this.usrseq++;
35073 try {
35074 this.onInitialized();
35075 } catch (ex) {
35076 console.log("Error in onInitialized: " + NdnCommon.getErrorWithStackTrace(ex));
35077 }
35078 var content = [new this.SyncState({ name:this.applicationDataPrefixUri,
35079 type:'UPDATE',
35080 seqno: {
35081 seq:this.usrseq,
35082 session:this.session
35083 }
35084 })];
35085 this.update(content);
35086 var n = new Name(this.applicationBroadcastPrefix);
35087 n.append(this.digest_tree.getRoot());
35088 var retryInterest = new Interest(n);
35089 retryInterest.setInterestLifetimeMilliseconds(this.sync_lifetime);
35090
35091 this.face.expressInterest(retryInterest, this.onData.bind(this), this.syncTimeout.bind(this));
35092};
35093
35094ChronoSync2013.prototype.processRecoveryInst = function(interest, syncdigest, face)
35095{
35096 if (this.logfind(syncdigest) != -1) {
35097 var content = [];
35098
35099 for(var i = 0; i < this.digest_tree.digestnode.length; i++) {
35100 content[i] = new this.SyncState({ name:this.digest_tree.digestnode[i].getDataPrefix(),
35101 type:'UPDATE',
35102 seqno:{
35103 seq:this.digest_tree.digestnode[i].getSequenceNo(),
35104 session:this.digest_tree.digestnode[i].getSessionNo()
35105 }
35106 });
35107 }
35108
35109 if (content.length != 0) {
35110 var content_t = new this.SyncStateMsg({ss:content});
35111 var str = new Uint8Array(content_t.toArrayBuffer());
35112 var co = new Data(interest.getName());
35113 co.setContent(new Blob(str, false));
35114 if (interest.getName().get(-1).toEscapedString() == "00")
35115 // Limit the lifetime of replies to interest for "00" since they can be different.
35116 co.getMetaInfo().setFreshnessPeriod(1000);
35117
35118 this.keyChain.sign(co, this.certificateName, function() {
35119 try {
35120 face.putData(co);
35121 } catch (e) {
35122 console.log(e.toString());
35123 }
35124 });
35125 }
35126 }
35127};
35128
35129/**
35130 * Common interest processing, using digest log to find the difference after syncdigest_t
35131 * @return True if sent a data packet to satisfy the interest.
35132 */
35133ChronoSync2013.prototype.processSyncInst = function(index, syncdigest_t, face)
35134{
35135 var content = [];
35136 var data_name = [];
35137 var data_seq = [];
35138 var data_ses = [];
35139
35140 for (var j = index + 1; j < this.digest_log.length; j++) {
35141 var temp = this.digest_log[j].getData();
35142 for (var i = 0 ; i < temp.length ; i++) {
35143 if (temp[i].type != 0) {
35144 continue;
35145 }
35146 if (this.digest_tree.find(temp[i].name, temp[i].seqno.session) != -1) {
35147 var n = data_name.indexOf(temp[i].name);
35148 if (n == -1) {
35149 data_name.push(temp[i].name);
35150 data_seq.push(temp[i].seqno.seq);
35151 data_ses.push(temp[i].seqno.session);
35152 }
35153 else {
35154 data_seq[n] = temp[i].seqno.seq;
35155 data_ses[n] = temp[i].seqno.session;
35156 }
35157 }
35158 }
35159 }
35160
35161 for(var i = 0; i < data_name.length; i++) {
35162 content[i] = new this.SyncState({ name:data_name[i],
35163 type:'UPDATE',
35164 seqno: {
35165 seq:data_seq[i],
35166 session:data_ses[i]
35167 }
35168 });
35169 }
35170 if (content.length != 0) {
35171 var content_t = new this.SyncStateMsg({ss:content});
35172 var str = new Uint8Array(content_t.toArrayBuffer());
35173 var n = new Name(this.prefix)
35174 n.append(this.chatroom).append(syncdigest_t);
35175
35176 var co = new Data(n);
35177 co.setContent(new Blob(str, false));
35178 this.keyChain.sign(co, this.certificateName, function() {
35179 try {
35180 face.putData(co);
35181 }
35182 catch (e) {
35183 console.log(e.toString());
35184 }
35185 });
35186 }
35187};
35188
35189/**
35190 * Send recovery interset.
35191 * @param {string} syncdigest_t
35192 */
35193ChronoSync2013.prototype.sendRecovery = function(syncdigest_t)
35194{
35195 var n = new Name(this.applicationBroadcastPrefix);
35196 n.append("recovery").append(syncdigest_t);
35197
35198 var interest = new Interest(n);
35199
35200 interest.setInterestLifetimeMilliseconds(this.sync_lifetime);
35201
35202 this.face.expressInterest(interest, this.onData.bind(this), this.syncTimeout.bind(this));
35203};
35204
35205/**
35206 * This is called by onInterest after a timeout to check if a recovery is needed.
35207 * This method has an interest argument because we use it as the onTimeout for
35208 * Face.expressInterest.
35209 * @param {Interest}
35210 * @param {string}
35211 * @param {Face}
35212 */
35213ChronoSync2013.prototype.judgeRecovery = function(interest, syncdigest_t, face)
35214{
35215 //console.log("*** judgeRecovery interest " + interest.getName().toUri() + " times out. Digest: " + syncdigest_t + " ***");
35216 var index = this.logfind(syncdigest_t);
35217 if (index != -1) {
35218 if (syncdigest_t != this.digest_tree.root)
35219 this.processSyncInst(index, syncdigest_t, face);
35220 }
35221 else
35222 this.sendRecovery(syncdigest_t);
35223};
35224
35225ChronoSync2013.prototype.syncTimeout = function(interest)
35226{
35227 if (!this.enabled)
35228 // Ignore callbacks after the application calls shutdown().
35229 return;
35230
35231 var component = interest.getName().get(4).toEscapedString();
35232 if (component == this.digest_tree.root) {
35233 var n = new Name(interest.getName());
35234 var newInterest = new Interest(n);
35235
35236 interest.setInterestLifetimeMilliseconds(this.sync_lifetime);
35237 this.face.expressInterest(newInterest, this.onData.bind(this), this.syncTimeout.bind(this));
35238 }
35239};
35240
35241ChronoSync2013.prototype.initialOndata = function(content)
35242{
35243 this.update(content);
35244
35245 var digest_t = this.digest_tree.getRoot();
35246 for (var i = 0; i < content.length; i++) {
35247 if (content[i].name == this.applicationDataPrefixUri && content[i].seqno.session == this.session) {
35248 //if the user was an old comer, after add the static log he need to increase his seqno by 1
35249 var content_t = [new this.SyncState({ name:this.applicationDataPrefixUri,
35250 type:'UPDATE',
35251 seqno: {
35252 seq:content[i].seqno.seq + 1,
35253 session:this.session
35254 }
35255 })];
35256 if (this.update(content_t)) {
35257 var newlog = new ChronoSync2013.DigestLogEntry(this.digest_tree.getRoot(), content_t);
35258 this.digest_log.push(newlog);
35259 try {
35260 this.onInitialized();
35261 } catch (ex) {
35262 console.log("Error in onInitialized: " + NdnCommon.getErrorWithStackTrace(ex));
35263 }
35264 }
35265 }
35266 }
35267
35268 var content_t;
35269 if (this.usrseq >= 0) {
35270 //send the data packet with new seqno back
35271 content_t = new this.SyncState({ name:this.applicationDataPrefixUri,
35272 type:'UPDATE',
35273 seqno: {
35274 seq:this.usrseq,
35275 session:this.session
35276 }
35277 });
35278 }
35279 else
35280 content_t = new this.SyncState({ name:this.applicationDataPrefixUri,
35281 type:'UPDATE',
35282 seqno: {
35283 seq:0,
35284 session:this.session
35285 }
35286 });
35287 var content_tt = new this.SyncStateMsg({ss:content_t});
35288 this.broadcastSyncState(digest_t, content_tt);
35289
35290 if (this.digest_tree.find(this.applicationDataPrefixUri, this.session) == -1) {
35291 //the user haven't put himself in the digest tree
35292 this.usrseq++;
35293 var content = [new this.SyncState({ name:this.applicationDataPrefixUri,
35294 type:'UPDATE',
35295 seqno: {
35296 seq:this.usrseq,
35297 session:this.session
35298 }
35299 })];
35300 if (this.update(content)) {
35301 try {
35302 this.onInitialized();
35303 } catch (ex) {
35304 console.log("Error in onInitialized: " + NdnCommon.getErrorWithStackTrace(ex));
35305 }
35306 }
35307 }
35308};
35309
35310ChronoSync2013.prototype.dummyOnData = function(interest, data)
35311{
35312 console.log("*** dummyOnData called. ***");
35313};/**
35314 * This class represents the digest tree for chrono-sync2013.
35315 * Copyright (C) 2014-2016 Regents of the University of California.
35316 * @author: Zhehao Wang, based on Jeff T.'s implementation in ndn-cpp
35317 *
35318 * This program is free software: you can redistribute it and/or modify
35319 * it under the terms of the GNU Lesser General Public License as published by
35320 * the Free Software Foundation, either version 3 of the License, or
35321 * (at your option) any later version.
35322 *
35323 * This program is distributed in the hope that it will be useful,
35324 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35325 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35326 * GNU Lesser General Public License for more details.
35327 *
35328 * You should have received a copy of the GNU Lesser General Public License
35329 * along with this program. If not, see <http://www.gnu.org/licenses/>.
35330 * A copy of the GNU Lesser General Public License is in the file COPYING.
35331 */
35332
35333// Use capitalized Crypto to not clash with the browser's crypto.subtle.
35334/** @ignore */
35335var Crypto = require('../crypto.js');
35336
35337/**
35338 * @constructor
35339 */
35340var DigestTree = function DigestTree()
35341{
35342 this.root = "00";
35343 this.digestnode = [];
35344};
35345
35346exports.DigestTree = DigestTree;
35347
35348// The meaning of a session is explained here:
35349// http://named-data.net/doc/ndn-ccl-api/chrono-sync2013.html
35350// DigestTree.Node works with seqno_seq and seqno_session, without protobuf definition,
35351DigestTree.Node = function DigestTreeNode(dataPrefix, seqno_session, seqno_seq)
35352{
35353 // In this context, this should mean DigestTree.Node instead
35354 this.dataPrefix = dataPrefix;
35355 this.seqno_session = seqno_session;
35356 this.seqno_seq = seqno_seq;
35357
35358 this.recomputeDigest();
35359};
35360
35361DigestTree.Node.prototype.getDataPrefix = function()
35362{
35363 return this.dataPrefix;
35364};
35365
35366DigestTree.Node.prototype.getSessionNo = function()
35367{
35368 return this.seqno_session;
35369};
35370
35371DigestTree.Node.prototype.getSequenceNo = function()
35372{
35373 return this.seqno_seq;
35374};
35375
35376DigestTree.Node.prototype.getDigest = function()
35377{
35378 return this.digest;
35379};
35380
35381DigestTree.Node.prototype.setSequenceNo = function(sequenceNo)
35382{
35383 this.seqno_seq = sequenceNo;
35384 this.recomputeDigest();
35385};
35386
35387// Using Node.JS buffer, as documented here http://nodejs.org/api/buffer.html.
35388DigestTree.Node.prototype.Int32ToBuffer = function(value) {
35389 var result = new Buffer(4);
35390 for (var i = 0; i < 4; i++) {
35391 result[i] = value % 256;
35392 value = Math.floor(value / 256);
35393 }
35394 return result;
35395}
35396
35397DigestTree.Node.prototype.recomputeDigest = function()
35398{
35399 var seqHash = Crypto.createHash('sha256');
35400
35401 seqHash.update(this.Int32ToBuffer(this.seqno_session));
35402 seqHash.update(this.Int32ToBuffer(this.seqno_seq));
35403
35404 var digest_seq = seqHash.digest();
35405
35406 var nameHash = Crypto.createHash('sha256');
35407 nameHash.update(this.dataPrefix);
35408 var digest_name = nameHash.digest();
35409
35410 var hash = Crypto.createHash('sha256');
35411 hash.update(digest_name);
35412 hash.update(digest_seq);
35413
35414 this.digest = hash.digest('hex');
35415};
35416
35417// Do the work of string and then sequence number compare
35418DigestTree.Node.Compare = function(node1, node2)
35419{
35420 if (node1.dataPrefix != node2.dataPrefix)
35421 return node1.dataPrefix < node2.dataPrefix;
35422 return node1.seqno_session < node2.seqno_session;
35423};
35424
35425/**
35426 * Update the digest tree and recompute the root digest. If the combination of dataPrefix
35427 * and sessionNo already exists in the tree then update its sequenceNo (only if the given
35428 * sequenceNo is newer), otherwise add a new node.
35429 * @param {string} The name prefix.
35430 * @param {int} sessionNo The session number.
35431 * @param {int} sequenceNo The sequence number.
35432 * @return True if the digest tree is updated, false if not
35433 */
35434DigestTree.prototype.update = function(dataPrefix, sessionNo, sequenceNo)
35435{
35436 var n_index = this.find(dataPrefix, sessionNo);
35437 if (n_index >= 0) {
35438 if (this.digestnode[n_index].getSequenceNo() < sequenceNo)
35439 this.digestnode[n_index].setSequenceNo(sequenceNo);
35440 else
35441 return false;
35442 }
35443 else {
35444 var temp = new DigestTree.Node(dataPrefix, sessionNo, sequenceNo);
35445 this.digestnode.push(temp);
35446 this.digestnode.sort(this.sortNodes);
35447 }
35448 this.recomputeRoot();
35449 return true;
35450};
35451
35452// Need to confirm this sort works with the insertion in ndn-cpp.
35453DigestTree.prototype.sortNodes = function()
35454{
35455 var temp;
35456 for (var i = this.digestnode.length; i > 0; i--) {
35457 for (var j = 0; j < i - 1; j++) {
35458 if (this.digestnode[j].getDataPrefix() > this.digestnode[j + 1].getDataPrefix()) {
35459 temp = this.digestnode[j];
35460 this.digestnode[j] = this.digestnode[j + 1];
35461 this.digestnode[j + 1] = temp;
35462 }
35463 }
35464 }
35465};
35466
35467DigestTree.prototype.sortNodes = function (node1, node2)
35468{
35469 if (node1.getDataPrefix() == node2.getDataPrefix() &&
35470 node1.getSessionNo() == node2.getSessionNo())
35471 return 0;
35472
35473 if ((node1.getDataPrefix() > node2.getDataPrefix()) ||
35474 ((node1.getDataPrefix() == node2.getDataPrefix()) &&
35475 (node1.getSessionNo() >node2.getSessionNo())))
35476 return 1;
35477 else
35478 return -1;
35479}
35480
35481DigestTree.prototype.find = function(dataPrefix, sessionNo)
35482{
35483 for (var i = 0; i < this.digestnode.length; ++i) {
35484 if (this.digestnode[i].getDataPrefix() == dataPrefix &&
35485 this.digestnode[i].getSessionNo() == sessionNo)
35486 return i;
35487 }
35488 return -1;
35489};
35490
35491DigestTree.prototype.size = function()
35492{
35493 return this.digestnode.size();
35494};
35495
35496// Not really used
35497DigestTree.prototype.get = function(i)
35498{
35499 return this.digestnode[i];
35500};
35501
35502DigestTree.prototype.getRoot = function()
35503{
35504 return this.root;
35505};
35506
35507DigestTree.prototype.recomputeRoot = function()
35508{
35509 var md = Crypto.createHash('sha256');
35510 // The result of updateHex is related with the sequence of participants,
35511 // I don't think that should be the case.
35512 for (var i = 0; i < this.digestnode.length; i++) {
35513 md.update(new Buffer(this.digestnode[i].digest, 'hex'));
35514 }
35515 this.root = md.digest('hex');
35516};
35517// Just define the SyncStateProto object. We do a Protobuf import dynamically
35518// when we need it so that protobufjs is optional.
35519var SyncStateProto = {
35520 "package": "Sync",
35521 "messages": [
35522 {
35523 "name": "SyncState",
35524 "fields": [
35525 {
35526 "rule": "required",
35527 "type": "string",
35528 "name": "name",
35529 "id": 1,
35530 "options": {}
35531 },
35532 {
35533 "rule": "required",
35534 "type": "ActionType",
35535 "name": "type",
35536 "id": 2,
35537 "options": {}
35538 },
35539 {
35540 "rule": "optional",
35541 "type": "SeqNo",
35542 "name": "seqno",
35543 "id": 3,
35544 "options": {}
35545 }
35546 ],
35547 "enums": [
35548 {
35549 "name": "ActionType",
35550 "values": [
35551 {
35552 "name": "UPDATE",
35553 "id": 0
35554 },
35555 {
35556 "name": "DELETE",
35557 "id": 1
35558 },
35559 {
35560 "name": "OTHER",
35561 "id": 2
35562 }
35563 ],
35564 "options": {}
35565 }
35566 ],
35567 "messages": [
35568 {
35569 "name": "SeqNo",
35570 "fields": [
35571 {
35572 "rule": "required",
35573 "type": "uint32",
35574 "name": "seq",
35575 "id": 1,
35576 "options": {}
35577 },
35578 {
35579 "rule": "required",
35580 "type": "uint32",
35581 "name": "session",
35582 "id": 2,
35583 "options": {}
35584 }
35585 ],
35586 "enums": [],
35587 "messages": [],
35588 "options": {}
35589 }
35590 ],
35591 "options": {}
35592 },
35593 {
35594 "name": "SyncStateMsg",
35595 "fields": [
35596 {
35597 "rule": "repeated",
35598 "type": "SyncState",
35599 "name": "ss",
35600 "id": 1,
35601 "options": {}
35602 }
35603 ],
35604 "enums": [],
35605 "messages": [],
35606 "options": {}
35607 }
35608 ],
35609 "enums": [],
35610 "imports": [],
35611 "options": {}
35612};
35613
35614exports.SyncStateProto = SyncStateProto;
35615/**
35616 * Copyright (C) 2014-2016 Regents of the University of California.
35617 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
35618 *
35619 * This program is free software: you can redistribute it and/or modify
35620 * it under the terms of the GNU Lesser General Public License as published by
35621 * the Free Software Foundation, either version 3 of the License, or
35622 * (at your option) any later version.
35623 *
35624 * This program is distributed in the hope that it will be useful,
35625 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35626 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35627 * GNU Lesser General Public License for more details.
35628 *
35629 * You should have received a copy of the GNU Lesser General Public License
35630 * along with this program. If not, see <http://www.gnu.org/licenses/>.
35631 * A copy of the GNU Lesser General Public License is in the file COPYING.
35632 */
35633
35634// Use capitalized Crypto to not clash with the browser's crypto.subtle.
35635/** @ignore */
35636var Crypto = require('../crypto.js'); /** @ignore */
35637var WireFormat = require('../encoding/wire-format.js').WireFormat; /** @ignore */
35638var TlvEncoder = require('../encoding/tlv/tlv-encoder.js').TlvEncoder; /** @ignore */
35639var Blob = require('./blob.js').Blob;
35640
35641/**
35642 * A CommandInterestGenerator keeps track of a timestamp and generates command
35643 * interests according to the NFD Signed Command Interests protocol:
35644 * http://redmine.named-data.net/projects/nfd/wiki/Command_Interests
35645 *
35646 * Create a new CommandInterestGenerator and initialize the timestamp to now.
35647 * @constructor
35648 */
35649var CommandInterestGenerator = function CommandInterestGenerator()
35650{
35651 this.lastTimestamp = Math.round(new Date().getTime());
35652};
35653
35654exports.CommandInterestGenerator = CommandInterestGenerator;
35655
35656/**
35657 * Append a timestamp component and a random value component to interest's name.
35658 * This ensures that the timestamp is greater than the timestamp used in the
35659 * previous call. Then use keyChain to sign the interest which appends a
35660 * SignatureInfo component and a component with the signature bits. If the
35661 * interest lifetime is not set, this sets it.
35662 * @param {Interest} interest The interest whose name is append with components.
35663 * @param {KeyChain} keyChain The KeyChain for calling sign.
35664 * @param {Name} certificateName The certificate name of the key to use for
35665 * signing.
35666 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
35667 * the SignatureInfo and to encode interest name for signing. If omitted, use
35668 * WireFormat.getDefaultWireFormat().
35669 * @param {function} onComplete (optional) This calls onComplete() when complete.
35670 * (Some crypto/database libraries only use a callback, so onComplete is
35671 * required to use these.)
35672 */
35673CommandInterestGenerator.prototype.generate = function
35674 (interest, keyChain, certificateName, wireFormat, onComplete)
35675{
35676 onComplete = (typeof wireFormat === "function") ? wireFormat : onComplete;
35677 wireFormat = (typeof wireFormat === "function" || !wireFormat) ?
35678 WireFormat.getDefaultWireFormat() : wireFormat;
35679
35680 var timestamp = Math.round(new Date().getTime());
35681 while (timestamp <= this.lastTimestamp)
35682 timestamp += 1.0;
35683
35684 // The timestamp is encoded as a TLV nonNegativeInteger.
35685 var encoder = new TlvEncoder(8);
35686 encoder.writeNonNegativeInteger(timestamp);
35687 interest.getName().append(new Blob(encoder.getOutput(), false));
35688
35689 // The random value is a TLV nonNegativeInteger too, but we know it is 8
35690 // bytes, so we don't need to call the nonNegativeInteger encoder.
35691 interest.getName().append(new Blob(Crypto.randomBytes(8), false));
35692
35693 // Update the timestamp before calling async sign.
35694 this.lastTimestamp = timestamp;
35695
35696 keyChain.sign(interest, certificateName, wireFormat, function() {
35697 if (interest.getInterestLifetimeMilliseconds() == null ||
35698 interest.getInterestLifetimeMilliseconds() < 0)
35699 // The caller has not set the interest lifetime, so set it here.
35700 interest.setInterestLifetimeMilliseconds(1000.0);
35701
35702 if (onComplete)
35703 onComplete();
35704 });
35705};
35706/**
35707 * Copyright (C) 2016 Regents of the University of California.
35708 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
35709 *
35710 * This program is free software: you can redistribute it and/or modify
35711 * it under the terms of the GNU Lesser General Public License as published by
35712 * the Free Software Foundation, either version 3 of the License, or
35713 * (at your option) any later version.
35714 *
35715 * This program is distributed in the hope that it will be useful,
35716 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35717 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35718 * GNU Lesser General Public License for more details.
35719 *
35720 * You should have received a copy of the GNU Lesser General Public License
35721 * along with this program. If not, see <http://www.gnu.org/licenses/>.
35722 * A copy of the GNU Lesser General Public License is in the file COPYING.
35723 */
35724
35725/** @ignore */
35726var LOG = require('../log.js').Log.LOG;
35727
35728/**
35729 * An InterestFilterTable is an internal class to hold a list of entries with
35730 * an interest Filter and its OnInterestCallback.
35731 * @constructor
35732 */
35733var InterestFilterTable = function InterestFilterTable()
35734{
35735 this.table_ = []; // of Entry
35736};
35737
35738exports.InterestFilterTable = InterestFilterTable;
35739
35740/**
35741 * InterestFilterTable.Entry holds an interestFilterId, an InterestFilter and
35742 * the OnInterestCallback with its related Face.
35743 * Create a new Entry with the given values.
35744 * @param {number} interestFilterId The ID from getNextEntryId().
35745 * @param {InterestFilter} filter The InterestFilter for this entry.
35746 * @param {function} onInterest The callback to call.
35747 * @param {Face} face The face on which was called registerPrefix or
35748 * setInterestFilter which is passed to the onInterest callback.
35749 * @constructor
35750 */
35751InterestFilterTable.Entry = function InterestFilterTableEntry
35752 (interestFilterId, filter, onInterest, face)
35753{
35754 this.interestFilterId_ = interestFilterId;
35755 this.filter_ = filter;
35756 this.onInterest_ = onInterest;
35757 this.face_ = face;
35758};
35759
35760/**
35761 * Get the interestFilterId given to the constructor.
35762 * @return {number} The interestFilterId.
35763 */
35764InterestFilterTable.Entry.prototype.getInterestFilterId = function()
35765{
35766 return this.interestFilterId_;
35767};
35768
35769/**
35770 * Get the InterestFilter given to the constructor.
35771 * @return {InterestFilter} The InterestFilter.
35772 */
35773InterestFilterTable.Entry.prototype.getFilter = function()
35774{
35775 return this.filter_;
35776};
35777
35778/**
35779 * Get the onInterest callback given to the constructor.
35780 * @return {function} The onInterest callback.
35781 */
35782InterestFilterTable.Entry.prototype.getOnInterest = function()
35783{
35784 return this.onInterest_;
35785};
35786
35787/**
35788 * Get the Face given to the constructor.
35789 * @return {Face} The Face.
35790 */
35791InterestFilterTable.Entry.prototype.getFace = function()
35792{
35793 return this.face_;
35794};
35795
35796/**
35797 * Add a new entry to the table.
35798 * @param {number} interestFilterId The ID from Node.getNextEntryId().
35799 * @param {InterestFilter} filter The InterestFilter for this entry.
35800 * @param {function} onInterest The callback to call.
35801 * @param {Face} face The face on which was called registerPrefix or
35802 * setInterestFilter which is passed to the onInterest callback.
35803 */
35804InterestFilterTable.prototype.setInterestFilter = function
35805 (interestFilterId, filter, onInterest, face)
35806{
35807 this.table_.push(new InterestFilterTable.Entry
35808 (interestFilterId, filter, onInterest, face));
35809};
35810
35811/**
35812 * Find all entries from the interest filter table where the interest conforms
35813 * to the entry's filter, and add to the matchedFilters list.
35814 * @param {Interest} interest The interest which may match the filter in
35815 * multiple entries.
35816 * @param {Array<InterestFilterTable.Entry>} matchedFilters Add each matching
35817 * InterestFilterTable.Entry from the interest filter table. The caller should
35818 * pass in an empty array.
35819 */
35820InterestFilterTable.prototype.getMatchedFilters = function
35821 (interest, matchedFilters)
35822{
35823 for (var i = 0; i < this.table_.length; ++i) {
35824 var entry = this.table_[i];
35825 if (entry.getFilter().doesMatch(interest.getName()))
35826 matchedFilters.push(entry);
35827 }
35828};
35829
35830/**
35831 * Remove the interest filter entry which has the interestFilterId from the
35832 * interest filter table. This does not affect another interest filter with a
35833 * different interestFilterId, even if it has the same prefix name. If there is
35834 * no entry with the interestFilterId, do nothing.
35835 * @param {number} interestFilterId The ID returned from setInterestFilter.
35836 */
35837InterestFilterTable.prototype.unsetInterestFilter = function(interestFilterId)
35838{
35839 // Go backwards through the list so we can erase entries.
35840 // Remove all entries even though interestFilterId should be unique.
35841 var count = 0;
35842 for (var i = this.table_.length - 1; i >= 0; --i) {
35843 if (this.table_[i].getInterestFilterId() == interestFilterId) {
35844 ++count;
35845 this.table_.splice(i, 1);
35846 }
35847 }
35848
35849 if (count === 0)
35850 if (LOG > 0) console.log
35851 ("unsetInterestFilter: Didn't find interestFilterId " + interestFilterId);
35852};
35853/**
35854 * Copyright (C) 2016 Regents of the University of California.
35855 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
35856 *
35857 * This program is free software: you can redistribute it and/or modify
35858 * it under the terms of the GNU Lesser General Public License as published by
35859 * the Free Software Foundation, either version 3 of the License, or
35860 * (at your option) any later version.
35861 *
35862 * This program is distributed in the hope that it will be useful,
35863 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35864 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35865 * GNU Lesser General Public License for more details.
35866 *
35867 * You should have received a copy of the GNU Lesser General Public License
35868 * along with this program. If not, see <http://www.gnu.org/licenses/>.
35869 * A copy of the GNU Lesser General Public License is in the file COPYING.
35870 */
35871
35872/** @ignore */
35873var NdnCommon = require('../util/ndn-common.js').NdnCommon; /** @ignore */
35874var LOG = require('../log.js').Log.LOG;
35875
35876/**
35877 * A PendingInterestTable is an internal class to hold a list of pending
35878 * interests with their callbacks.
35879 * @constructor
35880 */
35881var PendingInterestTable = function PendingInterestTable()
35882{
35883 this.table_ = []; // of Entry
35884 this.removeRequests_ = []; // of number
35885};
35886
35887exports.PendingInterestTable = PendingInterestTable;
35888
35889/**
35890 * PendingInterestTable.Entry holds the callbacks and other fields for an entry
35891 * in the pending interest table.
35892 * Create a new Entry with the given fields. Note: You should not call this
35893 * directly but call PendingInterestTable.add.
35894 * @constructor
35895 */
35896PendingInterestTable.Entry = function PendingInterestTableEntry
35897 (pendingInterestId, interest, onData, onTimeout, onNetworkNack)
35898{
35899 this.pendingInterestId_ = pendingInterestId;
35900 this.interest_ = interest;
35901 this.onData_ = onData;
35902 this.onTimeout_ = onTimeout;
35903 this.onNetworkNack_ = onNetworkNack;
35904 this.timerId_ = -1;
35905};
35906
35907/**
35908 * Get the pendingInterestId given to the constructor.
35909 * @return {number} The pendingInterestId.
35910 */
35911PendingInterestTable.Entry.prototype.getPendingInterestId = function()
35912{
35913 return this.pendingInterestId_;
35914};
35915
35916/**
35917 * Get the interest given to the constructor (from Face.expressInterest).
35918 * @return {Interest} The interest. NOTE: You must not change the interest
35919 * object - if you need to change it then make a copy.
35920 */
35921PendingInterestTable.Entry.prototype.getInterest = function()
35922{
35923 return this.interest_;
35924};
35925
35926/**
35927 * Get the OnData callback given to the constructor.
35928 * @return {function} The OnData callback.
35929 */
35930PendingInterestTable.Entry.prototype.getOnData = function()
35931{
35932 return this.onData_;
35933};
35934
35935/**
35936 * Get the OnNetworkNack callback given to the constructor.
35937 * @return {function} The OnNetworkNack callback.
35938 */
35939PendingInterestTable.Entry.prototype.getOnNetworkNack = function()
35940{
35941 return this.onNetworkNack_;
35942};
35943
35944/**
35945* Call onTimeout_ (if defined). This ignores exceptions from the call to
35946* onTimeout_.
35947*/
35948PendingInterestTable.Entry.prototype.callTimeout = function()
35949{
35950 if (this.onTimeout_) {
35951 try {
35952 this.onTimeout_(this.interest_);
35953 } catch (ex) {
35954 console.log("Error in onTimeout: " + NdnCommon.getErrorWithStackTrace(ex));
35955 }
35956 }
35957};
35958
35959/**
35960 * Call setTimeout(callback, milliseconds) and remember the timer ID. If the
35961 * timer ID has already been set on a prevous call, do nothing.
35962 */
35963PendingInterestTable.Entry.prototype.setTimeout = function(callback, milliseconds)
35964{
35965 if (this.timerId_ !== -1)
35966 // Already set a timeout.
35967 return;
35968 this.timerId_ = setTimeout(callback, milliseconds);
35969};
35970
35971/**
35972 * Clear the timeout timer and reset the timer ID.
35973 */
35974PendingInterestTable.Entry.prototype.clearTimeout = function()
35975{
35976 if (this.timerId_ !== -1) {
35977 clearTimeout(this.timerId_);
35978 this.timerId_ = -1;
35979 }
35980};
35981
35982/**
35983 * Add a new entry to the pending interest table. Also set a timer to call the
35984 * timeout. However, if removePendingInterest was already called with the
35985 * pendingInterestId, don't add an entry and return null.
35986 * @param {number} pendingInterestId
35987 * @param {Interest} interestCopy
35988 * @param {function} onData
35989 * @param {function} onTimeout
35990 * @param {function} onNetworkNack
35991 * @return {PendingInterestTable.Entry} The new PendingInterestTable.Entry, or
35992 * null if removePendingInterest was already called with the pendingInterestId.
35993 */
35994PendingInterestTable.prototype.add = function
35995 (pendingInterestId, interestCopy, onData, onTimeout, onNetworkNack)
35996{
35997 var removeRequestIndex = this.removeRequests_.indexOf(pendingInterestId);
35998 if (removeRequestIndex >= 0) {
35999 // removePendingInterest was called with the pendingInterestId returned by
36000 // expressInterest before we got here, so don't add a PIT entry.
36001 this.removeRequests_.splice(removeRequestIndex, 1);
36002 return null;
36003 }
36004
36005 var entry = new PendingInterestTable.Entry
36006 (pendingInterestId, interestCopy, onData, onTimeout, onNetworkNack);
36007 this.table_.push(entry);
36008
36009 // Set interest timer.
36010 var timeoutMilliseconds = (interestCopy.getInterestLifetimeMilliseconds() || 4000);
36011 var thisTable = this;
36012 var timeoutCallback = function() {
36013 if (LOG > 1) console.log("Interest time out: " + interestCopy.getName().toUri());
36014
36015 // Remove the entry from the table.
36016 var index = thisTable.table_.indexOf(entry);
36017 if (index >= 0)
36018 thisTable.table_.splice(index, 1);
36019
36020 entry.callTimeout();
36021 };
36022
36023 entry.setTimeout(timeoutCallback, timeoutMilliseconds);
36024 return entry;
36025};
36026
36027/**
36028 * Find all entries from the pending interest table where data conforms to
36029 * the entry's interest selectors, remove the entries from the table, and add to
36030 * the entries list.
36031 * @param {Data} data The incoming Data packet to find the interest for.
36032 * @param {Array<PendingInterestTable.Entry>} entries Add matching
36033 * PendingInterestTable.Entry from the pending interest table. The caller should
36034 * pass in an empty array.
36035 */
36036PendingInterestTable.prototype.extractEntriesForExpressedInterest = function
36037 (data, entries)
36038{
36039 // Go backwards through the list so we can erase entries.
36040 for (var i = this.table_.length - 1; i >= 0; --i) {
36041 var pendingInterest = this.table_[i];
36042 if (pendingInterest.getInterest().matchesData(data)) {
36043 pendingInterest.clearTimeout();
36044 entries.push(pendingInterest);
36045 this.table_.splice(i, 1);
36046 }
36047 }
36048};
36049
36050/**
36051 * Find all entries from the pending interest table where the OnNetworkNack
36052 * callback is not null and the entry's interest is the same as the given
36053 * interest, remove the entries from the table, and add to the entries list.
36054 * (We don't remove the entry if the OnNetworkNack callback is null so that
36055 * OnTimeout will be called later.) The interests are the same if their default
36056 * wire encoding is the same (which has everything including the name, nonce,
36057 * link object and selectors).
36058 * @param {Interest} interest The Interest to search for (typically from a Nack
36059 * packet).
36060 * @param {Array<PendingInterestTable.Entry>} entries Add matching
36061 * PendingInterestTable.Entry from the pending interest table. The caller should
36062 * pass in an empty array.
36063 */
36064PendingInterestTable.prototype.extractEntriesForNackInterest = function
36065 (interest, entries)
36066{
36067 var encoding = interest.wireEncode();
36068
36069 // Go backwards through the list so we can erase entries.
36070 for (var i = this.table_.length - 1; i >= 0; --i) {
36071 var pendingInterest = this.table_[i];
36072 if (pendingInterest.getOnNetworkNack() == null)
36073 continue;
36074
36075 // wireEncode returns the encoding cached when the interest was sent (if
36076 // it was the default wire encoding).
36077 if (pendingInterest.getInterest().wireEncode().equals(encoding)) {
36078 pendingInterest.clearTimeout();
36079 entries.push(pendingInterest);
36080 this.table_.splice(i, 1);
36081 }
36082 }
36083};
36084
36085/**
36086 * Remove the pending interest entry with the pendingInterestId from the pending
36087 * interest table. This does not affect another pending interest with a
36088 * different pendingInterestId, even if it has the same interest name.
36089 * If there is no entry with the pendingInterestId, do nothing.
36090 * @param {number} pendingInterestId The ID returned from expressInterest.
36091 */
36092PendingInterestTable.prototype.removePendingInterest = function
36093 (pendingInterestId)
36094{
36095 if (pendingInterestId == null)
36096 return;
36097
36098 // Go backwards through the list so we can erase entries.
36099 // Remove all entries even though pendingInterestId should be unique.
36100 var count = 0;
36101 for (var i = this.table_.length - 1; i >= 0; --i) {
36102 var entry = this.table_[i];
36103 if (entry.getPendingInterestId() == pendingInterestId) {
36104 entry.clearTimeout();
36105 this.table_.splice(i, 1);
36106 ++count;
36107 }
36108 }
36109
36110 if (count === 0)
36111 if (LOG > 0) console.log
36112 ("removePendingInterest: Didn't find pendingInterestId " + pendingInterestId);
36113
36114 if (count === 0) {
36115 // The pendingInterestId was not found. Perhaps this has been called before
36116 // the callback in expressInterest can add to the PIT. Add this
36117 // removal request which will be checked before adding to the PIT.
36118 if (this.removeRequests_.indexOf(pendingInterestId) < 0)
36119 // Not already requested, so add the request.
36120 this.removeRequests_.push(pendingInterestId);
36121 }
36122};
36123/**
36124 * Copyright (C) 2016 Regents of the University of California.
36125 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
36126 *
36127 * This program is free software: you can redistribute it and/or modify
36128 * it under the terms of the GNU Lesser General Public License as published by
36129 * the Free Software Foundation, either version 3 of the License, or
36130 * (at your option) any later version.
36131 *
36132 * This program is distributed in the hope that it will be useful,
36133 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36134 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36135 * GNU Lesser General Public License for more details.
36136 *
36137 * You should have received a copy of the GNU Lesser General Public License
36138 * along with this program. If not, see <http://www.gnu.org/licenses/>.
36139 * A copy of the GNU Lesser General Public License is in the file COPYING.
36140 */
36141
36142/** @ignore */
36143var LOG = require('../log.js').Log.LOG;
36144
36145/**
36146 * A RegisteredPrefixTable is an internal class to hold a list of registered
36147 * prefixes with information necessary to remove the registration later.
36148 * @param {InterestFilterTable} interestFilterTable See removeRegisteredPrefix(),
36149 * which may call interestFilterTable.unsetInterestFilter().
36150 * @constructor
36151 */
36152var RegisteredPrefixTable = function RegisteredPrefixTable(interestFilterTable)
36153{
36154 this.interestFilterTable_ = interestFilterTable;
36155 this.table_ = []; // of Entry
36156 this.removeRequests_ = []; // of number
36157};
36158
36159exports.RegisteredPrefixTable = RegisteredPrefixTable;
36160
36161/**
36162 * Add a new entry to the table. However, if removeRegisteredPrefix was already
36163 * called with the registeredPrefixId, don't add an entry and return false.
36164 * @param {number} registeredPrefixId The ID from Node.getNextEntryId().
36165 * @param {Name} prefix The name prefix.
36166 * @param {number} relatedInterestFilterId (optional) The related
36167 * interestFilterId for the filter set in the same registerPrefix operation. If
36168 * omitted, set to 0.
36169 * return {boolean} True if added an entry, false if removeRegisteredPrefix was
36170 * already called with the registeredPrefixId.
36171 */
36172RegisteredPrefixTable.prototype.add = function
36173 (registeredPrefixId, prefix, relatedInterestFilterId)
36174{
36175 var removeRequestIndex = this.removeRequests_.indexOf(registeredPrefixId);
36176 if (removeRequestIndex >= 0) {
36177 // removeRegisteredPrefix was called with the registeredPrefixId returned by
36178 // registerPrefix before we got here, so don't add a registered prefix
36179 // table entry.
36180 this.removeRequests_.splice(removeRequestIndex, 1);
36181 return false;
36182 }
36183
36184 this.table_.push(new RegisteredPrefixTable._Entry
36185 (registeredPrefixId, prefix, relatedInterestFilterId));
36186 return true;
36187};
36188
36189/**
36190 * Remove the registered prefix entry with the registeredPrefixId from the
36191 * registered prefix table. This does not affect another registered prefix with
36192 * a different registeredPrefixId, even if it has the same prefix name. If an
36193 * interest filter was automatically created by registerPrefix, also call
36194 * interestFilterTable_.unsetInterestFilter to remove it.
36195 * If there is no entry with the registeredPrefixId, do nothing.
36196 * @param {number} registeredPrefixId The ID returned from registerPrefix.
36197 */
36198RegisteredPrefixTable.prototype.removeRegisteredPrefix = function
36199 (registeredPrefixId)
36200{
36201 // Go backwards through the list so we can erase entries.
36202 // Remove all entries even though registeredPrefixId should be unique.
36203 var count = 0;
36204 for (var i = this.table_.length - 1; i >= 0; --i) {
36205 var entry = this.table_[i];
36206 if (entry.getRegisteredPrefixId() == registeredPrefixId) {
36207 ++count;
36208
36209 if (entry.getRelatedInterestFilterId() > 0)
36210 // Remove the related interest filter.
36211 this.interestFilterTable_.unsetInterestFilter
36212 (entry.getRelatedInterestFilterId());
36213
36214 this.table_.splice(i, 1);
36215 }
36216 }
36217
36218 if (count === 0)
36219 if (LOG > 0) console.log
36220 ("removeRegisteredPrefix: Didn't find registeredPrefixId " + registeredPrefixId);
36221
36222 if (count === 0) {
36223 // The registeredPrefixId was not found. Perhaps this has been called before
36224 // the callback in registerPrefix can add to the registered prefix table.
36225 // Add this removal request which will be checked before adding to the
36226 // registered prefix table.
36227 if (this.removeRequests_.indexOf(registeredPrefixId) < 0)
36228 // Not already requested, so add the request.
36229 this.removeRequests_.push(registeredPrefixId);
36230 }
36231};
36232
36233/**
36234 * RegisteredPrefixTable._Entry holds a registeredPrefixId and information
36235 * necessary to remove the registration later. It optionally holds a related
36236 * interestFilterId if the InterestFilter was set in the same registerPrefix
36237 * operation.
36238 * Create a RegisteredPrefixTable.Entry with the given values.
36239 * @param {number} registeredPrefixId The ID from Node.getNextEntryId().
36240 * @param {Name} prefix The name prefix.
36241 * @param {number} relatedInterestFilterId (optional) The related
36242 * interestFilterId for the filter set in the same registerPrefix operation. If
36243 * omitted, set to 0.
36244 * @constructor
36245 */
36246RegisteredPrefixTable._Entry = function RegisteredPrefixTableEntry
36247 (registeredPrefixId, prefix, relatedInterestFilterId)
36248{
36249 this.registeredPrefixId_ = registeredPrefixId;
36250 this.prefix_ = prefix;
36251 this.relatedInterestFilterId_ = relatedInterestFilterId;
36252};
36253
36254/**
36255 * Get the registeredPrefixId given to the constructor.
36256 * @return {number} The registeredPrefixId.
36257 */
36258RegisteredPrefixTable._Entry.prototype.getRegisteredPrefixId = function()
36259{
36260 return this.registeredPrefixId;
36261};
36262
36263/**
36264 * Get the name prefix given to the constructor.
36265 * @return {Name} The name prefix.
36266 */
36267RegisteredPrefixTable._Entry.prototype.getPrefix = function()
36268{
36269 return this.prefix;
36270};
36271
36272/**
36273 * Get the related interestFilterId given to the constructor.
36274 * @return {number} The related interestFilterId.
36275 */
36276RegisteredPrefixTable._Entry.prototype.getRelatedInterestFilterId = function()
36277{
36278 return this.relatedInterestFilterId;
36279};
36280/**
36281 * Copyright (C) 2016 Regents of the University of California.
36282 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
36283 * @author: From ndn-cxx fields.hpp https://github.com/named-data/ndn-cxx/blob/master/src/lp/fields.hpp
36284 *
36285 * This program is free software: you can redistribute it and/or modify
36286 * it under the terms of the GNU Lesser General Public License as published by
36287 * the Free Software Foundation, either version 3 of the License, or
36288 * (at your option) any later version.
36289 *
36290 * This program is distributed in the hope that it will be useful,
36291 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36292 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36293 * GNU Lesser General Public License for more details.
36294 *
36295 * You should have received a copy of the GNU Lesser General Public License
36296 * along with this program. If not, see <http://www.gnu.org/licenses/>.
36297 * A copy of the GNU Lesser General Public License is in the file COPYING.
36298 */
36299
36300/**
36301 * IncomingFaceId represents the incoming face ID header field in an NDNLPv2 packet.
36302 * http://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
36303 * @constructor
36304 */
36305var IncomingFaceId = function IncomingFaceId()
36306{
36307 this.faceId_ = null;
36308};
36309
36310exports.IncomingFaceId = IncomingFaceId;
36311
36312/**
36313 * Get the incoming face ID value.
36314 * @return {number} The face ID value.
36315 */
36316IncomingFaceId.prototype.getFaceId = function() { return this.faceId_; };
36317
36318/**
36319 * Set the face ID value.
36320 * @param {number} faceId The incoming face ID value.
36321 */
36322IncomingFaceId.prototype.setFaceId = function(faceId)
36323{
36324 this.faceId_ = faceId;
36325};
36326
36327/**
36328 * Get the first header field in lpPacket which is an IncomingFaceId. This is
36329 * an internal method which the application normally would not use.
36330 * @param {LpPacket} lpPacket The LpPacket with the header fields to search.
36331 * @return {IncomingFaceId} The first IncomingFaceId header field, or null if
36332 * not found.
36333 */
36334IncomingFaceId.getFirstHeader = function(lpPacket)
36335{
36336 for (var i = 0; i < lpPacket.countHeaderFields(); ++i) {
36337 var field = lpPacket.getHeaderField(i);
36338 if (field instanceof IncomingFaceId)
36339 return field;
36340 }
36341
36342 return null;
36343};
36344/**
36345 * Copyright (C) 2016 Regents of the University of California.
36346 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
36347 * @author: From ndn-cxx packet.hpp https://github.com/named-data/ndn-cxx/blob/master/src/lp/packet.hpp
36348 *
36349 * This program is free software: you can redistribute it and/or modify
36350 * it under the terms of the GNU Lesser General Public License as published by
36351 * the Free Software Foundation, either version 3 of the License, or
36352 * (at your option) any later version.
36353 *
36354 * This program is distributed in the hope that it will be useful,
36355 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36356 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36357 * GNU Lesser General Public License for more details.
36358 *
36359 * You should have received a copy of the GNU Lesser General Public License
36360 * along with this program. If not, see <http://www.gnu.org/licenses/>.
36361 * A copy of the GNU Lesser General Public License is in the file COPYING.
36362 */
36363
36364/** @ignore */
36365var Blob = require('../util/blob.js').Blob;
36366
36367/**
36368 * An LpPacket represents an NDNLPv2 packet including header fields an an
36369 * optional fragment. This is an internal class which the application normally
36370 * would not use.
36371 * http://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
36372 * @constructor
36373 */
36374var LpPacket = function LpPacket()
36375{
36376 this.headerFields_ = [];
36377 this.fragmentWireEncoding_ = new Blob();
36378};
36379
36380exports.LpPacket = LpPacket;
36381
36382/**
36383 * Get the fragment wire encoding.
36384 * @return {Blob} The wire encoding, or an isNull Blob if not specified.
36385 */
36386LpPacket.prototype.getFragmentWireEncoding = function()
36387{
36388 return this.fragmentWireEncoding_;
36389};
36390
36391/**
36392 * Get the number of header fields. This does not include the fragment.
36393 * @return {number} The number of header fields.
36394 */
36395LpPacket.prototype.countHeaderFields = function()
36396{
36397 return this.headerFields_.length;
36398};
36399
36400/**
36401 * Get the header field at the given index.
36402 * @param {number} index The index, starting from 0. It is an error if index is
36403 * greater to or equal to countHeaderFields().
36404 * @return {object} The header field at the index.
36405 */
36406LpPacket.prototype.getHeaderField = function(index)
36407{
36408 return this.headerFields_[index];
36409};
36410
36411/**
36412 * Remove all header fields and set the fragment to an isNull Blob.
36413 */
36414LpPacket.prototype.clear = function()
36415{
36416 this.headerFields_ = [];
36417 this.fragmentWireEncoding_ = new Blob();
36418};
36419
36420/**
36421 * Set the fragment wire encoding.
36422 * @param {Blob} fragmentWireEncoding The fragment wire encoding or an isNull
36423 * Blob if not specified.
36424 */
36425LpPacket.prototype.setFragmentWireEncoding = function(fragmentWireEncoding)
36426{
36427 this.fragmentWireEncoding_ =
36428 typeof fragmentWireEncoding === 'object' && fragmentWireEncoding instanceof Blob ?
36429 fragmentWireEncoding : new Blob(fragmentWireEncoding);
36430};
36431
36432/**
36433 * Add a header field. To add the fragment, use setFragmentWireEncoding().
36434 * @param {object} headerField The header field to add.
36435 */
36436LpPacket.prototype.addHeaderField = function(headerField)
36437{
36438 this.headerFields_.push(headerField);
36439};
36440/**
36441 * This class represents the top-level object for communicating with an NDN host.
36442 * Copyright (C) 2013-2016 Regents of the University of California.
36443 * @author: Meki Cherkaoui, Jeff Thompson <jefft0@remap.ucla.edu>, Wentao Shang
36444 *
36445 * This program is free software: you can redistribute it and/or modify
36446 * it under the terms of the GNU Lesser General Public License as published by
36447 * the Free Software Foundation, either version 3 of the License, or
36448 * (at your option) any later version.
36449 *
36450 * This program is distributed in the hope that it will be useful,
36451 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36452 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36453 * GNU Lesser General Public License for more details.
36454 *
36455 * You should have received a copy of the GNU Lesser General Public License
36456 * along with this program. If not, see <http://www.gnu.org/licenses/>.
36457 * A copy of the GNU Lesser General Public License is in the file COPYING.
36458 */
36459
36460/** @ignore */
36461var DataUtils = require('./encoding/data-utils.js').DataUtils; /** @ignore */
36462var Name = require('./name.js').Name; /** @ignore */
36463var Interest = require('./interest.js').Interest; /** @ignore */
36464var Data = require('./data.js').Data; /** @ignore */
36465var ControlParameters = require('./control-parameters.js').ControlParameters; /** @ignore */
36466var ControlResponse = require('./control-response.js').ControlResponse; /** @ignore */
36467var InterestFilter = require('./interest-filter.js').InterestFilter; /** @ignore */
36468var WireFormat = require('./encoding/wire-format.js').WireFormat; /** @ignore */
36469var TlvWireFormat = require('./encoding/tlv-wire-format.js').TlvWireFormat; /** @ignore */
36470var Tlv = require('./encoding/tlv/tlv.js').Tlv; /** @ignore */
36471var TlvDecoder = require('./encoding/tlv/tlv-decoder.js').TlvDecoder; /** @ignore */
36472var ForwardingFlags = require('./forwarding-flags.js').ForwardingFlags; /** @ignore */
36473var Transport = require('./transport/transport.js').Transport; /** @ignore */
36474var TcpTransport = require('./transport/tcp-transport.js').TcpTransport; /** @ignore */
36475var UnixTransport = require('./transport/unix-transport.js').UnixTransport; /** @ignore */
36476var CommandInterestGenerator = require('./util/command-interest-generator.js').CommandInterestGenerator; /** @ignore */
36477var Blob = require('./util/blob.js').Blob; /** @ignore */
36478var NdnCommon = require('./util/ndn-common.js').NdnCommon; /** @ignore */
36479var NetworkNack = require('./network-nack.js').NetworkNack; /** @ignore */
36480var LpPacket = require('./lp/lp-packet.js').LpPacket; /** @ignore */
36481var InterestFilterTable = require('./impl/interest-filter-table.js').InterestFilterTable; /** @ignore */
36482var PendingInterestTable = require('./impl/pending-interest-table.js').PendingInterestTable; /** @ignore */
36483var RegisteredPrefixTable = require('./impl/registered-prefix-table.js').RegisteredPrefixTable; /** @ignore */
36484var fs = require('fs'); /** @ignore */
36485var LOG = require('./log.js').Log.LOG;
36486
36487/**
36488 * Create a new Face with the given settings.
36489 * This throws an exception if Face.supported is false.
36490 * There are two forms of the constructor. The first form takes the transport and connectionInfo:
36491 * Face(transport, connectionInfo). The second form takes an optional settings object:
36492 * Face([settings]).
36493 * @constructor
36494 * @param {Transport} transport An object of a subclass of Transport to use for
36495 * communication.
36496 * @param {Transport.ConnectionInfo} connectionInfo This must be a ConnectionInfo
36497 * from the same subclass of Transport as transport. If omitted and transport is
36498 * a new UnixTransport() then attempt to create to the Unix socket for the local
36499 * forwarder.
36500 * @param {Object} settings (optional) An associative array with the following defaults:
36501 * {
36502 * getTransport: function() { return new WebSocketTransport(); }, // If in the browser.
36503 * OR function() { return new TcpTransport(); }, // If in Node.js.
36504 * // If getTransport creates a UnixTransport and connectionInfo is null,
36505 * // then connect to the local forwarder's Unix socket.
36506 * getConnectionInfo: transport.defaultGetConnectionInfo, // a function, on each call it returns a new Transport.ConnectionInfo or null if there are no more hosts.
36507 * // If connectionInfo or host is not null, getConnectionInfo is ignored.
36508 * connectionInfo: null,
36509 * host: null, // If null and connectionInfo is null, use getConnectionInfo when connecting.
36510 * // However, if connectionInfo is not null, use it instead.
36511 * port: 9696, // If in the browser.
36512 * OR 6363, // If in Node.js.
36513 * // However, if connectionInfo is not null, use it instead.
36514 * onopen: function() { if (LOG > 3) console.log("NDN connection established."); },
36515 * onclose: function() { if (LOG > 3) console.log("NDN connection closed."); },
36516 * }
36517 */
36518var Face = function Face(transportOrSettings, connectionInfo)
36519{
36520 if (!Face.supported)
36521 throw new Error("The necessary JavaScript support is not available on this platform.");
36522
36523 var settings;
36524 if (typeof transportOrSettings == 'object' && transportOrSettings instanceof Transport) {
36525 this.getConnectionInfo = null;
36526 this.transport = transportOrSettings;
36527 this.connectionInfo = (connectionInfo || null);
36528 // Use defaults for other settings.
36529 settings = {};
36530
36531 if (this.connectionInfo == null) {
36532 if (this.transport && this.transport.__proto__ &&
36533 this.transport.__proto__.name == "UnixTransport") {
36534 // Try to create the default connectionInfo for UnixTransport.
36535 var filePath = Face.getUnixSocketFilePathForLocalhost();
36536 if (filePath != null)
36537 this.connectionInfo = new UnixTransport.ConnectionInfo(filePath);
36538 else
36539 console.log
36540 ("Face constructor: Cannot determine the default Unix socket file path for UnixTransport");
36541 if (LOG > 0)
36542 console.log("Using " + this.connectionInfo.toString());
36543 }
36544 }
36545 }
36546 else {
36547 settings = (transportOrSettings || {});
36548 // For the browser, browserify-tcp-transport.js replaces TcpTransport with WebSocketTransport.
36549 var getTransport = (settings.getTransport || function() { return new TcpTransport(); });
36550 this.transport = getTransport();
36551 this.getConnectionInfo = (settings.getConnectionInfo || this.transport.defaultGetConnectionInfo);
36552
36553 this.connectionInfo = (settings.connectionInfo || null);
36554 if (this.connectionInfo == null) {
36555 var host = (settings.host !== undefined ? settings.host : null);
36556
36557 if (this.transport && this.transport.__proto__ &&
36558 this.transport.__proto__.name == "UnixTransport") {
36559 // We are using UnixTransport on Node.js. There is no IP-style host and port.
36560 if (host != null)
36561 // Assume the host is the local Unix socket path.
36562 this.connectionInfo = new UnixTransport.ConnectionInfo(host);
36563 else {
36564 // If getConnectionInfo is not null, it will be used instead so no
36565 // need to set this.connectionInfo.
36566 if (this.getConnectionInfo == null) {
36567 var filePath = Face.getUnixSocketFilePathForLocalhost();
36568 if (filePath != null)
36569 this.connectionInfo = new UnixTransport.ConnectionInfo(filePath);
36570 else
36571 console.log
36572 ("Face constructor: Cannot determine the default Unix socket file path for UnixTransport");
36573 }
36574 }
36575 }
36576 else {
36577 if (host != null) {
36578 if (typeof WebSocketTransport != 'undefined')
36579 this.connectionInfo = new WebSocketTransport.ConnectionInfo
36580 (host, settings.port || 9696);
36581 else
36582 this.connectionInfo = new TcpTransport.ConnectionInfo
36583 (host, settings.port || 6363);
36584 }
36585 }
36586 }
36587 }
36588
36589 // Deprecated: Set this.host and this.port for backwards compatibility.
36590 if (this.connectionInfo == null) {
36591 this.host = null;
36592 this.host = null;
36593 }
36594 else {
36595 this.host = this.connectionInfo.host;
36596 this.host = this.connectionInfo.port;
36597 }
36598
36599 this.readyStatus = Face.UNOPEN;
36600
36601 // Event handler
36602 this.onopen = (settings.onopen || function() { if (LOG > 3) console.log("Face connection established."); });
36603 this.onclose = (settings.onclose || function() { if (LOG > 3) console.log("Face connection closed."); });
36604 // This is used by reconnectAndExpressInterest.
36605 this.onConnectedCallbacks = [];
36606 this.commandKeyChain = null;
36607 this.commandCertificateName = new Name();
36608 this.commandInterestGenerator = new CommandInterestGenerator();
36609 this.timeoutPrefix = new Name("/local/timeout");
36610
36611 this.pendingInterestTable_ = new PendingInterestTable();
36612 this.interestFilterTable_ = new InterestFilterTable();
36613 this.registeredPrefixTable_ = new RegisteredPrefixTable(this.interestFilterTable_);
36614 this.lastEntryId = 0;
36615};
36616
36617exports.Face = Face;
36618
36619Face.UNOPEN = 0; // the Face is created but not opened yet
36620Face.OPEN_REQUESTED = 1; // requested to connect but onopen is not called.
36621Face.OPENED = 2; // connection to the forwarder opened
36622Face.CLOSED = 3; // connection to the forwarder closed
36623
36624TcpTransport.importFace(Face);
36625
36626/**
36627 * If the forwarder's Unix socket file path exists, then return the file path.
36628 * Otherwise return an empty string. This uses Node.js blocking file system
36629 * utilities.
36630 * @return The Unix socket file path to use, or an empty string.
36631 */
36632Face.getUnixSocketFilePathForLocalhost = function()
36633{
36634 var filePath = "/var/run/nfd.sock";
36635 if (fs.existsSync(filePath))
36636 return filePath;
36637 else {
36638 filePath = "/tmp/.ndnd.sock";
36639 if (fs.existsSync(filePath))
36640 return filePath;
36641 else
36642 return "";
36643 }
36644}
36645
36646/**
36647 * Return true if necessary JavaScript support is available, else log an error and return false.
36648 */
36649Face.getSupported = function()
36650{
36651 try {
36652 var dummy = new Buffer(1).slice(0, 1);
36653 }
36654 catch (ex) {
36655 console.log("NDN not available: Buffer not supported. " + ex);
36656 return false;
36657 }
36658
36659 return true;
36660};
36661
36662Face.supported = Face.getSupported();
36663
36664Face.prototype.createRoute = function(hostOrConnectionInfo, port)
36665{
36666 if (hostOrConnectionInfo instanceof Transport.ConnectionInfo)
36667 this.connectionInfo = hostOrConnectionInfo;
36668 else
36669 this.connectionInfo = new TcpTransport.ConnectionInfo(hostOrConnectionInfo, port);
36670
36671 // Deprecated: Set this.host and this.port for backwards compatibility.
36672 this.host = this.connectionInfo.host;
36673 this.host = this.connectionInfo.port;
36674};
36675
36676Face.prototype.close = function()
36677{
36678 if (this.readyStatus != Face.OPENED)
36679 return;
36680
36681 this.readyStatus = Face.CLOSED;
36682 this.transport.close();
36683};
36684
36685/**
36686 * An internal method to get the next unique entry ID for the pending interest
36687 * table, interest filter table, etc. Most entry IDs are for the pending
36688 * interest table (there usually are not many interest filter table entries) so
36689 * we use a common pool to only have to have one method which is called by Face.
36690 *
36691 * @return {number} The next entry ID.
36692 */
36693Face.prototype.getNextEntryId = function()
36694{
36695 return ++this.lastEntryId;
36696};
36697
36698/**
36699 * Return a function that selects a host at random from hostList and returns
36700 * makeConnectionInfo(host, port), and if no more hosts remain, return null.
36701 * @param {Array<string>} hostList An array of host names.
36702 * @param {number} port The port for the connection.
36703 * @param {function} makeConnectionInfo This calls makeConnectionInfo(host, port)
36704 * to make the Transport.ConnectionInfo. For example:
36705 * function(host, port) { return new TcpTransport.ConnectionInfo(host, port); }
36706 * @return {function} A function which returns a Transport.ConnectionInfo.
36707 */
36708Face.makeShuffledHostGetConnectionInfo = function(hostList, port, makeConnectionInfo)
36709{
36710 // Make a copy.
36711 hostList = hostList.slice(0, hostList.length);
36712 DataUtils.shuffle(hostList);
36713
36714 return function() {
36715 if (hostList.length == 0)
36716 return null;
36717
36718 return makeConnectionInfo(hostList.splice(0, 1)[0], port);
36719 };
36720};
36721
36722/**
36723 * Send the interest through the transport, read the entire response and call
36724 * onData, onTimeout or onNetworkNack as described below.
36725 * There are two forms of expressInterest. The first form takes the exact
36726 * interest (including lifetime):
36727 * expressInterest(interest, onData [, onTimeout] [, onNetworkNack] [, wireFormat]).
36728 * The second form creates the interest from a name and optional interest template:
36729 * expressInterest(name [, template], onData [, onTimeout] [, onNetworkNack] [, wireFormat]).
36730 * @param {Interest} interest The Interest to send which includes the interest lifetime for the timeout.
36731 * @param {function} onData When a matching data packet is received, this calls onData(interest, data) where
36732 * interest is the interest given to expressInterest and data is the received
36733 * Data object. NOTE: You must not change the interest object - if you need to
36734 * change it then make a copy.
36735 * NOTE: The library will log any exceptions thrown by this callback, but for
36736 * better error handling the callback should catch and properly handle any
36737 * exceptions.
36738 * @param {function} onTimeout (optional) If the interest times out according to the interest lifetime,
36739 * this calls onTimeout(interest) where:
36740 * interest is the interest given to expressInterest.
36741 * NOTE: The library will log any exceptions thrown by this callback, but for
36742 * better error handling the callback should catch and properly handle any
36743 * exceptions.
36744 * @param {function} onNetworkNack (optional) When a network Nack packet for the
36745 * interest is received and onNetworkNack is not null, this calls
36746 * onNetworkNack(interest, networkNack) and does not call onTimeout. interest is
36747 * the sent Interest and networkNack is the received NetworkNack. If
36748 * onNetworkNack is supplied, then onTimeout must be supplied too. However, if a
36749 * network Nack is received and onNetworkNack is null, do nothing and wait for
36750 * the interest to time out. (Therefore, an application which does not yet
36751 * process a network Nack reason treats a Nack the same as a timeout.)
36752 * NOTE: The library will log any exceptions thrown by this callback, but for
36753 * better error handling the callback should catch and properly handle any
36754 * exceptions.
36755 * @param {Name} name The Name for the interest. (only used for the second form of expressInterest).
36756 * @param {Interest} template (optional) If not omitted, copy the interest selectors from this Interest.
36757 * If omitted, use a default interest lifetime. (only used for the second form of expressInterest).
36758 * @param {WireFormat} (optional) A WireFormat object used to encode the message.
36759 * If omitted, use WireFormat.getDefaultWireFormat().
36760 * @return {number} The pending interest ID which can be used with removePendingInterest.
36761 * @throws Error If the encoded interest size exceeds Face.getMaxNdnPacketSize().
36762 */
36763Face.prototype.expressInterest = function
36764 (interestOrName, arg2, arg3, arg4, arg5, arg6)
36765{
36766 var interest;
36767 if (typeof interestOrName === 'object' && interestOrName instanceof Interest)
36768 // Just use a copy of the interest.
36769 interest = new Interest(interestOrName);
36770 else {
36771 // The first argument is a name. Make the interest from the name and possible template.
36772 if (arg2 && typeof arg2 === 'object' && arg2 instanceof Interest) {
36773 var template = arg2;
36774 // Copy the template.
36775 interest = new Interest(template);
36776 interest.setName(interestOrName);
36777
36778 // Shift the remaining args to be processed below.
36779 arg2 = arg3;
36780 arg3 = arg4;
36781 arg4 = arg5;
36782 arg5 = arg6;
36783 }
36784 else {
36785 // No template.
36786 interest = new Interest(interestOrName);
36787 interest.setInterestLifetimeMilliseconds(4000); // default interest timeout
36788 }
36789 }
36790
36791 var onData = arg2;
36792 var onTimeout;
36793 var onNetworkNack;
36794 var wireFormat;
36795 // arg3, arg4, arg5 may be:
36796 // OnTimeout, OnNetworkNack, WireFormat
36797 // OnTimeout, OnNetworkNack, null
36798 // OnTimeout, WireFormat, null
36799 // OnTimeout, null, null
36800 // WireFormat, null, null
36801 // null, null, null
36802 if (typeof arg3 === "function")
36803 onTimeout = arg3;
36804 else
36805 onTimeout = function() {};
36806
36807 if (typeof arg4 === "function")
36808 onNetworkNack = arg4;
36809 else
36810 onNetworkNack = null;
36811
36812 if (arg3 instanceof WireFormat)
36813 wireFormat = arg3;
36814 else if (arg4 instanceof WireFormat)
36815 wireFormat = arg4;
36816 else if (arg5 instanceof WireFormat)
36817 wireFormat = arg5;
36818 else
36819 wireFormat = WireFormat.getDefaultWireFormat();
36820
36821 var pendingInterestId = this.getNextEntryId();
36822
36823 // Set the nonce in our copy of the Interest so it is saved in the PIT.
36824 interest.setNonce(Face.nonceTemplate_);
36825 interest.refreshNonce();
36826
36827 if (this.connectionInfo == null) {
36828 if (this.getConnectionInfo == null)
36829 console.log('ERROR: connectionInfo is NOT SET');
36830 else {
36831 var thisFace = this;
36832 this.connectAndExecute(function() {
36833 thisFace.reconnectAndExpressInterest
36834 (pendingInterestId, interest, onData, onTimeout, onNetworkNack,
36835 wireFormat);
36836 });
36837 }
36838 }
36839 else
36840 this.reconnectAndExpressInterest
36841 (pendingInterestId, interest, onData, onTimeout, onNetworkNack, wireFormat);
36842
36843 return pendingInterestId;
36844};
36845
36846/**
Alexander Afanasyev1663a412013-03-02 13:52:00 -080036847 * If the host and port are different than the ones in this.transport, then call
36848 * this.transport.connect to change the connection (or connect for the first time).
36849 * Then call expressInterestHelper.
36850 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080036851Face.prototype.reconnectAndExpressInterest = function
36852 (pendingInterestId, interest, onData, onTimeout, onNetworkNack, wireFormat)
36853{
36854 var thisFace = this;
36855 if (!this.connectionInfo.equals(this.transport.connectionInfo) || this.readyStatus === Face.UNOPEN) {
36856 this.readyStatus = Face.OPEN_REQUESTED;
36857 this.onConnectedCallbacks.push
36858 (function() {
36859 thisFace.expressInterestHelper
36860 (pendingInterestId, interest, onData, onTimeout, onNetworkNack,
36861 wireFormat);
36862 });
Alexander Afanasyev1663a412013-03-02 13:52:00 -080036863
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080036864 this.transport.connect
36865 (this.connectionInfo, this,
36866 function() {
36867 thisFace.readyStatus = Face.OPENED;
Alexander Afanasyev1663a412013-03-02 13:52:00 -080036868
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080036869 // Execute each action requested while the connection was opening.
36870 while (thisFace.onConnectedCallbacks.length > 0) {
36871 try {
36872 thisFace.onConnectedCallbacks.shift()();
36873 } catch (ex) {
36874 console.log("Face.reconnectAndExpressInterest: ignoring exception from onConnectedCallbacks: " + ex);
36875 }
Alexander Afanasyev1663a412013-03-02 13:52:00 -080036876 }
Alexander Afanasyev1663a412013-03-02 13:52:00 -080036877
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080036878 if (thisFace.onopen)
36879 // Call Face.onopen after success
36880 thisFace.onopen();
36881 },
36882 function() { thisFace.closeByTransport(); });
36883 }
36884 else {
36885 if (this.readyStatus === Face.OPEN_REQUESTED)
36886 // The connection is still opening, so add to the interests to express.
36887 this.onConnectedCallbacks.push
36888 (function() {
36889 thisFace.expressInterestHelper
36890 (pendingInterestId, interest, onData, onTimeout, onNetworkNack,
36891 wireFormat);
36892 });
36893 else if (this.readyStatus === Face.OPENED)
36894 this.expressInterestHelper
36895 (pendingInterestId, interest, onData, onTimeout, onNetworkNack,
36896 wireFormat);
Alexander Afanasyev1663a412013-03-02 13:52:00 -080036897 else
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080036898 throw new Error
36899 ("reconnectAndExpressInterest: unexpected connection is not opened");
36900 }
Alexander Afanasyev1663a412013-03-02 13:52:00 -080036901};
36902
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080036903/**
36904 * Do the work of reconnectAndExpressInterest once we know we are connected.
36905 * Add the PendingInterest and call this.transport.send to send the interest.
Alexander Afanasyev1663a412013-03-02 13:52:00 -080036906 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080036907Face.prototype.expressInterestHelper = function
36908 (pendingInterestId, interest, onData, onTimeout, onNetworkNack, wireFormat)
36909{
36910 if (this.pendingInterestTable_.add
36911 (pendingInterestId, interest, onData, onTimeout, onNetworkNack) == null)
36912 // removePendingInterest was already called with the pendingInterestId.
36913 return;
Alexander Afanasyev1663a412013-03-02 13:52:00 -080036914
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080036915 // Special case: For timeoutPrefix we don't actually send the interest.
36916 if (!this.timeoutPrefix.match(interest.getName())) {
36917 var binaryInterest = interest.wireEncode(wireFormat);
36918 if (binaryInterest.size() > Face.getMaxNdnPacketSize())
36919 throw new Error
36920 ("The encoded interest size exceeds the maximum limit getMaxNdnPacketSize()");
36921
36922 this.transport.send(binaryInterest.buf());
36923 }
Alexander Afanasyev1663a412013-03-02 13:52:00 -080036924};
36925
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080036926/**
36927 * Remove the pending interest entry with the pendingInterestId from the pending
36928 * interest table. This does not affect another pending interest with a
36929 * different pendingInterestId, even if it has the same interest name.
36930 * If there is no entry with the pendingInterestId, do nothing.
36931 * @param {number} pendingInterestId The ID returned from expressInterest.
36932 */
36933Face.prototype.removePendingInterest = function(pendingInterestId)
36934{
36935 this.pendingInterestTable_.removePendingInterest(pendingInterestId);
36936};
Alexander Afanasyev1663a412013-03-02 13:52:00 -080036937
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080036938/**
36939 * Set the KeyChain and certificate name used to sign command interests (e.g.
36940 * for registerPrefix).
36941 * @param {KeyChain} keyChain The KeyChain object for signing interests, which
36942 * must remain valid for the life of this Face. You must create the KeyChain
36943 * object and pass it in. You can create a default KeyChain for your system with
36944 * the default KeyChain constructor.
36945 * @param {Name} certificateName The certificate name for signing interests.
36946 * This makes a copy of the Name. You can get the default certificate name with
36947 * keyChain.getDefaultCertificateName() .
36948 */
36949Face.prototype.setCommandSigningInfo = function(keyChain, certificateName)
36950{
36951 this.commandKeyChain = keyChain;
36952 this.commandCertificateName = new Name(certificateName);
36953};
36954
36955/**
36956 * Set the certificate name used to sign command interest (e.g. for
36957 * registerPrefix), using the KeyChain that was set with setCommandSigningInfo.
36958 * @param {Name} certificateName The certificate name for signing interest. This
36959 * makes a copy of the Name.
36960 */
36961Face.prototype.setCommandCertificateName = function(certificateName)
36962{
36963 this.commandCertificateName = new Name(certificateName);
36964};
36965
36966/**
36967 * Append a timestamp component and a random value component to interest's name.
36968 * Then use the keyChain and certificateName from setCommandSigningInfo to sign
36969 * the interest. If the interest lifetime is not set, this sets it.
36970 * @note This method is an experimental feature. See the API docs for more
36971 * detail at
36972 * http://named-data.net/doc/ndn-ccl-api/face.html#face-makecommandinterest-method .
36973 * @param {Interest} interest The interest whose name is appended with
36974 * components.
36975 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
36976 * the SignatureInfo and to encode the interest name for signing. If omitted,
36977 * use WireFormat.getDefaultWireFormat().
36978 * @param {function} onComplete (optional) This calls onComplete() when complete.
36979 * If omitted, block until complete. (Some crypto/database libraries only use a
36980 * callback, so onComplete is required to use these.)
36981 */
36982Face.prototype.makeCommandInterest = function(interest, wireFormat, onComplete)
36983{
36984 onComplete = (typeof wireFormat === "function") ? wireFormat : onComplete;
36985 wireFormat = (typeof wireFormat === "function" || !wireFormat) ?
36986 WireFormat.getDefaultWireFormat() : wireFormat;
36987 this.nodeMakeCommandInterest
36988 (interest, this.commandKeyChain, this.commandCertificateName, wireFormat,
36989 onComplete);
36990};
36991
36992/**
36993 * Append a timestamp component and a random value component to interest's name.
36994 * Then use the keyChain and certificateName from setCommandSigningInfo to sign
36995 * the interest. If the interest lifetime is not set, this sets it.
36996 * @param {Interest} interest The interest whose name is appended with
36997 * components.
36998 * @param {KeyChain} keyChain The KeyChain for calling sign.
36999 * @param {Name} certificateName The certificate name of the key to use for
37000 * signing.
37001 * @param {WireFormat} wireFormat A WireFormat object used to encode
37002 * the SignatureInfo and to encode the interest name for signing.
37003 * @param {function} onComplete (optional) This calls onComplete() when complete.
37004 * (Some crypto/database libraries only use a callback, so onComplete is
37005 * required to use these.)
37006 */
37007Face.prototype.nodeMakeCommandInterest = function
37008 (interest, keyChain, certificateName, wireFormat, onComplete)
37009{
37010 this.commandInterestGenerator.generate
37011 (interest, keyChain, certificateName, wireFormat, onComplete);
37012};
37013
37014/**
37015 * Register prefix with the connected NDN hub and call onInterest when a
37016 * matching interest is received. To register a prefix with NFD, you must
37017 * first call setCommandSigningInfo.
37018 * This uses the form:
37019 * @param {Name} prefix The Name prefix.
37020 * @param {function} onInterest (optional) If not null, this creates an interest
37021 * filter from prefix so that when an Interest is received which matches the
37022 * filter, this calls
37023 * onInterest(prefix, interest, face, interestFilterId, filter).
37024 * NOTE: You must not change the prefix object - if you need to change it then
37025 * make a copy. If onInterest is null, it is ignored and you must call
37026 * setInterestFilter.
37027 * NOTE: The library will log any exceptions thrown by this callback, but for
37028 * better error handling the callback should catch and properly handle any
37029 * exceptions.
37030 * @param {function} onRegisterFailed If register prefix fails for any reason,
37031 * this calls onRegisterFailed(prefix) where:
37032 * prefix is the prefix given to registerPrefix.
37033 * NOTE: The library will log any exceptions thrown by this callback, but for
37034 * better error handling the callback should catch and properly handle any
37035 * exceptions.
37036 * @param {function} onRegisterSuccess (optional) When this receives a success
37037 * message, this calls onRegisterSuccess(prefix, registeredPrefixId) where
37038 * prefix is the prefix given to registerPrefix and registeredPrefixId is
37039 * the value retured by registerPrefix. If onRegisterSuccess is null or omitted,
37040 * this does not use it. (The onRegisterSuccess parameter comes after
37041 * onRegisterFailed because it can be null or omitted, unlike onRegisterFailed.)
37042 * NOTE: The library will log any exceptions thrown by this callback, but for
37043 * better error handling the callback should catch and properly handle any
37044 * exceptions.
37045 * @param {ForwardingFlags} flags (optional) The ForwardingFlags object for
37046 * finer control of which interests are forward to the application. If omitted,
37047 * use the default flags defined by the default ForwardingFlags constructor.
37048 * @return {number} The registered prefix ID which can be used with
37049 * removeRegisteredPrefix.
37050 */
37051Face.prototype.registerPrefix = function
37052 (prefix, onInterest, onRegisterFailed, onRegisterSuccess, flags, wireFormat)
37053{
37054 // Temporarlity reassign to resolve the different overloaded forms.
37055 var arg4 = onRegisterSuccess;
37056 var arg5 = flags;
37057 var arg6 = wireFormat;
37058 // arg4, arg5, arg6 may be:
37059 // OnRegisterSuccess, ForwardingFlags, WireFormat
37060 // OnRegisterSuccess, ForwardingFlags, null
37061 // OnRegisterSuccess, WireFormat, null
37062 // OnRegisterSuccess, null, null
37063 // ForwardingFlags, WireFormat, null
37064 // ForwardingFlags, null, null
37065 // WireFormat, null, null
37066 // null, null, null
37067 if (typeof arg4 === "function")
37068 onRegisterSuccess = arg4;
37069 else
37070 onRegisterSuccess = null;
37071
37072 if (arg4 instanceof ForwardingFlags)
37073 flags = arg4;
37074 else if (arg5 instanceof ForwardingFlags)
37075 flags = arg5;
37076 else
37077 flags = new ForwardingFlags();
37078
37079 if (arg4 instanceof WireFormat)
37080 wireFormat = arg4;
37081 else if (arg5 instanceof WireFormat)
37082 wireFormat = arg5;
37083 else if (arg6 instanceof WireFormat)
37084 wireFormat = arg6;
37085 else
37086 wireFormat = WireFormat.getDefaultWireFormat();
37087
37088 if (!onRegisterFailed)
37089 onRegisterFailed = function() {};
37090
37091 var registeredPrefixId = this.getNextEntryId();
37092 var thisFace = this;
37093 var onConnected = function() {
37094 thisFace.nfdRegisterPrefix
37095 (registeredPrefixId, prefix, onInterest, flags, onRegisterFailed,
37096 onRegisterSuccess, thisFace.commandKeyChain,
37097 thisFace.commandCertificateName, wireFormat);
37098 };
37099
37100 if (this.connectionInfo == null) {
37101 if (this.getConnectionInfo == null)
37102 console.log('ERROR: connectionInfo is NOT SET');
37103 else
37104 this.connectAndExecute(onConnected);
37105 }
37106 else
37107 onConnected();
37108
37109 return registeredPrefixId;
37110};
37111
37112/**
37113 * Get the practical limit of the size of a network-layer packet. If a packet
37114 * is larger than this, the library or application MAY drop it.
37115 * @return {number} The maximum NDN packet size.
37116 */
37117Face.getMaxNdnPacketSize = function() { return NdnCommon.MAX_NDN_PACKET_SIZE; };
37118
37119/**
37120 * A RegisterResponse has onData to receive the response Data packet from the
37121 * register prefix interest sent to the connected NDN hub. If this gets a bad
37122 * response or onTimeout is called, then call onRegisterFailed.
37123 */
37124Face.RegisterResponse = function RegisterResponse
37125 (prefix, onRegisterFailed, onRegisterSuccess, registeredPrefixId, parent,
37126 onInterest)
37127{
37128 this.prefix = prefix;
37129 this.onRegisterFailed = onRegisterFailed;
37130 this.onRegisterSuccess= onRegisterSuccess;
37131 this.registeredPrefixId = registeredPrefixId;
37132 this.parent = parent;
37133 this.onInterest = onInterest;
37134};
37135
37136Face.RegisterResponse.prototype.onData = function(interest, responseData)
37137{
37138 // Decode responseData.getContent() and check for a success code.
37139 var controlResponse = new ControlResponse();
37140 try {
37141 controlResponse.wireDecode(responseData.getContent(), TlvWireFormat.get());
37142 }
37143 catch (e) {
37144 // Error decoding the ControlResponse.
37145 if (LOG > 0)
37146 console.log("Register prefix failed: Error decoding the NFD response: " + e);
37147 if (this.onRegisterFailed) {
37148 try {
37149 this.onRegisterFailed(this.prefix);
37150 } catch (ex) {
37151 console.log("Error in onRegisterFailed: " + NdnCommon.getErrorWithStackTrace(ex));
37152 }
37153 }
37154 return;
37155 }
37156
37157 // Status code 200 is "OK".
37158 if (controlResponse.getStatusCode() != 200) {
37159 if (LOG > 0)
37160 console.log("Register prefix failed: Expected NFD status code 200, got: " +
37161 controlResponse.getStatusCode());
37162 if (this.onRegisterFailed) {
37163 try {
37164 this.onRegisterFailed(this.prefix);
37165 } catch (ex) {
37166 console.log("Error in onRegisterFailed: " + NdnCommon.getErrorWithStackTrace(ex));
37167 }
37168 }
37169 return;
37170 }
37171
37172 // Success, so we can add to the registered prefix table.
37173 if (this.registeredPrefixId != 0) {
37174 var interestFilterId = 0;
37175 if (this.onInterest != null)
37176 // registerPrefix was called with the "combined" form that includes the
37177 // callback, so add an InterestFilterEntry.
37178 interestFilterId = this.parent.setInterestFilter
37179 (new InterestFilter(this.prefix), this.onInterest);
37180
37181 if (!this.parent.registeredPrefixTable_.add
37182 (this.registeredPrefixId, this.prefix, interestFilterId)) {
37183 // removeRegisteredPrefix was already called with the registeredPrefixId.
37184 if (interestFilterId > 0)
37185 // Remove the related interest filter we just added.
37186 this.parent.unsetInterestFilter(interestFilterId);
37187
37188 return;
37189 }
37190 }
37191
37192 if (LOG > 2)
37193 console.log("Register prefix succeeded with the NFD forwarder for prefix " +
37194 this.prefix.toUri());
37195 if (this.onRegisterSuccess != null) {
37196 try {
37197 this.onRegisterSuccess(this.prefix, this.registeredPrefixId);
37198 } catch (ex) {
37199 console.log("Error in onRegisterSuccess: " + NdnCommon.getErrorWithStackTrace(ex));
37200 }
37201 }
37202};
37203
37204/**
37205 * We timed out waiting for the response.
37206 */
37207Face.RegisterResponse.prototype.onTimeout = function(interest)
37208{
37209 if (LOG > 2)
37210 console.log("Timeout for NFD register prefix command.");
37211 if (this.onRegisterFailed) {
37212 try {
37213 this.onRegisterFailed(this.prefix);
37214 } catch (ex) {
37215 console.log("Error in onRegisterFailed: " + NdnCommon.getErrorWithStackTrace(ex));
37216 }
37217 }
37218};
37219
37220/**
37221 * Do the work of registerPrefix to register with NFD.
37222 * @param {number} registeredPrefixId The Face.getNextEntryId() which
37223 * registerPrefix got so it could return it to the caller. If this is 0, then
37224 * don't add to registeredPrefixTable (assuming it has already been done).
37225 * @param {Name} prefix
37226 * @param {function} onInterest
37227 * @param {ForwardingFlags} flags
37228 * @param {function} onRegisterFailed
37229 * @param {function} onRegisterSuccess
37230 * @param {KeyChain} commandKeyChain
37231 * @param {Name} commandCertificateName
37232 * @param {WireFormat} wireFormat
37233 */
37234Face.prototype.nfdRegisterPrefix = function
37235 (registeredPrefixId, prefix, onInterest, flags, onRegisterFailed,
37236 onRegisterSuccess, commandKeyChain, commandCertificateName, wireFormat)
37237{
37238 if (commandKeyChain == null)
37239 throw new Error
37240 ("registerPrefix: The command KeyChain has not been set. You must call setCommandSigningInfo.");
37241 if (commandCertificateName.size() == 0)
37242 throw new Error
37243 ("registerPrefix: The command certificate name has not been set. You must call setCommandSigningInfo.");
37244
37245 var controlParameters = new ControlParameters();
37246 controlParameters.setName(prefix);
37247 controlParameters.setForwardingFlags(flags);
37248
37249 // Make the callback for this.isLocal().
37250 var thisFace = this;
37251 var onIsLocalResult = function(isLocal) {
37252 var commandInterest = new Interest();
37253 if (isLocal) {
37254 commandInterest.setName(new Name("/localhost/nfd/rib/register"));
37255 // The interest is answered by the local host, so set a short timeout.
37256 commandInterest.setInterestLifetimeMilliseconds(2000.0);
37257 }
Alexander Afanasyev1663a412013-03-02 13:52:00 -080037258 else {
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080037259 commandInterest.setName(new Name("/localhop/nfd/rib/register"));
37260 // The host is remote, so set a longer timeout.
37261 commandInterest.setInterestLifetimeMilliseconds(4000.0);
37262 }
37263 // NFD only accepts TlvWireFormat packets.
37264 commandInterest.getName().append
37265 (controlParameters.wireEncode(TlvWireFormat.get()));
37266 thisFace.nodeMakeCommandInterest
37267 (commandInterest, commandKeyChain, commandCertificateName,
37268 TlvWireFormat.get(), function() {
37269 // Send the registration interest.
37270 var response = new Face.RegisterResponse
37271 (prefix, onRegisterFailed, onRegisterSuccess, registeredPrefixId,
37272 thisFace, onInterest);
37273 thisFace.reconnectAndExpressInterest
37274 (null, commandInterest, response.onData.bind(response),
37275 response.onTimeout.bind(response), null, wireFormat);
37276 });
37277 };
Alexander Afanasyev1663a412013-03-02 13:52:00 -080037278
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080037279 this.isLocal
37280 (onIsLocalResult,
37281 function(message) {
37282 if (LOG > 0)
37283 console.log("Error in Transport.isLocal: " + message);
37284 if (onRegisterFailed) {
37285 try {
37286 onRegisterFailed(prefix);
37287 } catch (ex) {
37288 console.log("Error in onRegisterFailed: " + NdnCommon.getErrorWithStackTrace(ex));
37289 }
37290 }
37291 });
Alexander Afanasyev1663a412013-03-02 13:52:00 -080037292};
37293
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080037294/**
37295 * Remove the registered prefix entry with the registeredPrefixId from the
37296 * registered prefix table. This does not affect another registered prefix with
37297 * a different registeredPrefixId, even if it has the same prefix name. If an
37298 * interest filter was automatically created by registerPrefix, also remove it.
37299 * If there is no entry with the registeredPrefixId, do nothing.
37300 *
37301 * @param {number} registeredPrefixId The ID returned from registerPrefix.
Alexander Afanasyev1663a412013-03-02 13:52:00 -080037302 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080037303Face.prototype.removeRegisteredPrefix = function(registeredPrefixId)
37304{
37305 this.registeredPrefixTable_.removeRegisteredPrefix(registeredPrefixId);
Alexander Afanasyev1663a412013-03-02 13:52:00 -080037306};
37307
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080037308/**
37309 * Add an entry to the local interest filter table to call the onInterest
37310 * callback for a matching incoming Interest. This method only modifies the
37311 * library's local callback table and does not register the prefix with the
37312 * forwarder. It will always succeed. To register a prefix with the forwarder,
37313 * use registerPrefix. There are two forms of setInterestFilter.
37314 * The first form uses the exact given InterestFilter:
37315 * setInterestFilter(filter, onInterest).
37316 * The second form creates an InterestFilter from the given prefix Name:
37317 * setInterestFilter(prefix, onInterest).
37318 * @param {InterestFilter} filter The InterestFilter with a prefix and optional
37319 * regex filter used to match the name of an incoming Interest. This makes a
37320 * copy of filter.
37321 * @param {Name} prefix The Name prefix used to match the name of an incoming
37322 * Interest.
37323 * @param {function} onInterest When an Interest is received which matches the
37324 * filter, this calls onInterest(prefix, interest, face, interestFilterId, filter).
37325 * NOTE: The library will log any exceptions thrown by this callback, but for
37326 * better error handling the callback should catch and properly handle any
37327 * exceptions.
Alexander Afanasyev1663a412013-03-02 13:52:00 -080037328 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080037329Face.prototype.setInterestFilter = function(filterOrPrefix, onInterest)
37330{
37331 var interestFilterId = this.getNextEntryId();
37332 this.interestFilterTable_.setInterestFilter
37333 (interestFilterId, new InterestFilter(filterOrPrefix), onInterest, this);
37334 return interestFilterId;
Alexander Afanasyev1663a412013-03-02 13:52:00 -080037335};
37336
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080037337/**
37338 * Remove the interest filter entry which has the interestFilterId from the
37339 * interest filter table. This does not affect another interest filter with a
37340 * different interestFilterId, even if it has the same prefix name. If there is
37341 * no entry with the interestFilterId, do nothing.
37342 * @param {number} interestFilterId The ID returned from setInterestFilter.
Alexander Afanasyev1663a412013-03-02 13:52:00 -080037343 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080037344Face.prototype.unsetInterestFilter = function(interestFilterId)
37345{
37346 this.interestFilterTable_.unsetInterestFilter(interestFilterId);
37347};
37348
37349/**
37350 * The OnInterest callback calls this to put a Data packet which satisfies an
37351 * Interest.
37352 * @param {Data} data The Data packet which satisfies the interest.
37353 * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
37354 * the Data packet. If omitted, use WireFormat.getDefaultWireFormat().
37355 * @throws Error If the encoded Data packet size exceeds getMaxNdnPacketSize().
37356 */
37357Face.prototype.putData = function(data, wireFormat)
37358{
37359 wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
37360
37361 var encoding = data.wireEncode(wireFormat);
37362 if (encoding.size() > Face.getMaxNdnPacketSize())
37363 throw new Error
37364 ("The encoded Data packet size exceeds the maximum limit getMaxNdnPacketSize()");
37365
37366 this.transport.send(encoding.buf());
37367};
37368
37369/**
37370 * Send the encoded packet out through the transport.
37371 * @param {Buffer} encoding The Buffer with the encoded packet to send.
37372 * @throws Error If the encoded packet size exceeds getMaxNdnPacketSize().
37373 */
37374Face.prototype.send = function(encoding)
37375{
37376 if (encoding.length > Face.getMaxNdnPacketSize())
37377 throw new Error
37378 ("The encoded packet size exceeds the maximum limit getMaxNdnPacketSize()");
37379
37380 this.transport.send(encoding);
37381};
37382
37383/**
37384 * Check if the face is local based on the current connection through the
37385 * Transport; some Transport may cause network I/O (e.g. an IP host name lookup).
37386 * @param {function} onResult On success, this calls onResult(isLocal) where
37387 * isLocal is true if the host is local, false if not. We use callbacks because
37388 * this may need to do network I/O (e.g. an IP host name lookup).
37389 * @param {function} onError On failure for DNS lookup or other error, this
37390 * calls onError(message) where message is an error string.
37391 */
37392Face.prototype.isLocal = function(onResult, onError)
37393{
37394 // TODO: How to call transport.isLocal when this.connectionInfo is null? (This
37395 // happens when the application does not supply a host but relies on the
37396 // getConnectionInfo function to select a host.) For now return true to keep
37397 // the same behavior from before we added Transport.isLocal.
37398 if (this.connectionInfo == null)
37399 onResult(false);
37400 else
37401 this.transport.isLocal(this.connectionInfo, onResult, onError);
37402};
37403
37404/**
37405 * This is called when an entire element is received, such as a Data or Interest.
37406 */
37407Face.prototype.onReceivedElement = function(element)
37408{
37409 if (LOG > 3) console.log('Complete element received. Length ' + element.length + '. Start decoding.');
37410
37411 var lpPacket = null;
37412 if (element[0] == Tlv.LpPacket_LpPacket) {
37413 // Decode the LpPacket and replace element with the fragment.
37414 lpPacket = new LpPacket();
37415 // Set copy false so that the fragment is a slice which will be copied below.
37416 // The header fields are all integers and don't need to be copied.
37417 TlvWireFormat.get().decodeLpPacket(lpPacket, element, false);
37418 element = lpPacket.getFragmentWireEncoding().buf();
37419 }
37420
37421 // First, decode as Interest or Data.
37422 var interest = null;
37423 var data = null;
37424 if (element[0] == Tlv.Interest || element[0] == Tlv.Data) {
37425 var decoder = new TlvDecoder (element);
37426 if (decoder.peekType(Tlv.Interest, element.length)) {
37427 interest = new Interest();
37428 interest.wireDecode(element, TlvWireFormat.get());
37429
37430 if (lpPacket != null)
37431 interest.setLpPacket(lpPacket);
37432 }
37433 else if (decoder.peekType(Tlv.Data, element.length)) {
37434 data = new Data();
37435 data.wireDecode(element, TlvWireFormat.get());
37436
37437 if (lpPacket != null)
37438 data.setLpPacket(lpPacket);
37439 }
37440 }
37441
37442 if (lpPacket !== null) {
37443 // We have decoded the fragment, so remove the wire encoding to save memory.
37444 lpPacket.setFragmentWireEncoding(new Blob());
37445
37446 var networkNack = NetworkNack.getFirstHeader(lpPacket);
37447 if (networkNack != null) {
37448 if (interest == null)
37449 // We got a Nack but not for an Interest, so drop the packet.
Alexander Afanasyev1663a412013-03-02 13:52:00 -080037450 return;
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080037451
37452 var pitEntries = [];
37453 this.pendingInterestTable_.extractEntriesForNackInterest(interest, pitEntries);
37454 for (var i = 0; i < pitEntries.length; ++i) {
37455 var pendingInterest = pitEntries[i];
37456 try {
37457 pendingInterest.getOnNetworkNack()(pendingInterest.getInterest(), networkNack);
37458 } catch (ex) {
37459 console.log("Error in onNetworkNack: " + NdnCommon.getErrorWithStackTrace(ex));
37460 }
37461 }
37462
37463 // We have processed the network Nack packet.
37464 return;
Alexander Afanasyev1663a412013-03-02 13:52:00 -080037465 }
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080037466 }
Alexander Afanasyev1663a412013-03-02 13:52:00 -080037467
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080037468 // Now process as Interest or Data.
37469 if (interest !== null) {
37470 if (LOG > 3) console.log('Interest packet received.');
37471
37472 // Call all interest filter callbacks which match.
37473 var matchedFilters = [];
37474 this.interestFilterTable_.getMatchedFilters(interest, matchedFilters);
37475 for (var i = 0; i < matchedFilters.length; ++i) {
37476 var entry = matchedFilters[i];
37477 if (LOG > 3)
37478 console.log("Found interest filter for " + interest.getName().toUri());
37479 try {
37480 entry.getOnInterest()
37481 (entry.getFilter().getPrefix(), interest, this,
37482 entry.getInterestFilterId(), entry.getFilter());
37483 } catch (ex) {
37484 console.log("Error in onInterest: " + NdnCommon.getErrorWithStackTrace(ex));
37485 }
Alexander Afanasyev1663a412013-03-02 13:52:00 -080037486 }
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080037487 }
37488 else if (data !== null) {
37489 if (LOG > 3) console.log('Data packet received.');
Alexander Afanasyev1663a412013-03-02 13:52:00 -080037490
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080037491 var pendingInterests = [];
37492 this.pendingInterestTable_.extractEntriesForExpressedInterest
37493 (data, pendingInterests);
37494 // Process each matching PIT entry (if any).
37495 for (var i = 0; i < pendingInterests.length; ++i) {
37496 var pendingInterest = pendingInterests[i];
37497 try {
37498 pendingInterest.getOnData()(pendingInterest.getInterest(), data);
37499 } catch (ex) {
37500 console.log("Error in onData: " + NdnCommon.getErrorWithStackTrace(ex));
37501 }
37502 }
37503 }
Alexander Afanasyev1663a412013-03-02 13:52:00 -080037504};
37505
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080037506/**
37507 * Assume this.getConnectionInfo is not null. This is called when
37508 * this.connectionInfo is null or its host is not alive.
37509 * Get a connectionInfo, connect, then execute onConnected().
Alexander Afanasyev1663a412013-03-02 13:52:00 -080037510 */
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080037511Face.prototype.connectAndExecute = function(onConnected)
37512{
37513 var connectionInfo = this.getConnectionInfo();
37514 if (connectionInfo == null) {
37515 console.log('ERROR: No more connectionInfo from getConnectionInfo');
37516 this.connectionInfo = null;
37517 // Deprecated: Set this.host and this.port for backwards compatibility.
37518 this.host = null;
37519 this.host = null;
37520
37521 return;
37522 }
37523
37524 if (connectionInfo.equals(this.connectionInfo)) {
37525 console.log
37526 ('ERROR: The host returned by getConnectionInfo is not alive: ' +
37527 this.connectionInfo.toString());
37528 return;
37529 }
37530
37531 this.connectionInfo = connectionInfo;
37532 if (LOG>0) console.log("connectAndExecute: trying host from getConnectionInfo: " +
37533 this.connectionInfo.toString());
37534 // Deprecated: Set this.host and this.port for backwards compatibility.
37535 this.host = this.connectionInfo.host;
37536 this.host = this.connectionInfo.port;
37537
37538 // Fetch any content.
37539 var interest = new Interest(new Name("/"));
37540 interest.setInterestLifetimeMilliseconds(4000);
37541
37542 var thisFace = this;
37543 var timerID = setTimeout(function() {
37544 if (LOG>0) console.log("connectAndExecute: timeout waiting for host " + thisFace.host);
37545 // Try again.
37546 thisFace.connectAndExecute(onConnected);
37547 }, 3000);
37548
37549 this.reconnectAndExpressInterest
37550 (null, interest,
37551 function(localInterest, localData) {
37552 // The host is alive, so cancel the timeout and continue with onConnected().
37553 clearTimeout(timerID);
37554
37555 if (LOG>0)
37556 console.log("connectAndExecute: connected to host " + thisFace.host);
37557 onConnected();
37558 },
37559 function(localInterest) { /* Ignore timeout */ },
37560 null, WireFormat.getDefaultWireFormat());
Alexander Afanasyev1663a412013-03-02 13:52:00 -080037561};
37562
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080037563/**
37564 * This is called by the Transport when the connection is closed by the remote host.
37565 */
37566Face.prototype.closeByTransport = function()
37567{
37568 this.readyStatus = Face.CLOSED;
37569 this.onclose();
37570};
Alexander Afanasyev1663a412013-03-02 13:52:00 -080037571
Alexander Afanasyeve16ed212016-12-25 18:09:44 -080037572Face.nonceTemplate_ = new Blob(new Buffer(4), false);
37573(function(n,t,i){"use strict";function s(n,t){return typeof t!="object"&&(t=t()),Object.keys(t).forEach(function(i){n[i]=t[i]}),n}function y(n){return{from:function(t){return n.prototype=Object.create(t.prototype),n.prototype.constructor=n,{extend:function(i){s(n.prototype,typeof i!="object"?i(t.prototype):i)}}}}}function p(n,t){return t(n)}function u(n,t){function cr(){w.on("versionchange",function(){w.close();w.on("error").fire(new g("Database version changed by other database connection."))})}function di(n){this._cfg={version:n,storesSource:null,dbschema:{},tables:{},contentUpgrade:null};this.stores({})}function lr(n,t,i,u){var e,f,s,h,l,c;if(n===0)Object.keys(st).forEach(function(n){gi(t,n,st[n].primKey,st[n].indexes)}),e=w._createTransaction(yt,ui,st),e.idbtrans=t,e.idbtrans.onerror=o(i,["populating database"]),e.on("error").subscribe(i),r.newPSD(function(){r.PSD.trans=e;try{w.on("populate").fire(e)}catch(n){u.onerror=t.onerror=function(n){n.preventDefault()};try{t.abort()}catch(f){}t.db.close();i(n)}});else{if(f=[],s=ri.filter(function(t){return t._cfg.version===n})[0],!s)throw new g("Dexie specification of currently installed DB version is missing");st=w._dbSchema=s._cfg.dbschema;h=!1;l=ri.filter(function(t){return t._cfg.version>n});l.forEach(function(n){var e=st,r=n._cfg.dbschema,u;fr(e,t);fr(r,t);st=w._dbSchema=r;u=ar(e,r);u.add.forEach(function(n){f.push(function(t,i){gi(t,n[0],n[1].primKey,n[1].indexes);i()})});u.change.forEach(function(n){if(n.recreate)throw new g("Not yet support for changing primary key");else f.push(function(t,i){var r=t.objectStore(n.name);n.add.forEach(function(n){nr(r,n)});n.change.forEach(function(n){r.deleteIndex(n.name);nr(r,n)});n.del.forEach(function(n){r.deleteIndex(n)});i()})});n._cfg.contentUpgrade&&f.push(function(t,u){var f,e;h=!0;f=w._createTransaction(yt,[].slice.call(t.db.objectStoreNames,0),r);f.idbtrans=t;e=0;f._promise=p(f._promise,function(n){return function(t,i,r){function f(n){return function(){n.apply(this,arguments);--e==0&&u()}}return++e,n.call(this,t,function(n,t){arguments[0]=f(n);arguments[1]=f(t);i.apply(this,arguments)},r)}});t.onerror=o(i,["running upgrader function for version",n._cfg.version]);f.on("error").subscribe(i);n._cfg.contentUpgrade(f);e===0&&u()});h&&dr()||f.push(function(n,t){yr(r,n);t()})});c=function(){try{f.length?f.shift()(t,c):vr(st,t)}catch(n){u.onerror=t.onerror=function(n){n.preventDefault()};try{t.abort()}catch(r){}t.db.close();i(n)}};c()}}function ar(n,t){var f={del:[],add:[],change:[]},r,e,o,i,c,s,u,l,h;for(r in n)t[r]||f.del.push(r);for(r in t)if(e=n[r],o=t[r],e)if(i={name:r,def:t[r],recreate:!1,del:[],add:[],change:[]},e.primKey.src!==o.primKey.src)i.recreate=!0,f.change.push(i);else{c=e.indexes.reduce(function(n,t){return n[t.name]=t,n},{});s=o.indexes.reduce(function(n,t){return n[t.name]=t,n},{});for(u in c)s[u]||i.del.push(u);for(u in s)l=c[u],h=s[u],l?l.src!==h.src&&i.change.push(h):i.add.push(h);(i.recreate||i.del.length>0||i.add.length>0||i.change.length>0)&&f.change.push(i)}else f.add.push([r,o]);return f}function gi(n,t,i,r){var u=n.db.createObjectStore(t,i.keyPath?{keyPath:i.keyPath,autoIncrement:i.auto}:{autoIncrement:i.auto});return r.forEach(function(n){nr(u,n)}),u}function vr(n,t){Object.keys(n).forEach(function(i){t.db.objectStoreNames.contains(i)||gi(t,i,n[i].primKey,n[i].indexes)})}function yr(n,t){for(var u,r=0;r<t.db.objectStoreNames.length;++r)u=t.db.objectStoreNames[r],(n[u]===null||n[u]===i)&&t.db.deleteObjectStore(u)}function nr(n,t){n.createIndex(t.name,t.keyPath,{unique:t.unique,multiEntry:t.multi})}function pr(n,t){throw new g("Table "+t[0]+" not part of transaction. Original Scope Function Source: "+u.Promise.PSD.trans.scopeFunc.toString());}function ei(n,t,i,r){this.name=n;this.schema=i;this.hook=ni[n]?ni[n].hook:v(null,{creating:[at,f],reading:[lt,nt],updating:[vt,f],deleting:[wt,f]});this._tpf=t;this._collClass=r||li}function tr(n,t,i,r){ei.call(this,n,t,i,r||rr)}function ir(n,t,i,r){function o(n,t,i,r){return s._promise(n,i,r)}var s=this,f,u,e;for(this.db=w,this.mode=n,this.storeNames=t,this.idbtrans=null,this.on=v(this,["complete","error"],"abort"),this._reculock=0,this._blockedFuncs=[],this._psd=null,this.active=!0,this._dbschema=i,r&&(this.parent=r),this._tpf=o,this.tables=Object.create(ki),f=t.length-1;f!==-1;--f)u=t[f],e=w._tableFactory(n,i[u],o),this.tables[u]=e,this[u]||(this[u]=e)}function ci(n,t,i){this._ctx={table:n,index:t===":id"?null:t,collClass:n._collClass,or:i}}function li(n,t){var r=null,u=null,i;if(t)try{r=t()}catch(f){u=f}i=n._ctx;this._ctx={table:i.table,index:i.index,isPrimKey:!i.index||i.table.schema.primKey.keyPath&&i.index===i.table.schema.primKey.name,range:r,op:"openCursor",dir:"next",unique:"",algorithm:null,filter:null,isMatch:null,offset:0,limit:Infinity,error:u,or:i.or}}function rr(){li.apply(this,arguments)}function wr(n,t){return n._cfg.version-t._cfg.version}function ur(n,t,i,u,f,e){i.forEach(function(i){var o=w._tableFactory(u,f[i],t);n.forEach(function(n){n[i]||(e?Object.defineProperty(n,i,{configurable:!0,enumerable:!0,get:function(){var n=r.PSD&&r.PSD.trans;return n&&n.db===w?n.tables[i]:o}}):n[i]=o)})})}function br(n){n.forEach(function(n){for(var t in n)n[t]instanceof ei&&delete n[t]})}function pi(n,t,i,u,f,e){var s=r.PSD;e=e||nt;n.onerror||(n.onerror=o(f));n.onsuccess=t?k(function(){var r=n.result,o;r?(o=function(){r.continue()},t(r,function(n){o=n},u,f)&&i(e(r.value),r,function(n){o=n}),o()):u()},f,s):k(function(){var t=n.result,r;t?(r=function(){t.continue()},i(e(t.value),t,function(n){r=n}),r()):u()},f,s)}function kr(n){var t=[];return n.split(",").forEach(function(n){n=n.trim();var i=n.replace("&","").replace("++","").replace("*",""),r=i.indexOf("[")!==0?i:n.substring(n.indexOf("[")+1,n.indexOf("]")).split("+");t.push(new a(i,r||null,n.indexOf("&")!==-1,n.indexOf("*")!==-1,n.indexOf("++")!==-1,Array.isArray(r),r.indexOf(".")!==-1))}),t}function wi(n,t){return n<t?-1:n>t?1:0}function or(n,t){return n<t?1:n>t?-1:0}function sr(n){return function(t,i){for(var r=0,u;;){if(u=n(t[r],i[r]),u!==0)return u;if(++r,r===t.length||r===i.length)return n(t.length,i.length)}}}function bi(n,t){return n?t?function(){return n.apply(this,arguments)&&t.apply(this,arguments)}:n:t}function dr(){return navigator.userAgent.indexOf("Trident")>=0||navigator.userAgent.indexOf("MSIE")>=0}function gr(){if(w.verno=et.version/10,w._dbSchema=st={},ui=[].slice.call(et.objectStoreNames,0),ui.length!==0){var n=et.transaction(ft(ui),"readonly");ui.forEach(function(t){for(var u,s,r=n.objectStore(t),i=r.keyPath,f=i&&typeof i=="string"&&i.indexOf(".")!==-1,h=new a(i,i||"",!1,!1,!!r.autoIncrement,i&&typeof i!="string",f),o=[],e=0;e<r.indexNames.length;++e)u=r.index(r.indexNames[e]),i=u.keyPath,f=i&&typeof i=="string"&&i.indexOf(".")!==-1,s=new a(u.name,i,!!u.unique,!!u.multiEntry,!1,i&&typeof i!="string",f),o.push(s);st[t]=new ut(t,h,o,{})});ur([ni],w._transPromiseFactory,Object.keys(st),yt,st)}}function fr(n,t){for(var i,r,u,o,s=t.db.objectStoreNames,f=0;f<s.length;++f)for(i=s[f],r=t.objectStore(i),u=0;u<r.indexNames.length;++u){var h=r.indexNames[u],e=r.index(h).keyPath,c=typeof e=="string"?e:"["+[].slice.call(e).join("+")+"]";n[i]&&(o=n[i].idxByName[c],o&&(o.name=h))}}var hr=t&&t.addons||u.addons,oi=u.dependencies,ai=oi.indexedDB,kt=oi.IDBKeyRange,nu=oi.IDBTransaction,tu=oi.DOMError,yi=oi.TypeError,g=oi.Error,st=this._dbSchema={},ri=[],ui=[],ni={},ki={},et=null,si=!0,fi=null,vi=!1,ti="readonly",yt="readwrite",w=this,ii=[],hi=!1,er=!!ct();this.version=function(n){if(et)throw new g("Cannot add version when database is open");this.verno=Math.max(this.verno,n);var t=ri.filter(function(t){return t._cfg.version===n})[0];return t?t:(t=new di(n),ri.push(t),ri.sort(wr),t)};s(di.prototype,{stores:function(n){var i,t;return this._cfg.storesSource=this._cfg.storesSource?s(this._cfg.storesSource,n):n,i={},ri.forEach(function(n){s(i,n._cfg.storesSource)}),t=this._cfg.dbschema={},this._parseStoresSpec(i,t),st=w._dbSchema=t,br([ni,w,ki]),ur([ki],pr,Object.keys(t),yt,t),ur([ni,w,this._cfg.tables],w._transPromiseFactory,Object.keys(t),yt,t,!0),ui=Object.keys(t),this},upgrade:function(n){var t=this;return e(function(){n(w._createTransaction(yt,Object.keys(t._cfg.dbschema),t._cfg.dbschema))}),this._cfg.contentUpgrade=n,this},_parseStoresSpec:function(n,t){Object.keys(n).forEach(function(i){if(n[i]!==null){var u={},f=kr(n[i]),r=f.shift();if(r.multi)throw new g("Primary key cannot be multi-valued");r.keyPath&&r.auto&&h(u,r.keyPath,0);f.forEach(function(n){if(n.auto)throw new g("Only primary key can be marked as autoIncrement (++)");if(!n.keyPath)throw new g("Index must have a name and cannot be an empty string");h(u,n.keyPath,n.compound?n.keyPath.map(function(){return""}):"")});t[i]=new ut(i,r,f,u)}})}});this._allTables=ni;this._tableFactory=function(n,t,i){return n===ti?new ei(t.name,i,t,li):new tr(t.name,i,t)};this._createTransaction=function(n,t,i,r){return new ir(n,t,i,r)};this._transPromiseFactory=function(n,t,i){var f,u;return!si||r.PSD&&r.PSD.letThrough?(u=w._createTransaction(n,t,st),u._promise(n,function(n,t){u.error(function(n){w.on("error").fire(n)});i(function(t){u.complete(function(){n(t)})},t,u)})):f=new r(function(r,u){ii.push({resume:function(){var e=w._transPromiseFactory(n,t,i);f.onuncatched=e.onuncatched;e.then(r,u)}})})};this._whenReady=function(n){return si&&(!r.PSD||!r.PSD.letThrough)?new r(function(t,i){e(function(){new r(function(){n(t,i)})});ii.push({resume:function(){n(t,i)}})}):new r(n)};this.verno=0;this.open=function(){return new r(function(t,i){function f(n){try{u.transaction.abort()}catch(t){}vi=!1;fi=n;si=!1;i(fi);ii.forEach(function(n){n.resume()});ii=[]}if(et||vi)throw new g("Database already opened or being opened");var u,e=!1;try{if(fi=null,vi=!0,ri.length===0&&(hi=!0),!ai)throw new g("indexedDB API not found. If using IE10+, make sure to run your code on a server URL (not locally). If using Safari, make sure to include indexedDB polyfill.");u=hi?ai.open(n):ai.open(n,Math.round(w.verno*10));u.onerror=o(f,["opening database",n]);u.onblocked=function(n){w.on("blocked").fire(n)};u.onupgradeneeded=k(function(t){var i,r;hi&&!w._allowEmptyDB?(u.onerror=function(n){n.preventDefault()},u.transaction.abort(),u.result.close(),i=ai.deleteDatabase(n),i.onsuccess=i.onerror=function(){f(new g("Database '"+n+"' doesnt exist"))}):(t.oldVersion===0&&(e=!0),u.transaction.onerror=o(f),r=t.oldVersion>Math.pow(2,62)?0:t.oldVersion,lr(r/10,u.transaction,f,u))},f);u.onsuccess=k(function(){vi=!1;et=u.result;hi?gr():et.objectStoreNames.length>0&&fr(st,et.transaction(ft(et.objectStoreNames),ti));et.onversionchange=w.on("versionchange").fire;er||rt(function(t){if(t.indexOf(n)===-1)return t.push(n)});r.newPSD(function(){function i(){si=!1;ii.forEach(function(n){n.resume()});ii=[];t()}r.PSD.letThrough=!0;try{var n=w.on.ready.fire();n&&typeof n.then=="function"?n.then(i,function(n){et.close();et=null;f(n)}):b(i)}catch(u){f(u)}})},f)}catch(s){f(s)}})};this.close=function(){et&&(et.close(),et=null,si=!0,fi=null)};this.delete=function(){var t=arguments;return new r(function(i,r){function u(){w.close();var t=ai.deleteDatabase(n);t.onsuccess=function(){er||rt(function(t){var i=t.indexOf(n);if(i>=0)return t.splice(i,1)});i()};t.onerror=o(r,["deleting",n]);t.onblocked=function(){w.on("blocked").fire()}}if(t.length>0)throw new g("Arguments not allowed in db.delete()");vi?ii.push({resume:u}):u()})};this.backendDB=function(){return et};this.isOpen=function(){return et!==null};this.hasFailed=function(){return fi!==null};this.dynamicallyOpened=function(){return hi};this.name=n;Object.defineProperty(this,"tables",{get:function(){return Object.keys(ni).map(function(n){return ni[n]})}});this.on=v(this,"error","populate","blocked",{ready:[bt,f],versionchange:[pt,f]});this.on.ready.subscribe=p(this.on.ready.subscribe,function(n){return function(t,i){function r(){return i||w.on.ready.unsubscribe(r),t.apply(this,arguments)}n.call(this,r);w.isOpen()&&(si?ii.push({resume:r}):r())}});e(function(){w.on("populate").fire(w._createTransaction(yt,ui,st));w.on("error").fire(new g)});this.transaction=function(n,t,i){function s(t,e){var s=null,c,a,h;try{if(f)throw f;s=w._createTransaction(n,o,st,u);c=o.map(function(n){return s.tables[n]});c.push(s);h=0;r.newPSD(function(){r.PSD.trans=s;s.scopeFunc=i;u&&(s.idbtrans=u.idbtrans,s._promise=p(s._promise,function(n){return function(t,i,u){function f(n){return function(t){var i;return r._rootExec(function(){i=n(t);r._tickFinalize(function(){--h==0&&s.active&&(s.active=!1,s.on.complete.fire())})}),i}}return++h,n.call(this,t,function(n,t,r){return i(f(n),f(t),r)},u)}}));s.complete(function(){t(a)});s.error(function(n){s.idbtrans&&(s.idbtrans.onerror=ht);try{s.abort()}catch(i){}u&&(u.active=!1,u.on.error.fire(n));var t=e(n);u||t||w.on.error.fire(n)});r._rootExec(function(){a=i.apply(s,c)})});(!s.idbtrans||u&&h===0)&&s._nop()}catch(l){s&&s.idbtrans&&(s.idbtrans.onerror=ht);s&&s.abort();u&&u.on.error.fire(l);b(function(){e(l)||w.on("error").fire(l)})}}var u,e;t=[].slice.call(arguments,1,arguments.length-1);i=arguments[arguments.length-1];u=r.PSD&&r.PSD.trans;u&&u.db===w&&n.indexOf("!")===-1||(u=null);e=n.indexOf("?")!==-1;n=n.replace("!","").replace("?","");var h=Array.isArray(t[0])?t.reduce(function(n,t){return n.concat(t)}):t,f=null,o=h.map(function(n){return typeof n=="string"?n:(n instanceof ei||(f=f||new yi("Invalid type. Arguments following mode must be instances of Table or String")),n.name)});return n=="r"||n==ti?n=ti:n=="rw"||n==yt?n=yt:f=new g("Invalid transaction mode: "+n),u&&(f||(u&&u.mode===ti&&n===yt&&(e?u=null:f=f||new g("Cannot enter a sub-transaction with READWRITE mode when parent transaction is READONLY")),u&&o.forEach(function(n){u.tables.hasOwnProperty(n)||(e?u=null:f=f||new g("Table "+n+" not included in parent transaction. Parent Transaction function: "+u.scopeFunc.toString()))}))),u?u._promise(n,s,"lock"):w._whenReady(s)};this.table=function(n){if(!hi&&!ni.hasOwnProperty(n))throw new g("Table does not exist");return ni[n]};s(ei.prototype,function(){function n(){throw new g("Current Transaction is READONLY");}return{_trans:function(n,t,i){return this._tpf(n,[this.name],t,i)},_idbstore:function(n,t,i){var r=this;return this._tpf(n,[this.name],function(n,i,u){t(n,i,u.idbtrans.objectStore(r.name),u)},i)},get:function(n,t){var i=this;return e(function(){t(i.schema.instanceTemplate)}),this._idbstore(ti,function(t,r,u){var f=u.get(n);f.onerror=o(r,["getting",n,"from",i.name]);f.onsuccess=function(){t(i.hook.reading.fire(f.result))}}).then(t)},where:function(n){return new ci(this,n)},count:function(n){return this.toCollection().count(n)},offset:function(n){return this.toCollection().offset(n)},limit:function(n){return this.toCollection().limit(n)},reverse:function(){return this.toCollection().reverse()},filter:function(n){return this.toCollection().and(n)},each:function(n){var t=this;return e(function(){n(t.schema.instanceTemplate)}),this._idbstore(ti,function(i,r,u){var f=u.openCursor();f.onerror=o(r,["calling","Table.each()","on",t.name]);pi(f,null,n,i,r,t.hook.reading.fire)})},toArray:function(n){var t=this;return e(function(){n([t.schema.instanceTemplate])}),this._idbstore(ti,function(n,i,r){var u=[],f=r.openCursor();f.onerror=o(i,["calling","Table.toArray()","on",t.name]);pi(f,null,function(n){u.push(n)},function(){n(u)},i,t.hook.reading.fire)}).then(n)},orderBy:function(n){return new this._collClass(new ci(this,n))},toCollection:function(){return new this._collClass(new ci(this))},mapToClass:function(n,t){var i,r;return this.schema.mappedClass=n,i=Object.create(n.prototype),this.schema.primKey.keyPath&&(h(i,this.schema.primKey.keyPath,this.schema.primKey.auto?0:""),ot(n.prototype,this.schema.primKey.keyPath)),t&&it(i,t),this.schema.instanceTemplate=i,r=Object.setPrototypeOf?function(t){return t?(Object.setPrototypeOf(t,n.prototype),t):t}:function(t){var r,i;if(!t)return t;r=Object.create(n.prototype);for(i in t)t.hasOwnProperty(i)&&(r[i]=t[i]);return r},this.schema.readHook&&this.hook.reading.unsubscribe(this.schema.readHook),this.schema.readHook=r,this.hook("reading",r),n},defineClass:function(n){return this.mapToClass(u.defineClass(n),n)},add:n,put:n,"delete":n,clear:n,update:n}});y(tr).from(ei).extend(function(){return{add:function(n,t){var u=this,r=this.hook.creating.fire;return this._idbstore(yt,function(e,s,l,a){var v={},w,y,p;r!==f&&(w=t||(l.keyPath?c(n,l.keyPath):i),y=r.call(v,w,n,a),w===i&&y!==i&&(l.keyPath?h(n,l.keyPath,y):t=y));p=t?l.add(n,t):l.add(n);p.onerror=o(function(n){if(v.onerror)v.onerror(n);return s(n)},["adding",n,"into",u.name]);p.onsuccess=function(t){var i=l.keyPath;if(i&&h(n,i,t.target.result),v.onsuccess)v.onsuccess(t.target.result);e(p.result)}})},put:function(n,t){var r=this,u=this.hook.creating.fire,e=this.hook.updating.fire;return u!==f||e!==f?this._trans(yt,function(u,f,e){var o=t||r.schema.primKey.keyPath&&c(n,r.schema.primKey.keyPath);o===i?e.tables[r.name].add(n).then(u,f):(e._lock(),n=l(n),e.tables[r.name].where(":id").equals(o).modify(function(){this.value=n}).then(function(i){return i===0?e.tables[r.name].add(n,t):o}).finally(function(){e._unlock()}).then(u,f))}):this._idbstore(yt,function(i,u,f){var e=t?f.put(n,t):f.put(n);e.onerror=o(u,["putting",n,"into",r.name]);e.onsuccess=function(t){var r=f.keyPath;r&&h(n,r,t.target.result);i(e.result)}})},"delete":function(n){return this.hook.deleting.subscribers.length?this.where(":id").equals(n).delete():this._idbstore(yt,function(t,i,r){var u=r.delete(n);u.onerror=o(i,["deleting",n,"from",r.name]);u.onsuccess=function(){t(u.result)}})},clear:function(){return this.hook.deleting.subscribers.length?this.toCollection().delete():this._idbstore(yt,function(n,t,i){var r=i.clear();r.onerror=o(t,["clearing",i.name]);r.onsuccess=function(){n(r.result)}})},update:function(n,t){if(typeof t!="object"||Array.isArray(t))throw new g("db.update(keyOrObject, modifications). modifications must be an object.");if(typeof n!="object"||Array.isArray(n))return this.where(":id").equals(n).modify(t);Object.keys(t).forEach(function(i){h(n,i,t[i])});var u=c(n,this.schema.primKey.keyPath);return u===i&&r.reject(new g("Object does not contain its primary key")),this.where(":id").equals(u).modify(t)}}});s(ir.prototype,{_lock:function(){return++this._reculock,this._reculock===1&&r.PSD&&(r.PSD.lockOwnerFor=this),this},_unlock:function(){if(--this._reculock==0)for(r.PSD&&(r.PSD.lockOwnerFor=null);this._blockedFuncs.length>0&&!this._locked();){var n=this._blockedFuncs.shift();try{n()}catch(t){}}return this},_locked:function(){return this._reculock&&(!r.PSD||r.PSD.lockOwnerFor!==this)},_nop:function(n){this.tables[this.storeNames[0]].get(0).then(n)},_promise:function(n,t,i){var f=this;return r.newPSD(function(){var e;return f._locked()?e=new r(function(r,u){f._blockedFuncs.push(function(){f._promise(n,t,i).then(r,u)})}):(e=f.active?new r(function(r,e){if(!f.idbtrans&&n){if(!et)throw fi?new g("Database not open. Following error in populate, ready or upgrade function made Dexie.open() fail: "+fi):new g("Database not open");var o=f.idbtrans=et.transaction(ft(f.storeNames),f.mode);o.onerror=function(n){f.on("error").fire(n&&n.target.error);n.preventDefault();f.abort()};o.onabort=function(n){f.active=!1;f.on("abort").fire(n)};o.oncomplete=function(n){f.active=!1;f.on("complete").fire(n)}}i&&f._lock();try{t(r,e,f)}catch(s){u.ignoreTransaction(function(){f.on("error").fire(s)});f.abort();e(s)}}):r.reject(gt(new g("Transaction is inactive. Original Scope Function Source: "+f.scopeFunc.toString()))),f.active&&i&&e.finally(function(){f._unlock()})),e.onuncatched=function(n){u.ignoreTransaction(function(){f.on("error").fire(n)});f.abort()},e})},complete:function(n){return this.on("complete",n)},error:function(n){return this.on("error",n)},abort:function(){if(this.idbtrans&&this.active)try{this.active=!1;this.idbtrans.abort();this.on.error.fire(new g("Transaction Aborted"))}catch(n){}},table:function(n){if(!this.tables.hasOwnProperty(n))throw new g("Table "+n+" not in transaction");return this.tables[n]}});s(ci.prototype,function(){function n(n,t){try{throw t;}catch(i){n._ctx.error=i}return n}function i(n){return Array.prototype.slice.call(n.length===1&&Array.isArray(n[0])?n[0]:n)}function r(n){return n==="next"?function(n){return n.toUpperCase()}:function(n){return n.toLowerCase()}}function u(n){return n==="next"?function(n){return n.toLowerCase()}:function(n){return n.toUpperCase()}}function f(n,t,i,r,u,f){for(var h,s=Math.min(n.length,r.length),o=-1,e=0;e<s;++e){if(h=t[e],h!==r[e])return u(n[e],i[e])<0?n.substr(0,e)+i[e]+i.substr(e+1):u(n[e],r[e])<0?n.substr(0,e)+r[e]+i.substr(e+1):o>=0?n.substr(0,o)+t[o]+i.substr(o+1):null;u(n[e],h)<0&&(o=e)}return s<r.length&&f==="next"?n+i.substr(n.length):s<n.length&&f==="prev"?n.substr(0,i.length):o<0?null:n.substr(0,o)+r[o]+i.substr(o+1)}function t(n,t,i){function a(n){s=r(n);e=u(n);h=n==="next"?wi:or;c=s(i);o=e(i);l=n}var s,e,h,c,o,l;a("next");n._ondirectionchange=function(n){a(n)};n._addAlgorithm(function(n,i,r){var u=n.key,s,a;return typeof u!="string"?!1:(s=e(u),t(s,o)?(i(function(){n.continue()}),!0):(a=f(u,s,c,o,h,l),a?i(function(){n.continue(a)}):i(r),!1))})}return{between:function(n,t,i,r){return(i=i!==!1,r=r===!0,n>t||n===t&&(i||r)&&!(i&&r))?new this._ctx.collClass(this,function(){return kt.only(n)}).limit(0):new this._ctx.collClass(this,function(){return kt.bound(n,t,!i,!r)})},equals:function(n){return new this._ctx.collClass(this,function(){return kt.only(n)})},above:function(n){return new this._ctx.collClass(this,function(){return kt.lowerBound(n,!0)})},aboveOrEqual:function(n){return new this._ctx.collClass(this,function(){return kt.lowerBound(n)})},below:function(n){return new this._ctx.collClass(this,function(){return kt.upperBound(n,!0)})},belowOrEqual:function(n){return new this._ctx.collClass(this,function(){return kt.upperBound(n)})},startsWith:function(t){return typeof t!="string"?n(new this._ctx.collClass(this),new yi("String expected")):this.between(t,t+String.fromCharCode(65535),!0,!0)},startsWithIgnoreCase:function(i){if(typeof i!="string")return n(new this._ctx.collClass(this),new yi("String expected"));if(i==="")return this.startsWith(i);var r=new this._ctx.collClass(this,function(){return kt.bound(i.toUpperCase(),i.toLowerCase()+String.fromCharCode(65535))});return t(r,function(n,t){return n.indexOf(t)===0},i),r._ondirectionchange=function(){n(r,new g("reverse() not supported with WhereClause.startsWithIgnoreCase()"))},r},equalsIgnoreCase:function(i){if(typeof i!="string")return n(new this._ctx.collClass(this),new yi("String expected"));var r=new this._ctx.collClass(this,function(){return kt.bound(i.toUpperCase(),i.toLowerCase())});return t(r,function(n,t){return n===t},i),r},anyOf:function(){var f=this._ctx,e=f.table.schema,o=f.index?e.idxByName[f.index]:e.primKey,s=o&&o.compound,n=i(arguments),t=s?sr(wi):wi,u,r;return(n.sort(t),n.length===0)?new this._ctx.collClass(this,function(){return kt.only("")}).limit(0):(u=new this._ctx.collClass(this,function(){return kt.bound(n[0],n[n.length-1])}),u._ondirectionchange=function(i){t=i==="next"?wi:or;s&&(t=sr(t));n.sort(t)},r=0,u._addAlgorithm(function(i,u,f){for(var e=i.key;t(e,n[r])>0;)if(++r,r===n.length)return u(f),!1;return t(e,n[r])===0?(u(function(){i.continue()}),!0):(u(function(){i.continue(n[r])}),!1)}),u)}}});s(li.prototype,function(){function t(n,t){n.filter=bi(n.filter,t)}function f(n,t){n.isMatch=bi(n.isMatch,t)}function r(n,t){if(n.isPrimKey)return t;var i=n.table.schema.idxByName[n.index];if(!i)throw new g("KeyPath "+n.index+" on object store "+t.name+" is not indexed");return n.isPrimKey?t:t.index(i.name)}function u(n,t){return r(n,t)[n.op](n.range||null,n.dir+n.unique)}function i(n,t,i,r,f){n.or?function(){function e(){++c==2&&i()}function h(n,i,u){if(!o||o(i,u,e,r)){var f=i.primaryKey.toString();s.hasOwnProperty(f)||(s[f]=!0,t(n,i,u))}}var o=n.filter,s={},l=n.table.schema.primKey.keyPath,c=0;n.or._iterate(h,e,r,f);pi(u(n,f),n.algorithm,h,e,r,n.table.hook.reading.fire)}():pi(u(n,f),bi(n.algorithm,n.filter),t,i,r,n.table.hook.reading.fire)}function n(n){return n.table.schema.instanceTemplate}return{_read:function(n,t){var i=this._ctx;return i.error?i.table._trans(null,function(n,t){t(i.error)}):i.table._idbstore(ti,n).then(t)},_write:function(n){var t=this._ctx;return t.error?t.table._trans(null,function(n,i){i(t.error)}):t.table._idbstore(yt,n,"locked")},_addAlgorithm:function(n){var t=this._ctx;t.algorithm=bi(t.algorithm,n)},_iterate:function(n,t,r,u){return i(this._ctx,n,t,r,u)},each:function(t){var r=this._ctx;return e(function(){t(n(r))}),this._read(function(n,u,f){i(r,t,n,u,f)})},count:function(n){var f,t,u;return e(function(){n(0)}),f=this,t=this._ctx,t.filter||t.algorithm||t.or?(u=0,this._read(function(n,r,f){i(t,function(){return++u,!1},function(){n(u)},r,f)},n)):this._read(function(n,i,u){var e=r(t,u),s=t.range?e.count(t.range):e.count();s.onerror=o(i,["calling","count()","on",f.name]);s.onsuccess=function(i){n(Math.min(i.target.result,Math.max(0,t.limit-t.offset)))}},n)},sortBy:function(t,i){function u(n,t){return t?u(n[r[t]],t-1):n[h]}function c(n,t){var i=u(n,o),r=u(t,o);return i<r?-f:i>r?f:0}var s=this._ctx,f;e(function(){i([n(s)])});var r=t.split(".").reverse(),h=r[0],o=r.length-1;return f=this._ctx.dir==="next"?1:-1,this.toArray(function(n){return n.sort(c)}).then(i)},toArray:function(t){var r=this._ctx;return e(function(){t([n(r)])}),this._read(function(n,t,u){var f=[];i(r,function(n){f.push(n)},function(){n(f)},t,u)},t)},offset:function(n){var i=this._ctx;return n<=0?this:(i.offset+=n,i.or||i.algorithm||i.filter?t(i,function(){return--n<0}):t(i,function(t,i){return n===0?!0:n===1?(--n,!1):(i(function(){t.advance(n);n=0}),!1)}),this)},limit:function(n){return this._ctx.limit=Math.min(this._ctx.limit,n),t(this._ctx,function(t,i,r){return--n<=0&&i(r),n>=0}),this},until:function(i,r){var u=this._ctx;return e(function(){i(n(u))}),t(this._ctx,function(n,t,u){return i(n.value)?(t(u),r):!0}),this},first:function(t){var i=this;return e(function(){t(n(i._ctx))}),this.limit(1).toArray(function(n){return n[0]}).then(t)},last:function(n){return this.reverse().first(n)},and:function(i){var r=this;return e(function(){i(n(r._ctx))}),t(this._ctx,function(n){return i(n.value)}),f(this._ctx,i),this},or:function(n){return new ci(this._ctx.table,n,this)},reverse:function(){return this._ctx.dir=this._ctx.dir==="prev"?"next":"prev",this._ondirectionchange&&this._ondirectionchange(this._ctx.dir),this},desc:function(){return this.reverse()},eachKey:function(t){var i=this,r=this._ctx;return e(function(){t(n(i._ctx)[i._ctx.index])}),r.isPrimKey||(r.op="openKeyCursor"),this.each(function(n,i){t(i.key,i)})},eachUniqueKey:function(n){return this._ctx.unique="unique",this.eachKey(n)},keys:function(t){var u,i,r;return e(function(){t([n(i)[u._ctx.index]])}),u=this,i=this._ctx,i.isPrimKey||(i.op="openKeyCursor"),r=[],this.each(function(n,t){r.push(t.key)}).then(function(){return r}).then(t)},uniqueKeys:function(n){return this._ctx.unique="unique",this.keys(n)},firstKey:function(n){var t=this;return this.limit(1).keys(function(n){return n[0]}).then(n)},lastKey:function(n){return this.reverse().firstKey(n)},distinct:function(){var n={};return t(this._ctx,function(t){var i=t.primaryKey.toString(),r=n.hasOwnProperty(i);return n[i]=!0,!r}),this}}});y(rr).from(li).extend({modify:function(n){var a=this,t=this._ctx,r=t.table.hook,i=r.updating.fire,u=r.deleting.fire;return e(function(){typeof n=="function"&&n.call({value:t.table.schema.instanceTemplate},t.table.schema.instanceTemplate)}),this._write(function(r,e,v,y){function st(n,i){var r,u,f;if(et=i.primaryKey,r={primKey:i.primaryKey,value:n},w.call(r,n)!==!1)u=!r.hasOwnProperty("value"),f=u?i.delete():i.update(r.value),++ut,f.onerror=o(function(n){if(p.push(n),nt.push(r.primKey),r.onerror)r.onerror(n);return it(),!0},u?["deleting",n,"from",t.table.name]:["modifying",n,"on",t.table.name]),f.onsuccess=function(){if(r.onsuccess)r.onsuccess(r.value);++b;it()};else if(r.onsuccess)r.onsuccess(r.value)}function ot(n){return n&&(p.push(n),nt.push(et)),e(new d("Error modifying one or more objects",p,b,nt))}function it(){ft&&b+p.length===ut&&(p.length>0?ot():r(b))}var w,k,rt,g;typeof n=="function"?w=i===f&&u===f?n:function(t){var f=l(t),e,r;if(n.call(this,t)===!1)return!1;this.hasOwnProperty("value")?(e=dt(f,this.value),r=i.call(this,e,this.primKey,f,y),r&&(t=this.value,Object.keys(r).forEach(function(n){h(t,n,r[n])}))):u.call(this,this.primKey,t,y)}:i===f?(k=Object.keys(n),rt=k.length,w=function(t){for(var i,u,f=!1,r=0;r<rt;++r)i=k[r],u=n[i],c(t,i)!==u&&(h(t,i,u),f=!0);return f}):(g=n,n=tt(g),w=function(t){var u=!1,r=i.call(this,n,this.primKey,l(t),y);return r&&s(n,r),Object.keys(n).forEach(function(i){var r=n[i];c(t,i)!==r&&(h(t,i,r),u=!0)}),r&&(n=tt(g)),u});var ut=0,b=0,ft=!1,p=[],nt=[],et=null;a._iterate(st,function(){ft=!0;it()},ot,v)})},"delete":function(){return this.modify(function(){delete this.value})}});s(this,{Collection:li,Table:ei,Transaction:ir,Version:di,WhereClause:ci,WriteableCollection:rr,WriteableTable:tr});cr();hr.forEach(function(n){n(w)})}function f(){}function nt(n){return n}function lt(n,t){return n===nt?t:function(i){return t(n(i))}}function w(n,t){return function(){n.apply(this,arguments);t.apply(this,arguments)}}function at(n,t){return n===f?t:function(){var f=n.apply(this,arguments),r,u,e;return f!==i&&(arguments[0]=f),r=this.onsuccess,u=this.onerror,delete this.onsuccess,delete this.onerror,e=t.apply(this,arguments),r&&(this.onsuccess=this.onsuccess?w(r,this.onsuccess):r),u&&(this.onerror=this.onerror?w(u,this.onerror):u),e!==i?e:f}}function vt(n,t){return n===f?t:function(){var r=n.apply(this,arguments),f,e,u;return r!==i&&s(arguments[0],r),f=this.onsuccess,e=this.onerror,delete this.onsuccess,delete this.onerror,u=t.apply(this,arguments),f&&(this.onsuccess=this.onsuccess?w(f,this.onsuccess):f),e&&(this.onerror=this.onerror?w(e,this.onerror):e),r===i?u===i?i:u:u===i?r:s(r,u)}}function yt(n,t){return n===f?t:function(){return n.apply(this,arguments)===!1?!1:t.apply(this,arguments)}}function pt(n,t){return n===f?t:function(){return t.apply(this,arguments)===!1?!1:n.apply(this,arguments)}}function wt(n,t){return n===f?t:function(){n.apply(this,arguments);t.apply(this,arguments)}}function bt(n,t){return n===f?t:function(){var i=n.apply(this,arguments),r,u;return i&&typeof i.then=="function"?(r=this,u=arguments,i.then(function(){return t.apply(r,u)})):t.apply(this,arguments)}}function v(t){function i(n,t,i){if(Array.isArray(n))return c(n);if(typeof n=="object")return h(n);t||(t=yt);i||(i=f);var r={subscribers:[],fire:i,subscribe:function(n){r.subscribers.push(n);r.fire=t(r.fire,n)},unsubscribe:function(n){r.subscribers=r.subscribers.filter(function(t){return t!==n});r.fire=r.subscribers.reduce(t,i)}};return u[n]=e[n]=r,r}function h(t){Object.keys(t).forEach(function(r){var f=t[r],u;if(Array.isArray(f))i(r,t[r][0],t[r][1]);else if(f==="asap")u=i(r,null,function(){var t=arguments;u.subscribers.forEach(function(i){b(function(){i.apply(n,t)})})}),u.subscribe=function(n){u.subscribers.indexOf(n)===-1&&u.subscribers.push(n)},u.unsubscribe=function(n){var t=u.subscribers.indexOf(n);t!==-1&&u.subscribers.splice(t,1)};else throw new Error("Invalid event config");})}function c(n){function r(){if(t)return!1;t=!0}var t=!1;n.forEach(function(n){i(n).subscribe(r)})}var o=arguments,u={},e=function(n,i){if(i){var f=[].slice.call(arguments,1),r=u[n];return r.subscribe.apply(r,f),t}if(typeof n=="string")return u[n]},r,s;for(e.addEventType=i,r=1,s=o.length;r<s;++r)i(o[r]);return e}function kt(n){if(!n)throw new Error("Assertion failed");}function b(t){n.setImmediate?setImmediate(t):setTimeout(t,0)}function et(n){var t=setTimeout(n,1e3);clearTimeout(t)}function k(n,t,i){return function(){var u=r.PSD;r.PSD=i;try{n.apply(this,arguments)}catch(f){t(f)}finally{r.PSD=u}}}function c(n,t){var f,r,o,s,u,e;if(n.hasOwnProperty(t))return n[t];if(!t)return n;if(typeof t!="string"){for(f=[],r=0,o=t.length;r<o;++r)s=c(n,t[r]),f.push(s);return f}return(u=t.indexOf("."),u!==-1)?(e=n[t.substr(0,u)],e===i?i:c(e,t.substr(u+1))):i}function h(n,t,r){var u,c,e,f,s,o;if(n&&t!==i)if(typeof t!="string"&&"length"in t)for(kt(typeof r!="string"&&"length"in r),u=0,c=t.length;u<c;++u)h(n,t[u],r[u]);else e=t.indexOf("."),e!==-1?(f=t.substr(0,e),s=t.substr(e+1),s===""?r===i?delete n[f]:n[f]=r:(o=n[f],o||(o=n[f]={}),h(o,s,r))):r===i?delete n[t]:n[t]=r}function ot(n,t){h(n,t,i)}function tt(n){var i={};for(var t in n)n.hasOwnProperty(t)&&(i[t]=n[t]);return i}function l(n){var t,i,u,r;if(!n||typeof n!="object")return n;if(Array.isArray(n))for(t=[],i=0,u=n.length;i<u;++i)t.push(l(n[i]));else if(n instanceof Date)t=new Date,t.setTime(n.getTime());else{t=n.constructor?Object.create(n.constructor.prototype):{};for(r in n)n.hasOwnProperty(r)&&(t[r]=l(n[r]))}return t}function dt(n,t){var u={};for(var r in n)n.hasOwnProperty(r)&&(t.hasOwnProperty(r)?n[r]!==t[r]&&JSON.stringify(n[r])!=JSON.stringify(t[r])&&(u[r]=t[r]):u[r]=i);for(r in t)t.hasOwnProperty(r)&&!n.hasOwnProperty(r)&&(u[r]=t[r]);return u}function st(n){if(typeof n=="function")return new n;if(Array.isArray(n))return[st(n[0])];if(n&&typeof n=="object"){var t={};return it(t,n),t}return n}function it(n,t){Object.keys(t).forEach(function(i){var r=st(t[i]);n[i]=r})}function o(n,t){return function(i){var r=i&&i.target.error||new Error,u;return t&&(u=" occurred when "+t.map(function(n){switch(typeof n){case"function":return n();case"string":return n;default:return JSON.stringify(n)}}).join(" "),r.name?r.toString=function(){return r.name+u+(r.message?". "+r.message:"")}:r=r+u),n(r),i&&(i.stopPropagation&&i.stopPropagation(),i.preventDefault&&i.preventDefault()),!1}}function gt(n){try{throw n;}catch(t){return t}}function ht(n){n.preventDefault()}function rt(n){var t,i=u.dependencies.localStorage;if(!i)return n([]);try{t=JSON.parse(i.getItem("Dexie.DatabaseNames")||"[]")}catch(r){t=[]}n(t)&&i.setItem("Dexie.DatabaseNames",JSON.stringify(t))}function a(n,t,i,r,u,f,e){this.name=n;this.keyPath=t;this.unique=i;this.multi=r;this.auto=u;this.compound=f;this.dotted=e;var o=typeof t=="string"?t:t&&"["+[].join.call(t,"+")+"]";this.src=(i?"&":"")+(r?"*":"")+(u?"++":"")+o}function ut(n,t,i,r){this.name=n;this.primKey=t||new a;this.indexes=i||[new a];this.instanceTemplate=r;this.mappedClass=null;this.idxByName=i.reduce(function(n,t){return n[t.name]=t,n},{})}function d(n,t,i,r){this.name="ModifyError";this.failures=t;this.failedKeys=r;this.successCount=i;this.message=t.join("\n")}function ft(n){return n.length===1?n[0]:n}function ct(){var n=u.dependencies.indexedDB,t=n&&(n.getDatabaseNames||n.webkitGetDatabaseNames);return t&&t.bind(n)}var r=function(){function y(n){u.push([n,a.call(arguments,1)])}function p(){var r=u,t,f,i;for(u=[],t=0,f=r.length;t<f;++t)i=r[t],i[0].apply(n,i[1])}function t(n){if(typeof this!="object")throw new TypeError("Promises must be constructed via new");if(typeof n!="function")throw new TypeError("not a function");this._state=null;this._value=null;this._deferreds=[];this._catched=!1;var r=this,u=!0;this._PSD=t.PSD;try{k(this,n,function(n){u?i(c,r,n):c(r,n)},function(n){return u?(i(s,r,n),!1):s(r,n)})}finally{u=!1}}function o(n,f){var s,o,l,a,b,c;if(n._state===null){n._deferreds.push(f);return}if(s=n._state?f.onFulfilled:f.onRejected,s===null)return(n._state?f.resolve:f.reject)(n._value);l=r;r=!1;i=y;try{a=t.PSD;t.PSD=n._PSD;o=s(n._value);n._state||o&&typeof o.then=="function"&&o._state===!1||w(n);f.resolve(o)}catch(v){if(b=f.reject(v),!b&&n.onuncatched)try{n.onuncatched(v)}catch(v){}}finally{if(t.PSD=a,l){do{while(u.length>0)p();if(c=e.pop(),c)try{c()}catch(v){}}while(e.length>0||u.length>0);i=h;r=!0}}}function d(n){var f=r,t;r=!1;i=y;try{n()}finally{if(f){do{while(u.length>0)p();if(t=e.pop(),t)try{t()}catch(o){}}while(e.length>0||u.length>0);i=h;r=!0}}}function w(n){n._catched=!0;n._parent&&w(n._parent)}function c(n,i){var r=t.PSD;t.PSD=n._PSD;try{if(i===n)throw new TypeError("A promise cannot be resolved with itself.");if(i&&(typeof i=="object"||typeof i=="function")&&typeof i.then=="function"){k(n,function(n,t){i.then(n,t)},function(t){c(n,t)},function(t){s(n,t)});return}n._state=!0;n._value=i;b.call(n)}catch(u){s(u)}finally{t.PSD=r}}function s(n,i){var r=t.PSD;if(t.PSD=n._PSD,n._state=!1,n._value=i,b.call(n),!n._catched)try{if(n.onuncatched)n.onuncatched(n._value);t.on.error.fire(n._value)}catch(u){}return t.PSD=r,n._catched}function b(){for(var n=0,t=this._deferreds.length;n<t;n++)o(this,this._deferreds[n]);this._deferreds=[]}function l(n,t,i,r){this.onFulfilled=typeof n=="function"?n:null;this.onRejected=typeof t=="function"?t:null;this.resolve=i;this.reject=r}function k(n,t,i,r){var u=!1;try{t(function(n){u||(u=!0,i(n))},function(t){return u?n._catched:(u=!0,r(t))})}catch(f){return u?void 0:r(f)}}var a=[].slice,h=typeof setImmediate=="undefined"?function(t){var i=arguments;setTimeout(function(){t.apply(n,a.call(i,1))},0)}:setImmediate,i=h,r=!0,u=[],e=[];return t.on=v(null,"error"),t.all=function(){var n=Array.prototype.slice.call(arguments.length===1&&Array.isArray(arguments[0])?arguments[0]:arguments);return new t(function(t,i){function f(r,e){try{if(e&&(typeof e=="object"||typeof e=="function")){var o=e.then;if(typeof o=="function"){o.call(e,function(n){f(r,n)},i);return}}n[r]=e;--u==0&&t(n)}catch(s){i(s)}}var u,r;if(n.length===0)return t([]);for(u=n.length,r=0;r<n.length;r++)f(r,n[r])})},t.prototype.then=function(n,r){var f=this,u=new t(function(t,u){f._state===null?o(f,new l(n,r,t,u)):i(o,f,new l(n,r,t,u))});return u._PSD=this._PSD,u.onuncatched=this.onuncatched,u._parent=this,u},t.prototype._then=function(n,t){o(this,new l(n,t,f,f))},t.prototype["catch"]=function(n){if(arguments.length===1)return this.then(null,n);var i=arguments[0],r=arguments[1];return typeof i=="function"?this.then(null,function(n){return n instanceof i?r(n):t.reject(n)}):this.then(null,function(n){return n&&n.name===i?r(n):t.reject(n)})},t.prototype["finally"]=function(n){return this.then(function(t){return n(),t},function(i){return n(),t.reject(i)})},t.prototype.onuncatched=null,t.resolve=function(n){var i=new t(function(){});return i._state=!0,i._value=n,i},t.reject=function(n){var i=new t(function(){});return i._state=!1,i._value=n,i},t.race=function(n){return new t(function(t,i){n.map(function(n){n.then(t,i)})})},t.PSD=null,t.newPSD=function(n){var i=t.PSD;t.PSD=i?Object.create(i):{};try{return n()}finally{t.PSD=i}},t._rootExec=d,t._tickFinalize=function(n){if(r)throw new Error("Not in a virtual tick");e.push(n)},t}(),e=function(){},g;y(d).from(Error);u.delete=function(n){var t=new u(n),i=t.delete();return i.onblocked=function(n){t.on("blocked",n);return this},i};u.getDatabaseNames=function(n){return new r(function(n,t){var r=ct(),i;r?(i=r(),i.onsuccess=function(t){n([].slice.call(t.target.result,0))},i.onerror=o(t)):rt(function(t){return n(t),!1})}).then(n)};u.defineClass=function(n){function t(n){n&&s(this,n)}return it(t.prototype,n),t};u.ignoreTransaction=function(n){return r.newPSD(function(){return r.PSD.trans=null,n()})};u.spawn=function(){return n.console&&console.warn("Dexie.spawn() is deprecated. Use Dexie.ignoreTransaction() instead."),u.ignoreTransaction.apply(this,arguments)};u.vip=function(n){return r.newPSD(function(){return r.PSD.letThrough=!0,n()})};Object.defineProperty(u,"currentTransaction",{get:function(){return r.PSD&&r.PSD.trans||null}});u.Promise=r;u.derive=y;u.extend=s;u.override=p;u.events=v;u.getByKeyPath=c;u.setByKeyPath=h;u.delByKeyPath=ot;u.shallowClone=tt;u.deepClone=l;u.addons=[];u.fakeAutoComplete=e;u.asap=b;u.ModifyError=d;u.MultiModifyError=d;u.IndexSpec=a;u.TableSchema=ut;g=n.idbModules&&n.idbModules.shimIndexedDB?n.idbModules:{};u.dependencies={indexedDB:g.shimIndexedDB||n.indexedDB||n.mozIndexedDB||n.webkitIndexedDB||n.msIndexedDB,IDBKeyRange:g.IDBKeyRange||n.IDBKeyRange||n.webkitIDBKeyRange,IDBTransaction:g.IDBTransaction||n.IDBTransaction||n.webkitIDBTransaction,Error:n.Error||String,SyntaxError:n.SyntaxError||String,TypeError:n.TypeError||String,DOMError:n.DOMError||String,localStorage:(typeof chrome!="undefined"&&chrome!==null?chrome.storage:void 0)!=null?null:n.localStorage};u.version=1.1;t("Dexie",u);et(function(){e=et})}).apply(null,typeof define=="function"&&define.amd?[self||window,function(n,t){define(n,function(){return t})}]:typeof global!="undefined"&&typeof module!="undefined"&&module.exports?[global,function(n,t){module.exports=t}]:[self||window,function(n,t){(self||window)[n]=t}]);
37574//# sourceMappingURL=Dexie.min.js.map